diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
index c013b733db95dab9f2f4d87a3b15bf878f7c170d..8cf6f1c38caf14daf82243682ec4b15f8ee0abe2 100644
--- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
+++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
@@ -8,8 +8,8 @@
     const volScalarField& cp = tcp();
 
     tmp<volScalarField> tkappa = thermo.K();
-    //tmp<volSymmTensorField> tkappa = thermo.directionalkappa();
     const volScalarField& kappa = tkappa();
+    //tmp<volSymmTensorField> tkappa = thermo.directionalK();
     //const volSymmTensorField& kappa = tkappa();
 
     volScalarField& T = thermo.T();
diff --git a/applications/utilities/mesh/generation/cvMesh/Allwmake b/applications/utilities/mesh/generation/cvMesh/Allwmake
index 688b3be475c5d9b2a0edb096018b01042de929cc..f059754bab6f69f793ddfd156f50e914d3cf3d55 100755
--- a/applications/utilities/mesh/generation/cvMesh/Allwmake
+++ b/applications/utilities/mesh/generation/cvMesh/Allwmake
@@ -4,5 +4,6 @@ set -x
 
 wmake libso conformalVoronoiMesh
 wmake
+wmake cvMeshSurfaceSimplify
 
 # ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/files b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..73871a7532e1c273d0030d8c8bc4180e1ecef2a7
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/files
@@ -0,0 +1,3 @@
+checkCvMesh.C
+
+EXE = $(FOAM_APPBIN)/checkCvMesh
diff --git a/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..ba68fd3819b53037f9711dfbb9691846a215f4d3
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/Make/options
@@ -0,0 +1,14 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/triSurface/lnInclude \
+    -I$(LIB_SRC)/mesh/autoMesh/lnInclude \
+    -I$(LIB_SRC)/dynamicMesh/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -ldynamicMesh \
+    -ltriSurface \
+    -lautoMesh \
+    -lmeshTools
+
diff --git a/applications/utilities/mesh/generation/cvMesh/checkCvMesh/checkCvMesh.C b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/checkCvMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..df2a3b90f81834625c22ab8fc3b490c4c0b73d99
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/checkCvMesh.C
@@ -0,0 +1,122 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Application
+    checkCvMesh
+
+Description
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvMesh.H"
+#include "autoSnapDriver.H"
+#include "faceSet.H"
+#include "motionSmoother.H"
+#include "timeSelector.H"
+
+
+using namespace Foam;
+
+
+int main(int argc, char *argv[])
+{
+#   include "addOverwriteOption.H"
+
+#   include "setRootCase.H"
+#   include "createTime.H"
+
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+#   include "createMesh.H"
+
+    runTime.functionObjects().off();
+
+    forAll(timeDirs, timeI)
+    {
+        runTime.setTime(timeDirs[timeI], timeI);
+
+        Info<< "Create mesh for time = " << runTime.timeName()
+            << nl << endl;
+
+        mesh.readUpdate();
+
+        Info<< "Read mesh in = "
+            << runTime.cpuTimeIncrement() << " s" << endl;
+
+        // Check patches and faceZones are synchronised
+        mesh.boundaryMesh().checkParallelSync(true);
+        meshRefinement::checkCoupledFaceZones(mesh);
+
+        // Read meshing dictionary
+        IOdictionary cvMeshDict
+        (
+           IOobject
+           (
+                "cvMeshDict",
+                runTime.system(),
+                mesh,
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE
+           )
+        );
+
+        // mesh motion and mesh quality parameters
+        const dictionary& meshQualityDict
+            = cvMeshDict.subDict("meshQualityControls");
+
+
+        Info<< "Checking initial mesh ..." << endl;
+        faceSet wrongFaces(mesh, "wrongFaces", mesh.nFaces()/100);
+        motionSmoother::checkMesh(false, mesh, meshQualityDict, wrongFaces);
+
+        const label nInitErrors = returnReduce
+        (
+            wrongFaces.size(),
+            sumOp<label>()
+        );
+
+        Info<< "Detected " << nInitErrors << " illegal faces"
+            << " (concave, zero area or negative cell pyramid volume)"
+            << endl;
+
+        if (nInitErrors > 0)
+        {
+            Info<< "Writing " << nInitErrors
+                << " faces in error to set "
+                << wrongFaces.name() << endl;
+
+            wrongFaces.instance() = mesh.pointsInstance();
+            wrongFaces.write();
+        }
+
+        Info<< nl << "End of time " << runTime.timeName() << nl << endl;
+    }
+
+    Info<< "End\n" << endl;
+
+    return 0;
+
+}
+
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C
index edafdb50f912e02a89acc6133fc0d7cf7491cd5c..a2d44f0ee1ab506045eabdeac7ccb7300ad3d275 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C
@@ -724,6 +724,8 @@ void Foam::backgroundMeshDecomposition::buildPatchAndTree()
 
     globalBackgroundBounds_ = treeBoundBox(bbMin, bbMax);
 
+    octreeNearestDistances_ = bFTreePtr_().calcNearestDistance();
+
     if (cvMesh_.cvMeshControls().objOutput())
     {
         OFstream fStr
@@ -795,6 +797,7 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition
     ),
     boundaryFacesPtr_(),
     bFTreePtr_(),
+    octreeNearestDistances_(),
     allBackgroundMeshBounds_(Pstream::nProcs()),
     globalBackgroundBounds_(),
     decomposeDict_
@@ -1150,6 +1153,8 @@ bool Foam::backgroundMeshDecomposition::positionOnThisProcessor
     const point& pt
 ) const
 {
+//    return bFTreePtr_().findAnyOverlap(pt, 0.0);
+
     return
         bFTreePtr_().getVolumeType(pt)
      == indexedOctree<treeDataBPatch>::INSIDE;
@@ -1176,6 +1181,7 @@ bool Foam::backgroundMeshDecomposition::overlapsThisProcessor
     const treeBoundBox& box
 ) const
 {
+//    return !procBounds().contains(box);
     return !bFTreePtr_().findBox(box).empty();
 }
 
@@ -1183,9 +1189,11 @@ bool Foam::backgroundMeshDecomposition::overlapsThisProcessor
 bool Foam::backgroundMeshDecomposition::overlapsThisProcessor
 (
     const point& centre,
-    scalar radiusSqr
+    const scalar radiusSqr
 ) const
 {
+    //return bFTreePtr_().findAnyOverlap(centre, radiusSqr);
+
     return bFTreePtr_().findNearest(centre, radiusSqr).hit();
 }
 
@@ -1645,6 +1653,7 @@ Foam::labelListList Foam::backgroundMeshDecomposition::overlapsProcessors
 
         // If the sphere finds a nearest element of the patch, then it overlaps
         sphereOverlapsCandidate[sI] = bFTreePtr_().findNearest(c, rSqr).hit();
+        //sphereOverlapsCandidate[sI] = bFTreePtr_().findAnyOverlap(c, rSqr);
     }
 
     map().reverseDistribute
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H
index 87ab88af356873a7fc4f4512645ac46873806110..d8e6388cfb00e28d73c38928d9be482179689697 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H
@@ -111,6 +111,8 @@ class backgroundMeshDecomposition
         //- Search tree for the boundaryFaces_ patch
         autoPtr<indexedOctree<treeDataBPatch> > bFTreePtr_;
 
+        List<scalar> octreeNearestDistances_;
+
         //- The bounds of all background meshes on all processors
         treeBoundBoxList allBackgroundMeshBounds_;
 
@@ -225,16 +227,16 @@ public:
         //- Are the given positions inside the domain of this decomposition
         boolList positionOnThisProcessor(const List<point>& pts) const;
 
-        //- Does the given box overlap the faces of the bounday of this
+        //- Does the given box overlap the faces of the boundary of this
         //  processor
         bool overlapsThisProcessor(const treeBoundBox& box) const;
 
-        //- Does the given sphere overlap the faces of the bounday of this
+        //- Does the given sphere overlap the faces of the boundary of this
         //  processor
         bool overlapsThisProcessor
         (
             const point& centre,
-            scalar radiusSqr
+            const scalar radiusSqr
         ) const;
 
         //- Find nearest intersection of line between start and end, (exposing
@@ -289,6 +291,12 @@ public:
             //- Return access to the underlying mesh
             inline const fvMesh& mesh() const;
 
+            //- Return access to the underlying tree
+            inline const indexedOctree<treeDataBPatch>& tree() const;
+
+            //- Return access to the nearest distance of the octree nodes
+            inline const List<scalar>& octreeNearestDistances() const;
+
             //- Return the boundBox of this processor
             inline const treeBoundBox& procBounds() const;
 };
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H
index df659cfd9cc0fed0f996b2bb97ff0b68622a1dcf..2897d3fc5830e133ba305b23436df6f829ccff99 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H
@@ -30,6 +30,18 @@ const Foam::fvMesh& Foam::backgroundMeshDecomposition::mesh() const
     return mesh_;
 }
 
+const Foam::indexedOctree<Foam::treeDataBPatch>&
+Foam::backgroundMeshDecomposition::tree() const
+{
+    return bFTreePtr_();
+}
+
+const Foam::List<Foam::scalar>&
+Foam::backgroundMeshDecomposition::octreeNearestDistances() const
+{
+    return octreeNearestDistances_;
+}
+
 
 const Foam::treeBoundBox& Foam::backgroundMeshDecomposition::procBounds() const
 {
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H
index 4b6c53bc2acb1eae64104a600358f67585e159dc..c813b9fe513e409e14f481ecee01caff978240a7 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -122,6 +122,10 @@ public:
             //- Return the surface indices
             inline const labelList& surfaces() const;
 
+            //- In regions where no cell size function is specified
+            // use defaultCellSize
+            inline scalar defaultCellSize() const;
+
         // Query
 
             //- Return the cell size at the given location
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfacesI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfacesI.H
index 57dca8cad40cef4dd365f368efa54b283473a490..973638d003ac681c43207ccd57557c848bff9736 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfacesI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfacesI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -37,4 +37,10 @@ const Foam::labelList& Foam::cellSizeControlSurfaces::surfaces() const
 }
 
 
+Foam::scalar Foam::cellSizeControlSurfaces::defaultCellSize() const
+{
+    return defaultCellSize_;
+}
+
+
 // ************************************************************************* //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
index e8cedc49c2cbd5e05256b513c4be1250f8140e4f..958fcf6763ec79332bf98faee94882df8eb0c640 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
@@ -240,9 +240,9 @@ void Foam::conformalVoronoiMesh::insertPoints
     {
         label preDistributionSize(points.size());
 
-        DynamicList<Foam::point> transferPoints(points.size()/2);
+        DynamicList<Foam::point> transferPoints;
 
-        DynamicList<Point> pointsOnProcessor(points.size()/2);
+        DynamicList<Point> pointsOnProcessor;
 
         for
         (
@@ -277,12 +277,16 @@ void Foam::conformalVoronoiMesh::insertPoints
             decomposition_().distributePoints(transferPoints)
         );
 
+        const label oldSize = points.size();
+
+        points.setSize(oldSize + transferPoints.size());
+
         forAll(transferPoints, tPI)
         {
-            points.append(toPoint(transferPoints[tPI]));
+            points[tPI + oldSize] = toPoint(transferPoints[tPI]);
         }
 
-        label sizeChange = preDistributionSize - label(points.size());
+        label sizeChange = preDistributionSize - points.size();
 
         // if (mag(sizeChange) > 0)
         // {
@@ -417,7 +421,6 @@ void Foam::conformalVoronoiMesh::insertPoints
 //        );
 //    }
 
-
     rangeInsertWithInfo
     (
         pts.begin(),
@@ -1246,6 +1249,8 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh
     // better balance the surface conformation load.
     distributeBackground();
 
+//    conformToSurface();
+
     buildSurfaceConformation(rmCoarse);
 
     // The introduction of the surface conformation may have distorted the
@@ -1313,7 +1318,7 @@ void Foam::conformalVoronoiMesh::move()
         {
             cit->cellIndex() = dualVertI;
 
-            dualVertices[dualVertI] = topoint(dual(cit));
+            dualVertices[dualVertI] = cit->dual();
 
             dualVertI++;
         }
@@ -1511,7 +1516,6 @@ void Foam::conformalVoronoiMesh::move()
                             (
                                 toPoint(0.5*(dVA + dVB))
                             );
-
                         }
                     }
                     else if
@@ -1671,9 +1675,57 @@ void Foam::conformalVoronoiMesh::move()
 
     insertPoints(pointsToInsert);
 
+    // Remove internal points that have been inserted outside the surface.
+    label internalPtIsOutside = 0;
+
+    for
+    (
+        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+        vit != finite_vertices_end();
+        ++vit
+    )
+    {
+        if (vit->internalPoint())
+        {
+            bool inside
+                = geometryToConformTo_.inside(topoint(vit->point()));
+
+            if (!inside)
+            {
+                remove(vit);
+                internalPtIsOutside++;
+            }
+        }
+    }
+
+    Info<< "    " << internalPtIsOutside
+        << " internal points were inserted outside the domain. "
+        << "They have been removed." << endl;
+
+    // Fix points that have not been significantly displaced
+//    for
+//    (
+//        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+//        vit != finite_vertices_end();
+//        ++vit
+//    )
+//    {
+//        if (vit->internalPoint())
+//        {
+//            if
+//            (
+//                mag(displacementAccumulator[vit->index()])
+//              < 0.1*targetCellSize(topoint(vit->point()))
+//            )
+//            {
+//                vit->setVertexFixed();
+//            }
+//        }
+//    }
+
     if (cvMeshControls().objOutput() && runTime_.outputTime())
     {
-        writePoints("points_" + runTime_.timeName() + ".obj", false);
+        writePoints("points_" + runTime_.timeName() + ".obj", true);
     }
 
     timeCheck("Internal points inserted");
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
index b590eb31cd67383146216cfbdc4f211a38397137..a514c660a1d96350897478ca826dba7efe5af1d8 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
@@ -48,7 +48,6 @@ SourceFiles
 #define CGAL_INEXACT
 
 #include "CGALTriangulation3Ddefs.H"
-#include <CGAL/Spatial_sort_traits_adapter_3.h>
 #include "uint.H"
 #include "ulong.H"
 #include "searchableSurfaces.H"
@@ -595,6 +594,12 @@ private:
             Foam::point& b
         ) const;
 
+        label removeProcessorBoundarySeeds(bool reinsertBoundPts);
+
+        void seedProcessorBoundarySurfaces(bool seedProcessors);
+
+        label numberOfUnusedReferredPoints() const;
+
         //- Build the parallelInterfaces of the mesh
         void buildParallelInterface
         (
@@ -1240,7 +1245,7 @@ public:
                     Traits_for_spatial_sort<Triangulation>()
                 );
 
-                typename Triangulation::Cell_handle hint;
+                typename Triangulation::Vertex_handle hint;
 
                 for
                 (
@@ -1250,16 +1255,9 @@ public:
                     ++p
                 )
                 {
-                    typename Triangulation::Locate_type lt;
-                    typename Triangulation::Cell_handle c;
-                    label li, lj;
-
-                    c = T.locate(*(p->first), lt, li, lj, hint);
-
                     const size_t checkInsertion = T.number_of_vertices();
 
-                    typename Triangulation::Vertex_handle v
-                        = T.insert(*(p->first), lt, c, li, lj);
+                    hint = T.insert(*(p->first), hint);
 
                     if (checkInsertion != T.number_of_vertices() - 1)
                     {
@@ -1278,12 +1276,11 @@ public:
                             // type directly (note that this routine never gets
                             // called for referredPoints so type will never be
                             // -procI
-                            type += T.number_of_vertices() - 1;
+                            type += checkInsertion;
                         }
 
-                        v->index() = indices[oldIndex]
-                                   + T.number_of_vertices() - 1;
-                        v->type() = type;
+                        hint->index() = indices[oldIndex] + checkInsertion;
+                        hint->type() = type;
                     }
                 }
             }
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
index 04ef2af045d22226200bce8d1943ec4ed9438696..d103d3c0fcb1ff968452105319a3c304e5a65578 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
@@ -1890,7 +1890,7 @@ void Foam::conformalVoronoiMesh::indexDualVertices
         {
             cit->cellIndex() = dualVertI;
 
-            pts[dualVertI] = topoint(dual(cit));
+            pts[dualVertI] = cit->dual();
 
             if
             (
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
index 847974a2f4ed3c01bdc652fe52baafafcb8bc96c..7f4c7abb6ef2cd34a4513fda2e94a41cf5af0d9b 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
@@ -41,6 +41,11 @@ void Foam::conformalVoronoiMesh::conformToSurface()
 {
     reconformationMode reconfMode = reconformationControl();
 
+    if (Pstream::parRun())
+    {
+        seedProcessorBoundarySurfaces(true);
+    }
+
     if (reconfMode == rmNone)
     {
         // Reinsert stored surface conformation
@@ -69,6 +74,16 @@ void Foam::conformalVoronoiMesh::conformToSurface()
         storeSurfaceConformation();
     }
 
+    if (Pstream::parRun())
+    {
+        label nFarPoints = removeProcessorBoundarySeeds(true);
+
+        reduce(nFarPoints, sumOp<label>());
+
+        Info<< "    Removed " << nFarPoints
+            << " far points from the mesh." << endl;
+    }
+
     // reportSurfaceConformationQuality();
 }
 
@@ -140,13 +155,8 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
     buildEdgeLocationTree(existingEdgeLocations);
     buildSurfacePtLocationTree(existingSurfacePtLocations);
 
-
-    // Initialise the edgeLocationTree
-    //buildEdgeLocationTree(edgeLocationTree, existingEdgeLocations);
-
     label initialTotalHits = 0;
 
-
     // Surface protrusion conformation is done in two steps.
     // 1. the dual edges (of all internal vertices) can stretch to
     //    'infinity' so any intersection would be badly behaved. So
@@ -382,7 +392,7 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
         (
             Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
             vit != finite_vertices_end();
-            vit++
+            ++vit
         )
         {
             // The initial surface conformation has already identified the
@@ -511,14 +521,18 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
 
         timeCheck("Conformation iteration " + name(iterationNo));
 
-        // Update the parallel interface
-        buildParallelInterface
-        (
-            referralVertices,
-            receivedVertices,
-            false,
-            name(iterationNo)
-        );
+        // Only need to update the interface if there are surface/edge hits
+        if (totalHits > 0)
+        {
+            // Update the parallel interface
+            buildParallelInterface
+            (
+                referralVertices,
+                receivedVertices,
+                false,
+                name(iterationNo)
+            );
+        }
 
         iterationNo++;
 
@@ -563,8 +577,8 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAnyIntersection
             continue;
         }
 
-        Foam::point dE0 = topoint(dual(fit->first));
-        Foam::point dE1 = topoint(dual(fit->first->neighbor(fit->second)));
+        Foam::point dE0 = fit->first->dual();
+        Foam::point dE1 = fit->first->neighbor(fit->second)->dual();
 
         if (Pstream::parRun())
         {
@@ -631,8 +645,8 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections
 
         // Construct the dual edge and search for intersections of the edge
         // with the surface
-        Foam::point dE0 = topoint(dual(fit->first));
-        Foam::point dE1 = topoint(dual(fit->first->neighbor(fit->second)));
+        Foam::point dE0 = fit->first->dual();
+        Foam::point dE1 = fit->first->neighbor(fit->second)->dual();
 
         pointIndexHit infoIntersection;
         label hitSurfaceIntersection = -1;
@@ -801,6 +815,144 @@ void Foam::conformalVoronoiMesh::buildParallelInterface
 }
 
 
+Foam::label Foam::conformalVoronoiMesh::removeProcessorBoundarySeeds
+(
+    bool reinsertBoundPts
+)
+{
+    label nFarPoints = 0;
+
+
+
+    std::list<Vertex_handle> toRemove;
+
+    for
+    (
+        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+        vit != finite_vertices_end();
+        ++vit
+    )
+    {
+        if (vit->farPoint())
+        {
+            //remove(vit);
+            toRemove.push_back(vit);
+            nFarPoints++;
+        }
+    }
+
+    // This function removes the points in the iterator range and then
+    // retriangulates.
+    timeCheck("Start Removing Seeded Points " + name(toRemove.size()));
+
+    remove_cluster(toRemove.begin(), toRemove.end());
+
+
+    // Need to do this to make sure the triangulation is well-behaved
+    if (reinsertBoundPts)
+    {
+        reinsertBoundingPoints();
+    }
+
+
+
+//    DynamicList<Foam::point> toAdd;
+//    DynamicList<label> indices;
+//    DynamicList<label> types;
+//
+//    for
+//    (
+//        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+//        vit != finite_vertices_end();
+//        ++vit
+//    )
+//    {
+//        if (!vit->farPoint())
+//        {
+//            toAdd.append(topoint(vit->point()));
+//            indices.append(vit->index());
+//            types.append(vit->type());
+//
+//            nFarPoints++;
+//        }
+//    }
+//
+//    this->clear();
+//
+//    // Need to do this to make sure the triangulation is well-behaved
+//    if (reinsertBoundPts)
+//    {
+//        reinsertBoundingPoints();
+//    }
+//
+//    forAll(toAdd, pI)
+//    {
+//        insertPoint(toAdd[pI], indices[pI], types[pI]);
+//    }
+
+
+    timeCheck("End Removing Seeded Points");
+
+    return nFarPoints;
+}
+
+
+void Foam::conformalVoronoiMesh::seedProcessorBoundarySurfaces
+(
+    bool seedProcessors
+)
+{
+    //removeProcessorBoundarySeeds(false);
+
+    // Loop over processor patch faces and insert a point in the centre of the
+    // face
+    const fvMesh& mesh = decomposition_().mesh();
+    const polyBoundaryMesh& bMesh = mesh.boundaryMesh();
+
+    DynamicList<Foam::point> pts;
+    DynamicList<label> indices;
+    DynamicList<label> types;
+
+    label nFarPoints = 0;
+
+    const scalar normalDistance = 5.0;
+    const scalar pert = 0.1*(rndGen_.scalar01() - 0.5);
+
+    forAll(bMesh, patchI)
+    {
+        const polyPatch& patch = bMesh[patchI];
+
+        if (!seedProcessors && isA<processorPolyPatch>(patch))
+        {
+            continue;
+        }
+
+        forAll(patch, faceI)
+        {
+            if (faceI % 1 == 0)
+            {
+                const face& f = patch[faceI];
+
+                pts.append
+                (
+                    f.centre(mesh.points())
+                  + pert*normalDistance*f.normal(mesh.points())
+                );
+                indices.append(nFarPoints++);
+                types.append(Vb::vtFar);
+            }
+        }
+    }
+
+    insertPoints(pts, indices, types, false);
+
+    reduce(nFarPoints, sumOp<label>());
+
+    Info<< "    Inserted " << nFarPoints
+        << " far points into the mesh." << endl;
+}
+
+
 void Foam::conformalVoronoiMesh::buildParallelInterface
 (
     List<labelHashSet>& referralVertices,
@@ -835,22 +987,88 @@ void Foam::conformalVoronoiMesh::buildParallelInterface
         timeCheck("After buildParallelInterfaceAll");
     }
 
-    if (initialEdgeReferral)
-    {
-        // Used as an initial pass to localise the vertex referring - find
-        // vertices whose dual edges pierce nearby processor volumes and refer
-        // them to establish a sensible boundary interface region before
-        // running a circumsphere assessment.
 
-        buildParallelInterfaceIntersection
-        (
-            referralVertices,
-            receivedVertices,
-            outputName
-        );
+    // Reject points that are not near the boundary from the subsequent
+    // searches
 
-        timeCheck("After buildParallelInterfaceIntersection");
-    }
+//    label nearProcCount = 0;
+//    label notNearProcCount = 0;
+//    boundBox quickRejectionBox(decomposition_().procBounds());
+//
+////    Pout<< "Processor boundBox: " << quickRejectionBox << endl;
+//
+//    quickRejectionBox.inflate(-0.1);
+//
+//    OFstream str("rejectionBox_" + name(Pstream::myProcNo()) + ".obj");
+//
+//    meshTools::writeOBJ
+//    (
+//        str,
+//        boundBox::faces(),
+//        quickRejectionBox.points()
+//    );
+//
+//    Pout<< "Inflated rejection boundBox: " << quickRejectionBox << endl;
+
+//    for
+//    (
+//        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+//        vit != finite_vertices_end();
+//        vit++
+//    )
+//    {
+//        if (vit->real() && !vit->nearProcBoundary())
+//        {
+//            const Foam::point& pt = topoint(vit->point());
+//            const scalar range = targetCellSize(pt);
+//
+////            if
+////            (
+////                decomposition_().overlapsThisProcessor
+////                (
+////                    pt,
+////                    range
+////                )
+////            )
+//            if (!quickRejectionBox.contains(pt))
+//            {
+//                vit->setNearProcBoundary();
+//                nearProcCount++;
+//            }
+//            else
+//            {
+//                //vit->setNearProcBoundary();
+//                notNearProcCount++;
+//            }
+//        }
+//    }
+//
+//    reduce(nearProcCount, sumOp<label>());
+//    reduce(notNearProcCount, sumOp<label>());
+//
+//    timeCheck
+//    (
+//        "End of potential intersection search. "
+//      + name(nearProcCount) + " are near a processor boundary. "
+//      + name(notNearProcCount) + " are not."
+//    );
+
+//    if (initialEdgeReferral)
+//    {
+//        // Used as an initial pass to localise the vertex referring - find
+//        // vertices whose dual edges pierce nearby processor volumes and refer
+//        // them to establish a sensible boundary interface region before
+//        // running a circumsphere assessment.
+//
+//        buildParallelInterfaceIntersection
+//        (
+//            referralVertices,
+//            receivedVertices,
+//            outputName
+//        );
+//
+//        timeCheck("After buildParallelInterfaceIntersection");
+//    }
 
     buildParallelInterfaceInfluence
     (
@@ -860,6 +1078,56 @@ void Foam::conformalVoronoiMesh::buildParallelInterface
     );
 
     timeCheck("After buildParallelInterface");
+
+    // Check all referred vertices are actually used on the processor.
+    label nUnusedReferred = numberOfUnusedReferredPoints();
+
+    reduce(nUnusedReferred, sumOp<label>());
+
+    Info<< "    Number of referred points that are not used : "
+        << nUnusedReferred << " (approximate)" << endl;
+}
+
+
+Foam::label Foam::conformalVoronoiMesh::numberOfUnusedReferredPoints() const
+{
+    label nUnusedPoints = 0;
+
+    for
+    (
+        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+        vit != finite_vertices_end();
+        ++vit
+    )
+    {
+        if (vit->referred())
+        {
+            std::list<Vertex_handle> adjVertices;
+            finite_adjacent_vertices(vit, std::back_inserter(adjVertices));
+
+            bool isUsed = false;
+
+            for
+            (
+                std::list<Vertex_handle>::iterator adjVit = adjVertices.begin();
+                adjVit != adjVertices.end();
+                ++adjVit
+            )
+            {
+                if ((*adjVit)->real())
+                {
+                    isUsed = true;
+                }
+            }
+
+            if (!isUsed)
+            {
+                nUnusedPoints++;
+            }
+        }
+    }
+
+    return nUnusedPoints;
 }
 
 
@@ -880,7 +1148,7 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceAll
     (
         Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
         vit != finite_vertices_end();
-        vit++
+        ++vit
     )
     {
         if (!vit->farPoint())
@@ -966,7 +1234,10 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceIntersection
 
         // If either Delaunay cell at the end of the Dual edge is infinite,
         // skip.
-        if (!is_infinite(c1) && !is_infinite(c2))
+        if
+        (
+            !is_infinite(c1) && !is_infinite(c2)
+        )
         {
             // The Delaunauy cells at either end of the dual edge need to be
             // real, i.e. all vertices form part of the internal or boundary
@@ -977,12 +1248,14 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceIntersection
              && c2->internalOrBoundaryDualVertex()
             )
             {
-                Foam::point a = topoint(dual(c1));
-                Foam::point b = topoint(dual(c2));
+                const Foam::point& a = c1->dual();
+                const Foam::point& b = c2->dual();
 
                 // Only if the dual edge cuts the boundary of this processor is
                 // it going to be counted.
-                if (decomposition_().findLineAny(a, b).hit())
+                pointIndexHit info = decomposition_().findLineAny(a, b);
+
+                if (info.hit())
                 {
                     dE0.append(a);
                     dE1.append(b);
@@ -995,11 +1268,22 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceIntersection
         fIOuter++;
     }
 
+    reduce(fIOuter, sumOp<label>());
+
+    timeCheck
+    (
+        "End of actual intersection search over "
+      + name(fIOuter)
+      + " faces."
+    );
+
     // Preform intersections in both directions, as there is no sense
     // associated with the Dual edge
     List<List<pointIndexHit> > intersectionForward(intersectsProc(dE0, dE1));
     List<List<pointIndexHit> > intersectionReverse(intersectsProc(dE1, dE0));
 
+    timeCheck("End of find processor intersection");
+
     // Reset counter
     fIOuter = 0;
 
@@ -1175,13 +1459,58 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
     DynamicList<Foam::point> circumcentre;
     DynamicList<scalar> circumradiusSqr;
 
-    PackedBoolList testCellInfluence(number_of_cells(), false);
 
     // Index outer (all) Delaunauy cells for whether they are potential
     // overlaps, index (inner) the list of tests an results.
     label cIInner = 0;
     label cIOuter = 0;
 
+
+    label cellIndexCount = 0;
+    for
+    (
+        Delaunay::Finite_cells_iterator cit = finite_cells_begin();
+        cit != finite_cells_end();
+        ++cit
+    )
+    {
+        cit->cellIndex() = cellIndexCount++;
+    }
+
+    timeCheck("End of cell Indexing");
+
+    labelList testCellInfluence(number_of_cells(), 0);
+
+    label nQuickRejections = 0;
+
+    for
+    (
+        Delaunay::Finite_cells_iterator cit = finite_cells_begin();
+        cit != finite_cells_end();
+        ++cit
+    )
+    {
+        const Foam::point& cc = cit->dual();
+
+        const scalar crSqr = magSqr(cc - topoint(cit->vertex(0)->point()));
+
+        if
+        (
+            decomposition_().tree().quickCircumsphereRejection
+            (
+                cc,
+                crSqr,
+                decomposition_().octreeNearestDistances()
+            )
+        )
+        {
+            nQuickRejections++;
+            testCellInfluence[cit->cellIndex()] = -1;
+        }
+    }
+
+    timeCheck("End of octreeNearestDistances calculation");
+
     for
     (
         Delaunay::Finite_cells_iterator cit = finite_cells_begin();
@@ -1196,14 +1525,15 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
 
         // The Delaunay cells to assess have to be real, i.e. all vertices form
         // part of the internal or any part of the boundary definition
-        if (cit->real())
+        if
+        (
+            (testCellInfluence[cit->cellIndex()] == 0)
+         && (cit->real() || cit->hasFarPoint())
+        )
         {
-            Foam::point cc(topoint(dual(cit)));
+            const Foam::point& cc = cit->dual();
 
-            scalar crSqr
-            (
-                magSqr(cc - topoint(cit->vertex(0)->point()))
-            );
+            const scalar crSqr = magSqr(cc - topoint(cit->vertex(0)->point()));
 
             // Only if the circumsphere overlaps the boundary of this processor
             // is there a chance of it overlapping others
@@ -1212,7 +1542,7 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
                 circumcentre.append(cc);
                 circumradiusSqr.append(crSqr);
 
-                testCellInfluence[cIOuter] = true;
+                testCellInfluence[cit->cellIndex()] = 1;
             }
         }
 
@@ -1221,6 +1551,9 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
 
     timeCheck("End of testing cell influence");
 
+    Pout<< "Number of quick rejections = " << nQuickRejections << endl;
+    Pout<< "Number of influences = " << circumcentre.size() << endl;
+
     // Increasing the circumspheres to increase the overlaps and compensate for
     // floating point errors missing some referrals
     labelListList circumsphereOverlaps
@@ -1242,7 +1575,7 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
     )
     {
         // Pre-tested circumsphere potential influence
-        if (testCellInfluence[cIOuter])
+        if (testCellInfluence[cit->cellIndex()] == 1)
         {
             const labelList& citOverlaps = circumsphereOverlaps[cIInner];
 
@@ -1289,6 +1622,70 @@ void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence
         cIOuter++;
     }
 
+
+//    label nFarPoints = removeProcessorBoundarySeeds(true);
+//
+//    reduce(nFarPoints, sumOp<label>());
+//
+//    Info<< "    Removed " << nFarPoints
+//        << " far points from the mesh." << endl;
+
+
+//    seedProcessorBoundarySurfaces(false);
+
+//    cIInner = 0;
+//    cIOuter = 0;
+
+
+    // Relying on the order of iteration of cells being the same as before
+//    for
+//    (
+//        Delaunay::Finite_cells_iterator cit = finite_cells_begin();
+//        cit != finite_cells_end();
+//        ++cit
+//    )
+//    {
+//        // Pre-tested circumsphere potential influence
+//        if (testCellInfluence[cIOuter])
+//        {
+//            const labelList& citOverlaps = circumsphereOverlaps[cIInner];
+//
+//            forAll(citOverlaps, cOI)
+//            {
+//                label procI = citOverlaps[cOI];
+//
+//                recursiveCircumsphereSearch
+//                (
+//                    cit,
+//                    procI,
+//                    referralVertices,
+//                    checkedCells,
+//                    parallelInfluencePoints,
+//                    parallelInfluenceIndices,
+//                    targetProcessor
+//                );
+//            }
+//
+//            cIInner++;
+//        }
+//
+//        cIOuter++;
+//    }
+
+//    for
+//    (
+//        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+//        vit != finite_vertices_end();
+//        ++vit
+//    )
+//    {
+//        if (vit->referred())
+//        {
+//            //Pout << "REMOVE: " << topoint(vit->point()) << endl;
+//            remove(vit);
+//        }
+//    }
+
     referVertices
     (
         targetProcessor,
@@ -1344,6 +1741,8 @@ void Foam::conformalVoronoiMesh::referVertices
         );
     }
 
+    timeCheck("Start of referVertices " + stageName + " insertion.");
+
     for (label procI = 0; procI < Pstream::nProcs(); procI++)
     {
         const labelList& constructMap = pointMap.constructMap()[procI];
@@ -1397,7 +1796,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion
     hitSurfaceLargest = -1;
 
     std::list<Facet> facets;
-    incident_facets(vit, std::back_inserter(facets));
+    finite_incident_facets(vit, std::back_inserter(facets));
 
     const Foam::point vert = topoint(vit->point());
 
@@ -1410,52 +1809,45 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion
         ++fit
     )
     {
-        if
+        const Foam::point edgeMid =
+            0.5
+           *(
+                fit->first->dual()
+              + fit->first->neighbor(fit->second)->dual()
+            );
+
+        pointIndexHit surfHit;
+        label hitSurface;
+
+        geometryToConformTo_.findSurfaceAnyIntersection
         (
-            !is_infinite(fit->first)
-         && !is_infinite(fit->first->neighbor(fit->second))
-        )
-        {
-            const Foam::point edgeMid =
-                0.5
-               *(
-                    topoint(dual(fit->first))
-                  + topoint(dual(fit->first->neighbor(fit->second)))
-                );
+            vert,
+            edgeMid,
+            surfHit,
+            hitSurface
+        );
 
-            pointIndexHit surfHit;
-            label hitSurface;
+        if (surfHit.hit())
+        {
+            vectorField norm(1);
 
-            geometryToConformTo_.findSurfaceAnyIntersection
+            allGeometry_[hitSurface].getNormal
             (
-                vert,
-                edgeMid,
-                surfHit,
-                hitSurface
+                List<pointIndexHit>(1, surfHit),
+                norm
             );
 
-            if (surfHit.hit())
-            {
-                vectorField norm(1);
-
-                allGeometry_[hitSurface].getNormal
-                (
-                    List<pointIndexHit>(1, surfHit),
-                    norm
-                );
-
-                const vector& n = norm[0];
+            const vector& n = norm[0];
 
-                const scalar normalProtrusionDistance =
-                    (edgeMid - surfHit.hitPoint()) & n;
+            const scalar normalProtrusionDistance =
+                (edgeMid - surfHit.hitPoint()) & n;
 
-                if (normalProtrusionDistance > maxProtrusionDistance)
-                {
-                    surfHitLargest = surfHit;
-                    hitSurfaceLargest = hitSurface;
+            if (normalProtrusionDistance > maxProtrusionDistance)
+            {
+                surfHitLargest = surfHit;
+                hitSurfaceLargest = hitSurface;
 
-                    maxProtrusionDistance = normalProtrusionDistance;
-                }
+                maxProtrusionDistance = normalProtrusionDistance;
             }
         }
     }
@@ -1489,9 +1881,9 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceIncursion
     hitSurfaceLargest = -1;
 
     std::list<Facet> facets;
-    incident_facets(vit, std::back_inserter(facets));
+    finite_incident_facets(vit, std::back_inserter(facets));
 
-    Foam::point vert(topoint(vit->point()));
+    const Foam::point vert = topoint(vit->point());
 
     scalar minIncursionDistance = -maxSurfaceProtrusion(vert);
 
@@ -1502,57 +1894,50 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceIncursion
         ++fit
     )
     {
-        if
+        const Foam::point edgeMid =
+            0.5
+           *(
+                fit->first->dual()
+              + fit->first->neighbor(fit->second)->dual()
+            );
+
+        pointIndexHit surfHit;
+        label hitSurface;
+
+        geometryToConformTo_.findSurfaceAnyIntersection
         (
-            !is_infinite(fit->first)
-         && !is_infinite(fit->first->neighbor(fit->second))
-        )
-        {
-            Foam::point edgeMid =
-                0.5
-               *(
-                    topoint(dual(fit->first))
-                  + topoint(dual(fit->first->neighbor(fit->second)))
-                );
+            vert,
+            edgeMid,
+            surfHit,
+            hitSurface
+        );
 
-            pointIndexHit surfHit;
-            label hitSurface;
+        if (surfHit.hit())
+        {
+            vectorField norm(1);
 
-            geometryToConformTo_.findSurfaceAnyIntersection
+            allGeometry_[hitSurface].getNormal
             (
-                vert,
-                edgeMid,
-                surfHit,
-                hitSurface
+                List<pointIndexHit>(1, surfHit),
+                norm
             );
 
-            if (surfHit.hit())
-            {
-                vectorField norm(1);
-
-                allGeometry_[hitSurface].getNormal
-                (
-                    List<pointIndexHit>(1, surfHit),
-                    norm
-                );
-
-                const vector& n = norm[0];
+            const vector& n = norm[0];
 
-                scalar normalIncursionDistance =
-                    (edgeMid - surfHit.hitPoint()) & n;
+            scalar normalIncursionDistance =
+                (edgeMid - surfHit.hitPoint()) & n;
 
-                if (normalIncursionDistance < minIncursionDistance)
-                {
-                    surfHitLargest = surfHit;
-                    hitSurfaceLargest = hitSurface;
+            if (normalIncursionDistance < minIncursionDistance)
+            {
+                surfHitLargest = surfHit;
+                hitSurfaceLargest = hitSurface;
 
-                    minIncursionDistance = normalIncursionDistance;
+                minIncursionDistance = normalIncursionDistance;
 
-                    // Info<< nl << "# Incursion: " << endl;
-                    // meshTools::writeOBJ(Info, vert);
-                    // meshTools::writeOBJ(Info, edgeMid);
-                    // Info<< "l Na Nb" << endl;
-                }
+                // Info<< nl << "# Incursion: " << endl;
+                // meshTools::writeOBJ(Info, vert);
+                // meshTools::writeOBJ(Info, edgeMid);
+                // Info<< "l Na Nb" << endl;
             }
         }
     }
@@ -1948,6 +2333,35 @@ bool Foam::conformalVoronoiMesh::appendToEdgeLocationTree
 }
 
 
+Foam::List<Foam::pointIndexHit>
+Foam::conformalVoronoiMesh::nearestFeatureEdgeLocations
+(
+    const Foam::point& pt
+) const
+{
+    const scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
+
+    labelList elems
+        = edgeLocationTreePtr_().findSphere(pt, exclusionRangeSqr);
+
+    DynamicList<pointIndexHit> dynPointHit;
+
+    forAll(elems, elemI)
+    {
+        label index = elems[elemI];
+
+        const Foam::point& pointI
+            = edgeLocationTreePtr_().shapes().shapePoints()[index];
+
+        pointIndexHit nearHit(true, pointI, index);
+
+        dynPointHit.append(nearHit);
+    }
+
+    return dynPointHit;
+}
+
+
 bool Foam::conformalVoronoiMesh::pointIsNearFeatureEdgeLocation
 (
     const Foam::point& pt
@@ -2009,103 +2423,77 @@ bool Foam::conformalVoronoiMesh::nearFeatureEdgeLocation
     DynamicList<Foam::point>& existingEdgeLocations
 ) const
 {
-    const Foam::point pt = pHit.hitPoint();
+    Foam::point pt = pHit.hitPoint();
 
     const scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
 
-    pointIndexHit info;
-
-    bool closeToFeatureEdge = pointIsNearFeatureEdgeLocation(pt, info);
+    bool closeToFeatureEdge = pointIsNearFeatureEdgeLocation(pt);
 
-    if (!closeToFeatureEdge)
-    {
-        appendToEdgeLocationTree(pt, existingEdgeLocations);
-    }
-    else
+    if (closeToFeatureEdge)
     {
-        // Check if the edge location that the new edge location is near to
-        // "might" be on a different edge. If so, add it anyway.
-        pointIndexHit edgeHit;
-        label featureHit = -1;
+        List<pointIndexHit> nearHits = nearestFeatureEdgeLocations(pt);
 
-        geometryToConformTo_.findEdgeNearest
-        (
-            pt,
-            exclusionRangeSqr,
-            edgeHit,
-            featureHit
-        );
+        forAll(nearHits, elemI)
+        {
+            pointIndexHit& info = nearHits[elemI];
 
-        const extendedFeatureEdgeMesh& eMesh
-            = geometryToConformTo_.features()[featureHit];
+            // Check if the edge location that the new edge location is near to
+            // "might" be on a different edge. If so, add it anyway.
+            pointIndexHit edgeHit;
+            label featureHit = -1;
 
-        const vector& edgeDir = eMesh.edgeDirections()[edgeHit.index()];
+            geometryToConformTo_.findEdgeNearest
+            (
+                pt,
+                exclusionRangeSqr,
+                edgeHit,
+                featureHit
+            );
 
-        const vector lineBetweenPoints = pt - info.hitPoint();
+            const extendedFeatureEdgeMesh& eMesh
+                = geometryToConformTo_.features()[featureHit];
 
-        const scalar cosAngle = vectorTools::cosPhi(edgeDir, lineBetweenPoints);
+            const vector& edgeDir = eMesh.edgeDirections()[edgeHit.index()];
 
-        // Allow the point to be added if it is almost at right angles to the
-        // other point. Also check it is not the same point.
-//        Info<< cosAngle<< " "
-//            << radToDeg(acos(cosAngle)) << " "
-//            << searchConeAngle << " "
-//            << radToDeg(acos(searchConeAngle)) << endl;
-        if
-        (
-            mag(cosAngle) < searchConeAngle
-         && mag(lineBetweenPoints) > SMALL
-        )
-        {
-            closeToFeatureEdge = false;
-            appendToEdgeLocationTree(pt, existingEdgeLocations);
-        }
-    }
+            const vector lineBetweenPoints = pt - info.hitPoint();
 
-    return closeToFeatureEdge;
+            const scalar cosAngle
+                = vectorTools::cosPhi(edgeDir, lineBetweenPoints);
 
-    // Searching for the nearest point in existingEdgeLocations using the
-    // indexedOctree
+            // Allow the point to be added if it is almost at right angles to
+            // the other point. Also check it is not the same point.
+    //        Info<< cosAngle<< " "
+    //            << radToDeg(acos(cosAngle)) << " "
+    //            << searchConeAngle << " "
+    //            << radToDeg(acos(searchConeAngle)) << endl;
 
-    // Average the points...
-//    if (info.hit())
-//    {
-//        Foam::point newPt = 0.5*(info.hitPoint() + pt);
-//
-//        pHit.setPoint(newPt);
-//
-//        //boolList toRemove(existingEdgeLocations.size(), false);
-//
-//        forAll(existingEdgeLocations, pI)
-//        {
-//            if (pI == info.index())
-//            {
-//                //toRemove[pI] = true;
-//                edgeLocationTree.remove(pI);
-//            }
-//        }
-////
-////        pointField newExistingEdgeLocations(existingEdgeLocations.size());
-////
-////        label count = 0;
-////        forAll(existingEdgeLocations, pI)
-////        {
-////            if (toRemove[pI] == false)
-////            {
-////                newExistingEdgeLocations[count++] =
-////                    existingEdgeLocations[pI];
-////            }
-////        }
-////
-////        newExistingEdgeLocations.resize(count);
-////
-////        existingEdgeLocations = newExistingEdgeLocations;
-////
-////        existingEdgeLocations.append(newPt);
-//
-//        return !info.hit();
-//    }
+            if
+            (
+                mag(cosAngle) < searchConeAngle
+             && (
+                    mag(lineBetweenPoints)
+                  > cvMeshControls().pointPairDistanceCoeff()*targetCellSize(pt)
+                )
+            )
+            {
+                pt = edgeHit.hitPoint();
+                pHit.setPoint(pt);
+                closeToFeatureEdge = false;
+            }
+            else
+            {
+                closeToFeatureEdge = true;
+                break;
+            }
+        }
+    }
+
+    if (!closeToFeatureEdge)
+    {
+        appendToEdgeLocationTree(pt, existingEdgeLocations);
+    }
 
+    return closeToFeatureEdge;
 }
 
 
@@ -2265,12 +2653,6 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits
             featuresHit
         );
 
-        // Gather edge locations but do not add them to newEdgeLocations inside
-        // the loop as they will prevent nearby edge locations of different
-        // types being conformed to.
-
-        DynamicList<Foam::point> currentEdgeLocations;
-
         forAll(edHitsByFeature, i)
         {
             const label featureHit = featuresHit[i];
@@ -2281,39 +2663,43 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits
             {
                 pointIndexHit& edHit = edHits[eHitI];
 
-                if (!nearFeaturePt(edHit.hitPoint()) && keepSurfacePoint)
+                if (edHit.hit())
                 {
-                    if
-                    (
-                        magSqr(edHit.hitPoint() - surfHitI.hitPoint())
-                      < surfacePtReplaceDistCoeffSqr*cellSizeSqr
-                    )
+                    if (!nearFeaturePt(edHit.hitPoint()))
                     {
-                        // If the point is within a given distance of a feature
-                        // edge, give control to edge control points instead,
-                        // this will prevent "pits" forming.
+                        if
+                        (
+                            magSqr(edHit.hitPoint() - surfHitI.hitPoint())
+                          < surfacePtReplaceDistCoeffSqr*cellSizeSqr
+                        )
+                        {
+                            // If the point is within a given distance of a
+                            // feature edge, give control to edge control points
+                            // instead, this will prevent "pits" forming.
 
-                        keepSurfacePoint = false;
+                            keepSurfacePoint = false;
 
-                        // NEED TO REMOVE FROM THE SURFACE TREE...
-                    }
+                            // NEED TO REMOVE FROM THE SURFACE TREE...
+                            surfacePtLocationTreePtr_().remove
+                            (
+                                existingSurfacePtLocations.size()
+                            );
+                        }
 
-                    if
-                    (
-                        !nearFeatureEdgeLocation
+                        if
                         (
-                            edHit,
-                            existingEdgeLocations
+                            !nearFeatureEdgeLocation
+                            (
+                                edHit,
+                                existingEdgeLocations
+                            )
                         )
-                    )
-                    {
-                        // Do not place edge control points too close to a
-                        // feature point or existing edge control points
-
-                        featureEdgeHits.append(edHit);
-                        featureEdgeFeaturesHit.append(featureHit);
-
-                        currentEdgeLocations.append(edHit.hitPoint());
+                        {
+                            // Do not place edge control points too close to a
+                            // feature point or existing edge control points
+                            featureEdgeHits.append(edHit);
+                            featureEdgeFeaturesHit.append(featureHit);
+                        }
                     }
                 }
             }
@@ -2322,7 +2708,6 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits
         if (keepSurfacePoint)
         {
             surfaceHits.append(surfHitI);
-
             hitSurfaces.append(hitSurfaceI);
         }
     }
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
index ab7ce33f8563760f144c6aff33f6893a1a7e0078..89afb87134a98ce7b7c9c5ec37afe4764ed4f4b2 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
@@ -125,7 +125,7 @@ void Foam::conformalVoronoiMesh::drawDelaunayCell
     os  << "# cell index: " << label(c->cellIndex()) << endl;
 
     os  << "# circumradius "
-        << mag(topoint(dual(c)) - topoint(c->vertex(0)->point()))
+        << mag(c->dual() - topoint(c->vertex(0)->point()))
         << endl;
 
     for (int i = 0; i < 4; i++)
@@ -144,7 +144,7 @@ void Foam::conformalVoronoiMesh::drawDelaunayCell
 
     os  << "# cicumcentre " << endl;
 
-    meshTools::writeOBJ(os, topoint(dual(c)));
+    meshTools::writeOBJ(os, c->dual());
 
     os  << "l " << 1 + offset << " " << 5 + offset << endl;
 }
@@ -167,7 +167,7 @@ void Foam::conformalVoronoiMesh::writePoints
         ++vit
     )
     {
-        if (!internalOnly || vit->internalOrBoundaryPoint())
+        if (!internalOnly || vit->internalPoint())
         {
             meshTools::writeOBJ(str, topoint(vit->point()));
         }
@@ -241,7 +241,7 @@ void Foam::conformalVoronoiMesh::writeProcessorInterface
     {
         if (!cit->farCell())
         {
-            points[cit->cellIndex()] = topoint(dual(cit));
+            points[cit->cellIndex()] = cit->dual();
         }
     }
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
index 7ab4f10853427619285ce87430f1ccf14cd31e42..5fc7e970b1131c78607d13f71c91ff3b90aeb276 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
@@ -51,6 +51,7 @@ SourceFiles
 #include "Swap.H"
 #include "InfoProxy.H"
 #include "tetCell.H"
+#include "typeInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -154,6 +155,8 @@ public:
 
         inline int cellIndex() const;
 
+        inline const Foam::point& dual();
+
         inline bool farCell() const;
 
         inline int& filterCount();
@@ -163,6 +166,11 @@ public:
         //- Is the Delaunay cell real, i.e. any real vertex
         inline bool real() const;
 
+        //- Does the Delaunay cell have a far point
+        inline bool hasFarPoint() const;
+
+        inline bool hasInternalPoint() const;
+
         //- Does the Dual vertex form part of a processor patch
         inline bool parallelDualVertex() const;
 
@@ -190,6 +198,8 @@ public:
         //  least one Delaunay vertex outside and at least one inside
         inline bool boundaryDualVertex() const;
 
+        inline bool nearProcBoundary() const;
+
 
     // Info
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H
index 5fbd378f9d9a220845245127070d9624f2ac9bba..6450b01908a44149dbde6d8abc6d8e927f6083b1 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H
@@ -86,6 +86,24 @@ int CGAL::indexedCell<Gt, Cb>::cellIndex() const
 }
 
 
+template<class Gt, class Cb>
+const Foam::point& CGAL::indexedCell<Gt, Cb>::dual()
+{
+#ifdef CGAL_INEXACT
+    return reinterpret_cast<const Foam::point&>(this->circumcenter());
+#else
+    const typename Gt::Point_3& P = this->circumcenter();
+
+    return
+    (
+        CGAL::to_double(P.x()),
+        CGAL::to_double(P.y()),
+        CGAL::to_double(P.z())
+    );
+#endif
+}
+
+
 template<class Gt, class Cb>
 inline bool CGAL::indexedCell<Gt, Cb>::farCell() const
 {
@@ -112,10 +130,45 @@ inline bool CGAL::indexedCell<Gt, Cb>::real() const
 {
     return
     (
-        this->vertex(0)->real()
-     || this->vertex(1)->real()
-     || this->vertex(2)->real()
-     || this->vertex(3)->real()
+        (
+            this->vertex(0)->real()
+         || this->vertex(1)->real()
+         || this->vertex(2)->real()
+         || this->vertex(3)->real()
+        )
+        &&
+        !(
+            this->vertex(0)->farPoint()
+         || this->vertex(1)->farPoint()
+         || this->vertex(2)->farPoint()
+         || this->vertex(3)->farPoint()
+        )
+    );
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::hasFarPoint() const
+{
+    return
+    (
+        this->vertex(0)->farPoint()
+     || this->vertex(1)->farPoint()
+     || this->vertex(2)->farPoint()
+     || this->vertex(3)->farPoint()
+    );
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::hasInternalPoint() const
+{
+    return
+    (
+        this->vertex(0)->internalPoint()
+     || this->vertex(1)->internalPoint()
+     || this->vertex(2)->internalPoint()
+     || this->vertex(3)->internalPoint()
     );
 }
 
@@ -285,4 +338,17 @@ inline bool CGAL::indexedCell<Gt, Cb>::boundaryDualVertex() const
 }
 
 
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::nearProcBoundary() const
+{
+    return
+    (
+        this->vertex(0)->nearProcBoundary()
+     || this->vertex(1)->nearProcBoundary()
+     || this->vertex(2)->nearProcBoundary()
+     || this->vertex(3)->nearProcBoundary()
+    );
+}
+
+
 // * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C
index 9ad21f92feade712950e9aed5d5cb6d1a21a3eaf..2173e7f5fa7b6be6a0469b004a46e9148f4195f7 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C
@@ -29,7 +29,6 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "indexedVertex.H"
-//#include "conformalVoronoiMesh.H"
 #include "point.H"
 
 // * * * * * * * * * * * * * * * *  IOStream operators * * * * * * * * * * * //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
index 246020fd172bbeb127089dc9bcc085c0aa7908e2..525c2156e82b60682ca93eb20d44fc4d34d051d7 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
@@ -45,6 +45,7 @@ SourceFiles
 #include <CGAL/Triangulation_3.h>
 #include "tensor.H"
 #include "InfoProxy.H"
+#include "point.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -101,6 +102,8 @@ class indexedVertex
         //- Specify whether the vertex is fixed or movable.
         bool vertexFixed_;
 
+        bool nearProcBoundary_;
+
 
 public:
 
@@ -198,6 +201,12 @@ public:
         //- Set the point to be near the boundary
         inline void setNearBoundary();
 
+        //- Is point internal and near a proc boundary
+        inline bool nearProcBoundary() const;
+
+        //- Set the point to be near a proc boundary
+        inline void setNearProcBoundary();
+
         //- Either master or slave of pointPair.
         inline bool pairPoint() const;
 
@@ -227,7 +236,7 @@ public:
         inline bool isVertexFixed() const;
 
         //- Fix the vertex so that it can't be moved
-        inline void setVertexFixed() const;
+        inline void setVertexFixed();
 
     // inline void operator=(const Delaunay::Finite_vertices_iterator vit)
     // {
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H
index c02ec4df2009489efa9fe91221a666b9f9ae0050..1e225eaa2ed02a2674b57a713fbc142f05d451b4 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H
@@ -38,7 +38,8 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex()
     type_(vtInternal),
     alignment_(),
     targetCellSize_(0.0),
-    vertexFixed_(false)
+    vertexFixed_(false),
+    nearProcBoundary_(false)
 {}
 
 
@@ -50,7 +51,8 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p)
     type_(vtInternal),
     alignment_(),
     targetCellSize_(0.0),
-    vertexFixed_(false)
+    vertexFixed_(false),
+    nearProcBoundary_(false)
 {}
 
 
@@ -67,7 +69,8 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex
     type_(type),
     alignment_(),
     targetCellSize_(0.0),
-    vertexFixed_(false)
+    vertexFixed_(false),
+    nearProcBoundary_(false)
 {}
 
 
@@ -79,7 +82,8 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p, Cell_handle f)
     type_(vtInternal),
     alignment_(),
     targetCellSize_(0.0),
-    vertexFixed_(false)
+    vertexFixed_(false),
+    nearProcBoundary_(false)
 {}
 
 
@@ -91,7 +95,8 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(Cell_handle f)
     type_(vtInternal),
     alignment_(),
     targetCellSize_(0.0),
-    vertexFixed_(false)
+    vertexFixed_(false),
+    nearProcBoundary_(false)
 {}
 
 
@@ -251,6 +256,20 @@ inline void CGAL::indexedVertex<Gt, Vb>::setNearBoundary()
 }
 
 
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::nearProcBoundary() const
+{
+    return nearProcBoundary_;
+}
+
+
+template<class Gt, class Vb>
+inline void CGAL::indexedVertex<Gt, Vb>::setNearProcBoundary()
+{
+    nearProcBoundary_ = true;
+}
+
+
 template<class Gt, class Vb>
 inline bool CGAL::indexedVertex<Gt, Vb>::pairPoint() const
 {
@@ -331,7 +350,7 @@ inline bool CGAL::indexedVertex<Gt, Vb>::isVertexFixed() const
 
 
 template<class Gt, class Vb>
-inline void CGAL::indexedVertex<Gt, Vb>::setVertexFixed() const
+inline void CGAL::indexedVertex<Gt, Vb>::setVertexFixed()
 {
     vertexFixed_ = true;
 }
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
index d8e5fd016616633358be21ac667efdac3eab22bf..ce56a977aa8e676c6f30f655a2730a90f2e4c3d8 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
@@ -285,7 +285,9 @@ public:
             ) const;
 
             //- Find the nearest points on each feature edge that is within
-            //  a given distance from the sample point
+            //  a given distance from the sample point. Will need to check for
+            //  a hit or a miss because near edges may not have a nearest point
+            //  on them which is perpendicular to the sample point.
             void findAllNearestEdges
             (
                 const point& sample,
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..a0fcd8f0bf85d8c5624f026c6cae568cd63f7251
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/files
@@ -0,0 +1,6 @@
+cvMeshSurfaceSimplify.C
+
+MarchingCubes/MarchingCubes.cpp
+MarchingCubes/ply.c
+
+EXE = $(FOAM_APPBIN)/cvMeshSurfaceSimplify
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..1711b9ba615e3d9a77ea1e005fc6dc392a93a06e
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/Make/options
@@ -0,0 +1,17 @@
+include $(GENERAL_RULES)/CGAL
+
+EXE_INC = \
+    -IMarchingCubes \
+    -I../conformalVoronoiMesh/lnInclude \
+    -I$(LIB_SRC)/edgeMesh/lnInclude \
+    -I$(LIB_SRC)/triSurface/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+    $(CGAL_LIBS) \
+    -lconformalVoronoiMesh \
+    -ldecompositionMethods -L$(FOAM_LIBBIN)/dummy -lscotchDecomp \
+    -ledgeMesh \
+    -ltriSurface \
+    -lmeshTools \
+    -ldynamicMesh
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h
new file mode 100755
index 0000000000000000000000000000000000000000..5529346954a3fb59076c85d2edaf980978f4a245
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/LookUpTable.h
@@ -0,0 +1,2322 @@
+/**
+ * @file    LookUpTable.h
+ * @author  Thomas Lewiner <thomas.lewiner@polytechnique.org>
+ * @author  Math Dept, PUC-Rio
+ * @version 0.2
+ * @date    12/08/2002
+ *
+ * @brief   LookUpTable for the MarchingCubes 33 Algorithm
+ */
+//________________________________________________
+
+
+
+#ifndef _LOOKUPTABLE_H_
+#define _LOOKUPTABLE_H_
+
+
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief case mapping
+ * For each of the possible vertex states listed in this table there is a
+ * specific triangulation of the edge intersection points.  The table lists
+ * all of them in the form of 0-5 edge triples with the list terminated by
+ * the invalid value -1.  For example: case[3] list the 2 triangles
+ * formed when cube[0] and cube[1] are inside of the surface, but the rest of
+ * the cube is not.
+ *
+ * Cube description:
+ *         7 ________ 6           _____6__             ________
+ *         /|       /|         7/|       /|          /|       /|
+ *       /  |     /  |        /  |     /5 |        /  6     /  |
+ *   4 /_______ /    |      /__4____ /    10     /_______3/    |
+ *    |     |  |5    |     |    11  |     |     |     |  |   2 |
+ *    |    3|__|_____|2    |     |__|__2__|     | 4   |__|_____|
+ *    |    /   |    /      8   3/   9    /      |    /   |    /
+ *    |  /     |  /        |  /     |  /1       |  /     5  /
+ *    |/_______|/          |/___0___|/          |/_1_____|/
+ *   0          1        0          1
+ */
+//-----------------------------------------------------------------------------
+static const char cases[256][2] = {
+/*   0:                          */  {  0, -1 },
+/*   1: 0,                       */  {  1,  0 },
+/*   2:    1,                    */  {  1,  1 },
+/*   3: 0, 1,                    */  {  2,  0 },
+/*   4:       2,                 */  {  1,  2 },
+/*   5: 0,    2,                 */  {  3,  0 },
+/*   6:    1, 2,                 */  {  2,  3 },
+/*   7: 0, 1, 2,                 */  {  5,  0 },
+/*   8:          3,              */  {  1,  3 },
+/*   9: 0,       3,              */  {  2,  1 },
+/*  10:    1,    3,              */  {  3,  3 },
+/*  11: 0, 1,    3,              */  {  5,  1 },
+/*  12:       2, 3,              */  {  2,  5 },
+/*  13: 0,    2, 3,              */  {  5,  4 },
+/*  14:    1, 2, 3,              */  {  5,  9 },
+/*  15: 0, 1, 2, 3,              */  {  8,  0 },
+/*  16:             4,           */  {  1,  4 },
+/*  17: 0,          4,           */  {  2,  2 },
+/*  18:    1,       4,           */  {  3,  4 },
+/*  19: 0, 1,       4,           */  {  5,  2 },
+/*  20:       2,    4,           */  {  4,  2 },
+/*  21: 0,    2,    4,           */  {  6,  2 },
+/*  22:    1, 2,    4,           */  {  6,  9 },
+/*  23: 0, 1, 2,    4,           */  { 11,  0 },
+/*  24:          3, 4,           */  {  3,  8 },
+/*  25: 0,       3, 4,           */  {  5,  5 },
+/*  26:    1,    3, 4,           */  {  7,  3 },
+/*  27: 0, 1,    3, 4,           */  {  9,  1 },
+/*  28:       2, 3, 4,           */  {  6, 16 },
+/*  29: 0,    2, 3, 4,           */  { 14,  3 },
+/*  30:    1, 2, 3, 4,           */  { 12, 12 },
+/*  31: 0, 1, 2, 3, 4,           */  {  5, 24 },
+/*  32:                5,        */  {  1,  5 },
+/*  33: 0,             5,        */  {  3,  1 },
+/*  34:    1,          5,        */  {  2,  4 },
+/*  35: 0, 1,          5,        */  {  5,  3 },
+/*  36:       2,       5,        */  {  3,  6 },
+/*  37: 0,    2,       5,        */  {  7,  0 },
+/*  38:    1, 2,       5,        */  {  5, 10 },
+/*  39: 0, 1, 2,       5,        */  {  9,  0 },
+/*  40:          3,    5,        */  {  4,  3 },
+/*  41: 0,       3,    5,        */  {  6,  4 },
+/*  42:    1,    3,    5,        */  {  6, 11 },
+/*  43: 0, 1,    3,    5,        */  { 14,  1 },
+/*  44:       2, 3,    5,        */  {  6, 17 },
+/*  45: 0,    2, 3,    5,        */  { 12,  4 },
+/*  46:    1, 2, 3,    5,        */  { 11,  6 },
+/*  47: 0, 1, 2, 3,    5,        */  {  5, 25 },
+/*  48:             4, 5,        */  {  2,  8 },
+/*  49: 0,          4, 5,        */  {  5,  7 },
+/*  50:    1,       4, 5,        */  {  5, 12 },
+/*  51: 0, 1,       4, 5,        */  {  8,  1 },
+/*  52:       2,    4, 5,        */  {  6, 18 },
+/*  53: 0,    2,    4, 5,        */  { 12,  5 },
+/*  54:    1, 2,    4, 5,        */  { 14,  7 },
+/*  55: 0, 1, 2,    4, 5,        */  {  5, 28 },
+/*  56:          3, 4, 5,        */  {  6, 21 },
+/*  57: 0,       3, 4, 5,        */  { 11,  4 },
+/*  58:    1,    3, 4, 5,        */  { 12, 15 },
+/*  59: 0, 1,    3, 4, 5,        */  {  5, 30 },
+/*  60:       2, 3, 4, 5,        */  { 10,  5 },
+/*  61: 0,    2, 3, 4, 5,        */  {  6, 32 },
+/*  62:    1, 2, 3, 4, 5,        */  {  6, 39 },
+/*  63: 0, 1, 2, 3, 4, 5,        */  {  2, 12 },
+/*  64:                   6,     */  {  1,  6 },
+/*  65: 0,                6,     */  {  4,  0 },
+/*  66:    1,             6,     */  {  3,  5 },
+/*  67: 0, 1,             6,     */  {  6,  0 },
+/*  68:       2,          6,     */  {  2,  6 },
+/*  69: 0,    2,          6,     */  {  6,  3 },
+/*  70:    1, 2,          6,     */  {  5, 11 },
+/*  71: 0, 1, 2,          6,     */  { 14,  0 },
+/*  72:          3,       6,     */  {  3,  9 },
+/*  73: 0,       3,       6,     */  {  6,  5 },
+/*  74:    1,    3,       6,     */  {  7,  4 },
+/*  75: 0, 1,    3,       6,     */  { 12,  1 },
+/*  76:       2, 3,       6,     */  {  5, 14 },
+/*  77: 0,    2, 3,       6,     */  { 11,  3 },
+/*  78:    1, 2, 3,       6,     */  {  9,  4 },
+/*  79: 0, 1, 2, 3,       6,     */  {  5, 26 },
+/*  80:             4,    6,     */  {  3, 10 },
+/*  81: 0,          4,    6,     */  {  6,  6 },
+/*  82:    1,       4,    6,     */  {  7,  5 },
+/*  83: 0, 1,       4,    6,     */  { 12,  2 },
+/*  84:       2,    4,    6,     */  {  6, 19 },
+/*  85: 0,    2,    4,    6,     */  { 10,  1 },
+/*  86:    1, 2,    4,    6,     */  { 12, 13 },
+/*  87: 0, 1, 2,    4,    6,     */  {  6, 24 },
+/*  88:          3, 4,    6,     */  {  7,  7 },
+/*  89: 0,       3, 4,    6,     */  { 12,  9 },
+/*  90:    1,    3, 4,    6,     */  { 13,  1 },
+/*  91: 0, 1,    3, 4,    6,     */  {  7,  9 },
+/*  92:       2, 3, 4,    6,     */  { 12, 20 },
+/*  93: 0,    2, 3, 4,    6,     */  {  6, 33 },
+/*  94:    1, 2, 3, 4,    6,     */  {  7, 13 },
+/*  95: 0, 1, 2, 3, 4,    6,     */  {  3, 12 },
+/*  96:                5, 6,     */  {  2, 10 },
+/*  97: 0,             5, 6,     */  {  6,  7 },
+/*  98:    1,          5, 6,     */  {  5, 13 },
+/*  99: 0, 1,          5, 6,     */  { 11,  2 },
+/* 100:       2,       5, 6,     */  {  5, 16 },
+/* 101: 0,    2,       5, 6,     */  { 12,  7 },
+/* 102:    1, 2,       5, 6,     */  {  8,  3 },
+/* 103: 0, 1, 2,       5, 6,     */  {  5, 29 },
+/* 104:          3,    5, 6,     */  {  6, 22 },
+/* 105: 0,       3,    5, 6,     */  { 10,  2 },
+/* 106:    1,    3,    5, 6,     */  { 12, 17 },
+/* 107: 0, 1,    3,    5, 6,     */  {  6, 27 },
+/* 108:       2, 3,    5, 6,     */  { 14,  9 },
+/* 109: 0,    2, 3,    5, 6,     */  {  6, 34 },
+/* 110:    1, 2, 3,    5, 6,     */  {  5, 39 },
+/* 111: 0, 1, 2, 3,    5, 6,     */  {  2, 14 },
+/* 112:             4, 5, 6,     */  {  5, 20 },
+/* 113: 0,          4, 5, 6,     */  { 14,  5 },
+/* 114:    1,       4, 5, 6,     */  {  9,  5 },
+/* 115: 0, 1,       4, 5, 6,     */  {  5, 32 },
+/* 116:       2,    4, 5, 6,     */  { 11, 10 },
+/* 117: 0,    2,    4, 5, 6,     */  {  6, 35 },
+/* 118:    1, 2,    4, 5, 6,     */  {  5, 41 },
+/* 119: 0, 1, 2,    4, 5, 6,     */  {  2, 16 },
+/* 120:          3, 4, 5, 6,     */  { 12, 23 },
+/* 121: 0,       3, 4, 5, 6,     */  {  6, 37 },
+/* 122:    1,    3, 4, 5, 6,     */  {  7, 14 },
+/* 123: 0, 1,    3, 4, 5, 6,     */  {  3, 16 },
+/* 124:       2, 3, 4, 5, 6,     */  {  6, 46 },
+/* 125: 0,    2, 3, 4, 5, 6,     */  {  4,  6 },
+/* 126:    1, 2, 3, 4, 5, 6,     */  {  3, 21 },
+/* 127: 0, 1, 2, 3, 4, 5, 6,     */  {  1,  8 },
+/* 128:                      7,  */  {  1,  7 },
+/* 129: 0,                   7,  */  {  3,  2 },
+/* 130:    1,                7,  */  {  4,  1 },
+/* 131: 0, 1,                7,  */  {  6,  1 },
+/* 132:       2,             7,  */  {  3,  7 },
+/* 133: 0,    2,             7,  */  {  7,  1 },
+/* 134:    1, 2,             7,  */  {  6, 10 },
+/* 135: 0, 1, 2,             7,  */  { 12,  0 },
+/* 136:          3,          7,  */  {  2,  7 },
+/* 137: 0,       3,          7,  */  {  5,  6 },
+/* 138:    1,    3,          7,  */  {  6, 12 },
+/* 139: 0, 1,    3,          7,  */  { 11,  1 },
+/* 140:       2, 3,          7,  */  {  5, 15 },
+/* 141: 0,    2, 3,          7,  */  {  9,  2 },
+/* 142:    1, 2, 3,          7,  */  { 14,  6 },
+/* 143: 0, 1, 2, 3,          7,  */  {  5, 27 },
+/* 144:             4,       7,  */  {  2,  9 },
+/* 145: 0,          4,       7,  */  {  5,  8 },
+/* 146:    1,       4,       7,  */  {  6, 13 },
+/* 147: 0, 1,       4,       7,  */  { 14,  2 },
+/* 148:       2,    4,       7,  */  {  6, 20 },
+/* 149: 0,    2,    4,       7,  */  { 12,  6 },
+/* 150:    1, 2,    4,       7,  */  { 10,  3 },
+/* 151: 0, 1, 2,    4,       7,  */  {  6, 25 },
+/* 152:          3, 4,       7,  */  {  5, 18 },
+/* 153: 0,       3, 4,       7,  */  {  8,  2 },
+/* 154:    1,    3, 4,       7,  */  { 12, 16 },
+/* 155: 0, 1,    3, 4,       7,  */  {  5, 31 },
+/* 156:       2, 3, 4,       7,  */  { 11,  9 },
+/* 157: 0,    2, 3, 4,       7,  */  {  5, 34 },
+/* 158:    1, 2, 3, 4,       7,  */  {  6, 40 },
+/* 159: 0, 1, 2, 3, 4,       7,  */  {  2, 13 },
+/* 160:                5,    7,  */  {  3, 11 },
+/* 161: 0,             5,    7,  */  {  7,  2 },
+/* 162:    1,          5,    7,  */  {  6, 14 },
+/* 163: 0, 1,          5,    7,  */  { 12,  3 },
+/* 164:       2,       5,    7,  */  {  7,  6 },
+/* 165: 0,    2,       5,    7,  */  { 13,  0 },
+/* 166:    1, 2,       5,    7,  */  { 12, 14 },
+/* 167: 0, 1, 2,       5,    7,  */  {  7,  8 },
+/* 168:          3,    5,    7,  */  {  6, 23 },
+/* 169: 0,       3,    5,    7,  */  { 12, 10 },
+/* 170:    1,    3,    5,    7,  */  { 10,  4 },
+/* 171: 0, 1,    3,    5,    7,  */  {  6, 28 },
+/* 172:       2, 3,    5,    7,  */  { 12, 21 },
+/* 173: 0,    2, 3,    5,    7,  */  {  7, 10 },
+/* 174:    1, 2, 3,    5,    7,  */  {  6, 41 },
+/* 175: 0, 1, 2, 3,    5,    7,  */  {  3, 13 },
+/* 176:             4, 5,    7,  */  {  5, 21 },
+/* 177: 0,          4, 5,    7,  */  {  9,  3 },
+/* 178:    1,       4, 5,    7,  */  { 11,  8 },
+/* 179: 0, 1,       4, 5,    7,  */  {  5, 33 },
+/* 180:       2,    4, 5,    7,  */  { 12, 22 },
+/* 181: 0,    2,    4, 5,    7,  */  {  7, 11 },
+/* 182:    1, 2,    4, 5,    7,  */  {  6, 42 },
+/* 183: 0, 1, 2,    4, 5,    7,  */  {  3, 14 },
+/* 184:          3, 4, 5,    7,  */  { 14, 11 },
+/* 185: 0,       3, 4, 5,    7,  */  {  5, 36 },
+/* 186:    1,    3, 4, 5,    7,  */  {  6, 44 },
+/* 187: 0, 1,    3, 4, 5,    7,  */  {  2, 17 },
+/* 188:       2, 3, 4, 5,    7,  */  {  6, 47 },
+/* 189: 0,    2, 3, 4, 5,    7,  */  {  3, 18 },
+/* 190:    1, 2, 3, 4, 5,    7,  */  {  4,  7 },
+/* 191: 0, 1, 2, 3, 4, 5,    7,  */  {  1,  9 },
+/* 192:                   6, 7,  */  {  2, 11 },
+/* 193: 0,                6, 7,  */  {  6,  8 },
+/* 194:    1,             6, 7,  */  {  6, 15 },
+/* 195: 0, 1,             6, 7,  */  { 10,  0 },
+/* 196:       2,          6, 7,  */  {  5, 17 },
+/* 197: 0,    2,          6, 7,  */  { 12,  8 },
+/* 198:    1, 2,          6, 7,  */  { 11,  7 },
+/* 199: 0, 1, 2,          6, 7,  */  {  6, 26 },
+/* 200:          3,       6, 7,  */  {  5, 19 },
+/* 201: 0,       3,       6, 7,  */  { 14,  4 },
+/* 202:    1,    3,       6, 7,  */  { 12, 18 },
+/* 203: 0, 1,    3,       6, 7,  */  {  6, 29 },
+/* 204:       2, 3,       6, 7,  */  {  8,  4 },
+/* 205: 0,    2, 3,       6, 7,  */  {  5, 35 },
+/* 206:    1, 2, 3,       6, 7,  */  {  5, 40 },
+/* 207: 0, 1, 2, 3,       6, 7,  */  {  2, 15 },
+/* 208:             4,    6, 7,  */  {  5, 22 },
+/* 209: 0,          4,    6, 7,  */  { 11,  5 },
+/* 210:    1,       4,    6, 7,  */  { 12, 19 },
+/* 211: 0, 1,       4,    6, 7,  */  {  6, 30 },
+/* 212:       2,    4,    6, 7,  */  { 14, 10 },
+/* 213: 0,    2,    4,    6, 7,  */  {  6, 36 },
+/* 214:    1, 2,    4,    6, 7,  */  {  6, 43 },
+/* 215: 0, 1, 2,    4,    6, 7,  */  {  4,  4 },
+/* 216:          3, 4,    6, 7,  */  {  9,  7 },
+/* 217: 0,       3, 4,    6, 7,  */  {  5, 37 },
+/* 218:    1,    3, 4,    6, 7,  */  {  7, 15 },
+/* 219: 0, 1,    3, 4,    6, 7,  */  {  3, 17 },
+/* 220:       2, 3, 4,    6, 7,  */  {  5, 44 },
+/* 221: 0,    2, 3, 4,    6, 7,  */  {  2, 19 },
+/* 222:    1, 2, 3, 4,    6, 7,  */  {  3, 22 },
+/* 223: 0, 1, 2, 3, 4,    6, 7,  */  {  1, 10 },
+/* 224:                5, 6, 7,  */  {  5, 23 },
+/* 225: 0,             5, 6, 7,  */  { 12, 11 },
+/* 226:    1,          5, 6, 7,  */  { 14,  8 },
+/* 227: 0, 1,          5, 6, 7,  */  {  6, 31 },
+/* 228:       2,       5, 6, 7,  */  {  9,  6 },
+/* 229: 0,    2,       5, 6, 7,  */  {  7, 12 },
+/* 230:    1, 2,       5, 6, 7,  */  {  5, 42 },
+/* 231: 0, 1, 2,       5, 6, 7,  */  {  3, 15 },
+/* 232:          3,    5, 6, 7,  */  { 11, 11 },
+/* 233: 0,       3,    5, 6, 7,  */  {  6, 38 },
+/* 234:    1,    3,    5, 6, 7,  */  {  6, 45 },
+/* 235: 0, 1,    3,    5, 6, 7,  */  {  4,  5 },
+/* 236:       2, 3,    5, 6, 7,  */  {  5, 45 },
+/* 237: 0,    2, 3,    5, 6, 7,  */  {  3, 19 },
+/* 238:    1, 2, 3,    5, 6, 7,  */  {  2, 21 },
+/* 239: 0, 1, 2, 3,    5, 6, 7,  */  {  1, 11 },
+/* 240:             4, 5, 6, 7,  */  {  8,  5 },
+/* 241: 0,          4, 5, 6, 7,  */  {  5, 38 },
+/* 242:    1,       4, 5, 6, 7,  */  {  5, 43 },
+/* 243: 0, 1,       4, 5, 6, 7,  */  {  2, 18 },
+/* 244:       2,    4, 5, 6, 7,  */  {  5, 46 },
+/* 245: 0,    2,    4, 5, 6, 7,  */  {  3, 20 },
+/* 246:    1, 2,    4, 5, 6, 7,  */  {  2, 22 },
+/* 247: 0, 1, 2,    4, 5, 6, 7,  */  {  1, 12 },
+/* 248:          3, 4, 5, 6, 7,  */  {  5, 47 },
+/* 249: 0,       3, 4, 5, 6, 7,  */  {  2, 20 },
+/* 250:    1,    3, 4, 5, 6, 7,  */  {  3, 23 },
+/* 251: 0, 1,    3, 4, 5, 6, 7,  */  {  1, 13 },
+/* 252:       2, 3, 4, 5, 6, 7,  */  {  2, 23 },
+/* 253: 0,    2, 3, 4, 5, 6, 7,  */  {  1, 14 },
+/* 254:    1, 2, 3, 4, 5, 6, 7,  */  {  1, 15 },
+/* 255: 0, 1, 2, 3, 4, 5, 6, 7,  */  {  0, -1 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling1[16][3] = {
+/*   1: 0,                       */  {  0,  8,  3 },
+/*   2:    1,                    */  {  0,  1,  9 },
+/*   4:       2,                 */  {  1,  2, 10 },
+/*   8:          3,              */  {  3, 11,  2 },
+/*  16:             4,           */  {  4,  7,  8 },
+/*  32:                5,        */  {  9,  5,  4 },
+/*  64:                   6,     */  { 10,  6,  5 },
+/* 128:                      7,  */  {  7,  6, 11 },
+/* 127: 0, 1, 2, 3, 4, 5, 6,     */  {  7, 11,  6 },
+/* 191: 0, 1, 2, 3, 4, 5,    7,  */  { 10,  5,  6 },
+/* 223: 0, 1, 2, 3, 4,    6, 7,  */  {  9,  4,  5 },
+/* 239: 0, 1, 2, 3,    5, 6, 7,  */  {  4,  8,  7 },
+/* 247: 0, 1, 2,    4, 5, 6, 7,  */  {  3,  2, 11 },
+/* 251: 0, 1,    3, 4, 5, 6, 7,  */  {  1, 10,  2 },
+/* 253: 0,    2, 3, 4, 5, 6, 7,  */  {  0,  9,  1 },
+/* 254:    1, 2, 3, 4, 5, 6, 7,  */  {  0,  3,  8 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling2[24][6] = {
+/*   3: 0, 1,                    */  {  1,  8,  3,  9,  8,  1 },
+/*   9: 0,       3,              */  {  0, 11,  2,  8, 11,  0 },
+/*  17: 0,          4,           */  {  4,  3,  0,  7,  3,  4 },
+/*   6:    1, 2,                 */  {  9,  2, 10,  0,  2,  9 },
+/*  34:    1,          5,        */  {  0,  5,  4,  1,  5,  0 },
+/*  12:       2, 3,              */  {  3, 10,  1, 11, 10,  3 },
+/*  68:       2,          6,     */  {  1,  6,  5,  2,  6,  1 },
+/* 136:          3,          7,  */  {  7,  2,  3,  6,  2,  7 },
+/*  48:             4, 5,        */  {  9,  7,  8,  5,  7,  9 },
+/* 144:             4,       7,  */  {  6,  8,  4, 11,  8,  6 },
+/*  96:                5, 6,     */  { 10,  4,  9,  6,  4, 10 },
+/* 192:                   6, 7,  */  { 11,  5, 10,  7,  5, 11 },
+/*  63: 0, 1, 2, 3, 4, 5,        */  { 11, 10,  5,  7, 11,  5 },
+/* 159: 0, 1, 2, 3, 4,       7,  */  { 10,  9,  4,  6, 10,  4 },
+/* 111: 0, 1, 2, 3,    5, 6,     */  {  6,  4,  8, 11,  6,  8 },
+/* 207: 0, 1, 2, 3,       6, 7,  */  {  9,  8,  7,  5,  9,  7 },
+/* 119: 0, 1, 2,    4, 5, 6,     */  {  7,  3,  2,  6,  7,  2 },
+/* 187: 0, 1,    3, 4, 5,    7,  */  {  1,  5,  6,  2,  1,  6 },
+/* 243: 0, 1,       4, 5, 6, 7,  */  {  3,  1, 10, 11,  3, 10 },
+/* 221: 0,    2, 3, 4,    6, 7,  */  {  0,  4,  5,  1,  0,  5 },
+/* 249: 0,       3, 4, 5, 6, 7,  */  {  9, 10,  2,  0,  9,  2 },
+/* 238:    1, 2, 3,    5, 6, 7,  */  {  4,  0,  3,  7,  4,  3 },
+/* 246:    1, 2,    4, 5, 6, 7,  */  {  0,  2, 11,  8,  0, 11 },
+/* 252:       2, 3, 4, 5, 6, 7,  */  {  1,  3,  8,  9,  1,  8 }
+};
+//_____________________________________________________________________________
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 3
+ * One face to test
+ * When the test on the specified face is positive : 4 first triangles
+ * When the test on the specified face is negative : 2 last triangles
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test3[24] = {
+/*   5: 0,    2,                 */    5,
+/*  33: 0,             5,        */    1,
+/* 129: 0,                   7,  */    4,
+/*  10:    1,    3,              */    5,
+/*  18:    1,       4,           */    1,
+/*  66:    1,             6,     */    2,
+/*  36:       2,       5,        */    2,
+/* 132:       2,             7,  */    3,
+/*  24:          3, 4,           */    4,
+/*  72:          3,       6,     */    3,
+/*  80:             4,    6,     */    6,
+/* 160:                5,    7,  */    6,
+/*  95: 0, 1, 2, 3, 4,    6,     */   -6,
+/* 175: 0, 1, 2, 3,    5,    7,  */   -6,
+/* 183: 0, 1, 2,    4, 5,    7,  */   -3,
+/* 231: 0, 1, 2,       5, 6, 7,  */   -4,
+/* 123: 0, 1,    3, 4, 5, 6,     */   -3,
+/* 219: 0, 1,    3, 4,    6, 7,  */   -2,
+/* 189: 0,    2, 3, 4, 5,    7,  */   -2,
+/* 237: 0,    2, 3,    5, 6, 7,  */   -1,
+/* 245: 0,    2,    4, 5, 6, 7,  */   -5,
+/* 126:    1, 2, 3, 4, 5, 6,     */   -4,
+/* 222:    1, 2, 3, 4,    6, 7,  */   -1,
+/* 250:    1,    3, 4, 5, 6, 7,  */   -5
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 3.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling3_1[24][6] = {
+/*   5: 0,    2,                 */  {  0,  8,  3,  1,  2, 10 },
+/*  33: 0,             5,        */  {  9,  5,  4,  0,  8,  3 },
+/* 129: 0,                   7,  */  {  3,  0,  8, 11,  7,  6 },
+/*  10:    1,    3,              */  {  1,  9,  0,  2,  3, 11 },
+/*  18:    1,       4,           */  {  0,  1,  9,  8,  4,  7 },
+/*  66:    1,             6,     */  {  9,  0,  1,  5, 10,  6 },
+/*  36:       2,       5,        */  {  1,  2, 10,  9,  5,  4 },
+/* 132:       2,             7,  */  { 10,  1,  2,  6, 11,  7 },
+/*  24:          3, 4,           */  {  8,  4,  7,  3, 11,  2 },
+/*  72:          3,       6,     */  {  2,  3, 11, 10,  6,  5 },
+/*  80:             4,    6,     */  {  5, 10,  6,  4,  7,  8 },
+/* 160:                5,    7,  */  {  4,  9,  5,  7,  6, 11 },
+/*  95: 0, 1, 2, 3, 4,    6,     */  {  5,  9,  4, 11,  6,  7 },
+/* 175: 0, 1, 2, 3,    5,    7,  */  {  6, 10,  5,  8,  7,  4 },
+/* 183: 0, 1, 2,    4, 5,    7,  */  { 11,  3,  2,  5,  6, 10 },
+/* 231: 0, 1, 2,       5, 6, 7,  */  {  7,  4,  8,  2, 11,  3 },
+/* 123: 0, 1,    3, 4, 5, 6,     */  {  2,  1, 10,  7, 11,  6 },
+/* 219: 0, 1,    3, 4,    6, 7,  */  { 10,  2,  1,  4,  5,  9 },
+/* 189: 0,    2, 3, 4, 5,    7,  */  {  1,  0,  9,  6, 10,  5 },
+/* 237: 0,    2, 3,    5, 6, 7,  */  {  9,  1,  0,  7,  4,  8 },
+/* 245: 0,    2,    4, 5, 6, 7,  */  {  0,  9,  1, 11,  3,  2 },
+/* 126:    1, 2, 3, 4, 5, 6,     */  {  8,  0,  3,  6,  7, 11 },
+/* 222:    1, 2, 3, 4,    6, 7,  */  {  4,  5,  9,  3,  8,  0 },
+/* 250:    1,    3, 4, 5, 6, 7,  */  {  3,  8,  0, 10,  2,  1 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 3.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling3_2[24][12] = {
+/*   5: 0,    2,                 */  { 10,  3,  2, 10,  8,  3, 10,  1,  0,  8, 10,  0 },
+/*  33: 0,             5,        */  {  3,  4,  8,  3,  5,  4,  3,  0,  9,  5,  3,  9 },
+/* 129: 0,                   7,  */  {  6,  8,  7,  6,  0,  8,  6, 11,  3,  0,  6,  3 },
+/*  10:    1,    3,              */  { 11,  0,  3, 11,  9,  0, 11,  2,  1,  9, 11,  1 },
+/*  18:    1,       4,           */  {  7,  9,  4,  7,  1,  9,  7,  8,  0,  1,  7,  0 },
+/*  66:    1,             6,     */  {  6,  1, 10,  6,  0,  1,  9,  0,  6,  9,  6,  5 },
+/*  36:       2,       5,        */  {  4, 10,  5,  4,  2, 10,  4,  9,  1,  2,  4,  1 },
+/* 132:       2,             7,  */  {  7,  2, 11,  7,  1,  2,  7,  6, 10,  1,  7, 10 },
+/*  24:          3, 4,           */  {  2,  7, 11,  2,  4,  7,  2,  3,  8,  4,  2,  8 },
+/*  72:          3,       6,     */  {  5, 11,  6,  5,  3, 11,  5, 10,  2,  3,  5,  2 },
+/*  80:             4,    6,     */  {  8,  6,  7,  8, 10,  6,  8,  4,  5, 10,  8,  5 },
+/* 160:                5,    7,  */  { 11,  5,  6, 11,  9,  5, 11,  7,  4,  9, 11,  4 },
+/*  95: 0, 1, 2, 3, 4,    6,     */  {  6,  5, 11,  5,  9, 11,  4,  7, 11,  4, 11,  9 },
+/* 175: 0, 1, 2, 3,    5,    7,  */  {  7,  6,  8,  6, 10,  8,  5,  4,  8,  5,  8, 10 },
+/* 183: 0, 1, 2,    4, 5,    7,  */  {  6, 11,  5, 11,  3,  5,  2, 10,  5,  2,  5,  3 },
+/* 231: 0, 1, 2,       5, 6, 7,  */  { 11,  7,  2,  7,  4,  2,  8,  3,  2,  8,  2,  4 },
+/* 123: 0, 1,    3, 4, 5, 6,     */  { 11,  2,  7,  2,  1,  7, 10,  6,  7, 10,  7,  1 },
+/* 219: 0, 1,    3, 4,    6, 7,  */  {  5, 10,  4, 10,  2,  4,  1,  9,  4,  1,  4,  2 },
+/* 189: 0,    2, 3, 4, 5,    7,  */  { 10,  1,  6,  1,  0,  6,  6,  0,  9,  5,  6,  9 },
+/* 237: 0,    2, 3,    5, 6, 7,  */  {  4,  9,  7,  9,  1,  7,  0,  8,  7,  0,  7,  1 },
+/* 245: 0,    2,    4, 5, 6, 7,  */  {  3,  0, 11,  0,  9, 11,  1,  2, 11,  1, 11,  9 },
+/* 126:    1, 2, 3, 4, 5, 6,     */  {  7,  8,  6,  8,  0,  6,  3, 11,  6,  3,  6,  0 },
+/* 222:    1, 2, 3, 4,    6, 7,  */  {  8,  4,  3,  4,  5,  3,  9,  0,  3,  9,  3,  5 },
+/* 250:    1,    3, 4, 5, 6, 7,  */  {  2,  3, 10,  3,  8, 10,  0,  1, 10,  0, 10,  8 }
+};
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 4
+ * Interior to test
+ * When the test on the interior is negative : 2 first triangles
+ * When the test on the interior is positive : 6 last triangles
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test4[8] = {
+/*  65: 0,                6,     */   7,
+/* 130:    1,                7,  */   7,
+/*  20:       2,    4,           */   7,
+/*  40:          3,    5,        */   7,
+/* 215: 0, 1, 2,    4,    6, 7,  */  -7,
+/* 235: 0, 1,    3,    5, 6, 7,  */  -7,
+/* 125: 0,    2, 3, 4, 5, 6,     */  -7,
+/* 190:    1, 2, 3, 4, 5,    7,  */  -7
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 4.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling4_1[8][6] = {
+/*  65: 0,                6,     */  {  0,  8,  3,  5, 10,  6 },
+/* 130:    1,                7,  */  {  0,  1,  9, 11,  7,  6 },
+/*  20:       2,    4,           */  {  1,  2, 10,  8,  4,  7 },
+/*  40:          3,    5,        */  {  9,  5,  4,  2,  3, 11 },
+/* 215: 0, 1, 2,    4,    6, 7,  */  {  4,  5,  9, 11,  3,  2 },
+/* 235: 0, 1,    3,    5, 6, 7,  */  { 10,  2,  1,  7,  4,  8 },
+/* 125: 0,    2, 3, 4, 5, 6,     */  {  9,  1,  0,  6,  7, 11 },
+/* 190:    1, 2, 3, 4, 5,    7,  */  {  3,  8,  0,  6, 10,  5 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 4.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling4_2[8][18] = {
+/*  65: 0,                6,     */  {  8,  5,  0,  5,  8,  6,  3,  6,  8,  6,  3, 10,  0, 10,  3, 10,  0,  5 },
+/* 130:    1,                7,  */  {  9,  6,  1,  6,  9,  7,  0,  7,  9,  7,  0, 11,  1, 11,  0, 11,  1,  6 },
+/*  20:       2,    4,           */  { 10,  7,  2,  7, 10,  4,  1,  4, 10,  4,  1,  8,  2,  8,  1,  8,  2,  7 },
+/*  40:          3,    5,        */  { 11,  4,  3,  4, 11,  5,  2,  5, 11,  5,  2,  9,  3,  9,  2,  9,  3,  4 },
+/* 215: 0, 1, 2,    4,    6, 7,  */  {  3,  4, 11,  5, 11,  4, 11,  5,  2,  9,  2,  5,  2,  9,  3,  4,  3,  9 },
+/* 235: 0, 1,    3,    5, 6, 7,  */  {  2,  7, 10,  4, 10,  7, 10,  4,  1,  8,  1,  4,  1,  8,  2,  7,  2,  8 },
+/* 125: 0,    2, 3, 4, 5, 6,     */  {  1,  6,  9,  7,  9,  6,  9,  7,  0, 11,  0,  7,  0, 11,  1,  6,  1, 11 },
+/* 190:    1, 2, 3, 4, 5,    7,  */  {  0,  5,  8,  6,  8,  5,  8,  6,  3, 10,  3,  6,  3, 10,  0,  5,  0, 10 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 5
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling5[48][9] = {
+/*   7: 0, 1, 2,                 */  {  2,  8,  3,  2, 10,  8, 10,  9,  8 },
+/*  11: 0, 1,    3,              */  {  1, 11,  2,  1,  9, 11,  9,  8, 11 },
+/*  19: 0, 1,       4,           */  {  4,  1,  9,  4,  7,  1,  7,  3,  1 },
+/*  35: 0, 1,          5,        */  {  8,  5,  4,  8,  3,  5,  3,  1,  5 },
+/*  13: 0,    2, 3,              */  {  0, 10,  1,  0,  8, 10,  8, 11, 10 },
+/*  25: 0,       3, 4,           */  { 11,  4,  7, 11,  2,  4,  2,  0,  4 },
+/* 137: 0,       3,          7,  */  {  7,  0,  8,  7,  6,  0,  6,  2,  0 },
+/*  49: 0,          4, 5,        */  {  9,  3,  0,  9,  5,  3,  5,  7,  3 },
+/* 145: 0,          4,       7,  */  {  3,  6, 11,  3,  0,  6,  0,  4,  6 },
+/*  14:    1, 2, 3,              */  {  3,  9,  0,  3, 11,  9, 11, 10,  9 },
+/*  38:    1, 2,       5,        */  {  5,  2, 10,  5,  4,  2,  4,  0,  2 },
+/*  70:    1, 2,          6,     */  {  9,  6,  5,  9,  0,  6,  0,  2,  6 },
+/*  50:    1,       4, 5,        */  {  0,  7,  8,  0,  1,  7,  1,  5,  7 },
+/*  98:    1,          5, 6,     */  { 10,  0,  1, 10,  6,  0,  6,  4,  0 },
+/*  76:       2, 3,       6,     */  {  6,  3, 11,  6,  5,  3,  5,  1,  3 },
+/* 140:       2, 3,          7,  */  { 10,  7,  6, 10,  1,  7,  1,  3,  7 },
+/* 100:       2,       5, 6,     */  {  1,  4,  9,  1,  2,  4,  2,  6,  4 },
+/* 196:       2,          6, 7,  */  { 11,  1,  2, 11,  7,  1,  7,  5,  1 },
+/* 152:          3, 4,       7,  */  {  8,  2,  3,  8,  4,  2,  4,  6,  2 },
+/* 200:          3,       6, 7,  */  {  2,  5, 10,  2,  3,  5,  3,  7,  5 },
+/* 112:             4, 5, 6,     */  {  7, 10,  6,  7,  8, 10,  8,  9, 10 },
+/* 176:             4, 5,    7,  */  {  6,  9,  5,  6, 11,  9, 11,  8,  9 },
+/* 208:             4,    6, 7,  */  {  5,  8,  4,  5, 10,  8, 10, 11,  8 },
+/* 224:                5, 6, 7,  */  {  4, 11,  7,  4,  9, 11,  9, 10, 11 },
+/*  31: 0, 1, 2, 3, 4,           */  {  4,  7, 11,  4, 11,  9,  9, 11, 10 },
+/*  47: 0, 1, 2, 3,    5,        */  {  5,  4,  8,  5,  8, 10, 10,  8, 11 },
+/*  79: 0, 1, 2, 3,       6,     */  {  6,  5,  9,  6,  9, 11, 11,  9,  8 },
+/* 143: 0, 1, 2, 3,          7,  */  {  7,  6, 10,  7, 10,  8,  8, 10,  9 },
+/*  55: 0, 1, 2,    4, 5,        */  {  2, 10,  5,  2,  5,  3,  3,  5,  7 },
+/* 103: 0, 1, 2,       5, 6,     */  {  8,  3,  2,  8,  2,  4,  4,  2,  6 },
+/*  59: 0, 1,    3, 4, 5,        */  { 11,  2,  1, 11,  1,  7,  7,  1,  5 },
+/* 155: 0, 1,    3, 4,       7,  */  {  1,  9,  4,  1,  4,  2,  2,  4,  6 },
+/* 115: 0, 1,       4, 5, 6,     */  { 10,  6,  7, 10,  7,  1,  1,  7,  3 },
+/* 179: 0, 1,       4, 5,    7,  */  {  6, 11,  3,  6,  3,  5,  5,  3,  1 },
+/* 157: 0,    2, 3, 4,       7,  */  { 10,  1,  0, 10,  0,  6,  6,  0,  4 },
+/* 205: 0,    2, 3,       6, 7,  */  {  0,  8,  7,  0,  7,  1,  1,  7,  5 },
+/* 185: 0,       3, 4, 5,    7,  */  {  9,  5,  6,  9,  6,  0,  0,  6,  2 },
+/* 217: 0,       3, 4,    6, 7,  */  {  5, 10,  2,  5,  2,  4,  4,  2,  0 },
+/* 241: 0,          4, 5, 6, 7,  */  {  3,  0,  9,  3,  9, 11, 11,  9, 10 },
+/* 110:    1, 2, 3,    5, 6,     */  {  3, 11,  6,  3,  6,  0,  0,  6,  4 },
+/* 206:    1, 2, 3,       6, 7,  */  {  9,  0,  3,  9,  3,  5,  5,  3,  7 },
+/* 118:    1, 2,    4, 5, 6,     */  {  7,  8,  0,  7,  0,  6,  6,  0,  2 },
+/* 230:    1, 2,       5, 6, 7,  */  { 11,  7,  4, 11,  4,  2,  2,  4,  0 },
+/* 242:    1,       4, 5, 6, 7,  */  {  0,  1, 10,  0, 10,  8,  8, 10, 11 },
+/* 220:       2, 3, 4,    6, 7,  */  {  8,  4,  5,  8,  5,  3,  3,  5,  1 },
+/* 236:       2, 3,    5, 6, 7,  */  {  4,  9,  1,  4,  1,  7,  7,  1,  3 },
+/* 244:       2,    4, 5, 6, 7,  */  {  1,  2, 11,  1, 11,  9,  9, 11,  8 },
+/* 248:          3, 4, 5, 6, 7,  */  {  2,  3,  8,  2,  8, 10, 10,  8,  9 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 6
+ * 1 face to test + eventually the interior
+ * When the test on the specified face is positive : 5 first triangles
+ * When the test on the specified face is negative :
+ * - if the test on the interior is negative : 3 middle triangles
+ * - if the test on the interior is positive : 8 last triangles
+ * The support edge for the interior test is marked as the 3rd column.
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test6[48][3] = {
+/*  67: 0, 1,             6,     */  {  2,  7,  10  },
+/* 131: 0, 1,                7,  */  {  4,  7,  11  },
+/*  21: 0,    2,    4,           */  {  5,  7,   1  },
+/*  69: 0,    2,          6,     */  {  5,  7,   3  },
+/*  41: 0,       3,    5,        */  {  1,  7,   9  },
+/*  73: 0,       3,       6,     */  {  3,  7,  10  },
+/*  81: 0,          4,    6,     */  {  6,  7,   5  },
+/*  97: 0,             5, 6,     */  {  1,  7,   8  },
+/* 193: 0,                6, 7,  */  {  4,  7,   8  },
+/*  22:    1, 2,    4,           */  {  1,  7,   8  },
+/* 134:    1, 2,             7,  */  {  3,  7,  11  },
+/*  42:    1,    3,    5,        */  {  5,  7,   2  },
+/* 138:    1,    3,          7,  */  {  5,  7,   0  },
+/* 146:    1,       4,       7,  */  {  1,  7,   9  },
+/* 162:    1,          5,    7,  */  {  6,  7,   6  },
+/* 194:    1,             6, 7,  */  {  2,  7,   9  },
+/*  28:       2, 3, 4,           */  {  4,  7,   8  },
+/*  44:       2, 3,    5,        */  {  2,  7,   9  },
+/*  52:       2,    4, 5,        */  {  2,  7,  10  },
+/*  84:       2,    4,    6,     */  {  6,  7,   7  },
+/* 148:       2,    4,       7,  */  {  3,  7,  10  },
+/*  56:          3, 4, 5,        */  {  4,  7,  11  },
+/* 104:          3,    5, 6,     */  {  3,  7,  11  },
+/* 168:          3,    5,    7,  */  {  6,  7,   4  },
+/*  87: 0, 1, 2,    4,    6,     */  { -6, -7,   4  },
+/* 151: 0, 1, 2,    4,       7,  */  { -3, -7,  11  },
+/* 199: 0, 1, 2,          6, 7,  */  { -4, -7,  11  },
+/* 107: 0, 1,    3,    5, 6,     */  { -3, -7,  10  },
+/* 171: 0, 1,    3,    5,    7,  */  { -6, -7,   7  },
+/* 203: 0, 1,    3,       6, 7,  */  { -2, -7,  10  },
+/* 211: 0, 1,       4,    6, 7,  */  { -2, -7,   9  },
+/* 227: 0, 1,          5, 6, 7,  */  { -4, -7,   8  },
+/*  61: 0,    2, 3, 4, 5,        */  { -2, -7,   9  },
+/*  93: 0,    2, 3, 4,    6,     */  { -6, -7,   6  },
+/* 109: 0,    2, 3,    5, 6,     */  { -1, -7,   9  },
+/* 117: 0,    2,    4, 5, 6,     */  { -5, -7,   0  },
+/* 213: 0,    2,    4,    6, 7,  */  { -5, -7,   2  },
+/* 121: 0,       3, 4, 5, 6,     */  { -3, -7,  11  },
+/* 233: 0,       3,    5, 6, 7,  */  { -1, -7,   8  },
+/*  62:    1, 2, 3, 4, 5,        */  { -4, -7,   8  },
+/* 158:    1, 2, 3, 4,       7,  */  { -1, -7,   8  },
+/* 174:    1, 2, 3,    5,    7,  */  { -6, -7,   5  },
+/* 182:    1, 2,    4, 5,    7,  */  { -3, -7,  10  },
+/* 214:    1, 2,    4,    6, 7,  */  { -1, -7,   9  },
+/* 186:    1,    3, 4, 5,    7,  */  { -5, -7,   3  },
+/* 234:    1,    3,    5, 6, 7,  */  { -5, -7,   1  },
+/* 124:       2, 3, 4, 5, 6,     */  { -4, -7,  11  },
+/* 188:       2, 3, 4, 5,    7,  */  { -2, -7,  10  }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 6.1.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling6_1_1[48][9] = {
+/*  67: 0, 1,             6,     */  {  6,  5, 10,  3,  1,  8,  9,  8,  1 },
+/* 131: 0, 1,                7,  */  { 11,  7,  6,  9,  3,  1,  3,  9,  8 },
+/*  21: 0,    2,    4,           */  {  1,  2, 10,  7,  0,  4,  0,  7,  3 },
+/*  69: 0,    2,          6,     */  {  3,  0,  8,  5,  2,  6,  2,  5,  1 },
+/*  41: 0,       3,    5,        */  {  5,  4,  9,  2,  0, 11,  8, 11,  0 },
+/*  73: 0,       3,       6,     */  { 10,  6,  5,  8,  2,  0,  2,  8, 11 },
+/*  81: 0,          4,    6,     */  { 10,  6,  5,  0,  4,  3,  7,  3,  4 },
+/*  97: 0,             5, 6,     */  {  3,  0,  8,  6,  4, 10,  9, 10,  4 },
+/* 193: 0,                6, 7,  */  {  8,  3,  0, 10,  7,  5,  7, 10, 11 },
+/*  22:    1, 2,    4,           */  {  8,  4,  7, 10,  0,  2,  0, 10,  9 },
+/* 134:    1, 2,             7,  */  {  7,  6, 11,  0,  2,  9, 10,  9,  2 },
+/*  42:    1,    3,    5,        */  {  2,  3, 11,  4,  1,  5,  1,  4,  0 },
+/* 138:    1,    3,          7,  */  {  0,  1,  9,  6,  3,  7,  3,  6,  2 },
+/* 146:    1,       4,       7,  */  {  9,  0,  1, 11,  4,  6,  4, 11,  8 },
+/* 162:    1,          5,    7,  */  { 11,  7,  6,  1,  5,  0,  4,  0,  5 },
+/* 194:    1,             6, 7,  */  {  0,  1,  9,  7,  5, 11, 10, 11,  5 },
+/*  28:       2, 3, 4,           */  {  4,  7,  8,  1,  3, 10, 11, 10,  3 },
+/*  44:       2, 3,    5,        */  {  9,  5,  4, 11,  1,  3,  1, 11, 10 },
+/*  52:       2,    4, 5,        */  { 10,  1,  2,  8,  5,  7,  5,  8,  9 },
+/*  84:       2,    4,    6,     */  {  8,  4,  7,  2,  6,  1,  5,  1,  6 },
+/* 148:       2,    4,       7,  */  {  1,  2, 10,  4,  6,  8, 11,  8,  6 },
+/*  56:          3, 4, 5,        */  {  2,  3, 11,  5,  7,  9,  8,  9,  7 },
+/* 104:          3,    5, 6,     */  { 11,  2,  3,  9,  6,  4,  6,  9, 10 },
+/* 168:          3,    5,    7,  */  {  9,  5,  4,  3,  7,  2,  6,  2,  7 },
+/*  87: 0, 1, 2,    4,    6,     */  {  4,  5,  9,  2,  7,  3,  7,  2,  6 },
+/* 151: 0, 1, 2,    4,       7,  */  {  3,  2, 11,  4,  6,  9, 10,  9,  6 },
+/* 199: 0, 1, 2,          6, 7,  */  { 11,  3,  2,  9,  7,  5,  7,  9,  8 },
+/* 107: 0, 1,    3,    5, 6,     */  { 10,  2,  1,  8,  6,  4,  6,  8, 11 },
+/* 171: 0, 1,    3,    5,    7,  */  {  7,  4,  8,  1,  6,  2,  6,  1,  5 },
+/* 203: 0, 1,    3,       6, 7,  */  {  2,  1, 10,  7,  5,  8,  9,  8,  5 },
+/* 211: 0, 1,       4,    6, 7,  */  {  4,  5,  9,  3,  1, 11, 10, 11,  1 },
+/* 227: 0, 1,          5, 6, 7,  */  {  8,  7,  4, 10,  3,  1,  3, 10, 11 },
+/*  61: 0,    2, 3, 4, 5,        */  {  9,  1,  0, 11,  5,  7,  5, 11, 10 },
+/*  93: 0,    2, 3, 4,    6,     */  {  6,  7, 11,  0,  5,  1,  5,  0,  4 },
+/* 109: 0,    2, 3,    5, 6,     */  {  1,  0,  9,  6,  4, 11,  8, 11,  4 },
+/* 117: 0,    2,    4, 5, 6,     */  {  9,  1,  0,  7,  3,  6,  2,  6,  3 },
+/* 213: 0,    2,    4,    6, 7,  */  { 11,  3,  2,  5,  1,  4,  0,  4,  1 },
+/* 121: 0,       3, 4, 5, 6,     */  { 11,  6,  7,  9,  2,  0,  2,  9, 10 },
+/* 233: 0,       3,    5, 6, 7,  */  {  7,  4,  8,  2,  0, 10,  9, 10,  0 },
+/*  62:    1, 2, 3, 4, 5,        */  {  0,  3,  8,  5,  7, 10, 11, 10,  7 },
+/* 158:    1, 2, 3, 4,       7,  */  {  8,  0,  3, 10,  4,  6,  4, 10,  9 },
+/* 174:    1, 2, 3,    5,    7,  */  {  5,  6, 10,  3,  4,  0,  4,  3,  7 },
+/* 182:    1, 2,    4, 5,    7,  */  {  5,  6, 10,  0,  2,  8, 11,  8,  2 },
+/* 214:    1, 2,    4,    6, 7,  */  {  9,  4,  5, 11,  0,  2,  0, 11,  8 },
+/* 186:    1,    3, 4, 5,    7,  */  {  8,  0,  3,  6,  2,  5,  1,  5,  2 },
+/* 234:    1,    3,    5, 6, 7,  */  { 10,  2,  1,  4,  0,  7,  3,  7,  0 },
+/* 124:       2, 3, 4, 5, 6,     */  {  6,  7, 11,  1,  3,  9,  8,  9,  3 },
+/* 188:       2, 3, 4, 5,    7,  */  { 10,  5,  6,  8,  1,  3,  1,  8,  9 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 6.1.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling6_1_2[48][27] = {
+  /*  67: 0, 1,             6,     */ {  1, 12,  3,   12, 10,  3,    6,  3, 10,    3,  6,  8,    5,  8,  6,    8,  5, 12,   12,  9,  8,    1,  9, 12,   12,  5, 10  },
+  /* 131: 0, 1,                7,  */ {  1, 12,  3,    1, 11, 12,   11,  1,  6,    9,  6,  1,    6,  9,  7,   12,  7,  9,    9,  8, 12,   12,  8,  3,   11,  7, 12  },
+  /*  21: 0,    2,    4,           */ {  4, 12,  0,    4,  1, 12,    1,  4, 10,    7, 10,  4,   10,  7,  2,   12,  2,  7,    7,  3, 12,   12,  3,  0,    1,  2, 12  },
+  /*  69: 0,    2,          6,     */ {  6, 12,  2,    6,  3, 12,    3,  6,  8,    5,  8,  6,    8,  5,  0,   12,  0,  5,    5,  1, 12,   12,  1,  2,    3,  0, 12  },
+  /*  41: 0,       3,    5,        */ {  0, 12,  2,   12,  9,  2,    5,  2,  9,    2,  5, 11,    4, 11,  5,   11,  4, 12,   12,  8, 11,    0,  8, 12,   12,  4,  9  },
+  /*  73: 0,       3,       6,     */ {  0, 12,  2,    0, 10, 12,   10,  0,  5,    8,  5,  0,    5,  8,  6,   12,  6,  8,    8, 11, 12,   12, 11,  2,   10,  6, 12  },
+  /*  81: 0,          4,    6,     */ {  4, 12,  0,   12,  5,  0,   10,  0,  5,    0, 10,  3,    6,  3, 10,    3,  6, 12,   12,  7,  3,    4,  7, 12,   12,  6,  5  },
+  /*  97: 0,             5, 6,     */ {  4, 12,  6,   12,  8,  6,    3,  6,  8,    6,  3, 10,    0, 10,  3,   10,  0, 12,   12,  9, 10,    4,  9, 12,   12,  0,  8  },
+  /* 193: 0,                6, 7,  */ {  5, 12,  7,    5,  8, 12,    8,  5,  0,   10,  0,  5,    0, 10,  3,   12,  3, 10,   10, 11, 12,   12, 11,  7,    8,  3, 12  },
+  /*  22:    1, 2,    4,           */ {  2, 12,  0,    2,  8, 12,    8,  2,  7,   10,  7,  2,    7, 10,  4,   12,  4, 10,   10,  9, 12,   12,  9,  0,    8,  4, 12  },
+  /* 134:    1, 2,             7,  */ {  2, 12,  0,   12, 11,  0,    7,  0, 11,    0,  7,  9,    6,  9,  7,    9,  6, 12,   12, 10,  9,    2, 10, 12,   12,  6, 11  },
+  /*  42:    1,    3,    5,        */ {  5, 12,  1,    5,  2, 12,    2,  5, 11,    4, 11,  5,   11,  4,  3,   12,  3,  4,    4,  0, 12,   12,  0,  1,    2,  3, 12  },
+  /* 138:    1,    3,          7,  */ {  7, 12,  3,    7,  0, 12,    0,  7,  9,    6,  9,  7,    9,  6,  1,   12,  1,  6,    6,  2, 12,   12,  2,  3,    0,  1, 12  },
+  /* 146:    1,       4,       7,  */ {  6, 12,  4,    6,  9, 12,    9,  6,  1,   11,  1,  6,    1, 11,  0,   12,  0, 11,   11,  8, 12,   12,  8,  4,    9,  0, 12  },
+  /* 162:    1,          5,    7,  */ {  5, 12,  1,   12,  6,  1,   11,  1,  6,    1, 11,  0,    7,  0, 11,    0,  7, 12,   12,  4,  0,    5,  4, 12,   12,  7,  6  },
+  /* 194:    1,             6, 7,  */ {  5, 12,  7,   12,  9,  7,    0,  7,  9,    7,  0, 11,    1, 11,  0,   11,  1, 12,   12, 10, 11,    5, 10, 12,   12,  1,  9  },
+  /*  28:       2, 3, 4,           */ {  3, 12,  1,   12,  8,  1,    4,  1,  8,    1,  4, 10,    7, 10,  4,   10,  7, 12,   12, 11, 10,    3, 11, 12,   12,  7,  8  },
+  /*  44:       2, 3,    5,        */ {  3, 12,  1,    3,  9, 12,    9,  3,  4,   11,  4,  3,    4, 11,  5,   12,  5, 11,   11, 10, 12,   12, 10,  1,    9,  5, 12  },
+  /*  52:       2,    4, 5,        */ {  7, 12,  5,    7, 10, 12,   10,  7,  2,    8,  2,  7,    2,  8,  1,   12,  1,  8,    8,  9, 12,   12,  9,  5,   10,  1, 12  },
+  /*  84:       2,    4,    6,     */ {  6, 12,  2,   12,  7,  2,    8,  2,  7,    2,  8,  1,    4,  1,  8,    1,  4, 12,   12,  5,  1,    6,  5, 12,   12,  4,  7  },
+  /* 148:       2,    4,       7,  */ {  6, 12,  4,   12, 10,  4,    1,  4, 10,    4,  1,  8,    2,  8,  1,    8,  2, 12,   12, 11,  8,    6, 11, 12,   12,  2, 10  },
+  /*  56:          3, 4, 5,        */ {  7, 12,  5,   12, 11,  5,    2,  5, 11,    5,  2,  9,    3,  9,  2,    9,  3, 12,   12,  8,  9,    7,  8, 12,   12,  3, 11  },
+  /* 104:          3,    5, 6,     */ {  4, 12,  6,    4, 11, 12,   11,  4,  3,    9,  3,  4,    3,  9,  2,   12,  2,  9,    9, 10, 12,   12, 10,  6,   11,  2, 12  },
+  /* 168:          3,    5,    7,  */ {  7, 12,  3,   12,  4,  3,    9,  3,  4,    3,  9,  2,    5,  2,  9,    2,  5, 12,   12,  6,  2,    7,  6, 12,   12,  5,  4  },
+  /*  87: 0, 1, 2,    4,    6,     */ {  3, 12,  7,    3,  4, 12,    4,  3,  9,    2,  9,  3,    9,  2,  5,   12,  5,  2,    2,  6, 12,   12,  6,  7,    4,  5, 12  },
+  /* 151: 0, 1, 2,    4,       7,  */ {  6, 12,  4,   12, 11,  4,    3,  4, 11,    4,  3,  9,    2,  9,  3,    9,  2, 12,   12, 10,  9,    6, 10, 12,   12,  2, 11  },
+  /* 199: 0, 1, 2,          6, 7,  */ {  5, 12,  7,    5, 11, 12,   11,  5,  2,    9,  2,  5,    2,  9,  3,   12,  3,  9,    9,  8, 12,   12,  8,  7,   11,  3, 12  },
+  /* 107: 0, 1,    3,    5, 6,     */ {  4, 12,  6,    4, 10, 12,   10,  4,  1,    8,  1,  4,    1,  8,  2,   12,  2,  8,    8, 11, 12,   12, 11,  6,   10,  2, 12  },
+  /* 171: 0, 1,    3,    5,    7,  */ {  2, 12,  6,    2,  7, 12,    7,  2,  8,    1,  8,  2,    8,  1,  4,   12,  4,  1,    1,  5, 12,   12,  5,  6,    7,  4, 12  },
+  /* 203: 0, 1,    3,       6, 7,  */ {  5, 12,  7,   12, 10,  7,    2,  7, 10,    7,  2,  8,    1,  8,  2,    8,  1, 12,   12,  9,  8,    5,  9, 12,   12,  1, 10  },
+  /* 211: 0, 1,       4,    6, 7,  */ {  1, 12,  3,   12,  9,  3,    4,  3,  9,    3,  4, 11,    5, 11,  4,   11,  5, 12,   12, 10, 11,    1, 10, 12,   12,  5,  9  },
+  /* 227: 0, 1,          5, 6, 7,  */ {  1, 12,  3,    1,  8, 12,    8,  1,  4,   10,  4,  1,    4, 10,  7,   12,  7, 10,   10, 11, 12,   12, 11,  3,    8,  7, 12  },
+  /*  61: 0,    2, 3, 4, 5,        */ {  7, 12,  5,    7,  9, 12,    9,  7,  0,   11,  0,  7,    0, 11,  1,   12,  1, 11,   11, 10, 12,   12, 10,  5,    9,  1, 12  },
+  /*  93: 0,    2, 3, 4,    6,     */ {  1, 12,  5,    1,  6, 12,    6,  1, 11,    0, 11,  1,   11,  0,  7,   12,  7,  0,    0,  4, 12,   12,  4,  5,    6,  7, 12  },
+  /* 109: 0,    2, 3,    5, 6,     */ {  4, 12,  6,   12,  9,  6,    1,  6,  9,    6,  1, 11,    0, 11,  1,   11,  0, 12,   12,  8, 11,    4,  8, 12,   12,  0,  9  },
+  /* 117: 0,    2,    4, 5, 6,     */ {  3, 12,  7,   12,  0,  7,    9,  7,  0,    7,  9,  6,    1,  6,  9,    6,  1, 12,   12,  2,  6,    3,  2, 12,   12,  1,  0  },
+  /* 213: 0,    2,    4,    6, 7,  */ {  1, 12,  5,   12,  2,  5,   11,  5,  2,    5, 11,  4,    3,  4, 11,    4,  3, 12,   12,  0,  4,    1,  0, 12,   12,  3,  2  },
+  /* 121: 0,       3, 4, 5, 6,     */ {  0, 12,  2,    0, 11, 12,   11,  0,  7,    9,  7,  0,    7,  9,  6,   12,  6,  9,    9, 10, 12,   12, 10,  2,   11,  6, 12  },
+  /* 233: 0,       3,    5, 6, 7,  */ {  0, 12,  2,   12,  8,  2,    7,  2,  8,    2,  7, 10,    4, 10,  7,   10,  4, 12,   12,  9, 10,    0,  9, 12,   12,  4,  8  },
+  /*  62:    1, 2, 3, 4, 5,        */ {  7, 12,  5,   12,  8,  5,    0,  5,  8,    5,  0, 10,    3, 10,  0,   10,  3, 12,   12, 11, 10,    7, 11, 12,   12,  3,  8  },
+  /* 158:    1, 2, 3, 4,       7,  */ {  6, 12,  4,    6,  8, 12,    8,  6,  3,   10,  3,  6,    3, 10,  0,   12,  0, 10,   10,  9, 12,   12,  9,  4,    8,  0, 12  },
+  /* 174:    1, 2, 3,    5,    7,  */ {  0, 12,  4,    0,  5, 12,    5,  0, 10,    3, 10,  0,   10,  3,  6,   12,  6,  3,    3,  7, 12,   12,  7,  4,    5,  6, 12  },
+  /* 182:    1, 2,    4, 5,    7,  */ {  2, 12,  0,   12, 10,  0,    5,  0, 10,    0,  5,  8,    6,  8,  5,    8,  6, 12,   12, 11,  8,    2, 11, 12,   12,  6, 10  },
+  /* 214:    1, 2,    4,    6, 7,  */ {  2, 12,  0,    2,  9, 12,    9,  2,  5,   11,  5,  2,    5, 11,  4,   12,  4, 11,   11,  8, 12,   12,  8,  0,    9,  4, 12  },
+  /* 186:    1,    3, 4, 5,    7,  */ {  2, 12,  6,   12,  3,  6,    8,  6,  3,    6,  8,  5,    0,  5,  8,    5,  0, 12,   12,  1,  5,    2,  1, 12,   12,  0,  3  },
+  /* 234:    1,    3,    5, 6, 7,  */ {  0, 12,  4,   12,  1,  4,   10,  4,  1,    4, 10,  7,    2,  7, 10,    7,  2, 12,   12,  3,  7,    0,  3, 12,   12,  2,  1  },
+  /* 124:       2, 3, 4, 5, 6,     */ {  3, 12,  1,   12, 11,  1,    6,  1, 11,    1,  6,  9,    7,  9,  6,    9,  7, 12,   12,  8,  9,    3,  8, 12,   12,  7, 11  },
+  /* 188:       2, 3, 4, 5,    7,  */ {  3, 12,  1,    3, 10, 12,   10,  3,  6,    8,  6,  3,    6,  8,  5,   12,  5,  8,    8,  9, 12,   12,  9,  1,   10,  5, 12  },
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 6.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling6_2[48][15] = {
+/*  67: 0, 1,             6,     */  {  1, 10,  3,  6,  3, 10,  3,  6,  8,  5,  8,  6,  8,  5,  9 },
+/* 131: 0, 1,                7,  */  {  1, 11,  3, 11,  1,  6,  9,  6,  1,  6,  9,  7,  8,  7,  9 },
+/*  21: 0,    2,    4,           */  {  4,  1,  0,  1,  4, 10,  7, 10,  4, 10,  7,  2,  3,  2,  7 },
+/*  69: 0,    2,          6,     */  {  6,  3,  2,  3,  6,  8,  5,  8,  6,  8,  5,  0,  1,  0,  5 },
+/*  41: 0,       3,    5,        */  {  0,  9,  2,  5,  2,  9,  2,  5, 11,  4, 11,  5, 11,  4,  8 },
+/*  73: 0,       3,       6,     */  {  0, 10,  2, 10,  0,  5,  8,  5,  0,  5,  8,  6, 11,  6,  8 },
+/*  81: 0,          4,    6,     */  {  4,  5,  0, 10,  0,  5,  0, 10,  3,  6,  3, 10,  3,  6,  7 },
+/*  97: 0,             5, 6,     */  {  4,  8,  6,  3,  6,  8,  6,  3, 10,  0, 10,  3, 10,  0,  9 },
+/* 193: 0,                6, 7,  */  {  5,  8,  7,  8,  5,  0, 10,  0,  5,  0, 10,  3, 11,  3, 10 },
+/*  22:    1, 2,    4,           */  {  2,  8,  0,  8,  2,  7, 10,  7,  2,  7, 10,  4,  9,  4, 10 },
+/* 134:    1, 2,             7,  */  {  2, 11,  0,  7,  0, 11,  0,  7,  9,  6,  9,  7,  9,  6, 10 },
+/*  42:    1,    3,    5,        */  {  5,  2,  1,  2,  5, 11,  4, 11,  5, 11,  4,  3,  0,  3,  4 },
+/* 138:    1,    3,          7,  */  {  7,  0,  3,  0,  7,  9,  6,  9,  7,  9,  6,  1,  2,  1,  6 },
+/* 146:    1,       4,       7,  */  {  6,  9,  4,  9,  6,  1, 11,  1,  6,  1, 11,  0,  8,  0, 11 },
+/* 162:    1,          5,    7,  */  {  5,  6,  1, 11,  1,  6,  1, 11,  0,  7,  0, 11,  0,  7,  4 },
+/* 194:    1,             6, 7,  */  {  5,  9,  7,  0,  7,  9,  7,  0, 11,  1, 11,  0, 11,  1, 10 },
+/*  28:       2, 3, 4,           */  {  3,  8,  1,  4,  1,  8,  1,  4, 10,  7, 10,  4, 10,  7, 11 },
+/*  44:       2, 3,    5,        */  {  3,  9,  1,  9,  3,  4, 11,  4,  3,  4, 11,  5, 10,  5, 11 },
+/*  52:       2,    4, 5,        */  {  7, 10,  5, 10,  7,  2,  8,  2,  7,  2,  8,  1,  9,  1,  8 },
+/*  84:       2,    4,    6,     */  {  6,  7,  2,  8,  2,  7,  2,  8,  1,  4,  1,  8,  1,  4,  5 },
+/* 148:       2,    4,       7,  */  {  6, 10,  4,  1,  4, 10,  4,  1,  8,  2,  8,  1,  8,  2, 11 },
+/*  56:          3, 4, 5,        */  {  7, 11,  5,  2,  5, 11,  5,  2,  9,  3,  9,  2,  9,  3,  8 },
+/* 104:          3,    5, 6,     */  {  4, 11,  6, 11,  4,  3,  9,  3,  4,  3,  9,  2, 10,  2,  9 },
+/* 168:          3,    5,    7,  */  {  7,  4,  3,  9,  3,  4,  3,  9,  2,  5,  2,  9,  2,  5,  6 },
+/*  87: 0, 1, 2,    4,    6,     */  {  3,  4,  7,  4,  3,  9,  2,  9,  3,  9,  2,  5,  6,  5,  2 },
+/* 151: 0, 1, 2,    4,       7,  */  {  6, 11,  4,  3,  4, 11,  4,  3,  9,  2,  9,  3,  9,  2, 10 },
+/* 199: 0, 1, 2,          6, 7,  */  {  5, 11,  7, 11,  5,  2,  9,  2,  5,  2,  9,  3,  8,  3,  9 },
+/* 107: 0, 1,    3,    5, 6,     */  {  4, 10,  6, 10,  4,  1,  8,  1,  4,  1,  8,  2, 11,  2,  8 },
+/* 171: 0, 1,    3,    5,    7,  */  {  2,  7,  6,  7,  2,  8,  1,  8,  2,  8,  1,  4,  5,  4,  1 },
+/* 203: 0, 1,    3,       6, 7,  */  {  5, 10,  7,  2,  7, 10,  7,  2,  8,  1,  8,  2,  8,  1,  9 },
+/* 211: 0, 1,       4,    6, 7,  */  {  1,  9,  3,  4,  3,  9,  3,  4, 11,  5, 11,  4, 11,  5, 10 },
+/* 227: 0, 1,          5, 6, 7,  */  {  1,  8,  3,  8,  1,  4, 10,  4,  1,  4, 10,  7, 11,  7, 10 },
+/*  61: 0,    2, 3, 4, 5,        */  {  7,  9,  5,  9,  7,  0, 11,  0,  7,  0, 11,  1, 10,  1, 11 },
+/*  93: 0,    2, 3, 4,    6,     */  {  1,  6,  5,  6,  1, 11,  0, 11,  1, 11,  0,  7,  4,  7,  0 },
+/* 109: 0,    2, 3,    5, 6,     */  {  4,  9,  6,  1,  6,  9,  6,  1, 11,  0, 11,  1, 11,  0,  8 },
+/* 117: 0,    2,    4, 5, 6,     */  {  3,  0,  7,  9,  7,  0,  7,  9,  6,  1,  6,  9,  6,  1,  2 },
+/* 213: 0,    2,    4,    6, 7,  */  {  1,  2,  5, 11,  5,  2,  5, 11,  4,  3,  4, 11,  4,  3,  0 },
+/* 121: 0,       3, 4, 5, 6,     */  {  0, 11,  2, 11,  0,  7,  9,  7,  0,  7,  9,  6, 10,  6,  9 },
+/* 233: 0,       3,    5, 6, 7,  */  {  0,  8,  2,  7,  2,  8,  2,  7, 10,  4, 10,  7, 10,  4,  9 },
+/*  62:    1, 2, 3, 4, 5,        */  {  7,  8,  5,  0,  5,  8,  5,  0, 10,  3, 10,  0, 10,  3, 11 },
+/* 158:    1, 2, 3, 4,       7,  */  {  6,  8,  4,  8,  6,  3, 10,  3,  6,  3, 10,  0,  9,  0, 10 },
+/* 174:    1, 2, 3,    5,    7,  */  {  0,  5,  4,  5,  0, 10,  3, 10,  0, 10,  3,  6,  7,  6,  3 },
+/* 182:    1, 2,    4, 5,    7,  */  {  2, 10,  0,  5,  0, 10,  0,  5,  8,  6,  8,  5,  8,  6, 11 },
+/* 214:    1, 2,    4,    6, 7,  */  {  2,  9,  0,  9,  2,  5, 11,  5,  2,  5, 11,  4,  8,  4, 11 },
+/* 186:    1,    3, 4, 5,    7,  */  {  2,  3,  6,  8,  6,  3,  6,  8,  5,  0,  5,  8,  5,  0,  1 },
+/* 234:    1,    3,    5, 6, 7,  */  {  0,  1,  4, 10,  4,  1,  4, 10,  7,  2,  7, 10,  7,  2,  3 },
+/* 124:       2, 3, 4, 5, 6,     */  {  3, 11,  1,  6,  1, 11,  1,  6,  9,  7,  9,  6,  9,  7,  8 },
+/* 188:       2, 3, 4, 5,    7,  */  {  3, 10,  1, 10,  3,  6,  8,  6,  3,  6,  8,  5,  9,  5,  8 }
+};
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 7
+ * 3 faces to test + eventually the interior
+ * When the tests on the 3 specified faces are positive :
+ * - if the test on the interior is positive : 5 first triangles
+ * - if the test on the interior is negative : 9 next triangles
+ * When the tests on the first  and the second specified faces are positive : 9 next triangles
+ * When the tests on the first  and the third  specified faces are positive : 9 next triangles
+ * When the tests on the second and the third  specified faces are positive : 9 next triangles
+ * When the test on the first  specified face is positive : 5 next triangles
+ * When the test on the second specified face is positive : 5 next triangles
+ * When the test on the third  specified face is positive : 5 next triangles
+ * When the tests on the 3 specified faces are negative : 3 last triangles
+ * The support edge for the interior test is marked as the 5th column.
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test7[16][5] = {
+/*  37: 0,    2,       5,        */  {  1,  2,  5,  7,   1 },
+/* 133: 0,    2,             7,  */  {  3,  4,  5,  7,   3 },
+/* 161: 0,             5,    7,  */  {  4,  1,  6,  7,   4 },
+/*  26:    1,    3, 4,           */  {  4,  1,  5,  7,   0 },
+/*  74:    1,    3,       6,     */  {  2,  3,  5,  7,   2 },
+/*  82:    1,       4,    6,     */  {  1,  2,  6,  7,   5 },
+/* 164:       2,       5,    7,  */  {  2,  3,  6,  7,   6 },
+/*  88:          3, 4,    6,     */  {  3,  4,  6,  7,   7 },
+/* 167: 0, 1, 2,       5,    7,  */  { -3, -4, -6, -7,   7 },
+/*  91: 0, 1,    3, 4,    6,     */  { -2, -3, -6, -7,   6 },
+/* 173: 0,    2, 3,    5,    7,  */  { -1, -2, -6, -7,   5 },
+/* 181: 0,    2,    4, 5,    7,  */  { -2, -3, -5, -7,   2 },
+/* 229: 0,    2,       5, 6, 7,  */  { -4, -1, -5, -7,   0 },
+/*  94:    1, 2, 3, 4,    6,     */  { -4, -1, -6, -7,   4 },
+/* 122:    1,    3, 4, 5, 6,     */  { -3, -4, -5, -7,   3 },
+/* 218:    1,    3, 4,    6, 7,  */  { -1, -2, -5, -7,   1 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 7.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling7_1[16][9] = {
+/*  37: 0,    2,       5,        */  {  9,  5,  4, 10,  1,  2,  8,  3,  0 },
+/* 133: 0,    2,             7,  */  { 11,  7,  6,  8,  3,  0, 10,  1,  2 },
+/* 161: 0,             5,    7,  */  {  3,  0,  8,  5,  4,  9,  7,  6, 11 },
+/*  26:    1,    3, 4,           */  {  8,  4,  7,  9,  0,  1, 11,  2,  3 },
+/*  74:    1,    3,       6,     */  { 10,  6,  5, 11,  2,  3,  9,  0,  1 },
+/*  82:    1,       4,    6,     */  {  0,  1,  9,  6,  5, 10,  4,  7,  8 },
+/* 164:       2,       5,    7,  */  {  1,  2, 10,  7,  6, 11,  5,  4,  9 },
+/*  88:          3, 4,    6,     */  {  2,  3, 11,  4,  7,  8,  6,  5, 10 },
+/* 167: 0, 1, 2,       5,    7,  */  { 11,  3,  2,  8,  7,  4, 10,  5,  6 },
+/*  91: 0, 1,    3, 4,    6,     */  { 10,  2,  1, 11,  6,  7,  9,  4,  5 },
+/* 173: 0,    2, 3,    5,    7,  */  {  9,  1,  0, 10,  5,  6,  8,  7,  4 },
+/* 181: 0,    2,    4, 5,    7,  */  {  5,  6, 10,  3,  2, 11,  1,  0,  9 },
+/* 229: 0,    2,       5, 6, 7,  */  {  7,  4,  8,  1,  0,  9,  3,  2, 11 },
+/*  94:    1, 2, 3, 4,    6,     */  {  8,  0,  3,  9,  4,  5, 11,  6,  7 },
+/* 122:    1,    3, 4, 5, 6,     */  {  6,  7, 11,  0,  3,  8,  2,  1, 10 },
+/* 218:    1,    3, 4,    6, 7,  */  {  4,  5,  9,  2,  1, 10,  0,  3,  8 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 7.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling7_2[16][3][15] = {
+/*  37: 0,    2,       5,        */  {
+ /* 1,0 */ {  1,  2, 10,  3,  4,  8,  4,  3,  5,  0,  5,  3,  5,  0,  9 },
+ /* 0,1 */ {  3,  0,  8,  9,  1,  4,  2,  4,  1,  4,  2,  5, 10,  5,  2 },
+ /* 1,1 */ {  9,  5,  4,  0, 10,  1, 10,  0,  8, 10,  8,  2,  3,  2,  8 }
+},
+/* 133: 0,    2,             7,  */  {
+ /* 1,0 */ {  3,  0,  8,  1,  6, 10,  6,  1,  7,  2,  7,  1,  7,  2, 11 },
+ /* 0,1 */ {  1,  2, 10, 11,  3,  6,  0,  6,  3,  6,  0,  7,  8,  7,  0 },
+ /* 1,1 */ { 11,  7,  6,  2,  8,  3,  8,  2, 10,  8, 10,  0,  1,  0, 10 }
+},
+/* 161: 0,             5,    7,  */  {
+ /* 1,0 */ {  9,  5,  4, 11,  3,  6,  0,  6,  3,  6,  0,  7,  8,  7,  0 },
+ /* 0,1 */ { 11,  7,  6,  3,  4,  8,  4,  3,  5,  0,  5,  3,  5,  0,  9 },
+ /* 1,1 */ {  3,  0,  8,  4,  9,  7, 11,  7,  9,  5, 11,  9, 11,  5,  6 }
+},
+/*  26:    1,    3, 4,           */  {
+ /* 1,0 */ {  0,  1,  9,  2,  7, 11,  7,  2,  4,  3,  4,  2,  4,  3,  8 },
+ /* 0,1 */ {  2,  3, 11,  8,  0,  7,  1,  7,  0,  7,  1,  4,  9,  4,  1 },
+ /* 1,1 */ {  8,  4,  7,  3,  9,  0,  9,  3, 11,  9, 11,  1,  2,  1, 11 }
+},
+/*  74:    1,    3,       6,     */  {
+ /* 1,0 */ {  2,  3, 11,  0,  5,  9,  5,  0,  6,  1,  6,  0,  6,  1, 10 },
+ /* 0,1 */ {  0,  1,  9, 10,  2,  5,  3,  5,  2,  5,  3,  6, 11,  6,  3 },
+ /* 1,1 */ {  6,  5, 10,  1, 11,  2, 11,  1,  9, 11,  9,  3,  0,  3,  9 }
+},
+/*  82:    1,       4,    6,     */  {
+ /* 1,0 */ {  6,  5, 10,  8,  0,  7,  1,  7,  0,  7,  1,  4,  9,  4,  1 },
+ /* 0,1 */ {  8,  4,  7,  0,  5,  9,  5,  0,  6,  1,  6,  0,  6,  1, 10 },
+ /* 1,1 */ {  0,  1,  9,  5, 10,  4,  8,  4, 10,  6,  8, 10,  8,  6,  7 }
+},
+/* 164:       2,       5,    7,  */  {
+ /* 1,0 */ { 11,  7,  6,  9,  1,  4,  2,  4,  1,  4,  2,  5, 10,  5,  2 },
+ /* 0,1 */ {  9,  5,  4,  1,  6, 10,  6,  1,  7,  2,  7,  1,  7,  2, 11 },
+ /* 1,1 */ {  1,  2, 10,  6, 11,  5,  9,  5, 11,  7,  9, 11,  9,  7,  4 }
+},
+/*  88:          3, 4,    6,     */  {
+ /* 1,0 */ {  8,  4,  7, 10,  2,  5,  3,  5,  2,  5,  3,  6, 11,  6,  3 },
+ /* 0,1 */ {  6,  5, 10,  2,  7, 11,  7,  2,  4,  3,  4,  2,  4,  3,  8 },
+ /* 1,1 */ {  2,  3, 11,  7,  8,  6, 10,  6,  8,  4, 10,  8, 10,  4,  5 }
+},
+/* 167: 0, 1, 2,       5,    7,  */  {
+ /* 1,0 */ {  7,  4,  8,  5,  2, 10,  2,  5,  3,  6,  3,  5,  3,  6, 11 },
+ /* 0,1 */ { 10,  5,  6, 11,  7,  2,  4,  2,  7,  2,  4,  3,  8,  3,  4 },
+ /* 1,1 */ { 11,  3,  2,  6,  8,  7,  8,  6, 10,  8, 10,  4,  5,  4, 10 }
+},
+/*  91: 0, 1,    3, 4,    6,     */  {
+ /* 1,0 */ {  6,  7, 11,  4,  1,  9,  1,  4,  2,  5,  2,  4,  2,  5, 10 },
+ /* 0,1 */ {  4,  5,  9, 10,  6,  1,  7,  1,  6,  1,  7,  2, 11,  2,  7 },
+ /* 1,1 */ { 10,  2,  1,  5, 11,  6, 11,  5,  9, 11,  9,  7,  4,  7,  9 }
+},
+/* 173: 0,    2, 3,    5,    7,  */  {
+ /* 1,0 */ { 10,  5,  6,  7,  0,  8,  0,  7,  1,  4,  1,  7,  1,  4,  9 },
+ /* 0,1 */ {  7,  4,  8,  9,  5,  0,  6,  0,  5,  0,  6,  1, 10,  1,  6 },
+ /* 1,1 */ {  9,  1,  0,  4, 10,  5, 10,  4,  8, 10,  8,  6,  7,  6,  8 }
+},
+/* 181: 0,    2,    4, 5,    7,  */  {
+ /* 1,0 */ { 11,  3,  2,  9,  5,  0,  6,  0,  5,  0,  6,  1, 10,  1,  6 },
+ /* 0,1 */ {  9,  1,  0,  5,  2, 10,  2,  5,  3,  6,  3,  5,  3,  6, 11 },
+ /* 1,1 */ { 10,  5,  6,  2, 11,  1,  9,  1, 11,  3,  9, 11,  9,  3,  0 }
+},
+/* 229: 0,    2,       5, 6, 7,  */  {
+ /* 1,0 */ {  9,  1,  0, 11,  7,  2,  4,  2,  7,  2,  4,  3,  8,  3,  4 },
+ /* 0,1 */ { 11,  3,  2,  7,  0,  8,  0,  7,  1,  4,  1,  7,  1,  4,  9 },
+ /* 1,1 */ {  7,  4,  8,  0,  9,  3, 11,  3,  9,  1, 11,  9, 11,  1,  2 }
+},
+/*  94:    1, 2, 3, 4,    6,     */  {
+ /* 1,0 */ {  4,  5,  9,  6,  3, 11,  3,  6,  0,  7,  0,  6,  0,  7,  8 },
+ /* 0,1 */ {  6,  7, 11,  8,  4,  3,  5,  3,  4,  3,  5,  0,  9,  0,  5 },
+ /* 1,1 */ {  8,  0,  3,  7,  9,  4,  9,  7, 11,  9, 11,  5,  6,  5, 11 }
+},
+/* 122:    1,    3, 4, 5, 6,     */  {
+ /* 1,0 */ {  8,  0,  3, 10,  6,  1,  7,  1,  6,  1,  7,  2, 11,  2,  7 },
+ /* 0,1 */ { 10,  2,  1,  6,  3, 11,  3,  6,  0,  7,  0,  6,  0,  7,  8 },
+ /* 1,1 */ {  6,  7, 11,  3,  8,  2, 10,  2,  8,  0, 10,  8, 10,  0,  1 }
+},
+/* 218:    1,    3, 4,    6, 7,  */  {
+ /* 1,0 */ { 10,  2,  1,  8,  4,  3,  5,  3,  4,  3,  5,  0,  9,  0,  5 },
+ /* 0,1 */ {  8,  0,  3,  4,  1,  9,  1,  4,  2,  5,  2,  4,  2,  5, 10 },
+ /* 1,1 */ {  4,  5,  9,  1, 10,  0,  8,  0, 10,  2,  8, 10,  8,  2,  3 } }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 7.3
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling7_3[16][3][27] = {
+/*  37: 0,    2,       5,        */  {
+ /* 1,0 */ { 12,  2, 10, 12, 10,  5, 12,  5,  4, 12,  4,  8, 12,  8,  3, 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2 },
+ /* 0,1 */ { 12,  5,  4, 12,  4,  8, 12,  8,  3, 12,  3,  2, 12,  2, 10, 12, 10,  1, 12,  1,  0, 12,  0,  9, 12,  9,  5 },
+ /* 1,1 */ {  5,  4, 12, 10,  5, 12,  2, 10, 12,  3,  2, 12,  8,  3, 12,  0,  8, 12,  1,  0, 12,  9,  1, 12,  4,  9, 12 }
+},
+/* 133: 0,    2,             7,  */  {
+ /* 1,0 */ { 12,  0,  8, 12,  8,  7, 12,  7,  6, 12,  6, 10, 12, 10,  1, 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0 },
+ /* 0,1 */ { 12,  7,  6, 12,  6, 10, 12, 10,  1, 12,  1,  0, 12,  0,  8, 12,  8,  3, 12,  3,  2, 12,  2, 11, 12, 11,  7 },
+ /* 1,1 */ {  7,  6, 12,  8,  7, 12,  0,  8, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12, 11,  3, 12,  6, 11, 12 }
+},
+/* 161: 0,             5,    7,  */  {
+ /* 1,0 */ {  9,  5, 12,  0,  9, 12,  3,  0, 12, 11,  3, 12,  6, 11, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12 },
+ /* 0,1 */ {  3,  0, 12, 11,  3, 12,  6, 11, 12,  5,  6, 12,  9,  5, 12,  4,  9, 12,  7,  4, 12,  8,  7, 12,  0,  8, 12 },
+ /* 1,1 */ { 12,  3,  0, 12,  0,  9, 12,  9,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4, 12,  4,  8, 12,  8,  3 }
+},
+/*  26:    1,    3, 4,           */  {
+ /* 1,0 */ { 12,  1,  9, 12,  9,  4, 12,  4,  7, 12,  7, 11, 12, 11,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1 },
+ /* 0,1 */ { 12,  4,  7, 12,  7, 11, 12, 11,  2, 12,  2,  1, 12,  1,  9, 12,  9,  0, 12,  0,  3, 12,  3,  8, 12,  8,  4 },
+ /* 1,1 */ {  4,  7, 12,  9,  4, 12,  1,  9, 12,  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12,  8,  0, 12,  7,  8, 12 }
+},
+/*  74:    1,    3,       6,     */  {
+ /* 1,0 */ { 12,  3, 11, 12, 11,  6, 12,  6,  5, 12,  5,  9, 12,  9,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3 },
+ /* 0,1 */ { 12,  6,  5, 12,  5,  9, 12,  9,  0, 12,  0,  3, 12,  3, 11, 12, 11,  2, 12,  2,  1, 12,  1, 10, 12, 10,  6 },
+ /* 1,1 */ {  6,  5, 12, 11,  6, 12,  3, 11, 12,  0,  3, 12,  9,  0, 12,  1,  9, 12,  2,  1, 12, 10,  2, 12,  5, 10, 12 }
+},
+/*  82:    1,       4,    6,     */  {
+ /* 1,0 */ { 10,  6, 12,  1, 10, 12,  0,  1, 12,  8,  0, 12,  7,  8, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12 },
+ /* 0,1 */ {  0,  1, 12,  8,  0, 12,  7,  8, 12,  6,  7, 12, 10,  6, 12,  5, 10, 12,  4,  5, 12,  9,  4, 12,  1,  9, 12 },
+ /* 1,1 */ { 12,  0,  1, 12,  1, 10, 12, 10,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5, 12,  5,  9, 12,  9,  0 }
+},
+/* 164:       2,       5,    7,  */  {
+ /* 1,0 */ { 11,  7, 12,  2, 11, 12,  1,  2, 12,  9,  1, 12,  4,  9, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12 },
+ /* 0,1 */ {  1,  2, 12,  9,  1, 12,  4,  9, 12,  7,  4, 12, 11,  7, 12,  6, 11, 12,  5,  6, 12, 10,  5, 12,  2, 10, 12 },
+ /* 1,1 */ { 12,  1,  2, 12,  2, 11, 12, 11,  7, 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6, 12,  6, 10, 12, 10,  1 }
+},
+/*  88:          3, 4,    6,     */  {
+ /* 1,0 */ {  8,  4, 12,  3,  8, 12,  2,  3, 12, 10,  2, 12,  5, 10, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12 },
+ /* 0,1 */ {  2,  3, 12, 10,  2, 12,  5, 10, 12,  4,  5, 12,  8,  4, 12,  7,  8, 12,  6,  7, 12, 11,  6, 12,  3, 11, 12 },
+ /* 1,1 */ { 12,  2,  3, 12,  3,  8, 12,  8,  4, 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7, 12,  7, 11, 12, 11,  2 }
+},
+/* 167: 0, 1, 2,       5,    7,  */  {
+ /* 1,0 */ { 12,  4,  8, 12,  8,  3, 12,  3,  2, 12,  2, 10, 12, 10,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4 },
+ /* 0,1 */ { 12,  3,  2, 12,  2, 10, 12, 10,  5, 12,  5,  4, 12,  4,  8, 12,  8,  7, 12,  7,  6, 12,  6, 11, 12, 11,  3 },
+ /* 1,1 */ {  3,  2, 12,  8,  3, 12,  4,  8, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12, 11,  7, 12,  2, 11, 12 }
+},
+/*  91: 0, 1,    3, 4,    6,     */  {
+ /* 1,0 */ { 12,  7, 11, 12, 11,  2, 12,  2,  1, 12,  1,  9, 12,  9,  4, 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7 },
+ /* 0,1 */ { 12,  2,  1, 12,  1,  9, 12,  9,  4, 12,  4,  7, 12,  7, 11, 12, 11,  6, 12,  6,  5, 12,  5, 10, 12, 10,  2 },
+ /* 1,1 */ {  2,  1, 12, 11,  2, 12,  7, 11, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12, 10,  6, 12,  1, 10, 12 }
+},
+/* 173: 0,    2, 3,    5,    7,  */  {
+ /* 1,0 */ { 12,  6, 10, 12, 10,  1, 12,  1,  0, 12,  0,  8, 12,  8,  7, 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6 },
+ /* 0,1 */ { 12,  1,  0, 12,  0,  8, 12,  8,  7, 12,  7,  6, 12,  6, 10, 12, 10,  5, 12,  5,  4, 12,  4,  9, 12,  9,  1 },
+ /* 1,1 */ {  1,  0, 12, 10,  1, 12,  6, 10, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12,  9,  5, 12,  0,  9, 12 }
+},
+/* 181: 0,    2,    4, 5,    7,  */  {
+ /* 1,0 */ { 11,  3, 12,  6, 11, 12,  5,  6, 12,  9,  5, 12,  0,  9, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12 },
+ /* 0,1 */ {  5,  6, 12,  9,  5, 12,  0,  9, 12,  3,  0, 12, 11,  3, 12,  2, 11, 12,  1,  2, 12, 10,  1, 12,  6, 10, 12 },
+ /* 1,1 */ { 12,  5,  6, 12,  6, 11, 12, 11,  3, 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2, 12,  2, 10, 12, 10,  5 }
+},
+/* 229: 0,    2,       5, 6, 7,  */  {
+ /* 1,0 */ {  9,  1, 12,  4,  9, 12,  7,  4, 12, 11,  7, 12,  2, 11, 12,  3,  2, 12,  8,  3, 12,  0,  8, 12,  1,  0, 12 },
+ /* 0,1 */ {  7,  4, 12, 11,  7, 12,  2, 11, 12,  1,  2, 12,  9,  1, 12,  0,  9, 12,  3,  0, 12,  8,  3, 12,  4,  8, 12 },
+ /* 1,1 */ { 12,  7,  4, 12,  4,  9, 12,  9,  1, 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0, 12,  0,  8, 12,  8,  7 }
+},
+/*  94:    1, 2, 3, 4,    6,     */  {
+ /* 1,0 */ { 12,  5,  9, 12,  9,  0, 12,  0,  3, 12,  3, 11, 12, 11,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5 },
+ /* 0,1 */ { 12,  0,  3, 12,  3, 11, 12, 11,  6, 12,  6,  5, 12,  5,  9, 12,  9,  4, 12,  4,  7, 12,  7,  8, 12,  8,  0 },
+ /* 1,1 */ {  0,  3, 12,  9,  0, 12,  5,  9, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12,  8,  4, 12,  3,  8, 12 }
+},
+/* 122:    1,    3, 4, 5, 6,     */  {
+ /* 1,0 */ {  8,  0, 12,  7,  8, 12,  6,  7, 12, 10,  6, 12,  1, 10, 12,  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12 },
+ /* 0,1 */ {  6,  7, 12, 10,  6, 12,  1, 10, 12,  0,  1, 12,  8,  0, 12,  3,  8, 12,  2,  3, 12, 11,  2, 12,  7, 11, 12 },
+ /* 1,1 */ { 12,  6,  7, 12,  7,  8, 12,  8,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3, 12,  3, 11, 12, 11,  6 }
+},
+/* 218:    1,    3, 4,    6, 7,  */  {
+ /* 1,0 */ { 10,  2, 12,  5, 10, 12,  4,  5, 12,  8,  4, 12,  3,  8, 12,  0,  3, 12,  9,  0, 12,  1,  9, 12,  2,  1, 12 },
+ /* 0,1 */ {  4,  5, 12,  8,  4, 12,  3,  8, 12,  2,  3, 12, 10,  2, 12,  1, 10, 12,  0,  1, 12,  9,  0, 12,  5,  9, 12 },
+ /* 1,1 */ { 12,  4,  5, 12,  5, 10, 12, 10,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1, 12,  1,  9, 12,  9,  4 } }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 7.4.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling7_4_1[16][15] = {
+/*  37: 0,    2,       5,        */  {  3,  4,  8,  4,  3, 10,  2, 10,  3,  4, 10,  5,  9,  1,  0 },
+/* 133: 0,    2,             7,  */  {  1,  6, 10,  6,  1,  8,  0,  8,  1,  6,  8,  7, 11,  3,  2 },
+/* 161: 0,             5,    7,  */  { 11,  3,  6,  9,  6,  3,  6,  9,  5,  0,  9,  3,  7,  4,  8 },
+/*  26:    1,    3, 4,           */  {  2,  7, 11,  7,  2,  9,  1,  9,  2,  7,  9,  4,  8,  0,  3 },
+/*  74:    1,    3,       6,     */  {  0,  5,  9,  5,  0, 11,  3, 11,  0,  5, 11,  6, 10,  2,  1 },
+/*  82:    1,       4,    6,     */  {  8,  0,  7, 10,  7,  0,  7, 10,  6,  1, 10,  0,  4,  5,  9 },
+/* 164:       2,       5,    7,  */  {  9,  1,  4, 11,  4,  1,  4, 11,  7,  2, 11,  1,  5,  6, 10 },
+/*  88:          3, 4,    6,     */  { 10,  2,  5,  8,  5,  2,  5,  8,  4,  3,  8,  2,  6,  7, 11 },
+/* 167: 0, 1, 2,       5,    7,  */  {  5,  2, 10,  2,  5,  8,  4,  8,  5,  2,  8,  3, 11,  7,  6 },
+/*  91: 0, 1,    3, 4,    6,     */  {  4,  1,  9,  1,  4, 11,  7, 11,  4,  1, 11,  2, 10,  6,  5 },
+/* 173: 0,    2, 3,    5,    7,  */  {  7,  0,  8,  0,  7, 10,  6, 10,  7,  0, 10,  1,  9,  5,  4 },
+/* 181: 0,    2,    4, 5,    7,  */  {  9,  5,  0, 11,  0,  5,  0, 11,  3,  6, 11,  5,  1,  2, 10 },
+/* 229: 0,    2,       5, 6, 7,  */  { 11,  7,  2,  9,  2,  7,  2,  9,  1,  4,  9,  7,  3,  0,  8 },
+/*  94:    1, 2, 3, 4,    6,     */  {  6,  3, 11,  3,  6,  9,  5,  9,  6,  3,  9,  0,  8,  4,  7 },
+/* 122:    1,    3, 4, 5, 6,     */  { 10,  6,  1,  8,  1,  6,  1,  8,  0,  7,  8,  6,  2,  3, 11 },
+/* 218:    1,    3, 4,    6, 7,  */  {  8,  4,  3, 10,  3,  4,  3, 10,  2,  5, 10,  4,  0,  1,  9 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 7.4.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling7_4_2[16][27] = {
+/*  37: 0,    2,       5,        */  {   9,  4,  8,  4,  9,  5, 10,  5,  9,  1, 10,  9, 10,  1,  2,  0,  2,  1,  2,  0,  3,  8,  3,  0,  9,  8,  0 },
+/* 133: 0,    2,             7,  */  {  11,  6, 10,  6, 11,  7,  8,  7, 11,  3,  8, 11,  8,  3,  0,  2,  0,  3,  0,  2,  1, 10,  1,  2, 11, 10,  2 },
+/* 161: 0,             5,    7,  */  {  11,  3,  8,  0,  8,  3,  8,  0,  9,  8,  9,  4,  5,  4,  9,  4,  5,  7,  6,  7,  5,  7,  6, 11,  7, 11,  8 },
+/*  26:    1,    3, 4,           */  {   8,  7, 11,  7,  8,  4,  9,  4,  8,  0,  9,  8,  9,  0,  1,  3,  1,  0,  1,  3,  2, 11,  2,  3,  8, 11,  3 },
+/*  74:    1,    3,       6,     */  {  10,  5,  9,  5, 10,  6, 11,  6, 10,  2, 11, 10, 11,  2,  3,  1,  3,  2,  3,  1,  0,  9,  0,  1, 10,  9,  1 },
+/*  82:    1,       4,    6,     */  {   8,  0,  9,  1,  9,  0,  9,  1, 10,  9, 10,  5,  6,  5, 10,  5,  6,  4,  7,  4,  6,  4,  7,  8,  4,  8,  9 },
+/* 164:       2,       5,    7,  */  {   9,  1, 10,  2, 10,  1, 10,  2, 11, 10, 11,  6,  7,  6, 11,  6,  7,  5,  4,  5,  7,  5,  4,  9,  5,  9, 10 },
+/*  88:          3, 4,    6,     */  {  10,  2, 11,  3, 11,  2, 11,  3,  8, 11,  8,  7,  4,  7,  8,  7,  4,  6,  5,  6,  4,  6,  5, 10,  6, 10, 11 },
+/* 167: 0, 1, 2,       5,    7,  */  {  11,  2, 10,  2, 11,  3,  8,  3, 11,  7,  8, 11,  8,  7,  4,  6,  4,  7,  4,  6,  5, 10,  5,  6, 11, 10,  6 },
+/*  91: 0, 1,    3, 4,    6,     */  {  10,  1,  9,  1, 10,  2, 11,  2, 10,  6, 11, 10, 11,  6,  7,  5,  7,  6,  7,  5,  4,  9,  4,  5, 10,  9,  5 },
+/* 173: 0,    2, 3,    5,    7,  */  {   9,  0,  8,  0,  9,  1, 10,  1,  9,  5, 10,  9, 10,  5,  6,  4,  6,  5,  6,  4,  7,  8,  7,  4,  9,  8,  4 },
+/* 181: 0,    2,    4, 5,    7,  */  {   9,  5, 10,  6, 10,  5, 10,  6, 11, 10, 11,  2,  3,  2, 11,  2,  3,  1,  0,  1,  3,  1,  0,  9,  1,  9, 10 },
+/* 229: 0,    2,       5, 6, 7,  */  {  11,  7,  8,  4,  8,  7,  8,  4,  9,  8,  9,  0,  1,  0,  9,  0,  1,  3,  2,  3,  1,  3,  2, 11,  3, 11,  8 },
+/*  94:    1, 2, 3, 4,    6,     */  {   8,  3, 11,  3,  8,  0,  9,  0,  8,  4,  9,  8,  9,  4,  5,  7,  5,  4,  5,  7,  6, 11,  6,  7,  8, 11,  7 },
+/* 122:    1,    3, 4, 5, 6,     */  {  10,  6, 11,  7, 11,  6, 11,  7,  8, 11,  8,  3,  0,  3,  8,  3,  0,  2,  1,  2,  0,  2,  1, 10,  2, 10, 11 },
+/* 218:    1,    3, 4,    6, 7,  */  {   8,  4,  9,  5,  9,  4,  9,  5, 10,  9, 10,  1,  2,  1, 10,  1,  2,  0,  3,  0,  2,  0,  3,  8,  0,  8,  9 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 8
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling8[6][6] = {
+/*  15: 0, 1, 2, 3,              */  { 9,  8, 10, 10,  8, 11 },
+/*  51: 0, 1,       4, 5,        */  { 1,  5,  3,  3,  5,  7 },
+/* 153: 0,       3, 4,       7,  */  { 0,  4,  2,  4,  6,  2 },
+/* 102:    1, 2,       5, 6,     */  { 0,  2,  4,  4,  2,  6 },
+/* 204:       2, 3,       6, 7,  */  { 1,  3,  5,  3,  7,  5 },
+/* 240:             4, 5, 6, 7,  */  { 9, 10,  8, 10, 11,  8 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 9
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling9[8][12] = {
+/*  39: 0, 1, 2,       5,        */  {  2, 10,  5,  3,  2,  5,  3,  5,  4,  3,  4,  8 },
+/*  27: 0, 1,    3, 4,           */  {  4,  7, 11,  9,  4, 11,  9, 11,  2,  9,  2,  1 },
+/* 141: 0,    2, 3,          7,  */  { 10,  7,  6,  1,  7, 10,  1,  8,  7,  1,  0,  8 },
+/* 177: 0,          4, 5,    7,  */  {  3,  6, 11,  0,  6,  3,  0,  5,  6,  0,  9,  5 },
+/*  78:    1, 2, 3,       6,     */  {  3, 11,  6,  0,  3,  6,  0,  6,  5,  0,  5,  9 },
+/* 114:    1,       4, 5, 6,     */  { 10,  6,  7,  1, 10,  7,  1,  7,  8,  1,  8,  0 },
+/* 228:       2,       5, 6, 7,  */  {  4, 11,  7,  9, 11,  4,  9,  2, 11,  9,  1,  2 },
+/* 216:          3, 4,    6, 7,  */  {  2,  5, 10,  3,  5,  2,  3,  4,  5,  3,  8,  4 }
+};
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 10
+ * 2 faces to test + eventually the interior
+ * When the tests on both specified faces are positive : 4 middle triangles (1)
+ * When the test on the first  specified face is positive : 8 first triangles
+ * When the test on the second specified face is positive : 8 next triangles
+ * When the tests on both specified faces are negative :
+ * - if the test on the interior is negative : 4 middle triangles
+ * - if the test on the interior is positive : 8 last triangles
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test10[6][3] = {
+/* 195: 0, 1,             6, 7,  */  {  2,  4,  7 },
+/*  85: 0,    2,    4,    6,     */  {  5,  6,  7 },
+/* 105: 0,       3,    5, 6,     */  {  1,  3,  7 },
+/* 150:    1, 2,    4,       7,  */  {  1,  3,  7 },
+/* 170:    1,    3,    5,    7,  */  {  5,  6,  7 },
+/*  60:       2, 3, 4, 5,        */  {  2,  4,  7 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 10.1.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling10_1_1[6][12] = {
+/* 195: 0, 1,             6, 7,  */  {  5, 10,  7, 11,  7, 10,  8,  1,  9,  1,  8,  3 },
+/*  85: 0,    2,    4,    6,     */  {  1,  2,  5,  6,  5,  2,  4,  3,  0,  3,  4,  7 },
+/* 105: 0,       3,    5, 6,     */  { 11,  0,  8,  0, 11,  2,  4,  9,  6, 10,  6,  9 },
+/* 150:    1, 2,    4,       7,  */  {  9,  0, 10,  2, 10,  0,  6,  8,  4,  8,  6, 11 },
+/* 170:    1,    3,    5,    7,  */  {  7,  2,  3,  2,  7,  6,  0,  1,  4,  5,  4,  1 },
+/*  60:       2, 3, 4, 5,        */  {  7,  9,  5,  9,  7,  8, 10,  1, 11,  3, 11,  1 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 10.1.1 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling10_1_1_[6][12] = {
+/* 195: 0, 1,             6, 7,  */  {  5,  9,  7,  8,  7,  9, 11,  1, 10,  1, 11,  3 },
+/*  85: 0,    2,    4,    6,     */  {  3,  2,  7,  6,  7,  2,  4,  1,  0,  1,  4,  5 },
+/* 105: 0,       3,    5, 6,     */  { 10,  0,  9,  0, 10,  2,  4,  8,  6, 11,  6,  8 },
+/* 150:    1, 2,    4,       7,  */  {  8,  0, 11,  2, 11,  0,  6,  9,  4,  9,  6, 10 },
+/* 170:    1,    3,    5,    7,  */  {  5,  2,  1,  2,  5,  6,  0,  3,  4,  7,  4,  3 },
+/*  60:       2, 3, 4, 5,        */  {  7, 10,  5, 10,  7, 11,  9,  1,  8,  3,  8,  1 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 10.1.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling10_1_2[6][24] = {
+/* 195: 0, 1,             6, 7,  */  {  3, 11,  7,  3,  7,  8,  9,  8,  7,  5,  9,  7,  9,  5, 10,  9, 10,  1,  3,  1, 10, 11,  3, 10 },
+/*  85: 0,    2,    4,    6,     */  {  7,  6,  5,  7,  5,  4,  0,  4,  5,  1,  0,  5,  0,  1,  2,  0,  2,  3,  7,  3,  2,  6,  7,  2 },
+/* 105: 0,       3,    5, 6,     */  { 11,  2, 10,  6, 11, 10, 11,  6,  4, 11,  4,  8,  0,  8,  4,  9,  0,  4,  0,  9, 10,  0, 10,  2 },
+/* 150:    1, 2,    4,       7,  */  { 11,  2, 10, 11, 10,  6,  4,  6, 10,  9,  4, 10,  4,  9,  0,  4,  0,  8, 11,  8,  0,  2, 11,  0 },
+/* 170:    1,    3,    5,    7,  */  {  7,  6,  5,  4,  7,  5,  7,  4,  0,  7,  0,  3,  2,  3,  0,  1,  2,  0,  2,  1,  5,  2,  5,  6 },
+/*  60:       2, 3, 4, 5,        */  {  7,  8,  3, 11,  7,  3,  7, 11, 10,  7, 10,  5,  9,  5, 10,  1,  9, 10,  9,  1,  3,  9,  3,  8 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 10.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling10_2[6][24] = {
+/* 195: 0, 1,             6, 7,  */  { 12,  5,  9, 12,  9,  8, 12,  8,  3, 12,  3,  1, 12,  1, 10, 12, 10, 11, 12, 11,  7, 12,  7,  5 },
+/*  85: 0,    2,    4,    6,     */  { 12,  1,  0, 12,  0,  4, 12,  4,  7, 12,  7,  3, 12,  3,  2, 12,  2,  6, 12,  6,  5, 12,  5,  1 },
+/* 105: 0,       3,    5, 6,     */  {  4,  8, 12,  6,  4, 12, 10,  6, 12,  9, 10, 12,  0,  9, 12,  2,  0, 12, 11,  2, 12,  8, 11, 12 },
+/* 150:    1, 2,    4,       7,  */  { 12,  9,  4, 12,  4,  6, 12,  6, 11, 12, 11,  8, 12,  8,  0, 12,  0,  2, 12,  2, 10, 12, 10,  9 },
+/* 170:    1,    3,    5,    7,  */  {  0,  3, 12,  4,  0, 12,  5,  4, 12,  1,  5, 12,  2,  1, 12,  6,  2, 12,  7,  6, 12,  3,  7, 12 },
+/*  60:       2, 3, 4, 5,        */  { 10,  5, 12, 11, 10, 12,  3, 11, 12,  1,  3, 12,  9,  1, 12,  8,  9, 12,  7,  8, 12,  5,  7, 12 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 10.2 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling10_2_[6][24] = {
+/* 195: 0, 1,             6, 7,  */  {  8,  7, 12,  9,  8, 12,  1,  9, 12,  3,  1, 12, 11,  3, 12, 10, 11, 12,  5, 10, 12,  7,  5, 12 },
+/*  85: 0,    2,    4,    6,     */  {  4,  5, 12,  0,  4, 12,  3,  0, 12,  7,  3, 12,  6,  7, 12,  2,  6, 12,  1,  2, 12,  5,  1, 12 },
+/* 105: 0,       3,    5, 6,     */  { 12, 11,  6, 12,  6,  4, 12,  4,  9, 12,  9, 10, 12, 10,  2, 12,  2,  0, 12,  0,  8, 12,  8, 11 },
+/* 150:    1, 2,    4,       7,  */  {  6, 10, 12,  4,  6, 12,  8,  4, 12, 11,  8, 12,  2, 11, 12,  0,  2, 12,  9,  0, 12, 10,  9, 12 },
+/* 170:    1,    3,    5,    7,  */  { 12,  7,  4, 12,  4,  0, 12,  0,  1, 12,  1,  5, 12,  5,  6, 12,  6,  2, 12,  2,  3, 12,  3,  7 },
+/*  60:       2, 3, 4, 5,        */  { 12,  7, 11, 12, 11, 10, 12, 10,  1, 12,  1,  3, 12,  3,  8, 12,  8,  9, 12,  9,  5, 12,  5,  7 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 11
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling11[12][12] = {
+/*  23: 0, 1, 2,    4,           */  { 2, 10,  9,  2,  9,  7,  2,  7,  3,  7,  9,  4 },
+/* 139: 0, 1,    3,          7,  */  { 1,  6,  2,  1,  8,  6,  1,  9,  8,  8,  7,  6 },
+/*  99: 0, 1,          5, 6,     */  { 8,  3,  1,  8,  1,  6,  8,  6,  4,  6,  1, 10 },
+/*  77: 0,    2, 3,       6,     */  { 0,  8, 11,  0, 11,  5,  0,  5,  1,  5, 11,  6 },
+/*  57: 0,       3, 4, 5,        */  { 9,  5,  7,  9,  7,  2,  9,  2,  0,  2,  7, 11 },
+/* 209: 0,          4,    6, 7,  */  { 5,  0,  4,  5, 11,  0,  5, 10, 11, 11,  3,  0 },
+/*  46:    1, 2, 3,    5,        */  { 5,  4,  0,  5,  0, 11,  5, 11, 10, 11,  0,  3 },
+/* 198:    1, 2,          6, 7,  */  { 9,  7,  5,  9,  2,  7,  9,  0,  2,  2, 11,  7 },
+/* 178:    1,       4, 5,    7,  */  { 0, 11,  8,  0,  5, 11,  0,  1,  5,  5,  6, 11 },
+/* 156:       2, 3, 4,       7,  */  { 8,  1,  3,  8,  6,  1,  8,  4,  6,  6, 10,  1 },
+/* 116:       2,    4, 5, 6,     */  { 1,  2,  6,  1,  6,  8,  1,  8,  9,  8,  6,  7 },
+/* 232:          3,    5, 6, 7,  */  { 2,  9, 10,  2,  7,  9,  2,  3,  7,  7,  4,  9 }
+};
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 12
+ * 2 faces to test + eventually the interior
+ * When the tests on both specified faces are positive : 4 middle triangles (1)
+ * When the test on the first  specified face is positive : 8 first triangles
+ * When the test on the second specified face is positive : 8 next triangles
+ * When the tests on both specified faces are negative :
+ * - if the test on the interior is negative : 4 middle triangles
+ * - if the test on the interior is positive : 8 last triangles
+ * The support edge for the interior test is marked as the 4th column.
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char test12[24][4] = {
+/* 135: 0, 1, 2,             7,  */  {  4,  3,  7,  11 },
+/*  75: 0, 1,    3,       6,     */  {  3,  2,  7,  10 },
+/*  83: 0, 1,       4,    6,     */  {  2,  6,  7,   5 },
+/* 163: 0, 1,          5,    7,  */  {  6,  4,  7,   7 },
+/*  45: 0,    2, 3,    5,        */  {  2,  1,  7,   9 },
+/*  53: 0,    2,    4, 5,        */  {  5,  2,  7,   1 },
+/* 149: 0,    2,    4,       7,  */  {  5,  3,  7,   2 },
+/* 101: 0,    2,       5, 6,     */  {  5,  1,  7,   0 },
+/* 197: 0,    2,          6, 7,  */  {  5,  4,  7,   3 },
+/*  89: 0,       3, 4,    6,     */  {  6,  3,  7,   6 },
+/* 169: 0,       3,    5,    7,  */  {  1,  6,  7,   4 },
+/* 225: 0,             5, 6, 7,  */  {  1,  4,  7,   8 },
+/*  30:    1, 2, 3, 4,           */  {  4,  1,  7,   8 },
+/*  86:    1, 2,    4,    6,     */  {  6,  1,  7,   4 },
+/* 166:    1, 2,       5,    7,  */  {  3,  6,  7,   6 },
+/*  58:    1,    3, 4, 5,        */  {  4,  5,  7,   3 },
+/* 154:    1,    3, 4,       7,  */  {  1,  5,  7,   0 },
+/* 106:    1,    3,    5, 6,     */  {  3,  5,  7,   2 },
+/* 202:    1,    3,       6, 7,  */  {  2,  5,  7,   1 },
+/* 210:    1,       4,    6, 7,  */  {  1,  2,  7,   9 },
+/*  92:       2, 3, 4,    6,     */  {  4,  6,  7,   7 },
+/* 172:       2, 3,    5,    7,  */  {  6,  2,  7,   5 },
+/* 180:       2,    4, 5,    7,  */  {  2,  3,  7,  10 },
+/* 120:          3, 4, 5, 6,     */  {  3,  4,  7,  11 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 12.1.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling12_1_1[24][12] = {
+/* 135: 0, 1, 2,             7,  */  {  7,  6, 11, 10,  3,  2,  3, 10,  8,  9,  8, 10 },
+/*  75: 0, 1,    3,       6,     */  {  6,  5, 10,  9,  2,  1,  2,  9, 11,  8, 11,  9 },
+/*  83: 0, 1,       4,    6,     */  { 10,  6,  5,  7,  9,  4,  9,  7,  1,  3,  1,  7 },
+/* 163: 0, 1,          5,    7,  */  {  7,  6, 11,  4,  8,  5,  3,  5,  8,  5,  3,  1 },
+/*  45: 0,    2, 3,    5,        */  {  5,  4,  9,  8,  1,  0,  1,  8, 10, 11, 10,  8 },
+/*  53: 0,    2,    4, 5,        */  {  1,  2, 10,  0,  9,  3,  5,  3,  9,  3,  5,  7 },
+/* 149: 0,    2,    4,       7,  */  { 10,  1,  2,  0, 11,  3, 11,  0,  6,  4,  6,  0 },
+/* 101: 0,    2,       5, 6,     */  {  8,  3,  0,  2,  9,  1,  9,  2,  4,  6,  4,  2 },
+/* 197: 0,    2,          6, 7,  */  {  3,  0,  8,  2, 11,  1,  7,  1, 11,  1,  7,  5 },
+/*  89: 0,       3, 4,    6,     */  {  6,  5, 10,  7, 11,  4,  2,  4, 11,  4,  2,  0 },
+/* 169: 0,       3,    5,    7,  */  {  9,  5,  4,  6,  8,  7,  8,  6,  0,  2,  0,  6 },
+/* 225: 0,             5, 6, 7,  */  {  8,  3,  0,  7,  4, 11,  9, 11,  4, 11,  9, 10 },
+/*  30:    1, 2, 3, 4,           */  {  4,  7,  8, 11,  0,  3,  0, 11,  9, 10,  9, 11 },
+/*  86:    1, 2,    4,    6,     */  {  4,  7,  8,  5,  9,  6,  0,  6,  9,  6,  0,  2 },
+/* 166:    1, 2,       5,    7,  */  { 11,  7,  6,  4, 10,  5, 10,  4,  2,  0,  2,  4 },
+/*  58:    1,    3, 4, 5,        */  { 11,  2,  3,  1,  8,  0,  8,  1,  7,  5,  7,  1 },
+/* 154:    1,    3, 4,       7,  */  {  0,  1,  9,  3,  8,  2,  4,  2,  8,  2,  4,  6 },
+/* 106:    1,    3,    5, 6,     */  {  2,  3, 11,  1, 10,  0,  6,  0, 10,  0,  6,  4 },
+/* 202:    1,    3,       6, 7,  */  {  9,  0,  1,  3, 10,  2, 10,  3,  5,  7,  5,  3 },
+/* 210:    1,       4,    6, 7,  */  {  9,  0,  1,  4,  5,  8, 10,  8,  5,  8, 10, 11 },
+/*  92:       2, 3, 4,    6,     */  {  8,  4,  7,  5, 11,  6, 11,  5,  3,  1,  3,  5 },
+/* 172:       2, 3,    5,    7,  */  {  5,  4,  9,  6, 10,  7,  1,  7, 10,  7,  1,  3 },
+/* 180:       2,    4, 5,    7,  */  { 10,  1,  2,  5,  6,  9, 11,  9,  6,  9, 11,  8 },
+/* 120:          3, 4, 5, 6,     */  { 11,  2,  3,  6,  7, 10,  8, 10,  7, 10,  8,  9 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 12.1.1 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling12_1_1_[24][12] = {
+/* 135: 0, 1, 2,             7,  */  {  3,  2, 11, 10,  7,  6,  7, 10,  8,  9,  8, 10 },
+/*  75: 0, 1,    3,       6,     */  {  2,  1, 10,  9,  6,  5,  6,  9, 11,  8, 11,  9 },
+/*  83: 0, 1,       4,    6,     */  {  9,  4,  5,  7, 10,  6, 10,  7,  1,  3,  1,  7 },
+/* 163: 0, 1,          5,    7,  */  {  7,  4,  8,  6, 11,  5,  3,  5, 11,  5,  3,  1 },
+/*  45: 0,    2, 3,    5,        */  {  1,  0,  9,  8,  5,  4,  5,  8, 10, 11, 10,  8 },
+/*  53: 0,    2,    4, 5,        */  {  1,  0,  9,  2, 10,  3,  5,  3, 10,  3,  5,  7 },
+/* 149: 0,    2,    4,       7,  */  { 11,  3,  2,  0, 10,  1, 10,  0,  6,  4,  6,  0 },
+/* 101: 0,    2,       5, 6,     */  {  9,  1,  0,  2,  8,  3,  8,  2,  4,  6,  4,  2 },
+/* 197: 0,    2,          6, 7,  */  {  3,  2, 11,  0,  8,  1,  7,  1,  8,  1,  7,  5 },
+/*  89: 0,       3, 4,    6,     */  {  6,  7, 11,  5, 10,  4,  2,  4, 10,  4,  2,  0 },
+/* 169: 0,       3,    5,    7,  */  {  8,  7,  4,  6,  9,  5,  9,  6,  0,  2,  0,  6 },
+/* 225: 0,             5, 6, 7,  */  {  8,  7,  4,  3,  0, 11,  9, 11,  0, 11,  9, 10 },
+/*  30:    1, 2, 3, 4,           */  {  0,  3,  8, 11,  4,  7,  4, 11,  9, 10,  9, 11 },
+/*  86:    1, 2,    4,    6,     */  {  4,  5,  9,  7,  8,  6,  0,  6,  8,  6,  0,  2 },
+/* 166:    1, 2,       5,    7,  */  { 10,  5,  6,  4, 11,  7, 11,  4,  2,  0,  2,  4 },
+/*  58:    1,    3, 4, 5,        */  {  8,  0,  3,  1, 11,  2, 11,  1,  7,  5,  7,  1 },
+/* 154:    1,    3, 4,       7,  */  {  0,  3,  8,  1,  9,  2,  4,  2,  9,  2,  4,  6 },
+/* 106:    1,    3,    5, 6,     */  {  2,  1, 10,  3, 11,  0,  6,  0, 11,  0,  6,  4 },
+/* 202:    1,    3,       6, 7,  */  { 10,  2,  1,  3,  9,  0,  9,  3,  5,  7,  5,  3 },
+/* 210:    1,       4,    6, 7,  */  {  9,  4,  5,  0,  1,  8, 10,  8,  1,  8, 10, 11 },
+/*  92:       2, 3, 4,    6,     */  { 11,  6,  7,  5,  8,  4,  8,  5,  3,  1,  3,  5 },
+/* 172:       2, 3,    5,    7,  */  {  5,  6, 10,  4,  9,  7,  1,  7,  9,  7,  1,  3 },
+/* 180:       2,    4, 5,    7,  */  { 10,  5,  6,  1,  2,  9, 11,  9,  2,  9, 11,  8 },
+/* 120:          3, 4, 5, 6,     */  { 11,  6,  7,  2,  3, 10,  8, 10,  3, 10,  8,  9 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 12.1.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling12_1_2[24][24] = {
+/* 135: 0, 1, 2,             7,  */  {  7,  3, 11,  3,  7,  8,  9,  8,  7,  6,  9,  7,  9,  6, 10,  2, 10,  6, 11,  2,  6,  2, 11,  3 },
+/*  75: 0, 1,    3,       6,     */  {  6,  2, 10,  2,  6, 11,  8, 11,  6,  5,  8,  6,  8,  5,  9,  1,  9,  5, 10,  1,  5,  1, 10,  2 },
+/*  83: 0, 1,       4,    6,     */  { 10,  9,  5,  9, 10,  1,  3,  1, 10,  6,  3, 10,  3,  6,  7,  4,  7,  6,  5,  4,  6,  4,  5,  9 },
+/* 163: 0, 1,          5,    7,  */  {  7,  8, 11,  3, 11,  8, 11,  3,  1, 11,  1,  6,  5,  6,  1,  6,  5,  4,  6,  4,  7,  8,  7,  4 },
+/*  45: 0,    2, 3,    5,        */  {  5,  1,  9,  1,  5, 10, 11, 10,  5,  4, 11,  5, 11,  4,  8,  0,  8,  4,  9,  0,  4,  0,  9,  1 },
+/*  53: 0,    2,    4, 5,        */  {  1,  9, 10,  5, 10,  9, 10,  5,  7, 10,  7,  2,  3,  2,  7,  2,  3,  0,  2,  0,  1,  9,  1,  0 },
+/* 149: 0,    2,    4,       7,  */  { 10, 11,  2, 11, 10,  6,  4,  6, 10,  1,  4, 10,  4,  1,  0,  3,  0,  1,  2,  3,  1,  3,  2, 11 },
+/* 101: 0,    2,       5, 6,     */  {  8,  9,  0,  9,  8,  4,  6,  4,  8,  3,  6,  8,  6,  3,  2,  1,  2,  3,  0,  1,  3,  1,  0,  9 },
+/* 197: 0,    2,          6, 7,  */  {  3, 11,  8,  7,  8, 11,  8,  7,  5,  8,  5,  0,  1,  0,  5,  0,  1,  2,  0,  2,  3, 11,  3,  2 },
+/*  89: 0,       3, 4,    6,     */  {  6, 11, 10,  2, 10, 11, 10,  2,  0, 10,  0,  5,  4,  5,  0,  5,  4,  7,  5,  7,  6, 11,  6,  7 },
+/* 169: 0,       3,    5,    7,  */  {  9,  8,  4,  8,  9,  0,  2,  0,  9,  5,  2,  9,  2,  5,  6,  7,  6,  5,  4,  7,  5,  7,  4,  8 },
+/* 225: 0,             5, 6, 7,  */  {  8,  4,  0,  9,  0,  4,  0,  9, 10,  0, 10,  3, 11,  3, 10,  3, 11,  7,  3,  7,  8,  4,  8,  7 },
+/*  30:    1, 2, 3, 4,           */  {  4,  0,  8,  0,  4,  9, 10,  9,  4,  7, 10,  4, 10,  7, 11,  3, 11,  7,  8,  3,  7,  3,  8,  0 },
+/*  86:    1, 2,    4,    6,     */  {  4,  9,  8,  0,  8,  9,  8,  0,  2,  8,  2,  7,  6,  7,  2,  7,  6,  5,  7,  5,  4,  9,  4,  5 },
+/* 166:    1, 2,       5,    7,  */  { 11, 10,  6, 10, 11,  2,  0,  2, 11,  7,  0, 11,  0,  7,  4,  5,  4,  7,  6,  5,  7,  5,  6, 10 },
+/*  58:    1,    3, 4, 5,        */  { 11,  8,  3,  8, 11,  7,  5,  7, 11,  2,  5, 11,  5,  2,  1,  0,  1,  2,  3,  0,  2,  0,  3,  8 },
+/* 154:    1,    3, 4,       7,  */  {  0,  8,  9,  4,  9,  8,  9,  4,  6,  9,  6,  1,  2,  1,  6,  1,  2,  3,  1,  3,  0,  8,  0,  3 },
+/* 106:    1,    3,    5, 6,     */  {  2, 10, 11,  6, 11, 10, 11,  6,  4, 11,  4,  3,  0,  3,  4,  3,  0,  1,  3,  1,  2, 10,  2,  1 },
+/* 202:    1,    3,       6, 7,  */  {  9, 10,  1, 10,  9,  5,  7,  5,  9,  0,  7,  9,  7,  0,  3,  2,  3,  0,  1,  2,  0,  2,  1, 10 },
+/* 210:    1,       4,    6, 7,  */  {  9,  5,  1, 10,  1,  5,  1, 10, 11,  1, 11,  0,  8,  0, 11,  0,  8,  4,  0,  4,  9,  5,  9,  4 },
+/*  92:       2, 3, 4,    6,     */  {  8, 11,  7, 11,  8,  3,  1,  3,  8,  4,  1,  8,  1,  4,  5,  6,  5,  4,  7,  6,  4,  6,  7, 11 },
+/* 172:       2, 3,    5,    7,  */  {  5, 10,  9,  1,  9, 10,  9,  1,  3,  9,  3,  4,  7,  4,  3,  4,  7,  6,  4,  6,  5, 10,  5,  6 },
+/* 180:       2,    4, 5,    7,  */  { 10,  6,  2, 11,  2,  6,  2, 11,  8,  2,  8,  1,  9,  1,  8,  1,  9,  5,  1,  5, 10,  6, 10,  5 },
+/* 120:          3, 4, 5, 6,     */  { 11,  7,  3,  8,  3,  7,  3,  8,  9,  3,  9,  2, 10,  2,  9,  2, 10,  6,  2,  6, 11,  7, 11,  6 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 12.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling12_2[24][24] = {
+/* 135: 0, 1, 2,             7,  */  {   9,  8, 12, 10,  9, 12,  2, 10, 12,  3,  2, 12, 11,  3, 12,  6, 11, 12,  7,  6, 12,  8,  7, 12 },
+/*  75: 0, 1,    3,       6,     */  {   8, 11, 12,  9,  8, 12,  1,  9, 12,  2,  1, 12, 10,  2, 12,  5, 10, 12,  6,  5, 12, 11,  6, 12 },
+/*  83: 0, 1,       4,    6,     */  {   3,  1, 12,  7,  3, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12, 10,  6, 12,  1, 10, 12 },
+/* 163: 0, 1,          5,    7,  */  {  12,  3,  1, 12,  1,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4, 12,  4,  8, 12,  8,  3 },
+/*  45: 0,    2, 3,    5,        */  {  11, 10, 12,  8, 11, 12,  0,  8, 12,  1,  0, 12,  9,  1, 12,  4,  9, 12,  5,  4, 12, 10,  5, 12 },
+/*  53: 0,    2,    4, 5,        */  {  12,  5,  7, 12,  7,  3, 12,  3,  2, 12,  2, 10, 12, 10,  1, 12,  1,  0, 12,  0,  9, 12,  9,  5 },
+/* 149: 0,    2,    4,       7,  */  {   4,  6, 12,  0,  4, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12, 11,  3, 12,  6, 11, 12 },
+/* 101: 0,    2,       5, 6,     */  {   6,  4, 12,  2,  6, 12,  3,  2, 12,  8,  3, 12,  0,  8, 12,  1,  0, 12,  9,  1, 12,  4,  9, 12 },
+/* 197: 0,    2,          6, 7,  */  {  12,  7,  5, 12,  5,  1, 12,  1,  0, 12,  0,  8, 12,  8,  3, 12,  3,  2, 12,  2, 11, 12, 11,  7 },
+/*  89: 0,       3, 4,    6,     */  {  12,  2,  0, 12,  0,  4, 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7, 12,  7, 11, 12, 11,  2 },
+/* 169: 0,       3,    5,    7,  */  {   2,  0, 12,  6,  2, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12,  9,  5, 12,  0,  9, 12 },
+/* 225: 0,             5, 6, 7,  */  {  12,  9, 10, 12, 10, 11, 12, 11,  7, 12,  7,  4, 12,  4,  8, 12,  8,  3, 12,  3,  0, 12,  0,  9 },
+/*  30:    1, 2, 3, 4,           */  {  10,  9, 12, 11, 10, 12,  7, 11, 12,  4,  7, 12,  8,  4, 12,  3,  8, 12,  0,  3, 12,  9,  0, 12 },
+/*  86:    1, 2,    4,    6,     */  {  12,  0,  2, 12,  2,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5, 12,  5,  9, 12,  9,  0 },
+/* 166:    1, 2,       5,    7,  */  {   0,  2, 12,  4,  0, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12, 11,  7, 12,  2, 11, 12 },
+/*  58:    1,    3, 4, 5,        */  {   5,  7, 12,  1,  5, 12,  0,  1, 12,  8,  0, 12,  3,  8, 12,  2,  3, 12, 11,  2, 12,  7, 11, 12 },
+/* 154:    1,    3, 4,       7,  */  {  12,  4,  6, 12,  6,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1, 12,  1,  9, 12,  9,  4 },
+/* 106:    1,    3,    5, 6,     */  {  12,  6,  4, 12,  4,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3, 12,  3, 11, 12, 11,  6 },
+/* 202:    1,    3,       6, 7,  */  {   7,  5, 12,  3,  7, 12,  2,  3, 12, 10,  2, 12,  1, 10, 12,  0,  1, 12,  9,  0, 12,  5,  9, 12 },
+/* 210:    1,       4,    6, 7,  */  {  12, 10, 11, 12, 11,  8, 12,  8,  0, 12,  0,  1, 12,  1,  9, 12,  9,  4, 12,  4,  5, 12,  5, 10 },
+/*  92:       2, 3, 4,    6,     */  {   1,  3, 12,  5,  1, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12,  8,  4, 12,  3,  8, 12 },
+/* 172:       2, 3,    5,    7,  */  {  12,  1,  3, 12,  3,  7, 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6, 12,  6, 10, 12, 10,  1 },
+/* 180:       2,    4, 5,    7,  */  {  12, 11,  8, 12,  8,  9, 12,  9,  1, 12,  1,  2, 12,  2, 10, 12, 10,  5, 12,  5,  6, 12,  6, 11 },
+/* 120:          3, 4, 5, 6,     */  {  12,  8,  9, 12,  9, 10, 12, 10,  2, 12,  2,  3, 12,  3, 11, 12, 11,  6, 12,  6,  7, 12,  7,  8 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 12.2 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling12_2_[24][24] = {
+/* 135: 0, 1, 2,             7,  */  { 12,  2, 11, 12, 11,  7, 12,  7,  6, 12,  6, 10, 12, 10,  9, 12,  9,  8, 12,  8,  3, 12,  3,  2 },
+/*  75: 0, 1,    3,       6,     */  { 12,  1, 10, 12, 10,  6, 12,  6,  5, 12,  5,  9, 12,  9,  8, 12,  8, 11, 12, 11,  2, 12,  2,  1 },
+/*  83: 0, 1,       4,    6,     */  { 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7, 12,  7,  3, 12,  3,  1, 12,  1,  9, 12,  9,  4 },
+/* 163: 0, 1,          5,    7,  */  {  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12,  1,  5, 12,  3,  1, 12, 11,  3, 12,  6, 11, 12 },
+/*  45: 0,    2, 3,    5,        */  { 12,  0,  9, 12,  9,  5, 12,  5,  4, 12,  4,  8, 12,  8, 11, 12, 11, 10, 12, 10,  1, 12,  1,  0 },
+/*  53: 0,    2,    4, 5,        */  {  1,  2, 12,  9,  1, 12,  0,  9, 12,  3,  0, 12,  7,  3, 12,  5,  7, 12, 10,  5, 12,  2, 10, 12 },
+/* 149: 0,    2,    4,       7,  */  { 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0, 12,  0,  4, 12,  4,  6, 12,  6, 10, 12, 10,  1 },
+/* 101: 0,    2,       5, 6,     */  { 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2, 12,  2,  6, 12,  6,  4, 12,  4,  8, 12,  8,  3 },
+/* 197: 0,    2,          6, 7,  */  {  3,  0, 12, 11,  3, 12,  2, 11, 12,  1,  2, 12,  5,  1, 12,  7,  5, 12,  8,  7, 12,  0,  8, 12 },
+/*  89: 0,       3, 4,    6,     */  {  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12,  0,  4, 12,  2,  0, 12, 10,  2, 12,  5, 10, 12 },
+/* 169: 0,       3,    5,    7,  */  { 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6, 12,  6,  2, 12,  2,  0, 12,  0,  8, 12,  8,  7 },
+/* 225: 0,             5, 6, 7,  */  {  8,  7, 12,  0,  8, 12,  3,  0, 12, 11,  3, 12, 10, 11, 12,  9, 10, 12,  4,  9, 12,  7,  4, 12 },
+/*  30:    1, 2, 3, 4,           */  { 12,  7,  8, 12,  8,  0, 12,  0,  3, 12,  3, 11, 12, 11, 10, 12, 10,  9, 12,  9,  4, 12,  4,  7 },
+/*  86:    1, 2,    4,    6,     */  {  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12,  2,  6, 12,  0,  2, 12,  8,  0, 12,  7,  8, 12 },
+/* 166:    1, 2,       5,    7,  */  { 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4, 12,  4,  0, 12,  0,  2, 12,  2, 10, 12, 10,  5 },
+/*  58:    1,    3, 4, 5,        */  { 12,  0,  3, 12,  3, 11, 12, 11,  2, 12,  2,  1, 12,  1,  5, 12,  5,  7, 12,  7,  8, 12,  8,  0 },
+/* 154:    1,    3, 4,       7,  */  {  0,  3, 12,  9,  0, 12,  1,  9, 12,  2,  1, 12,  6,  2, 12,  4,  6, 12,  8,  4, 12,  3,  8, 12 },
+/* 106:    1,    3,    5, 6,     */  {  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12,  4,  0, 12,  6,  4, 12, 10,  6, 12,  1, 10, 12 },
+/* 202:    1,    3,       6, 7,  */  { 12,  2,  1, 12,  1,  9, 12,  9,  0, 12,  0,  3, 12,  3,  7, 12,  7,  5, 12,  5, 10, 12, 10,  2 },
+/* 210:    1,       4,    6, 7,  */  {  9,  0, 12,  5,  9, 12,  4,  5, 12,  8,  4, 12, 11,  8, 12, 10, 11, 12,  1, 10, 12,  0,  1, 12 },
+/*  92:       2, 3, 4,    6,     */  { 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5, 12,  5,  1, 12,  1,  3, 12,  3, 11, 12, 11,  6 },
+/* 172:       2, 3,    5,    7,  */  {  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12,  3,  7, 12,  1,  3, 12,  9,  1, 12,  4,  9, 12 },
+/* 180:       2,    4, 5,    7,  */  { 10,  1, 12,  6, 10, 12,  5,  6, 12,  9,  5, 12,  8,  9, 12, 11,  8, 12,  2, 11, 12,  1,  2, 12 },
+/* 120:          3, 4, 5, 6,     */  { 11,  2, 12,  7, 11, 12,  6,  7, 12, 10,  6, 12,  9, 10, 12,  8,  9, 12,  3,  8, 12,  2,  3, 12 }
+};
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief test table for case 13
+ * All faces are to be tested
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13: face test */
+static const char test13[2][7] = {
+/* 165: 0,    2,       5,    7,  */  { 1,2,3,4,5,6,7 },
+/*  90:    1,    3, 4,    6,     */  { 2,3,4,1,5,6,7 },
+};
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief subconfiguration table for case 13
+ * Hard-coded tests for the subconfiguration determination
+ *
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13: sub configs */
+static const char subconfig13[64] = {
+/*  0: 0,0,0,0,0,0 */   0,
+/*  1: 1,0,0,0,0,0 */   1,
+/*  2: 0,1,0,0,0,0 */   2,
+/*  3: 1,1,0,0,0,0 */   7,
+/*  4: 0,0,1,0,0,0 */   3,
+/*  5: 1,0,1,0,0,0 */  -1,
+/*  6: 0,1,1,0,0,0 */  11,
+/*  7: 1,1,1,0,0,0 */  -1,
+/*  8: 0,0,0,1,0,0 */   4,
+/*  9: 1,0,0,1,0,0 */   8,
+/* 10: 0,1,0,1,0,0 */  -1,
+/* 11: 1,1,0,1,0,0 */  -1,
+/* 12: 0,0,1,1,0,0 */  14,
+/* 13: 1,0,1,1,0,0 */  -1,
+/* 14: 0,1,1,1,0,0 */  -1,
+/* 15: 1,1,1,1,0,0 */  -1,
+/* 16: 0,0,0,0,1,0 */   5,
+/* 17: 1,0,0,0,1,0 */   9,
+/* 18: 0,1,0,0,1,0 */  12,
+/* 19: 1,1,0,0,1,0 */  23,
+/* 20: 0,0,1,0,1,0 */  15,
+/* 21: 1,0,1,0,1,0 */  -1,
+/* 22: 0,1,1,0,1,0 */  21,
+/* 23: 1,1,1,0,1,0 */  38,
+/* 24: 0,0,0,1,1,0 */  17,
+/* 25: 1,0,0,1,1,0 */  20,
+/* 26: 0,1,0,1,1,0 */  -1,
+/* 27: 1,1,0,1,1,0 */  36,
+/* 28: 0,0,1,1,1,0 */  26,
+/* 29: 1,0,1,1,1,0 */  33,
+/* 30: 0,1,1,1,1,0 */  30,
+/* 31: 1,1,1,1,1,0 */  44,
+/* 32: 0,0,0,0,0,1 */   6,
+/* 33: 1,0,0,0,0,1 */  10,
+/* 34: 0,1,0,0,0,1 */  13,
+/* 35: 1,1,0,0,0,1 */  19,
+/* 36: 0,0,1,0,0,1 */  16,
+/* 37: 1,0,1,0,0,1 */  -1,
+/* 38: 0,1,1,0,0,1 */  25,
+/* 39: 1,1,1,0,0,1 */  37,
+/* 40: 0,0,0,1,0,1 */  18,
+/* 41: 1,0,0,1,0,1 */  24,
+/* 42: 0,1,0,1,0,1 */  -1,
+/* 43: 1,1,0,1,0,1 */  35,
+/* 44: 0,0,1,1,0,1 */  22,
+/* 45: 1,0,1,1,0,1 */  32,
+/* 46: 0,1,1,1,0,1 */  29,
+/* 47: 1,1,1,1,0,1 */  43,
+/* 48: 0,0,0,0,1,1 */  -1,
+/* 49: 1,0,0,0,1,1 */  -1,
+/* 50: 0,1,0,0,1,1 */  -1,
+/* 51: 1,1,0,0,1,1 */  34,
+/* 52: 0,0,1,0,1,1 */  -1,
+/* 53: 1,0,1,0,1,1 */  -1,
+/* 54: 0,1,1,0,1,1 */  28,
+/* 55: 1,1,1,0,1,1 */  42,
+/* 56: 0,0,0,1,1,1 */  -1,
+/* 57: 1,0,0,1,1,1 */  31,
+/* 58: 0,1,0,1,1,1 */  -1,
+/* 59: 1,1,0,1,1,1 */  41,
+/* 60: 0,0,1,1,1,1 */  27,
+/* 61: 1,0,1,1,1,1 */  40,
+/* 62: 0,1,1,1,1,1 */  39,
+/* 63: 1,1,1,1,1,1 */  45,
+};
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.1
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.1 */
+static const char tiling13_1[2][12] = {
+/* 165: 0,    2,       5,    7,  */  { 11,  7,  6,  1,  2, 10,  8,  3,  0,  9,  5, 4 },
+/*  90:    1,    3, 4,    6,     */  {  8,  4,  7,  2,  3, 11,  9,  0,  1, 10,  6, 5 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.1 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.1 */
+static const char tiling13_1_[2][12] = {
+/* 165: 0,    2,       5,    7,  */  { 7,  4,  8, 11,  3,  2,  1,  0,  9,  5,  6, 10 },
+/*  90:    1,    3, 4,    6,     */  { 6,  7, 11, 10,  2,  1,  0,  3,  8,  4,  5,  9 }
+};
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.2 */
+static const char tiling13_2[2][6][18] = {
+/* 165: 0,    2,       5,    7,  */  {
+ /* 1 */ { 1,  2, 10, 11,  7,  6,  3,  4,  8,  4,  3,  5,  0,  5,  3,  5,  0,  9 },
+ /* 2 */ { 8,  3,  0, 11,  7,  6,  9,  1,  4,  2,  4,  1,  4,  2,  5, 10,  5,  2 },
+ /* 3 */ { 9,  5,  4,  8,  3,  0,  1,  6, 10,  6,  1,  7,  2,  7,  1,  7,  2, 11 },
+ /* 4 */ { 9,  5,  4,  1,  2, 10, 11,  3,  6,  0,  6,  3,  6,  0,  7,  8,  7,  0 },
+ /* 5 */ { 9,  5,  4, 11,  7,  6,  0, 10,  1, 10,  0,  8, 10,  8,  2,  3,  2,  8 },
+ /* 6 */ { 1,  2, 10,  3,  0,  8,  4,  9,  7, 11,  7,  9,  5, 11,  9, 11,  5,  6 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+ /* 1 */ { 2,  3, 11,  8,  4,  7,  0,  5,  9,  5,  0,  6,  1,  6,  0,  6,  1, 10 },
+ /* 2 */ { 9,  0,  1,  8,  4,  7, 10,  2,  5,  3,  5,  2,  5,  3,  6, 11,  6,  3 },
+ /* 3 */ { 6,  5, 10,  9,  0,  1,  2,  7, 11,  7,  2,  4,  3,  4,  2,  4,  3,  8 },
+ /* 4 */ { 6,  5, 10,  2,  3, 11,  8,  0,  7,  1,  7,  0,  7,  1,  4,  9,  4,  1 },
+ /* 5 */ { 6,  5, 10,  8,  4,  7,  1, 11,  2, 11,  1,  9, 11,  9,  3,  0,  3,  9 },
+ /* 6 */ { 2,  3, 11,  0,  1,  9,  5, 10,  4,  8,  4, 10,  6,  8, 10,  8,  6,  7 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.2 inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.2 */
+static const char tiling13_2_[2][6][18] = {
+/* 165: 0,    2,       5,    7,  */  {
+ /* 1 */ { 10,  5,  6, 11,  3,  2,  7,  0,  8,  0,  7,  1,  4,  1,  7,  1,  4,  9 },
+ /* 2 */ { 11,  3,  2,  7,  4,  8,  9,  5,  0,  6,  0,  5,  0,  6,  1, 10,  1,  6 },
+ /* 3 */ {  1,  0,  9,  7,  4,  8,  5,  2, 10,  2,  5,  3,  6,  3,  5,  3,  6, 11 },
+ /* 4 */ { 10,  5,  6,  1,  0,  9, 11,  7,  2,  4,  2,  7,  2,  4,  3,  8,  3,  4 },
+ /* 5 */ { 10,  5,  6,  7,  4,  8,  2, 11,  1,  9,  1, 11,  3,  9, 11,  9,  3,  0 },
+ /* 6 */ { 11,  3,  2,  9,  1,  0,  4, 10,  5, 10,  4,  8, 10,  8,  6,  7,  6,  8 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+ /* 1 */ {  6,  7, 11,  8,  0,  3,  4,  1,  9,  1,  4,  2,  5,  2,  4,  2,  5, 10 },
+ /* 2 */ {  8,  0,  3,  4,  5,  9, 10,  6,  1,  7,  1,  6,  1,  7,  2, 11,  2,  7 },
+ /* 3 */ {  2,  1, 10,  4,  5,  9,  6,  3, 11,  3,  6,  0,  7,  0,  6,  0,  7,  8 },
+ /* 4 */ {  6,  7, 11,  2,  1, 10,  8,  4,  3,  5,  3,  4,  3,  5,  0,  9,  0,  5 },
+ /* 5 */ {  6,  7, 11,  4,  5,  9,  3,  8,  2, 10,  2,  8,  0, 10,  8, 10,  0,  1 },
+ /* 6 */ {  8,  0,  3, 10,  2,  1,  5, 11,  6, 11,  5,  9, 11,  9,  7,  4,  7,  9 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.3
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.3 */
+static const char tiling13_3[2][12][30] = {
+/* 165: 0,    2,       5,    7,  */  {
+ /* 1,2 */ { 11,  7,  6, 12,  2, 10, 12, 10,  5, 12,  5,  4, 12,  4,  8, 12,  8,  3, 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2 },
+ /* 1,4 */ {  1,  2, 10,  9,  5, 12,  0,  9, 12,  3,  0, 12, 11,  3, 12,  6, 11, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12 },
+ /* 1,5 */ { 11,  7,  6, 12,  5,  4, 12,  4,  8, 12,  8,  3, 12,  3,  2, 12,  2, 10, 12, 10,  1, 12,  1,  0, 12,  0,  9, 12,  9,  5 },
+ /* 1,6 */ {  1,  2, 10, 12,  3,  0, 12,  0,  9, 12,  9,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4, 12,  4,  8, 12,  8,  3 },
+ /* 2,3 */ {  8,  3,  0, 11,  7, 12,  2, 11, 12,  1,  2, 12,  9,  1, 12,  4,  9, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12 },
+ /* 2,5 */ { 11,  7,  6,  5,  4, 12, 10,  5, 12,  2, 10, 12,  3,  2, 12,  8,  3, 12,  0,  8, 12,  1,  0, 12,  9,  1, 12,  4,  9, 12 },
+ /* 2,6 */ {  8,  3,  0,  1,  2, 12,  9,  1, 12,  4,  9, 12,  7,  4, 12, 11,  7, 12,  6, 11, 12,  5,  6, 12, 10,  5, 12,  2, 10, 12 },
+ /* 3,4 */ {  9,  5,  4, 12,  0,  8, 12,  8,  7, 12,  7,  6, 12,  6, 10, 12, 10,  1, 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0 },
+ /* 3,5 */ {  9,  5,  4, 12,  7,  6, 12,  6, 10, 12, 10,  1, 12,  1,  0, 12,  0,  8, 12,  8,  3, 12,  3,  2, 12,  2, 11, 12, 11,  7 },
+ /* 3,6 */ {  8,  3,  0, 12,  1,  2, 12,  2, 11, 12, 11,  7, 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6, 12,  6, 10, 12, 10,  1 },
+ /* 4,5 */ {  9,  5,  4,  7,  6, 12,  8,  7, 12,  0,  8, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12, 11,  3, 12,  6, 11, 12 },
+ /* 4,6 */ {  1,  2, 10,  3,  0, 12, 11,  3, 12,  6, 11, 12,  5,  6, 12,  9,  5, 12,  4,  9, 12,  7,  4, 12,  8,  7, 12,  0,  8, 12 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+ /* 1,2 */ {  8,  4,  7, 12,  3, 11, 12, 11,  6, 12,  6,  5, 12,  5,  9, 12,  9,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3 },
+ /* 1,4 */ {  2,  3, 11, 10,  6, 12,  1, 10, 12,  0,  1, 12,  8,  0, 12,  7,  8, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12 },
+ /* 1,5 */ {  8,  4,  7, 12,  6,  5, 12,  5,  9, 12,  9,  0, 12,  0,  3, 12,  3, 11, 12, 11,  2, 12,  2,  1, 12,  1, 10, 12, 10,  6 },
+ /* 1,6 */ {  2,  3, 11, 12,  0,  1, 12,  1, 10, 12, 10,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5, 12,  5,  9, 12,  9,  0 },
+ /* 2,3 */ {  0,  1,  9,  8,  4, 12,  3,  8, 12,  2,  3, 12, 10,  2, 12,  5, 10, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12 },
+ /* 2,5 */ {  8,  4,  7,  6,  5, 12, 11,  6, 12,  3, 11, 12,  0,  3, 12,  9,  0, 12,  1,  9, 12,  2,  1, 12, 10,  2, 12,  5, 10, 12 },
+ /* 2,6 */ {  9,  0,  1,  2,  3, 12, 10,  2, 12,  5, 10, 12,  4,  5, 12,  8,  4, 12,  7,  8, 12,  6,  7, 12, 11,  6, 12,  3, 11, 12 },
+ /* 3,4 */ {  6,  5, 10, 12,  1,  9, 12,  9,  4, 12,  4,  7, 12,  7, 11, 12, 11,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1 },
+ /* 3,5 */ {  6,  5, 10, 12,  4,  7, 12,  7, 11, 12, 11,  2, 12,  2,  1, 12,  1,  9, 12,  9,  0, 12,  0,  3, 12,  3,  8, 12,  8,  4 },
+ /* 3,6 */ {  9,  0,  1, 12,  2,  3, 12,  3,  8, 12,  8,  4, 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7, 12,  7, 11, 12, 11,  2 },
+ /* 4,5 */ {  6,  5, 10,  4,  7, 12,  9,  4, 12,  1,  9, 12,  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12,  8,  0, 12,  7,  8, 12 },
+ /* 4,6 */ {  2,  3, 11,  0,  1, 12,  8,  0, 12,  7,  8, 12,  6,  7, 12, 10,  6, 12,  5, 10, 12,  4,  5, 12,  9,  4, 12,  1,  9, 12 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.3, inverted
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.3 */
+static const char tiling13_3_[2][12][30] = {
+/* 165: 0,    2,       5,    7,  */  {
+ /* 1,2 */ {  3,  2, 11,  8,  7, 12,  0,  8, 12,  1,  0, 12, 10,  1, 12,  6, 10, 12,  5,  6, 12,  9,  5, 12,  4,  9, 12,  7,  4, 12 },
+ /* 1,4 */ {  5,  6, 10, 12,  2, 11, 12, 11,  7, 12,  7,  4, 12,  4,  9, 12,  9,  1, 12,  1,  0, 12,  0,  8, 12,  8,  3, 12,  3,  2 },
+ /* 1,5 */ { 10,  5,  6, 12,  7,  4, 12,  4,  9, 12,  9,  1, 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0, 12,  0,  8, 12,  8,  7 },
+ /* 1,6 */ { 11,  3,  2, 12,  1,  0, 12,  0,  8, 12,  8,  7, 12,  7,  6, 12,  6, 10, 12, 10,  5, 12,  5,  4, 12,  4,  9, 12,  9,  1 },
+ /* 2,3 */ {  7,  4,  8, 11,  3, 12,  6, 11, 12,  5,  6, 12,  9,  5, 12,  0,  9, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12 },
+ /* 2,5 */ {  7,  4,  8,  5,  6, 12,  9,  5, 12,  0,  9, 12,  3,  0, 12, 11,  3, 12,  2, 11, 12,  1,  2, 12, 10,  1, 12,  6, 10, 12 },
+ /* 2,6 */ { 11,  3,  2,  1,  0, 12, 10,  1, 12,  6, 10, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12,  9,  5, 12,  0,  9, 12 },
+ /* 3,4 */ {  1,  0,  9, 12,  4,  8, 12,  8,  3, 12,  3,  2, 12,  2, 10, 12, 10,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4 },
+ /* 3,5 */ {  7,  4,  8, 12,  5,  6, 12,  6, 11, 12, 11,  3, 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2, 12,  2, 10, 12, 10,  5 },
+ /* 3,6 */ {  1,  0,  9, 12,  3,  2, 12,  2, 10, 12, 10,  5, 12,  5,  4, 12,  4,  8, 12,  8,  7, 12,  7,  6, 12,  6, 11, 12, 11,  3 },
+ /* 4,5 */ { 10,  5,  6,  7,  4, 12, 11,  7, 12,  2, 11, 12,  1,  2, 12,  9,  1, 12,  0,  9, 12,  3,  0, 12,  8,  3, 12,  4,  8, 12 },
+ /* 4,6 */ {  9,  1,  0,  3,  2, 12,  8,  3, 12,  4,  8, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12, 11,  7, 12,  2, 11, 12 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+ /* 1,2 */ {  0,  3,  8,  9,  4, 12,  1,  9, 12,  2,  1, 12, 11,  2, 12,  7, 11, 12,  6,  7, 12, 10,  6, 12,  5, 10, 12,  4,  5, 12 },
+ /* 1,4 */ { 11,  6,  7, 12,  3,  8, 12,  8,  4, 12,  4,  5, 12,  5, 10, 12, 10,  2, 12,  2,  1, 12,  1,  9, 12,  9,  0, 12,  0,  3 },
+ /* 1,5 */ {  6,  7, 11, 12,  4,  5, 12,  5, 10, 12, 10,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1, 12,  1,  9, 12,  9,  4 },
+ /* 1,6 */ {  8,  0,  3, 12,  2,  1, 12,  1,  9, 12,  9,  4, 12,  4,  7, 12,  7, 11, 12, 11,  6, 12,  6,  5, 12,  5, 10, 12, 10,  2 },
+ /* 2,3 */ {  4,  5,  9,  8,  0, 12,  7,  8, 12,  6,  7, 12, 10,  6, 12,  1, 10, 12,  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12 },
+ /* 2,5 */ {  4,  5,  9,  6,  7, 12, 10,  6, 12,  1, 10, 12,  0,  1, 12,  8,  0, 12,  3,  8, 12,  2,  3, 12, 11,  2, 12,  7, 11, 12 },
+ /* 2,6 */ {  8,  0,  3,  2,  1, 12, 11,  2, 12,  7, 11, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12, 10,  6, 12,  1, 10, 12 },
+ /* 3,4 */ {  2,  1, 10, 12,  5,  9, 12,  9,  0, 12,  0,  3, 12,  3, 11, 12, 11,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5 },
+ /* 3,5 */ {  4,  5,  9, 12,  6,  7, 12,  7,  8, 12,  8,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3, 12,  3, 11, 12, 11,  6 },
+ /* 3,6 */ {  2,  1, 10, 12,  0,  3, 12,  3, 11, 12, 11,  6, 12,  6,  5, 12,  5,  9, 12,  9,  4, 12,  4,  7, 12,  7,  8, 12,  8,  0 },
+ /* 4,5 */ {  6,  7, 11,  4,  5, 12,  8,  4, 12,  3,  8, 12,  2,  3, 12, 10,  2, 12,  1, 10, 12,  0,  1, 12,  9,  0, 12,  5,  9, 12 },
+ /* 4,6 */ { 10,  2,  1,  0,  3, 12,  9,  0, 12,  5,  9, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12,  8,  4, 12,  3,  8, 12 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.4
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.4 */
+static const char tiling13_4[2][4][36] = {
+/* 165: 0,    2,       5,    7,  */  {
+/* 1,2,6 */  { 12,  2, 10, 12, 10,  5, 12,  5,  6, 12,  6, 11, 12, 11,  7, 12,  7,  4, 12,  4,  8, 12,  8,  3, 12,  3,  0, 12,  0,  9, 12,  9,  1, 12,  1,  2 },
+/* 1,4,5 */  { 11,  3, 12,  6, 11, 12,  7,  6, 12,  8,  7, 12,  4,  8, 12,  5,  4, 12,  9,  5, 12,  0,  9, 12,  1,  0, 12, 10,  1, 12,  2, 10, 12,  3,  2, 12 },
+/* 2,3,5 */  {  9,  1, 12,  4,  9, 12,  5,  4, 12, 10,  5, 12,  6, 10, 12,  7,  6, 12, 11,  7, 12,  2, 11, 12,  3,  2, 12,  8,  3, 12,  0,  8, 12,  1,  0, 12 },
+/* 3,4,6 */  { 12,  0,  8, 12,  8,  7, 12,  7,  4, 12,  4,  9, 12,  9,  5, 12,  5,  6, 12,  6, 10, 12, 10,  1, 12,  1,  2, 12,  2, 11, 12, 11,  3, 12,  3,  0 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+/* 1,2,6 */  { 12,  3, 11, 12, 11,  6, 12,  6,  7, 12,  7,  8, 12,  8,  4, 12,  4,  5, 12,  5,  9, 12,  9,  0, 12,  0,  1, 12,  1, 10, 12, 10,  2, 12,  2,  3 },
+/* 1,4,5 */  {  8,  0, 12,  7,  8, 12,  4,  7, 12,  9,  4, 12,  5,  9, 12,  6,  5, 12, 10,  6, 12,  1, 10, 12,  2,  1, 12, 11,  2, 12,  3, 11, 12,  0,  3, 12 },
+/* 2,3,5 */  { 10,  2, 12,  5, 10, 12,  6,  5, 12, 11,  6, 12,  7, 11, 12,  4,  7, 12,  8,  4, 12,  3,  8, 12,  0,  3, 12,  9,  0, 12,  1,  9, 12,  2,  1, 12 },
+/* 3,4,6 */  { 12,  1,  9, 12,  9,  4, 12,  4,  5, 12,  5, 10, 12, 10,  6, 12,  6,  7, 12,  7, 11, 12, 11,  2, 12,  2,  3, 12,  3,  8, 12,  8,  0, 12,  0,  1 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.5.1
+ * The support edge for the interior test is marked as the 1st column.
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.5.1 */
+static const char tiling13_5_1[2][4][18] = {
+/* 165: 0,    2,       5,    7,  */  {
+/* 1,2,5 */  {  7,  6, 11,  1,  0,  9, 10,  3,  2,  3, 10,  5,  3,  5,  8,  4,  8, 5 },
+/* 1,4,6 */  {  1,  2, 10,  7,  4,  8,  3,  0, 11,  6, 11,  0,  9,  6,  0,  6,  9, 5 },
+/* 2,3,6 */  {  3,  0,  8,  5,  6, 10,  1,  2,  9,  4,  9,  2, 11,  4,  2,  4, 11, 7 },
+/* 3,4,5 */  {  5,  4,  9,  3,  2, 11,  8,  1,  0,  1,  8,  7,  1,  7, 10,  6, 10, 7 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+/* 1,2,5 */  {  4,  7,  8,  2,  1, 10, 11,  0,  3,  0, 11,  6,  0,  6,  9,  5,  9, 6 },
+/* 1,4,6 */  {  2,  3, 11,  4,  5,  9,  0,  1,  8,  7,  8,  1, 10,  7,  1,  7, 10, 6 },
+/* 2,3,6 */  {  0,  1,  9,  6,  7, 11,  2,  3, 10,  5, 10,  3,  8,  5,  3,  5,  8, 4 },
+/* 3,4,5 */  {  6,  5, 10,  0,  3,  8,  9,  2,  1,  2,  9,  4,  2,  4, 11,  7, 11, 4 }
+} };
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 13.5.2
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+/* 13.5.2 */
+static const char tiling13_5_2[2][4][30] = {
+/* 165: 0,    2,       5,    7,  */  {
+/* 1,2,5 */  { 1,  0,  9,  7,  4,  8,  7,  8,  3,  7,  3, 11,  2, 11,  3, 11,  2, 10, 11, 10,  6,  5,  6, 10,  6,  5,  7,  4,  7, 5 },
+/* 1,4,6 */  { 7,  4,  8, 11,  3,  2,  6, 11,  2, 10,  6,  2,  6, 10,  5,  9,  5, 10,  1,  9, 10,  9,  1,  0,  2,  0,  1,  0,  2, 3 },
+/* 2,3,6 */  { 5,  6, 10,  9,  1,  0,  4,  9,  0,  8,  4,  0,  4,  8,  7, 11,  7,  8,  3, 11,  8, 11,  3,  2,  0,  2,  3,  2,  0, 1 },
+/* 3,4,5 */  { 3,  2, 11,  5,  6, 10,  5, 10,  1,  5,  1,  9,  0,  9,  1,  9,  0,  8,  9,  8,  4,  4,  8,  7,  4,  7,  5,  6,  5, 7 }
+},
+/*  90:    1,    3, 4,    6,     */  {
+/* 1,2,5 */  { 2,  1, 10,  4,  5,  9,  4,  9,  0,  4,  0,  8,  3,  8,  0,  8,  3, 11,  8, 11,  7,  6,  7, 11,  7,  6,  4,  5,  4, 6 },
+/* 1,4,6 */  { 4,  5,  9,  8,  0,  3,  7,  8,  3, 11,  7,  3,  7, 11,  6, 10,  6, 11,  2, 10, 11, 10,  2,  1,  3,  1,  2,  1,  3, 0 },
+/* 2,3,6 */  { 6,  7, 11, 10,  2,  1,  5, 10,  1,  9,  5,  1,  5,  9,  4,  8,  4,  9,  0,  8,  9,  8,  0,  3,  1,  3,  0,  3,  1, 2 },
+/* 3,4,5 */  { 0,  3,  8,  6,  7, 11,  6, 11,  2,  6,  2, 10,  1, 10,  2, 10,  1,  9, 10,  9,  5,  5,  9,  4,  5,  4,  6,  7,  6, 4 }
+} };
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief tiling table for case 14
+ * For each of the case above, the specific triangulation of the edge
+ * intersection points is given.
+ * When a case is ambiguous, there is an auxiliary table that contains
+ * the face number to test and the tiling table contains the specific
+ * triangulations depending on the results
+ * A minus sign means to invert the result of the test.
+ */
+//-----------------------------------------------------------------------------
+static const char tiling14[12][12] = {
+/*  71: 0, 1, 2,          6,     */  {  5,  9,  8,  5,  8,  2,  5,  2,  6,  3,  2,  8 },
+/*  43: 0, 1,    3,    5,        */  {  2,  1,  5,  2,  5,  8,  2,  8, 11,  4,  8,  5 },
+/* 147: 0, 1,       4,       7,  */  {  9,  4,  6,  9,  6,  3,  9,  3,  1, 11,  3,  6 },
+/*  29: 0,    2, 3, 4,           */  {  1, 11, 10,  1,  4, 11,  1,  0,  4,  7, 11,  4 },
+/* 201: 0,       3,       6, 7,  */  {  8,  2,  0,  8,  5,  2,  8,  7,  5, 10,  2,  5 },
+/* 113: 0,          4, 5, 6,     */  {  0,  7,  3,  0, 10,  7,  0,  9, 10,  6,  7, 10 },
+/* 142:    1, 2, 3,          7,  */  {  0,  3,  7,  0,  7, 10,  0, 10,  9,  6, 10,  7 },
+/*  54:    1, 2,    4, 5,        */  {  8,  0,  2,  8,  2,  5,  8,  5,  7, 10,  5,  2 },
+/* 226:    1,          5, 6, 7,  */  {  1, 10, 11,  1, 11,  4,  1,  4,  0,  7,  4, 11 },
+/* 108:       2, 3,    5, 6,     */  {  9,  6,  4,  9,  3,  6,  9,  1,  3, 11,  6,  3 },
+/* 212:       2,    4,    6, 7,  */  {  2,  5,  1,  2,  8,  5,  2, 11,  8,  4,  5,  8 },
+/* 184:          3, 4, 5,    7,  */  {  5,  8,  9,  5,  2,  8,  5,  6,  2,  3,  8,  2 }
+};
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/**
+ * \brief original Marching Cubes implementation
+ * For each of the possible vertex states listed in this table there is a
+ * specific triangulation of the edge intersection points.  The table lists
+ * all of them in the form of 0-5 edge triples with the list terminated by
+ * the invalid value -1.  For example: casesClassic[3] list the 2 triangles
+ * formed when cube[0] and cube[1] are inside of the surface, but the rest of
+ * the cube is not.
+ */
+//-----------------------------------------------------------------------------
+static const char casesClassic[256][16] = {
+/*   0:                          */  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   1: 0,                       */  {  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   2:    1,                    */  {  0,  1,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   3: 0, 1,                    */  {  1,  8,  3,  9,  8,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   4:       2,                 */  {  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   5: 0,    2,                 */  {  0,  8,  3,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   6:    1, 2,                 */  {  9,  2, 10,  0,  2,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   7: 0, 1, 2,                 */  {  2,  8,  3,  2, 10,  8, 10,  9,  8, -1, -1, -1, -1, -1, -1, -1 },
+/*   8:          3,              */  {  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*   9: 0,       3,              */  {  0, 11,  2,  8, 11,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  10:    1,    3,              */  {  1,  9,  0,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  11: 0, 1,    3,              */  {  1, 11,  2,  1,  9, 11,  9,  8, 11, -1, -1, -1, -1, -1, -1, -1 },
+/*  12:       2, 3,              */  {  3, 10,  1, 11, 10,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  13: 0,    2, 3,              */  {  0, 10,  1,  0,  8, 10,  8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
+/*  14:    1, 2, 3,              */  {  3,  9,  0,  3, 11,  9, 11, 10,  9, -1, -1, -1, -1, -1, -1, -1 },
+/*  15: 0, 1, 2, 3,              */  {  9,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  16:             4,           */  {  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  17: 0,          4,           */  {  4,  3,  0,  7,  3,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  18:    1,       4,           */  {  0,  1,  9,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  19: 0, 1,       4,           */  {  4,  1,  9,  4,  7,  1,  7,  3,  1, -1, -1, -1, -1, -1, -1, -1 },
+/*  20:       2,    4,           */  {  1,  2, 10,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  21: 0,    2,    4,           */  {  3,  4,  7,  3,  0,  4,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1 },
+/*  22:    1, 2,    4,           */  {  9,  2, 10,  9,  0,  2,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 },
+/*  23: 0, 1, 2,    4,           */  {  2, 10,  9,  2,  9,  7,  2,  7,  3,  7,  9,  4, -1, -1, -1, -1 },
+/*  24:          3, 4,           */  {  8,  4,  7,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  25: 0,       3, 4,           */  { 11,  4,  7, 11,  2,  4,  2,  0,  4, -1, -1, -1, -1, -1, -1, -1 },
+/*  26:    1,    3, 4,           */  {  9,  0,  1,  8,  4,  7,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 },
+/*  27: 0, 1,    3, 4,           */  {  4,  7, 11,  9,  4, 11,  9, 11,  2,  9,  2,  1, -1, -1, -1, -1 },
+/*  28:       2, 3, 4,           */  {  3, 10,  1,  3, 11, 10,  7,  8,  4, -1, -1, -1, -1, -1, -1, -1 },
+/*  29: 0,    2, 3, 4,           */  {  1, 11, 10,  1,  4, 11,  1,  0,  4,  7, 11,  4, -1, -1, -1, -1 },
+/*  30:    1, 2, 3, 4,           */  {  4,  7,  8,  9,  0, 11,  9, 11, 10, 11,  0,  3, -1, -1, -1, -1 },
+/*  31: 0, 1, 2, 3, 4,           */  {  4,  7, 11,  4, 11,  9,  9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
+/*  32:                5,        */  {  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  33: 0,             5,        */  {  9,  5,  4,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  34:    1,          5,        */  {  0,  5,  4,  1,  5,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  35: 0, 1,          5,        */  {  8,  5,  4,  8,  3,  5,  3,  1,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  36:       2,       5,        */  {  1,  2, 10,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  37: 0,    2,       5,        */  {  3,  0,  8,  1,  2, 10,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  38:    1, 2,       5,        */  {  5,  2, 10,  5,  4,  2,  4,  0,  2, -1, -1, -1, -1, -1, -1, -1 },
+/*  39: 0, 1, 2,       5,        */  {  2, 10,  5,  3,  2,  5,  3,  5,  4,  3,  4,  8, -1, -1, -1, -1 },
+/*  40:          3,    5,        */  {  9,  5,  4,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  41: 0,       3,    5,        */  {  0, 11,  2,  0,  8, 11,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  42:    1,    3,    5,        */  {  0,  5,  4,  0,  1,  5,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 },
+/*  43: 0, 1,    3,    5,        */  {  2,  1,  5,  2,  5,  8,  2,  8, 11,  4,  8,  5, -1, -1, -1, -1 },
+/*  44:       2, 3,    5,        */  { 10,  3, 11, 10,  1,  3,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1 },
+/*  45: 0,    2, 3,    5,        */  {  4,  9,  5,  0,  8,  1,  8, 10,  1,  8, 11, 10, -1, -1, -1, -1 },
+/*  46:    1, 2, 3,    5,        */  {  5,  4,  0,  5,  0, 11,  5, 11, 10, 11,  0,  3, -1, -1, -1, -1 },
+/*  47: 0, 1, 2, 3,    5,        */  {  5,  4,  8,  5,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1 },
+/*  48:             4, 5,        */  {  9,  7,  8,  5,  7,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  49: 0,          4, 5,        */  {  9,  3,  0,  9,  5,  3,  5,  7,  3, -1, -1, -1, -1, -1, -1, -1 },
+/*  50:    1,       4, 5,        */  {  0,  7,  8,  0,  1,  7,  1,  5,  7, -1, -1, -1, -1, -1, -1, -1 },
+/*  51: 0, 1,       4, 5,        */  {  1,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  52:       2,    4, 5,        */  {  9,  7,  8,  9,  5,  7, 10,  1,  2, -1, -1, -1, -1, -1, -1, -1 },
+/*  53: 0,    2,    4, 5,        */  { 10,  1,  2,  9,  5,  0,  5,  3,  0,  5,  7,  3, -1, -1, -1, -1 },
+/*  54:    1, 2,    4, 5,        */  {  8,  0,  2,  8,  2,  5,  8,  5,  7, 10,  5,  2, -1, -1, -1, -1 },
+/*  55: 0, 1, 2,    4, 5,        */  {  2, 10,  5,  2,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1 },
+/*  56:          3, 4, 5,        */  {  7,  9,  5,  7,  8,  9,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1 },
+/*  57: 0,       3, 4, 5,        */  {  9,  5,  7,  9,  7,  2,  9,  2,  0,  2,  7, 11, -1, -1, -1, -1 },
+/*  58:    1,    3, 4, 5,        */  {  2,  3, 11,  0,  1,  8,  1,  7,  8,  1,  5,  7, -1, -1, -1, -1 },
+/*  59: 0, 1,    3, 4, 5,        */  { 11,  2,  1, 11,  1,  7,  7,  1,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  60:       2, 3, 4, 5,        */  {  9,  5,  8,  8,  5,  7, 10,  1,  3, 10,  3, 11, -1, -1, -1, -1 },
+/*  61: 0,    2, 3, 4, 5,        */  {  5,  7,  0,  5,  0,  9,  7, 11,  0,  1,  0, 10, 11, 10,  0, -1 },
+/*  62:    1, 2, 3, 4, 5,        */  { 11, 10,  0, 11,  0,  3, 10,  5,  0,  8,  0,  7,  5,  7,  0, -1 },
+/*  63: 0, 1, 2, 3, 4, 5,        */  { 11, 10,  5,  7, 11,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  64:                   6,     */  { 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  65: 0,                6,     */  {  0,  8,  3,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  66:    1,             6,     */  {  9,  0,  1,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  67: 0, 1,             6,     */  {  1,  8,  3,  1,  9,  8,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 },
+/*  68:       2,          6,     */  {  1,  6,  5,  2,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  69: 0,    2,          6,     */  {  1,  6,  5,  1,  2,  6,  3,  0,  8, -1, -1, -1, -1, -1, -1, -1 },
+/*  70:    1, 2,          6,     */  {  9,  6,  5,  9,  0,  6,  0,  2,  6, -1, -1, -1, -1, -1, -1, -1 },
+/*  71: 0, 1, 2,          6,     */  {  5,  9,  8,  5,  8,  2,  5,  2,  6,  3,  2,  8, -1, -1, -1, -1 },
+/*  72:          3,       6,     */  {  2,  3, 11, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  73: 0,       3,       6,     */  { 11,  0,  8, 11,  2,  0, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  74:    1,    3,       6,     */  {  0,  1,  9,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 },
+/*  75: 0, 1,    3,       6,     */  {  5, 10,  6,  1,  9,  2,  9, 11,  2,  9,  8, 11, -1, -1, -1, -1 },
+/*  76:       2, 3,       6,     */  {  6,  3, 11,  6,  5,  3,  5,  1,  3, -1, -1, -1, -1, -1, -1, -1 },
+/*  77: 0,    2, 3,       6,     */  {  0,  8, 11,  0, 11,  5,  0,  5,  1,  5, 11,  6, -1, -1, -1, -1 },
+/*  78:    1, 2, 3,       6,     */  {  3, 11,  6,  0,  3,  6,  0,  6,  5,  0,  5,  9, -1, -1, -1, -1 },
+/*  79: 0, 1, 2, 3,       6,     */  {  6,  5,  9,  6,  9, 11, 11,  9,  8, -1, -1, -1, -1, -1, -1, -1 },
+/*  80:             4,    6,     */  {  5, 10,  6,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  81: 0,          4,    6,     */  {  4,  3,  0,  4,  7,  3,  6,  5, 10, -1, -1, -1, -1, -1, -1, -1 },
+/*  82:    1,       4,    6,     */  {  1,  9,  0,  5, 10,  6,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 },
+/*  83: 0, 1,       4,    6,     */  { 10,  6,  5,  1,  9,  7,  1,  7,  3,  7,  9,  4, -1, -1, -1, -1 },
+/*  84:       2,    4,    6,     */  {  6,  1,  2,  6,  5,  1,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1 },
+/*  85: 0,    2,    4,    6,     */  {  1,  2,  5,  5,  2,  6,  3,  0,  4,  3,  4,  7, -1, -1, -1, -1 },
+/*  86:    1, 2,    4,    6,     */  {  8,  4,  7,  9,  0,  5,  0,  6,  5,  0,  2,  6, -1, -1, -1, -1 },
+/*  87: 0, 1, 2,    4,    6,     */  {  7,  3,  9,  7,  9,  4,  3,  2,  9,  5,  9,  6,  2,  6,  9, -1 },
+/*  88:          3, 4,    6,     */  {  3, 11,  2,  7,  8,  4, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 },
+/*  89: 0,       3, 4,    6,     */  {  5, 10,  6,  4,  7,  2,  4,  2,  0,  2,  7, 11, -1, -1, -1, -1 },
+/*  90:    1,    3, 4,    6,     */  {  0,  1,  9,  4,  7,  8,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1 },
+/*  91: 0, 1,    3, 4,    6,     */  {  9,  2,  1,  9, 11,  2,  9,  4, 11,  7, 11,  4,  5, 10,  6, -1 },
+/*  92:       2, 3, 4,    6,     */  {  8,  4,  7,  3, 11,  5,  3,  5,  1,  5, 11,  6, -1, -1, -1, -1 },
+/*  93: 0,    2, 3, 4,    6,     */  {  5,  1, 11,  5, 11,  6,  1,  0, 11,  7, 11,  4,  0,  4, 11, -1 },
+/*  94:    1, 2, 3, 4,    6,     */  {  0,  5,  9,  0,  6,  5,  0,  3,  6, 11,  6,  3,  8,  4,  7, -1 },
+/*  95: 0, 1, 2, 3, 4,    6,     */  {  6,  5,  9,  6,  9, 11,  4,  7,  9,  7, 11,  9, -1, -1, -1, -1 },
+/*  96:                5, 6,     */  { 10,  4,  9,  6,  4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/*  97: 0,             5, 6,     */  {  4, 10,  6,  4,  9, 10,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1 },
+/*  98:    1,          5, 6,     */  { 10,  0,  1, 10,  6,  0,  6,  4,  0, -1, -1, -1, -1, -1, -1, -1 },
+/*  99: 0, 1,          5, 6,     */  {  8,  3,  1,  8,  1,  6,  8,  6,  4,  6,  1, 10, -1, -1, -1, -1 },
+/* 100:       2,       5, 6,     */  {  1,  4,  9,  1,  2,  4,  2,  6,  4, -1, -1, -1, -1, -1, -1, -1 },
+/* 101: 0,    2,       5, 6,     */  {  3,  0,  8,  1,  2,  9,  2,  4,  9,  2,  6,  4, -1, -1, -1, -1 },
+/* 102:    1, 2,       5, 6,     */  {  0,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 103: 0, 1, 2,       5, 6,     */  {  8,  3,  2,  8,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1 },
+/* 104:          3,    5, 6,     */  { 10,  4,  9, 10,  6,  4, 11,  2,  3, -1, -1, -1, -1, -1, -1, -1 },
+/* 105: 0,       3,    5, 6,     */  {  0,  8,  2,  2,  8, 11,  4,  9, 10,  4, 10,  6, -1, -1, -1, -1 },
+/* 106:    1,    3,    5, 6,     */  {  3, 11,  2,  0,  1,  6,  0,  6,  4,  6,  1, 10, -1, -1, -1, -1 },
+/* 107: 0, 1,    3,    5, 6,     */  {  6,  4,  1,  6,  1, 10,  4,  8,  1,  2,  1, 11,  8, 11,  1, -1 },
+/* 108:       2, 3,    5, 6,     */  {  9,  6,  4,  9,  3,  6,  9,  1,  3, 11,  6,  3, -1, -1, -1, -1 },
+/* 109: 0,    2, 3,    5, 6,     */  {  8, 11,  1,  8,  1,  0, 11,  6,  1,  9,  1,  4,  6,  4,  1, -1 },
+/* 110:    1, 2, 3,    5, 6,     */  {  3, 11,  6,  3,  6,  0,  0,  6,  4, -1, -1, -1, -1, -1, -1, -1 },
+/* 111: 0, 1, 2, 3,    5, 6,     */  {  6,  4,  8, 11,  6,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 112:             4, 5, 6,     */  {  7, 10,  6,  7,  8, 10,  8,  9, 10, -1, -1, -1, -1, -1, -1, -1 },
+/* 113: 0,          4, 5, 6,     */  {  0,  7,  3,  0, 10,  7,  0,  9, 10,  6,  7, 10, -1, -1, -1, -1 },
+/* 114:    1,       4, 5, 6,     */  { 10,  6,  7,  1, 10,  7,  1,  7,  8,  1,  8,  0, -1, -1, -1, -1 },
+/* 115: 0, 1,       4, 5, 6,     */  { 10,  6,  7, 10,  7,  1,  1,  7,  3, -1, -1, -1, -1, -1, -1, -1 },
+/* 116:       2,    4, 5, 6,     */  {  1,  2,  6,  1,  6,  8,  1,  8,  9,  8,  6,  7, -1, -1, -1, -1 },
+/* 117: 0,    2,    4, 5, 6,     */  {  2,  6,  9,  2,  9,  1,  6,  7,  9,  0,  9,  3,  7,  3,  9, -1 },
+/* 118:    1, 2,    4, 5, 6,     */  {  7,  8,  0,  7,  0,  6,  6,  0,  2, -1, -1, -1, -1, -1, -1, -1 },
+/* 119: 0, 1, 2,    4, 5, 6,     */  {  7,  3,  2,  6,  7,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 120:          3, 4, 5, 6,     */  {  2,  3, 11, 10,  6,  8, 10,  8,  9,  8,  6,  7, -1, -1, -1, -1 },
+/* 121: 0,       3, 4, 5, 6,     */  {  2,  0,  7,  2,  7, 11,  0,  9,  7,  6,  7, 10,  9, 10,  7, -1 },
+/* 122:    1,    3, 4, 5, 6,     */  {  1,  8,  0,  1,  7,  8,  1, 10,  7,  6,  7, 10,  2,  3, 11, -1 },
+/* 123: 0, 1,    3, 4, 5, 6,     */  { 11,  2,  1, 11,  1,  7, 10,  6,  1,  6,  7,  1, -1, -1, -1, -1 },
+/* 124:       2, 3, 4, 5, 6,     */  {  8,  9,  6,  8,  6,  7,  9,  1,  6, 11,  6,  3,  1,  3,  6, -1 },
+/* 125: 0,    2, 3, 4, 5, 6,     */  {  0,  9,  1, 11,  6,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 126:    1, 2, 3, 4, 5, 6,     */  {  7,  8,  0,  7,  0,  6,  3, 11,  0, 11,  6,  0, -1, -1, -1, -1 },
+/* 127: 0, 1, 2, 3, 4, 5, 6,     */  {  7, 11,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 128:                      7,  */  {  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 129: 0,                   7,  */  {  3,  0,  8, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 130:    1,                7,  */  {  0,  1,  9, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 131: 0, 1,                7,  */  {  8,  1,  9,  8,  3,  1, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 },
+/* 132:       2,             7,  */  { 10,  1,  2,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 133: 0,    2,             7,  */  {  1,  2, 10,  3,  0,  8,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 },
+/* 134:    1, 2,             7,  */  {  2,  9,  0,  2, 10,  9,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 },
+/* 135: 0, 1, 2,             7,  */  {  6, 11,  7,  2, 10,  3, 10,  8,  3, 10,  9,  8, -1, -1, -1, -1 },
+/* 136:          3,          7,  */  {  7,  2,  3,  6,  2,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 137: 0,       3,          7,  */  {  7,  0,  8,  7,  6,  0,  6,  2,  0, -1, -1, -1, -1, -1, -1, -1 },
+/* 138:    1,    3,          7,  */  {  2,  7,  6,  2,  3,  7,  0,  1,  9, -1, -1, -1, -1, -1, -1, -1 },
+/* 139: 0, 1,    3,          7,  */  {  1,  6,  2,  1,  8,  6,  1,  9,  8,  8,  7,  6, -1, -1, -1, -1 },
+/* 140:       2, 3,          7,  */  { 10,  7,  6, 10,  1,  7,  1,  3,  7, -1, -1, -1, -1, -1, -1, -1 },
+/* 141: 0,    2, 3,          7,  */  { 10,  7,  6,  1,  7, 10,  1,  8,  7,  1,  0,  8, -1, -1, -1, -1 },
+/* 142:    1, 2, 3,          7,  */  {  0,  3,  7,  0,  7, 10,  0, 10,  9,  6, 10,  7, -1, -1, -1, -1 },
+/* 143: 0, 1, 2, 3,          7,  */  {  7,  6, 10,  7, 10,  8,  8, 10,  9, -1, -1, -1, -1, -1, -1, -1 },
+/* 144:             4,       7,  */  {  6,  8,  4, 11,  8,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 145: 0,          4,       7,  */  {  3,  6, 11,  3,  0,  6,  0,  4,  6, -1, -1, -1, -1, -1, -1, -1 },
+/* 146:    1,       4,       7,  */  {  8,  6, 11,  8,  4,  6,  9,  0,  1, -1, -1, -1, -1, -1, -1, -1 },
+/* 147: 0, 1,       4,       7,  */  {  9,  4,  6,  9,  6,  3,  9,  3,  1, 11,  3,  6, -1, -1, -1, -1 },
+/* 148:       2,    4,       7,  */  {  6,  8,  4,  6, 11,  8,  2, 10,  1, -1, -1, -1, -1, -1, -1, -1 },
+/* 149: 0,    2,    4,       7,  */  {  1,  2, 10,  3,  0, 11,  0,  6, 11,  0,  4,  6, -1, -1, -1, -1 },
+/* 150:    1, 2,    4,       7,  */  {  4, 11,  8,  4,  6, 11,  0,  2,  9,  2, 10,  9, -1, -1, -1, -1 },
+/* 151: 0, 1, 2,    4,       7,  */  { 10,  9,  3, 10,  3,  2,  9,  4,  3, 11,  3,  6,  4,  6,  3, -1 },
+/* 152:          3, 4,       7,  */  {  8,  2,  3,  8,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1 },
+/* 153: 0,       3, 4,       7,  */  {  0,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 154:    1,    3, 4,       7,  */  {  1,  9,  0,  2,  3,  4,  2,  4,  6,  4,  3,  8, -1, -1, -1, -1 },
+/* 155: 0, 1,    3, 4,       7,  */  {  1,  9,  4,  1,  4,  2,  2,  4,  6, -1, -1, -1, -1, -1, -1, -1 },
+/* 156:       2, 3, 4,       7,  */  {  8,  1,  3,  8,  6,  1,  8,  4,  6,  6, 10,  1, -1, -1, -1, -1 },
+/* 157: 0,    2, 3, 4,       7,  */  { 10,  1,  0, 10,  0,  6,  6,  0,  4, -1, -1, -1, -1, -1, -1, -1 },
+/* 158:    1, 2, 3, 4,       7,  */  {  4,  6,  3,  4,  3,  8,  6, 10,  3,  0,  3,  9, 10,  9,  3, -1 },
+/* 159: 0, 1, 2, 3, 4,       7,  */  { 10,  9,  4,  6, 10,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 160:                5,    7,  */  {  4,  9,  5,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 161: 0,             5,    7,  */  {  0,  8,  3,  4,  9,  5, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 },
+/* 162:    1,          5,    7,  */  {  5,  0,  1,  5,  4,  0,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 },
+/* 163: 0, 1,          5,    7,  */  { 11,  7,  6,  8,  3,  4,  3,  5,  4,  3,  1,  5, -1, -1, -1, -1 },
+/* 164:       2,       5,    7,  */  {  9,  5,  4, 10,  1,  2,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 },
+/* 165: 0,    2,       5,    7,  */  {  6, 11,  7,  1,  2, 10,  0,  8,  3,  4,  9,  5, -1, -1, -1, -1 },
+/* 166:    1, 2,       5,    7,  */  {  7,  6, 11,  5,  4, 10,  4,  2, 10,  4,  0,  2, -1, -1, -1, -1 },
+/* 167: 0, 1, 2,       5,    7,  */  {  3,  4,  8,  3,  5,  4,  3,  2,  5, 10,  5,  2, 11,  7,  6, -1 },
+/* 168:          3,    5,    7,  */  {  7,  2,  3,  7,  6,  2,  5,  4,  9, -1, -1, -1, -1, -1, -1, -1 },
+/* 169: 0,       3,    5,    7,  */  {  9,  5,  4,  0,  8,  6,  0,  6,  2,  6,  8,  7, -1, -1, -1, -1 },
+/* 170:    1,    3,    5,    7,  */  {  3,  6,  2,  3,  7,  6,  1,  5,  0,  5,  4,  0, -1, -1, -1, -1 },
+/* 171: 0, 1,    3,    5,    7,  */  {  6,  2,  8,  6,  8,  7,  2,  1,  8,  4,  8,  5,  1,  5,  8, -1 },
+/* 172:       2, 3,    5,    7,  */  {  9,  5,  4, 10,  1,  6,  1,  7,  6,  1,  3,  7, -1, -1, -1, -1 },
+/* 173: 0,    2, 3,    5,    7,  */  {  1,  6, 10,  1,  7,  6,  1,  0,  7,  8,  7,  0,  9,  5,  4, -1 },
+/* 174:    1, 2, 3,    5,    7,  */  {  4,  0, 10,  4, 10,  5,  0,  3, 10,  6, 10,  7,  3,  7, 10, -1 },
+/* 175: 0, 1, 2, 3,    5,    7,  */  {  7,  6, 10,  7, 10,  8,  5,  4, 10,  4,  8, 10, -1, -1, -1, -1 },
+/* 176:             4, 5,    7,  */  {  6,  9,  5,  6, 11,  9, 11,  8,  9, -1, -1, -1, -1, -1, -1, -1 },
+/* 177: 0,          4, 5,    7,  */  {  3,  6, 11,  0,  6,  3,  0,  5,  6,  0,  9,  5, -1, -1, -1, -1 },
+/* 178:    1,       4, 5,    7,  */  {  0, 11,  8,  0,  5, 11,  0,  1,  5,  5,  6, 11, -1, -1, -1, -1 },
+/* 179: 0, 1,       4, 5,    7,  */  {  6, 11,  3,  6,  3,  5,  5,  3,  1, -1, -1, -1, -1, -1, -1, -1 },
+/* 180:       2,    4, 5,    7,  */  {  1,  2, 10,  9,  5, 11,  9, 11,  8, 11,  5,  6, -1, -1, -1, -1 },
+/* 181: 0,    2,    4, 5,    7,  */  {  0, 11,  3,  0,  6, 11,  0,  9,  6,  5,  6,  9,  1,  2, 10, -1 },
+/* 182:    1, 2,    4, 5,    7,  */  { 11,  8,  5, 11,  5,  6,  8,  0,  5, 10,  5,  2,  0,  2,  5, -1 },
+/* 183: 0, 1, 2,    4, 5,    7,  */  {  6, 11,  3,  6,  3,  5,  2, 10,  3, 10,  5,  3, -1, -1, -1, -1 },
+/* 184:          3, 4, 5,    7,  */  {  5,  8,  9,  5,  2,  8,  5,  6,  2,  3,  8,  2, -1, -1, -1, -1 },
+/* 185: 0,       3, 4, 5,    7,  */  {  9,  5,  6,  9,  6,  0,  0,  6,  2, -1, -1, -1, -1, -1, -1, -1 },
+/* 186:    1,    3, 4, 5,    7,  */  {  1,  5,  8,  1,  8,  0,  5,  6,  8,  3,  8,  2,  6,  2,  8, -1 },
+/* 187: 0, 1,    3, 4, 5,    7,  */  {  1,  5,  6,  2,  1,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 188:       2, 3, 4, 5,    7,  */  {  1,  3,  6,  1,  6, 10,  3,  8,  6,  5,  6,  9,  8,  9,  6, -1 },
+/* 189: 0,    2, 3, 4, 5,    7,  */  { 10,  1,  0, 10,  0,  6,  9,  5,  0,  5,  6,  0, -1, -1, -1, -1 },
+/* 190:    1, 2, 3, 4, 5,    7,  */  {  0,  3,  8,  5,  6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 191: 0, 1, 2, 3, 4, 5,    7,  */  { 10,  5,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 192:                   6, 7,  */  { 11,  5, 10,  7,  5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 193: 0,                6, 7,  */  { 11,  5, 10, 11,  7,  5,  8,  3,  0, -1, -1, -1, -1, -1, -1, -1 },
+/* 194:    1,             6, 7,  */  {  5, 11,  7,  5, 10, 11,  1,  9,  0, -1, -1, -1, -1, -1, -1, -1 },
+/* 195: 0, 1,             6, 7,  */  { 10,  7,  5, 10, 11,  7,  9,  8,  1,  8,  3,  1, -1, -1, -1, -1 },
+/* 196:       2,          6, 7,  */  { 11,  1,  2, 11,  7,  1,  7,  5,  1, -1, -1, -1, -1, -1, -1, -1 },
+/* 197: 0,    2,          6, 7,  */  {  0,  8,  3,  1,  2,  7,  1,  7,  5,  7,  2, 11, -1, -1, -1, -1 },
+/* 198:    1, 2,          6, 7,  */  {  9,  7,  5,  9,  2,  7,  9,  0,  2,  2, 11,  7, -1, -1, -1, -1 },
+/* 199: 0, 1, 2,          6, 7,  */  {  7,  5,  2,  7,  2, 11,  5,  9,  2,  3,  2,  8,  9,  8,  2, -1 },
+/* 200:          3,       6, 7,  */  {  2,  5, 10,  2,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1 },
+/* 201: 0,       3,       6, 7,  */  {  8,  2,  0,  8,  5,  2,  8,  7,  5, 10,  2,  5, -1, -1, -1, -1 },
+/* 202:    1,    3,       6, 7,  */  {  9,  0,  1,  5, 10,  3,  5,  3,  7,  3, 10,  2, -1, -1, -1, -1 },
+/* 203: 0, 1,    3,       6, 7,  */  {  9,  8,  2,  9,  2,  1,  8,  7,  2, 10,  2,  5,  7,  5,  2, -1 },
+/* 204:       2, 3,       6, 7,  */  {  1,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 205: 0,    2, 3,       6, 7,  */  {  0,  8,  7,  0,  7,  1,  1,  7,  5, -1, -1, -1, -1, -1, -1, -1 },
+/* 206:    1, 2, 3,       6, 7,  */  {  9,  0,  3,  9,  3,  5,  5,  3,  7, -1, -1, -1, -1, -1, -1, -1 },
+/* 207: 0, 1, 2, 3,       6, 7,  */  {  9,  8,  7,  5,  9,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 208:             4,    6, 7,  */  {  5,  8,  4,  5, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1 },
+/* 209: 0,          4,    6, 7,  */  {  5,  0,  4,  5, 11,  0,  5, 10, 11, 11,  3,  0, -1, -1, -1, -1 },
+/* 210:    1,       4,    6, 7,  */  {  0,  1,  9,  8,  4, 10,  8, 10, 11, 10,  4,  5, -1, -1, -1, -1 },
+/* 211: 0, 1,       4,    6, 7,  */  { 10, 11,  4, 10,  4,  5, 11,  3,  4,  9,  4,  1,  3,  1,  4, -1 },
+/* 212:       2,    4,    6, 7,  */  {  2,  5,  1,  2,  8,  5,  2, 11,  8,  4,  5,  8, -1, -1, -1, -1 },
+/* 213: 0,    2,    4,    6, 7,  */  {  0,  4, 11,  0, 11,  3,  4,  5, 11,  2, 11,  1,  5,  1, 11, -1 },
+/* 214:    1, 2,    4,    6, 7,  */  {  0,  2,  5,  0,  5,  9,  2, 11,  5,  4,  5,  8, 11,  8,  5, -1 },
+/* 215: 0, 1, 2,    4,    6, 7,  */  {  9,  4,  5,  2, 11,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 216:          3, 4,    6, 7,  */  {  2,  5, 10,  3,  5,  2,  3,  4,  5,  3,  8,  4, -1, -1, -1, -1 },
+/* 217: 0,       3, 4,    6, 7,  */  {  5, 10,  2,  5,  2,  4,  4,  2,  0, -1, -1, -1, -1, -1, -1, -1 },
+/* 218:    1,    3, 4,    6, 7,  */  {  3, 10,  2,  3,  5, 10,  3,  8,  5,  4,  5,  8,  0,  1,  9, -1 },
+/* 219: 0, 1,    3, 4,    6, 7,  */  {  5, 10,  2,  5,  2,  4,  1,  9,  2,  9,  4,  2, -1, -1, -1, -1 },
+/* 220:       2, 3, 4,    6, 7,  */  {  8,  4,  5,  8,  5,  3,  3,  5,  1, -1, -1, -1, -1, -1, -1, -1 },
+/* 221: 0,    2, 3, 4,    6, 7,  */  {  0,  4,  5,  1,  0,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 222:    1, 2, 3, 4,    6, 7,  */  {  8,  4,  5,  8,  5,  3,  9,  0,  5,  0,  3,  5, -1, -1, -1, -1 },
+/* 223: 0, 1, 2, 3, 4,    6, 7,  */  {  9,  4,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 224:                5, 6, 7,  */  {  4, 11,  7,  4,  9, 11,  9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
+/* 225: 0,             5, 6, 7,  */  {  0,  8,  3,  4,  9,  7,  9, 11,  7,  9, 10, 11, -1, -1, -1, -1 },
+/* 226:    1,          5, 6, 7,  */  {  1, 10, 11,  1, 11,  4,  1,  4,  0,  7,  4, 11, -1, -1, -1, -1 },
+/* 227: 0, 1,          5, 6, 7,  */  {  3,  1,  4,  3,  4,  8,  1, 10,  4,  7,  4, 11, 10, 11,  4, -1 },
+/* 228:       2,       5, 6, 7,  */  {  4, 11,  7,  9, 11,  4,  9,  2, 11,  9,  1,  2, -1, -1, -1, -1 },
+/* 229: 0,    2,       5, 6, 7,  */  {  9,  7,  4,  9, 11,  7,  9,  1, 11,  2, 11,  1,  0,  8,  3, -1 },
+/* 230:    1, 2,       5, 6, 7,  */  { 11,  7,  4, 11,  4,  2,  2,  4,  0, -1, -1, -1, -1, -1, -1, -1 },
+/* 231: 0, 1, 2,       5, 6, 7,  */  { 11,  7,  4, 11,  4,  2,  8,  3,  4,  3,  2,  4, -1, -1, -1, -1 },
+/* 232:          3,    5, 6, 7,  */  {  2,  9, 10,  2,  7,  9,  2,  3,  7,  7,  4,  9, -1, -1, -1, -1 },
+/* 233: 0,       3,    5, 6, 7,  */  {  9, 10,  7,  9,  7,  4, 10,  2,  7,  8,  7,  0,  2,  0,  7, -1 },
+/* 234:    1,    3,    5, 6, 7,  */  {  3,  7, 10,  3, 10,  2,  7,  4, 10,  1, 10,  0,  4,  0, 10, -1 },
+/* 235: 0, 1,    3,    5, 6, 7,  */  {  1, 10,  2,  8,  7,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 236:       2, 3,    5, 6, 7,  */  {  4,  9,  1,  4,  1,  7,  7,  1,  3, -1, -1, -1, -1, -1, -1, -1 },
+/* 237: 0,    2, 3,    5, 6, 7,  */  {  4,  9,  1,  4,  1,  7,  0,  8,  1,  8,  7,  1, -1, -1, -1, -1 },
+/* 238:    1, 2, 3,    5, 6, 7,  */  {  4,  0,  3,  7,  4,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 239: 0, 1, 2, 3,    5, 6, 7,  */  {  4,  8,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 240:             4, 5, 6, 7,  */  {  9, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 241: 0,          4, 5, 6, 7,  */  {  3,  0,  9,  3,  9, 11, 11,  9, 10, -1, -1, -1, -1, -1, -1, -1 },
+/* 242:    1,       4, 5, 6, 7,  */  {  0,  1, 10,  0, 10,  8,  8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
+/* 243: 0, 1,       4, 5, 6, 7,  */  {  3,  1, 10, 11,  3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 244:       2,    4, 5, 6, 7,  */  {  1,  2, 11,  1, 11,  9,  9, 11,  8, -1, -1, -1, -1, -1, -1, -1 },
+/* 245: 0,    2,    4, 5, 6, 7,  */  {  3,  0,  9,  3,  9, 11,  1,  2,  9,  2, 11,  9, -1, -1, -1, -1 },
+/* 246:    1, 2,    4, 5, 6, 7,  */  {  0,  2, 11,  8,  0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 247: 0, 1, 2,    4, 5, 6, 7,  */  {  3,  2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 248:          3, 4, 5, 6, 7,  */  {  2,  3,  8,  2,  8, 10, 10,  8,  9, -1, -1, -1, -1, -1, -1, -1 },
+/* 249: 0,       3, 4, 5, 6, 7,  */  {  9, 10,  2,  0,  9,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 250:    1,    3, 4, 5, 6, 7,  */  {  2,  3,  8,  2,  8, 10,  0,  1,  8,  1, 10,  8, -1, -1, -1, -1 },
+/* 251: 0, 1,    3, 4, 5, 6, 7,  */  {  1, 10,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 252:       2, 3, 4, 5, 6, 7,  */  {  1,  3,  8,  9,  1,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 253: 0,    2, 3, 4, 5, 6, 7,  */  {  0,  9,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 254:    1, 2, 3, 4, 5, 6, 7,  */  {  0,  3,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+/* 255: 0, 1, 2, 3, 4, 5, 6, 7,  */  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+};
+//_____________________________________________________________________________
+
+
+
+#endif // _LOOKUPTABLE_H_
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..d9012f0405a2ea63c696e432250891477d75074e
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.cpp
@@ -0,0 +1,1302 @@
+/**
+ * @file    MarchingCubes.cpp
+ * @author  Thomas Lewiner <thomas.lewiner@polytechnique.org>
+ * @author  Math Dept, PUC-Rio
+ * @version 0.2
+ * @date    12/08/2002
+ *
+ * @brief   MarchingCubes Algorithm
+ */
+//________________________________________________
+
+
+#if !defined(WIN32) || defined(__CYGWIN__)
+#pragma implementation
+#endif // WIN32
+
+#include <math.h>
+#include <time.h>
+#include <memory.h>
+#include <stdlib.h>
+#include <float.h>
+#include "MarchingCubes.h"
+#include "ply.h"
+#include "LookUpTable.h"
+
+// step size of the arrays of vertices and triangles
+#define ALLOC_SIZE 65536
+
+//_____________________________________________________________________________
+// print cube for debug
+void MarchingCubes::print_cube() { printf( "\t%f %f %f %f %f %f %f %f\n", _cube[0], _cube[1], _cube[2], _cube[3], _cube[4], _cube[5], _cube[6], _cube[7]) ; }
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// Constructor
+MarchingCubes::MarchingCubes( const int size_x /*= -1*/, const int size_y /*= -1*/, const int size_z /*= -1*/ ) :
+//-----------------------------------------------------------------------------
+  _originalMC(false),
+  _ext_data  (false),
+  _size_x    (size_x),
+  _size_y    (size_y),
+  _size_z    (size_z),
+  _data      ((real *)NULL),
+  _x_verts   (( int *)NULL),
+  _y_verts   (( int *)NULL),
+  _z_verts   (( int *)NULL),
+  _nverts    (0),
+  _ntrigs    (0),
+  _Nverts    (0),
+  _Ntrigs    (0),
+  _vertices  (( Vertex *)NULL),
+  _triangles ((Triangle*)NULL)
+{}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// Destructor
+MarchingCubes::~MarchingCubes()
+//-----------------------------------------------------------------------------
+{
+  clean_all() ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// main algorithm
+void MarchingCubes::run( real iso )
+//-----------------------------------------------------------------------------
+{
+  clock_t time = clock() ;
+
+  compute_intersection_points( iso ) ;
+
+  for( _k = 0 ; _k < _size_z-1 ; _k++ )
+  for( _j = 0 ; _j < _size_y-1 ; _j++ )
+  for( _i = 0 ; _i < _size_x-1 ; _i++ )
+  {
+    _lut_entry = 0 ;
+    for( int p = 0 ; p < 8 ; ++p )
+    {
+      _cube[p] = get_data( _i+((p^(p>>1))&1), _j+((p>>1)&1), _k+((p>>2)&1) ) - iso ;
+      if( fabs( _cube[p] ) < FLT_EPSILON ) _cube[p] = FLT_EPSILON ;
+      if( _cube[p] > 0 ) _lut_entry += 1 << p ;
+    }
+/*
+    if( ( _cube[0] = get_data( _i , _j , _k ) ) > 0 ) _lut_entry +=   1 ;
+    if( ( _cube[1] = get_data(_i+1, _j , _k ) ) > 0 ) _lut_entry +=   2 ;
+    if( ( _cube[2] = get_data(_i+1,_j+1, _k ) ) > 0 ) _lut_entry +=   4 ;
+    if( ( _cube[3] = get_data( _i ,_j+1, _k ) ) > 0 ) _lut_entry +=   8 ;
+    if( ( _cube[4] = get_data( _i , _j ,_k+1) ) > 0 ) _lut_entry +=  16 ;
+    if( ( _cube[5] = get_data(_i+1, _j ,_k+1) ) > 0 ) _lut_entry +=  32 ;
+    if( ( _cube[6] = get_data(_i+1,_j+1,_k+1) ) > 0 ) _lut_entry +=  64 ;
+    if( ( _cube[7] = get_data( _i ,_j+1,_k+1) ) > 0 ) _lut_entry += 128 ;
+*/
+    process_cube( ) ;
+  }
+
+  printf("Marching Cubes ran in %lf secs.\n", (double)(clock() - time)/CLOCKS_PER_SEC) ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// init temporary structures (must set sizes before call)
+void MarchingCubes::init_temps()
+//-----------------------------------------------------------------------------
+{
+  if( !_ext_data )
+    _data    = new real [_size_x * _size_y * _size_z] ;
+  _x_verts = new int  [_size_x * _size_y * _size_z] ;
+  _y_verts = new int  [_size_x * _size_y * _size_z] ;
+  _z_verts = new int  [_size_x * _size_y * _size_z] ;
+
+  memset( _x_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ;
+  memset( _y_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ;
+  memset( _z_verts, -1, _size_x * _size_y * _size_z * sizeof( int ) ) ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// init all structures (must set sizes before call)
+void MarchingCubes::init_all ()
+//-----------------------------------------------------------------------------
+{
+  init_temps() ;
+
+  _nverts = _ntrigs = 0 ;
+  _Nverts = _Ntrigs = ALLOC_SIZE ;
+  _vertices  = new Vertex  [_Nverts] ;
+  _triangles = new Triangle[_Ntrigs] ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// clean temporary structures
+void MarchingCubes::clean_temps()
+//-----------------------------------------------------------------------------
+{
+  if( !_ext_data )
+    delete [] _data;
+  delete [] _x_verts;
+  delete [] _y_verts;
+  delete [] _z_verts;
+
+  if( !_ext_data )
+    _data     = (real*)NULL ;
+  _x_verts  = (int*)NULL ;
+  _y_verts  = (int*)NULL ;
+  _z_verts  = (int*)NULL ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// clean all structures
+void MarchingCubes::clean_all()
+//-----------------------------------------------------------------------------
+{
+  clean_temps() ;
+  delete [] _vertices  ;
+  delete [] _triangles ;
+  _vertices  = (Vertex   *)NULL ;
+  _triangles = (Triangle *)NULL ;
+  _nverts = _ntrigs = 0 ;
+  _Nverts = _Ntrigs = 0 ;
+
+  _size_x = _size_y = _size_z = -1 ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+// Compute the intersection points
+void MarchingCubes::compute_intersection_points( real iso )
+//-----------------------------------------------------------------------------
+{
+  for( _k = 0 ; _k < _size_z ; _k++ )
+  for( _j = 0 ; _j < _size_y ; _j++ )
+  for( _i = 0 ; _i < _size_x ; _i++ )
+  {
+    _cube[0] = get_data( _i, _j, _k ) - iso ;
+    if( _i < _size_x - 1 ) _cube[1] = get_data(_i+1, _j , _k ) - iso ;
+    else                   _cube[1] = _cube[0] ;
+
+    if( _j < _size_y - 1 ) _cube[3] = get_data( _i ,_j+1, _k ) - iso ;
+    else                   _cube[3] = _cube[0] ;
+
+    if( _k < _size_z - 1 ) _cube[4] = get_data( _i , _j ,_k+1) - iso ;
+    else                   _cube[4] = _cube[0] ;
+
+    if( fabs( _cube[0] ) < FLT_EPSILON ) _cube[0] = FLT_EPSILON ;
+    if( fabs( _cube[1] ) < FLT_EPSILON ) _cube[1] = FLT_EPSILON ;
+    if( fabs( _cube[3] ) < FLT_EPSILON ) _cube[3] = FLT_EPSILON ;
+    if( fabs( _cube[4] ) < FLT_EPSILON ) _cube[4] = FLT_EPSILON ;
+
+    if( _cube[0] < 0 )
+    {
+      if( _cube[1] > 0 ) set_x_vert( add_x_vertex( ), _i,_j,_k ) ;
+      if( _cube[3] > 0 ) set_y_vert( add_y_vertex( ), _i,_j,_k ) ;
+      if( _cube[4] > 0 ) set_z_vert( add_z_vertex( ), _i,_j,_k ) ;
+    }
+    else
+    {
+      if( _cube[1] < 0 ) set_x_vert( add_x_vertex( ), _i,_j,_k ) ;
+      if( _cube[3] < 0 ) set_y_vert( add_y_vertex( ), _i,_j,_k ) ;
+      if( _cube[4] < 0 ) set_z_vert( add_z_vertex( ), _i,_j,_k ) ;
+    }
+  }
+}
+//_____________________________________________________________________________
+
+
+
+
+
+//_____________________________________________________________________________
+// Test a face
+// if face>0 return true if the face contains a part of the surface
+bool MarchingCubes::test_face( schar face )
+//-----------------------------------------------------------------------------
+{
+  real A,B,C,D ;
+
+  switch( face )
+  {
+  case -1 : case 1 :  A = _cube[0] ;  B = _cube[4] ;  C = _cube[5] ;  D = _cube[1] ;  break ;
+  case -2 : case 2 :  A = _cube[1] ;  B = _cube[5] ;  C = _cube[6] ;  D = _cube[2] ;  break ;
+  case -3 : case 3 :  A = _cube[2] ;  B = _cube[6] ;  C = _cube[7] ;  D = _cube[3] ;  break ;
+  case -4 : case 4 :  A = _cube[3] ;  B = _cube[7] ;  C = _cube[4] ;  D = _cube[0] ;  break ;
+  case -5 : case 5 :  A = _cube[0] ;  B = _cube[3] ;  C = _cube[2] ;  D = _cube[1] ;  break ;
+  case -6 : case 6 :  A = _cube[4] ;  B = _cube[7] ;  C = _cube[6] ;  D = _cube[5] ;  break ;
+  default : printf( "Invalid face code %d\n", face ) ;  print_cube() ;  A = B = C = D = 0 ;
+  };
+
+  if( fabs( A*C - B*D ) < FLT_EPSILON )
+    return face >= 0 ;
+  return face * A * ( A*C - B*D ) >= 0  ;  // face and A invert signs
+}
+//_____________________________________________________________________________
+
+
+
+
+
+//_____________________________________________________________________________
+// Test the interior of a cube
+// if s == 7, return true  if the interior is empty
+// if s ==-7, return false if the interior is empty
+bool MarchingCubes::test_interior( schar s )
+//-----------------------------------------------------------------------------
+{
+  real t, At=0, Bt=0, Ct=0, Dt=0, a, b ;
+  char  test =  0 ;
+  char  edge = -1 ; // reference edge of the triangulation
+
+  switch( _case )
+  {
+  case  4 :
+  case 10 :
+    a = ( _cube[4] - _cube[0] ) * ( _cube[6] - _cube[2] ) - ( _cube[7] - _cube[3] ) * ( _cube[5] - _cube[1] ) ;
+    b =  _cube[2] * ( _cube[4] - _cube[0] ) + _cube[0] * ( _cube[6] - _cube[2] )
+             - _cube[1] * ( _cube[7] - _cube[3] ) - _cube[3] * ( _cube[5] - _cube[1] ) ;
+    t = - b / (2*a) ;
+    if( t<0 || t>1 ) return s>0 ;
+
+    At = _cube[0] + ( _cube[4] - _cube[0] ) * t ;
+    Bt = _cube[3] + ( _cube[7] - _cube[3] ) * t ;
+    Ct = _cube[2] + ( _cube[6] - _cube[2] ) * t ;
+    Dt = _cube[1] + ( _cube[5] - _cube[1] ) * t ;
+    break ;
+
+  case  6 :
+  case  7 :
+  case 12 :
+  case 13 :
+    switch( _case )
+    {
+    case  6 : edge = test6 [_config][2] ; break ;
+    case  7 : edge = test7 [_config][4] ; break ;
+    case 12 : edge = test12[_config][3] ; break ;
+    case 13 : edge = tiling13_5_1[_config][_subconfig][0] ; break ;
+    }
+    switch( edge )
+    {
+    case  0 :
+      t  = _cube[0] / ( _cube[0] - _cube[1] ) ;
+      At = 0 ;
+      Bt = _cube[3] + ( _cube[2] - _cube[3] ) * t ;
+      Ct = _cube[7] + ( _cube[6] - _cube[7] ) * t ;
+      Dt = _cube[4] + ( _cube[5] - _cube[4] ) * t ;
+      break ;
+    case  1 :
+      t  = _cube[1] / ( _cube[1] - _cube[2] ) ;
+      At = 0 ;
+      Bt = _cube[0] + ( _cube[3] - _cube[0] ) * t ;
+      Ct = _cube[4] + ( _cube[7] - _cube[4] ) * t ;
+      Dt = _cube[5] + ( _cube[6] - _cube[5] ) * t ;
+      break ;
+    case  2 :
+      t  = _cube[2] / ( _cube[2] - _cube[3] ) ;
+      At = 0 ;
+      Bt = _cube[1] + ( _cube[0] - _cube[1] ) * t ;
+      Ct = _cube[5] + ( _cube[4] - _cube[5] ) * t ;
+      Dt = _cube[6] + ( _cube[7] - _cube[6] ) * t ;
+      break ;
+    case  3 :
+      t  = _cube[3] / ( _cube[3] - _cube[0] ) ;
+      At = 0 ;
+      Bt = _cube[2] + ( _cube[1] - _cube[2] ) * t ;
+      Ct = _cube[6] + ( _cube[5] - _cube[6] ) * t ;
+      Dt = _cube[7] + ( _cube[4] - _cube[7] ) * t ;
+      break ;
+    case  4 :
+      t  = _cube[4] / ( _cube[4] - _cube[5] ) ;
+      At = 0 ;
+      Bt = _cube[7] + ( _cube[6] - _cube[7] ) * t ;
+      Ct = _cube[3] + ( _cube[2] - _cube[3] ) * t ;
+      Dt = _cube[0] + ( _cube[1] - _cube[0] ) * t ;
+      break ;
+    case  5 :
+      t  = _cube[5] / ( _cube[5] - _cube[6] ) ;
+      At = 0 ;
+      Bt = _cube[4] + ( _cube[7] - _cube[4] ) * t ;
+      Ct = _cube[0] + ( _cube[3] - _cube[0] ) * t ;
+      Dt = _cube[1] + ( _cube[2] - _cube[1] ) * t ;
+      break ;
+    case  6 :
+      t  = _cube[6] / ( _cube[6] - _cube[7] ) ;
+      At = 0 ;
+      Bt = _cube[5] + ( _cube[4] - _cube[5] ) * t ;
+      Ct = _cube[1] + ( _cube[0] - _cube[1] ) * t ;
+      Dt = _cube[2] + ( _cube[3] - _cube[2] ) * t ;
+      break ;
+    case  7 :
+      t  = _cube[7] / ( _cube[7] - _cube[4] ) ;
+      At = 0 ;
+      Bt = _cube[6] + ( _cube[5] - _cube[6] ) * t ;
+      Ct = _cube[2] + ( _cube[1] - _cube[2] ) * t ;
+      Dt = _cube[3] + ( _cube[0] - _cube[3] ) * t ;
+      break ;
+    case  8 :
+      t  = _cube[0] / ( _cube[0] - _cube[4] ) ;
+      At = 0 ;
+      Bt = _cube[3] + ( _cube[7] - _cube[3] ) * t ;
+      Ct = _cube[2] + ( _cube[6] - _cube[2] ) * t ;
+      Dt = _cube[1] + ( _cube[5] - _cube[1] ) * t ;
+      break ;
+    case  9 :
+      t  = _cube[1] / ( _cube[1] - _cube[5] ) ;
+      At = 0 ;
+      Bt = _cube[0] + ( _cube[4] - _cube[0] ) * t ;
+      Ct = _cube[3] + ( _cube[7] - _cube[3] ) * t ;
+      Dt = _cube[2] + ( _cube[6] - _cube[2] ) * t ;
+      break ;
+    case 10 :
+      t  = _cube[2] / ( _cube[2] - _cube[6] ) ;
+      At = 0 ;
+      Bt = _cube[1] + ( _cube[5] - _cube[1] ) * t ;
+      Ct = _cube[0] + ( _cube[4] - _cube[0] ) * t ;
+      Dt = _cube[3] + ( _cube[7] - _cube[3] ) * t ;
+      break ;
+    case 11 :
+      t  = _cube[3] / ( _cube[3] - _cube[7] ) ;
+      At = 0 ;
+      Bt = _cube[2] + ( _cube[6] - _cube[2] ) * t ;
+      Ct = _cube[1] + ( _cube[5] - _cube[1] ) * t ;
+      Dt = _cube[0] + ( _cube[4] - _cube[0] ) * t ;
+      break ;
+    default : printf( "Invalid edge %d\n", edge ) ;  print_cube() ;  break ;
+    }
+    break ;
+
+  default : printf( "Invalid ambiguous case %d\n", _case ) ;  print_cube() ;  break ;
+  }
+
+  if( At >= 0 ) test ++ ;
+  if( Bt >= 0 ) test += 2 ;
+  if( Ct >= 0 ) test += 4 ;
+  if( Dt >= 0 ) test += 8 ;
+  switch( test )
+  {
+  case  0 : return s>0 ;
+  case  1 : return s>0 ;
+  case  2 : return s>0 ;
+  case  3 : return s>0 ;
+  case  4 : return s>0 ;
+  case  5 : if( At * Ct - Bt * Dt <  FLT_EPSILON ) return s>0 ; break ;
+  case  6 : return s>0 ;
+  case  7 : return s<0 ;
+  case  8 : return s>0 ;
+  case  9 : return s>0 ;
+  case 10 : if( At * Ct - Bt * Dt >= FLT_EPSILON ) return s>0 ; break ;
+  case 11 : return s<0 ;
+  case 12 : return s>0 ;
+  case 13 : return s<0 ;
+  case 14 : return s<0 ;
+  case 15 : return s<0 ;
+  }
+
+  return s<0 ;
+}
+//_____________________________________________________________________________
+
+
+
+
+//_____________________________________________________________________________
+// Process a unit cube
+void MarchingCubes::process_cube( )
+//-----------------------------------------------------------------------------
+{
+  if( _originalMC )
+  {
+    char nt = 0 ;
+    while( casesClassic[_lut_entry][3*nt] != -1 ) nt++ ;
+    add_triangle( casesClassic[_lut_entry], nt ) ;
+    return ;
+  }
+
+  int   v12 = -1 ;
+  _case   = cases[_lut_entry][0] ;
+  _config = cases[_lut_entry][1] ;
+  _subconfig = 0 ;
+
+  switch( _case )
+  {
+  case  0 :
+    break ;
+
+  case  1 :
+    add_triangle( tiling1[_config], 1 ) ;
+    break ;
+
+  case  2 :
+    add_triangle( tiling2[_config], 2 ) ;
+    break ;
+
+  case  3 :
+    if( test_face( test3[_config]) )
+      add_triangle( tiling3_2[_config], 4 ) ; // 3.2
+    else
+      add_triangle( tiling3_1[_config], 2 ) ; // 3.1
+    break ;
+
+  case  4 :
+    if( test_interior( test4[_config]) )
+      add_triangle( tiling4_1[_config], 2 ) ; // 4.1.1
+    else
+      add_triangle( tiling4_2[_config], 6 ) ; // 4.1.2
+    break ;
+
+  case  5 :
+    add_triangle( tiling5[_config], 3 ) ;
+    break ;
+
+  case  6 :
+    if( test_face( test6[_config][0]) )
+      add_triangle( tiling6_2[_config], 5 ) ; // 6.2
+    else
+    {
+      if( test_interior( test6[_config][1]) )
+        add_triangle( tiling6_1_1[_config], 3 ) ; // 6.1.1
+      else
+	  {
+        v12 = add_c_vertex() ;
+        add_triangle( tiling6_1_2[_config], 9 , v12) ; // 6.1.2
+      }
+    }
+    break ;
+
+  case  7 :
+    if( test_face( test7[_config][0] ) ) _subconfig +=  1 ;
+    if( test_face( test7[_config][1] ) ) _subconfig +=  2 ;
+    if( test_face( test7[_config][2] ) ) _subconfig +=  4 ;
+    switch( _subconfig )
+      {
+      case 0 :
+        add_triangle( tiling7_1[_config], 3 ) ; break ;
+      case 1 :
+        add_triangle( tiling7_2[_config][0], 5 ) ; break ;
+      case 2 :
+        add_triangle( tiling7_2[_config][1], 5 ) ; break ;
+      case 3 :
+        v12 = add_c_vertex() ;
+        add_triangle( tiling7_3[_config][0], 9, v12 ) ; break ;
+      case 4 :
+        add_triangle( tiling7_2[_config][2], 5 ) ; break ;
+      case 5 :
+        v12 = add_c_vertex() ;
+        add_triangle( tiling7_3[_config][1], 9, v12 ) ; break ;
+      case 6 :
+        v12 = add_c_vertex() ;
+        add_triangle( tiling7_3[_config][2], 9, v12 ) ; break ;
+      case 7 :
+        if( test_interior( test7[_config][3]) )
+          add_triangle( tiling7_4_2[_config], 9 ) ;
+        else
+          add_triangle( tiling7_4_1[_config], 5 ) ;
+        break ;
+      };
+    break ;
+
+  case  8 :
+    add_triangle( tiling8[_config], 2 ) ;
+    break ;
+
+  case  9 :
+    add_triangle( tiling9[_config], 4 ) ;
+    break ;
+
+  case 10 :
+    if( test_face( test10[_config][0]) )
+    {
+      if( test_face( test10[_config][1]) )
+        add_triangle( tiling10_1_1_[_config], 4 ) ; // 10.1.1
+      else
+      {
+        v12 = add_c_vertex() ;
+        add_triangle( tiling10_2[_config], 8, v12 ) ; // 10.2
+      }
+    }
+    else
+    {
+      if( test_face( test10[_config][1]) )
+      {
+        v12 = add_c_vertex() ;
+        add_triangle( tiling10_2_[_config], 8, v12 ) ; // 10.2
+      }
+      else
+      {
+        if( test_interior( test10[_config][2]) )
+          add_triangle( tiling10_1_1[_config], 4 ) ; // 10.1.1
+        else
+          add_triangle( tiling10_1_2[_config], 8 ) ; // 10.1.2
+      }
+    }
+    break ;
+
+  case 11 :
+    add_triangle( tiling11[_config], 4 ) ;
+    break ;
+
+  case 12 :
+    if( test_face( test12[_config][0]) )
+    {
+      if( test_face( test12[_config][1]) )
+        add_triangle( tiling12_1_1_[_config], 4 ) ; // 12.1.1
+      else
+      {
+        v12 = add_c_vertex() ;
+        add_triangle( tiling12_2[_config], 8, v12 ) ; // 12.2
+      }
+    }
+    else
+    {
+      if( test_face( test12[_config][1]) )
+      {
+        v12 = add_c_vertex() ;
+        add_triangle( tiling12_2_[_config], 8, v12 ) ; // 12.2
+      }
+      else
+      {
+        if( test_interior( test12[_config][2]) )
+          add_triangle( tiling12_1_1[_config], 4 ) ; // 12.1.1
+        else
+          add_triangle( tiling12_1_2[_config], 8 ) ; // 12.1.2
+      }
+    }
+    break ;
+
+  case 13 :
+    if( test_face( test13[_config][0] ) ) _subconfig +=  1 ;
+    if( test_face( test13[_config][1] ) ) _subconfig +=  2 ;
+    if( test_face( test13[_config][2] ) ) _subconfig +=  4 ;
+    if( test_face( test13[_config][3] ) ) _subconfig +=  8 ;
+    if( test_face( test13[_config][4] ) ) _subconfig += 16 ;
+    if( test_face( test13[_config][5] ) ) _subconfig += 32 ;
+    switch( subconfig13[_subconfig] )
+    {
+      case 0 :/* 13.1 */
+        add_triangle( tiling13_1[_config], 4 ) ; break ;
+
+      case 1 :/* 13.2 */
+        add_triangle( tiling13_2[_config][0], 6 ) ; break ;
+      case 2 :/* 13.2 */
+        add_triangle( tiling13_2[_config][1], 6 ) ; break ;
+      case 3 :/* 13.2 */
+        add_triangle( tiling13_2[_config][2], 6 ) ; break ;
+      case 4 :/* 13.2 */
+        add_triangle( tiling13_2[_config][3], 6 ) ; break ;
+      case 5 :/* 13.2 */
+        add_triangle( tiling13_2[_config][4], 6 ) ; break ;
+      case 6 :/* 13.2 */
+        add_triangle( tiling13_2[_config][5], 6 ) ; break ;
+
+      case 7 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][0], 10, v12 ) ; break ;
+      case 8 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][1], 10, v12 ) ; break ;
+      case 9 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][2], 10, v12 ) ; break ;
+      case 10 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][3], 10, v12 ) ; break ;
+      case 11 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][4], 10, v12 ) ; break ;
+      case 12 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][5], 10, v12 ) ; break ;
+      case 13 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][6], 10, v12 ) ; break ;
+      case 14 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][7], 10, v12 ) ; break ;
+      case 15 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][8], 10, v12 ) ; break ;
+      case 16 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][9], 10, v12 ) ; break ;
+      case 17 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][10], 10, v12 ) ; break ;
+      case 18 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3[_config][11], 10, v12 ) ; break ;
+
+      case 19 :/* 13.4 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_4[_config][0], 12, v12 ) ; break ;
+      case 20 :/* 13.4 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_4[_config][1], 12, v12 ) ; break ;
+      case 21 :/* 13.4 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_4[_config][2], 12, v12 ) ; break ;
+      case 22 :/* 13.4 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_4[_config][3], 12, v12 ) ; break ;
+
+      case 23 :/* 13.5 */
+        _subconfig = 0 ;
+        if( test_interior( test13[_config][6] ) )
+          add_triangle( tiling13_5_1[_config][0], 6 ) ;
+        else
+          add_triangle( tiling13_5_2[_config][0], 10 ) ;
+        break ;
+      case 24 :/* 13.5 */
+        _subconfig = 1 ;
+        if( test_interior( test13[_config][6] ) )
+          add_triangle( tiling13_5_1[_config][1], 6 ) ;
+        else
+          add_triangle( tiling13_5_2[_config][1], 10 ) ;
+        break ;
+      case 25 :/* 13.5 */
+        _subconfig = 2 ;
+        if( test_interior( test13[_config][6] ) )
+          add_triangle( tiling13_5_1[_config][2], 6 ) ;
+        else
+          add_triangle( tiling13_5_2[_config][2], 10 ) ;
+        break ;
+      case 26 :/* 13.5 */
+        _subconfig = 3 ;
+        if( test_interior( test13[_config][6] ) )
+          add_triangle( tiling13_5_1[_config][3], 6 ) ;
+        else
+          add_triangle( tiling13_5_2[_config][3], 10 ) ;
+        break ;
+
+      case 27 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][0], 10, v12 ) ; break ;
+      case 28 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][1], 10, v12 ) ; break ;
+      case 29 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][2], 10, v12 ) ; break ;
+      case 30 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][3], 10, v12 ) ; break ;
+      case 31 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][4], 10, v12 ) ; break ;
+      case 32 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][5], 10, v12 ) ; break ;
+      case 33 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][6], 10, v12 ) ; break ;
+      case 34 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][7], 10, v12 ) ; break ;
+      case 35 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][8], 10, v12 ) ; break ;
+      case 36 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][9], 10, v12 ) ; break ;
+      case 37 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][10], 10, v12 ) ; break ;
+      case 38 :/* 13.3 */
+        v12 = add_c_vertex() ;
+        add_triangle( tiling13_3_[_config][11], 10, v12 ) ; break ;
+
+      case 39 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][0], 6 ) ; break ;
+      case 40 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][1], 6 ) ; break ;
+      case 41 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][2], 6 ) ; break ;
+      case 42 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][3], 6 ) ; break ;
+      case 43 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][4], 6 ) ; break ;
+      case 44 :/* 13.2 */
+        add_triangle( tiling13_2_[_config][5], 6 ) ; break ;
+
+      case 45 :/* 13.1 */
+        add_triangle( tiling13_1_[_config], 4 ) ; break ;
+
+      default :
+        printf("Marching Cubes: Impossible case 13?\n" ) ;  print_cube() ;
+      }
+      break ;
+
+  case 14 :
+    add_triangle( tiling14[_config], 4 ) ;
+    break ;
+  };
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// Adding triangles
+void MarchingCubes::add_triangle( const char* trig, char n, int v12 )
+//-----------------------------------------------------------------------------
+{
+  int    tv[3] ;
+
+  for( int t = 0 ; t < 3*n ; t++ )
+  {
+    switch( trig[t] )
+    {
+    case  0 : tv[ t % 3 ] = get_x_vert( _i , _j , _k ) ; break ;
+    case  1 : tv[ t % 3 ] = get_y_vert(_i+1, _j , _k ) ; break ;
+    case  2 : tv[ t % 3 ] = get_x_vert( _i ,_j+1, _k ) ; break ;
+    case  3 : tv[ t % 3 ] = get_y_vert( _i , _j , _k ) ; break ;
+    case  4 : tv[ t % 3 ] = get_x_vert( _i , _j ,_k+1) ; break ;
+    case  5 : tv[ t % 3 ] = get_y_vert(_i+1, _j ,_k+1) ; break ;
+    case  6 : tv[ t % 3 ] = get_x_vert( _i ,_j+1,_k+1) ; break ;
+    case  7 : tv[ t % 3 ] = get_y_vert( _i , _j ,_k+1) ; break ;
+    case  8 : tv[ t % 3 ] = get_z_vert( _i , _j , _k ) ; break ;
+    case  9 : tv[ t % 3 ] = get_z_vert(_i+1, _j , _k ) ; break ;
+    case 10 : tv[ t % 3 ] = get_z_vert(_i+1,_j+1, _k ) ; break ;
+    case 11 : tv[ t % 3 ] = get_z_vert( _i ,_j+1, _k ) ; break ;
+    case 12 : tv[ t % 3 ] = v12 ; break ;
+    default : break ;
+    }
+
+    if( tv[t%3] == -1 )
+    {
+      printf("Marching Cubes: invalid triangle %d\n", _ntrigs+1) ;
+      print_cube() ;
+    }
+
+    if( t%3 == 2 )
+    {
+      if( _ntrigs >= _Ntrigs )
+      {
+        Triangle *temp = _triangles ;
+        _triangles = new Triangle[ 2*_Ntrigs ] ;
+        memcpy( _triangles, temp, _Ntrigs*sizeof(Triangle) ) ;
+        delete[] temp ;
+        printf("%d allocated triangles\n", _Ntrigs) ;
+        _Ntrigs *= 2 ;
+      }
+
+      Triangle *T = _triangles + _ntrigs++ ;
+      T->v1    = tv[0] ;
+      T->v2    = tv[1] ;
+      T->v3    = tv[2] ;
+    }
+  }
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// Calculating gradient
+
+real MarchingCubes::get_x_grad( const int i, const int j, const int k ) const
+//-----------------------------------------------------------------------------
+{
+  if( i > 0 )
+  {
+    if ( i < _size_x - 1 )
+      return ( get_data( i+1, j, k ) - get_data( i-1, j, k ) ) / 2 ;
+    else
+      return get_data( i, j, k ) - get_data( i-1, j, k ) ;
+  }
+  else
+    return get_data( i+1, j, k ) - get_data( i, j, k ) ;
+}
+//-----------------------------------------------------------------------------
+
+real MarchingCubes::get_y_grad( const int i, const int j, const int k ) const
+//-----------------------------------------------------------------------------
+{
+  if( j > 0 )
+  {
+    if ( j < _size_y - 1 )
+      return ( get_data( i, j+1, k ) - get_data( i, j-1, k ) ) / 2 ;
+    else
+      return get_data( i, j, k ) - get_data( i, j-1, k ) ;
+  }
+  else
+    return get_data( i, j+1, k ) - get_data( i, j, k ) ;
+}
+//-----------------------------------------------------------------------------
+
+real MarchingCubes::get_z_grad( const int i, const int j, const int k ) const
+//-----------------------------------------------------------------------------
+{
+  if( k > 0 )
+  {
+    if ( k < _size_z - 1 )
+      return ( get_data( i, j, k+1 ) - get_data( i, j, k-1 ) ) / 2 ;
+    else
+      return get_data( i, j, k ) - get_data( i, j, k-1 ) ;
+  }
+  else
+    return get_data( i, j, k+1 ) - get_data( i, j, k ) ;
+}
+//_____________________________________________________________________________
+
+
+//_____________________________________________________________________________
+// Adding vertices
+
+void MarchingCubes::test_vertex_addition()
+{
+  if( _nverts >= _Nverts )
+  {
+    Vertex *temp = _vertices ;
+    _vertices = new Vertex[ _Nverts*2 ] ;
+    memcpy( _vertices, temp, _Nverts*sizeof(Vertex) ) ;
+    delete[] temp ;
+    printf("%d allocated vertices\n", _Nverts) ;
+    _Nverts *= 2 ;
+  }
+}
+
+
+int MarchingCubes::add_x_vertex( )
+//-----------------------------------------------------------------------------
+{
+  test_vertex_addition() ;
+  Vertex *vert = _vertices + _nverts++ ;
+
+  real u = ( _cube[0] ) / ( _cube[0] - _cube[1] ) ;
+
+  vert->x      = (real)_i+u;
+  vert->y      = (real) _j ;
+  vert->z      = (real) _k ;
+
+  vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i+1,_j,_k) ;
+  vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i+1,_j,_k) ;
+  vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i+1,_j,_k) ;
+
+  u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ;
+  if( u > 0 )
+  {
+    vert->nx /= u ;
+    vert->ny /= u ;
+    vert->nz /= u ;
+  }
+
+
+  return _nverts-1 ;
+}
+//-----------------------------------------------------------------------------
+
+int MarchingCubes::add_y_vertex( )
+//-----------------------------------------------------------------------------
+{
+  test_vertex_addition() ;
+  Vertex *vert = _vertices + _nverts++ ;
+
+  real u = ( _cube[0] ) / ( _cube[0] - _cube[3] ) ;
+
+  vert->x      = (real) _i ;
+  vert->y      = (real)_j+u;
+  vert->z      = (real) _k ;
+
+  vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i,_j+1,_k) ;
+  vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i,_j+1,_k) ;
+  vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i,_j+1,_k) ;
+
+  u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ;
+  if( u > 0 )
+  {
+    vert->nx /= u ;
+    vert->ny /= u ;
+    vert->nz /= u ;
+  }
+
+  return _nverts-1 ;
+}
+//-----------------------------------------------------------------------------
+
+int MarchingCubes::add_z_vertex( )
+//-----------------------------------------------------------------------------
+{
+  test_vertex_addition() ;
+  Vertex *vert = _vertices + _nverts++ ;
+
+  real u = ( _cube[0] ) / ( _cube[0] - _cube[4] ) ;
+
+  vert->x      = (real) _i ;
+  vert->y      = (real) _j ;
+  vert->z      = (real)_k+u;
+
+  vert->nx = (1-u)*get_x_grad(_i,_j,_k) + u*get_x_grad(_i,_j,_k+1) ;
+  vert->ny = (1-u)*get_y_grad(_i,_j,_k) + u*get_y_grad(_i,_j,_k+1) ;
+  vert->nz = (1-u)*get_z_grad(_i,_j,_k) + u*get_z_grad(_i,_j,_k+1) ;
+
+  u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ;
+  if( u > 0 )
+  {
+    vert->nx /= u ;
+    vert->ny /= u ;
+    vert->nz /= u ;
+  }
+
+  return _nverts-1 ;
+}
+
+
+int MarchingCubes::add_c_vertex( )
+//-----------------------------------------------------------------------------
+{
+  test_vertex_addition() ;
+  Vertex *vert = _vertices + _nverts++ ;
+
+  real u = 0 ;
+  int   vid ;
+
+  vert->x = vert->y = vert->z =  vert->nx = vert->ny = vert->nz = 0 ;
+
+  // Computes the average of the intersection points of the cube
+  vid = get_x_vert( _i , _j , _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_y_vert(_i+1, _j , _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_x_vert( _i ,_j+1, _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_y_vert( _i , _j , _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_x_vert( _i , _j ,_k+1) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_y_vert(_i+1, _j ,_k+1) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_x_vert( _i ,_j+1,_k+1) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_y_vert( _i , _j ,_k+1) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_z_vert( _i , _j , _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_z_vert(_i+1, _j , _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_z_vert(_i+1,_j+1, _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+  vid = get_z_vert( _i ,_j+1, _k ) ;
+  if( vid != -1 ) { ++u ; const Vertex &v = _vertices[vid] ; vert->x += v.x ;  vert->y += v.y ;  vert->z += v.z ;  vert->nx += v.nx ; vert->ny += v.ny ; vert->nz += v.nz ; }
+
+  vert->x  /= u ;
+  vert->y  /= u ;
+  vert->z  /= u ;
+
+  u = (real) sqrt( vert->nx * vert->nx + vert->ny * vert->ny +vert->nz * vert->nz ) ;
+  if( u > 0 )
+  {
+    vert->nx /= u ;
+    vert->ny /= u ;
+    vert->nz /= u ;
+  }
+
+  return _nverts-1 ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+//_____________________________________________________________________________
+
+
+
+
+//_____________________________________________________________________________
+// Grid exportation
+void MarchingCubes::writeISO(const char *fn )
+//-----------------------------------------------------------------------------
+{
+  unsigned char buf[sizeof(float)] ;
+
+  FILE *fp = fopen( fn, "wb" ) ;
+
+  // header
+  * (int*) buf = _size_x ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (int*) buf = _size_y ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (int*) buf = _size_z ;
+  fwrite(buf, sizeof(float), 1, fp);
+
+  * (float*) buf = -1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (float*) buf =  1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (float*) buf = -1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (float*) buf =  1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (float*) buf = -1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+  * (float*) buf =  1.0f ;
+  fwrite(buf, sizeof(float), 1, fp);
+
+  for( int i = 0 ; i < _size_x ; i++ )
+  {
+    for( int j = 0 ; j < _size_y ; j++ )
+    {
+      for( int k = 0 ; k < _size_z ; k++ )
+      {
+        * (float*) buf = (float)get_data( i,j,k ) ;
+        fwrite(buf, sizeof(float), 1, fp);
+      }
+    }
+  }
+
+  fclose(fp) ;
+}
+//_____________________________________________________________________________
+
+
+
+
+
+//_____________________________________________________________________________
+// PLY exportation
+void MarchingCubes::writePLY(const char *fn, bool bin )
+//-----------------------------------------------------------------------------
+{
+
+  typedef struct PlyFace {
+    unsigned char nverts;    /* number of Vertex indices in list */
+    int *verts;              /* Vertex index list */
+  } PlyFace;
+
+
+  PlyProperty vert_props[]  = { /* list of property information for a PlyVertex */
+    {"x", Float32, Float32, offsetof( Vertex,x ), 0, 0, 0, 0},
+    {"y", Float32, Float32, offsetof( Vertex,y ), 0, 0, 0, 0},
+    {"z", Float32, Float32, offsetof( Vertex,z ), 0, 0, 0, 0},
+    {"nx", Float32, Float32, offsetof( Vertex,nx ), 0, 0, 0, 0},
+    {"ny", Float32, Float32, offsetof( Vertex,ny ), 0, 0, 0, 0},
+    {"nz", Float32, Float32, offsetof( Vertex,nz ), 0, 0, 0, 0}
+  };
+
+  PlyProperty face_props[]  = { /* list of property information for a PlyFace */
+    {"vertex_indices", Int32, Int32, offsetof( PlyFace,verts ),
+      1, Uint8, Uint8, offsetof( PlyFace,nverts )},
+  };
+
+
+  PlyFile    *ply;
+  FILE       *fp = fopen( fn, "w" );
+
+  int          i ;
+  PlyFace     face ;
+  int         verts[3] ;
+  char       *elem_names[]  = { "vertex", "face" };
+  printf("Marching Cubes::writePLY(%s)...", fn ) ;
+  ply = write_ply ( fp, 2, elem_names, bin? PLY_BINARY_LE : PLY_ASCII );
+
+  /* describe what properties go into the PlyVertex elements */
+  describe_element_ply ( ply, "vertex", _nverts );
+  describe_property_ply ( ply, &vert_props[0] );
+  describe_property_ply ( ply, &vert_props[1] );
+  describe_property_ply ( ply, &vert_props[2] );
+  describe_property_ply ( ply, &vert_props[3] );
+  describe_property_ply ( ply, &vert_props[4] );
+  describe_property_ply ( ply, &vert_props[5] );
+
+  /* describe PlyFace properties (just list of PlyVertex indices) */
+  describe_element_ply ( ply, "face", _ntrigs );
+  describe_property_ply ( ply, &face_props[0] );
+
+  header_complete_ply ( ply );
+
+  /* set up and write the PlyVertex elements */
+  put_element_setup_ply ( ply, "vertex" );
+  for ( i = 0; i < _nverts; i++ )
+    put_element_ply ( ply, ( void * ) &(_vertices[i]) );
+  printf("   %d vertices written\n", _nverts ) ;
+
+  /* set up and write the PlyFace elements */
+  put_element_setup_ply ( ply, "face" );
+  face.nverts = 3 ;
+  face.verts  = verts ;
+  for ( i = 0; i < _ntrigs; i++ )
+  {
+    face.verts[0] = _triangles[i].v1 ;
+    face.verts[1] = _triangles[i].v2 ;
+    face.verts[2] = _triangles[i].v3 ;
+    put_element_ply ( ply, ( void * ) &face );
+  }
+  printf("   %d triangles written\n", _ntrigs ) ;
+
+  close_ply ( ply );
+  free_ply ( ply );
+  fclose( fp ) ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// PLY importation
+void MarchingCubes::readPLY(const char *fn )
+//-----------------------------------------------------------------------------
+{
+  typedef struct PlyFace {
+    unsigned char nverts;    /* number of Vertex indices in list */
+    int *verts;              /* Vertex index list */
+  } PlyFace;
+
+
+  PlyProperty vert_props[]  = { /* list of property information for a PlyVertex */
+    {"x", Float32, Float32, offsetof( Vertex,x ), 0, 0, 0, 0},
+    {"y", Float32, Float32, offsetof( Vertex,y ), 0, 0, 0, 0},
+    {"z", Float32, Float32, offsetof( Vertex,z ), 0, 0, 0, 0},
+    {"nx", Float32, Float32, offsetof( Vertex,nx ), 0, 0, 0, 0},
+    {"ny", Float32, Float32, offsetof( Vertex,ny ), 0, 0, 0, 0},
+    {"nz", Float32, Float32, offsetof( Vertex,nz ), 0, 0, 0, 0}
+  };
+
+  PlyProperty face_props[]  = { /* list of property information for a PlyFace */
+    {"vertex_indices", Int32, Int32, offsetof( PlyFace,verts ),
+      1, Uint8, Uint8, offsetof( PlyFace,nverts )},
+  };
+
+
+  FILE    *fp  = fopen( fn, "r" );
+  if( !fp ) return ;
+  PlyFile *ply = read_ply ( fp );
+  printf("Marching Cubes::readPLY(%s)...", fn ) ;
+
+  //-----------------------------------------------------------------------------
+
+  // gets the number of faces and vertices
+  for ( int i = 0; i < ply->num_elem_types; ++i )
+  {
+    int elem_count ;
+    char *elem_name = setup_element_read_ply ( ply, i, &elem_count );
+    if ( equal_strings ( "vertex", elem_name ) )
+      _Nverts = _nverts = elem_count;
+    if ( equal_strings ( "face",   elem_name ) )
+      _Ntrigs = _ntrigs = elem_count;
+  }
+  delete [] _vertices ;
+  _vertices  = new Vertex  [_Nverts] ;
+  delete [] _triangles ;
+  _triangles = new Triangle[_Ntrigs] ;
+
+  //-----------------------------------------------------------------------------
+
+  /* examine each element type that is in the file (PlyVertex, PlyFace) */
+
+  for ( int i = 0; i < ply->num_elem_types; ++i )
+  {
+    /* prepare to read the i'th list of elements */
+    int elem_count ;
+    char *elem_name = setup_element_read_ply ( ply, i, &elem_count );
+
+    //-----------------------------------------------------------------------------
+    if ( equal_strings ( "vertex", elem_name ) )
+    {
+      /* set up for getting PlyVertex elements */
+      setup_property_ply ( ply, &vert_props[0] );
+      setup_property_ply ( ply, &vert_props[1] );
+      setup_property_ply ( ply, &vert_props[2] );
+      setup_property_ply ( ply, &vert_props[3] );
+      setup_property_ply ( ply, &vert_props[4] );
+      setup_property_ply ( ply, &vert_props[5] );
+
+      for ( int j = 0; j < _nverts; ++j )
+      {
+        get_element_ply ( ply, ( void * ) (_vertices + j) );
+      }
+      printf("   %d vertices read\n", _nverts ) ;
+    }
+
+    //-----------------------------------------------------------------------------
+    else if ( equal_strings ( "face", elem_name ) )
+    {
+      /* set up for getting PlyFace elements */
+      /* (all we need are PlyVertex indices) */
+
+      setup_property_ply ( ply, &face_props[0] ) ;
+      PlyFace     face ;
+      for ( int j = 0; j < _ntrigs; ++j )
+      {
+        get_element_ply ( ply, ( void * ) &face );
+        if( face.nverts != 3 )
+        {
+          printf( "not a triangulated surface: polygon %d has %d sides\n", j, face.nverts ) ;
+          return ;
+        }
+
+        _triangles[j].v1 = face.verts[0] ;
+        _triangles[j].v2 = face.verts[1] ;
+        _triangles[j].v3 = face.verts[2] ;
+
+        free( face.verts ) ;
+      }
+      printf("   %d triangles read\n", _ntrigs ) ;
+    }
+    //-----------------------------------------------------------------------------
+
+    //-----------------------------------------------------------------------------
+    else  /* all non-PlyVertex and non-PlyFace elements are grabbed here */
+      get_other_element_ply ( ply );
+    //-----------------------------------------------------------------------------
+  }
+
+  close_ply ( ply );
+  free_ply  ( ply );
+
+//  fit_to_bbox() ;
+  fclose( fp ) ;
+}
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+// Open Inventor / VRML 1.0 ascii exportation
+void MarchingCubes::writeIV(const char *fn )
+//-----------------------------------------------------------------------------
+{
+  FILE *fp = fopen( fn, "w" ) ;
+  int   i ;
+
+  printf("Marching Cubes::exportIV(%s)...", fn) ;
+
+  fprintf( fp, "#Inventor V2.1 ascii \n\nSeparator { \n    ShapeHints {\n        vertexOrdering  COUNTERCLOCKWISE\n        shapeType       UNKNOWN_SHAPE_TYPE\n        creaseAngle     0.0\n    }\n Coordinate3 { \n point [  \n" ) ;
+  for ( i = 0; i < _nverts; i++ )
+    fprintf( fp, " %f %f %f,\n", _vertices[i].x, _vertices[i].y, _vertices[i].z ) ;
+  printf("   %d vertices written\n", _nverts ) ;
+
+  fprintf( fp, "\n ] \n} \nNormal { \nvector [ \n" ) ;
+  for ( i = 0; i < _nverts; i++ )
+    fprintf( fp, " %f %f %f,\n", _vertices[i].nx, _vertices[i].ny, _vertices[i].nz ) ;
+
+  fprintf( fp, "\n ] \n} \nIndexedFaceSet { \ncoordIndex [ \n" ) ;
+  for ( i = 0; i < _ntrigs; i++ )
+    fprintf( fp, "%d, %d, %d, -1,\n", _triangles[i].v1, _triangles[i].v2, _triangles[i].v3 ) ;
+
+  fprintf( fp, " ] \n } \n } \n" ) ;
+  fclose( fp ) ;
+  printf("   %d triangles written\n", _ntrigs ) ;
+}
+//_____________________________________________________________________________
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h
new file mode 100755
index 0000000000000000000000000000000000000000..c589bffb7f52d6574763fcdc8947f5539e0871a7
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/MarchingCubes.h
@@ -0,0 +1,343 @@
+/**
+ * @file    MarchingCubes.h
+ * @author  Thomas Lewiner <thomas.lewiner@polytechnique.org>
+ * @author  Math Dept, PUC-Rio
+ * @version 0.2
+ * @date    12/08/2002
+ *
+ * @brief   MarchingCubes Algorithm
+ */
+//________________________________________________
+
+
+#ifndef _MARCHINGCUBES_H_
+#define _MARCHINGCUBES_H_
+
+#if !defined(WIN32) || defined(__CYGWIN__)
+#pragma interface
+#endif // WIN32
+
+
+//_____________________________________________________________________________
+// types
+/** unsigned char alias */
+typedef unsigned char uchar ;
+/** signed char alias */
+typedef   signed char schar ;
+/** isovalue alias */
+typedef        float real  ;
+
+//-----------------------------------------------------------------------------
+// Vertex structure
+/** \struct Vertex "MarchingCubes.h" MarchingCubes
+ * Position and normal of a vertex
+ * \brief vertex structure
+ * \param x X coordinate
+ * \param y Y coordinate
+ * \param z Z coordinate
+ * \param nx X component of the normal
+ * \param ny Y component of the normal
+ * \param nz Z component of the normal
+ */
+typedef struct
+{
+  real  x,  y,  z ;  /**< Vertex coordinates */
+  real nx, ny, nz ;  /**< Vertex normal */
+} Vertex ;
+
+//-----------------------------------------------------------------------------
+// Triangle structure
+/** \struct Triangle "MarchingCubes.h" MarchingCubes
+ * Indices of the oriented triange vertices
+ * \brief triangle structure
+ * \param v1 First vertex index
+ * \param v2 Second vertex index
+ * \param v3 Third vertex index
+ */
+typedef struct
+{
+  int v1,v2,v3 ;  /**< Triangle vertices */
+} Triangle ;
+//_____________________________________________________________________________
+
+
+
+//_____________________________________________________________________________
+/** Marching Cubes algorithm wrapper */
+/** \class MarchingCubes
+  * \brief Marching Cubes algorithm.
+  */
+class MarchingCubes
+//-----------------------------------------------------------------------------
+{
+// Constructors
+public :
+  /**
+   * Main and default constructor
+   * \brief constructor
+   * \param size_x width  of the grid
+   * \param size_y depth  of the grid
+   * \param size_z height of the grid
+   */
+  MarchingCubes ( const int size_x = -1, const int size_y = -1, const int size_z = -1 ) ;
+  /** Destructor */
+  ~MarchingCubes() ;
+
+//-----------------------------------------------------------------------------
+// Accessors
+public :
+  /** accesses the number of vertices of the generated mesh */
+  inline const int nverts() const { return _nverts ; }
+  /** accesses the number of triangles of the generated mesh */
+  inline const int ntrigs() const { return _ntrigs ; }
+  /** accesses a specific vertex of the generated mesh */
+  inline Vertex   * vert( const int i ) const { if( i < 0  || i >= _nverts ) return ( Vertex *)NULL ; return _vertices  + i ; }
+  /** accesses a specific triangle of the generated mesh */
+  inline Triangle * trig( const int i ) const { if( i < 0  || i >= _ntrigs ) return (Triangle*)NULL ; return _triangles + i ; }
+
+  /** accesses the vertex buffer of the generated mesh */
+  inline Vertex   *vertices () { return _vertices  ; }
+  /** accesses the triangle buffer of the generated mesh */
+  inline Triangle *triangles() { return _triangles ; }
+
+  /**  accesses the width  of the grid */
+  inline const int size_x() const { return _size_x ; }
+  /**  accesses the depth  of the grid */
+  inline const int size_y() const { return _size_y ; }
+  /**  accesses the height of the grid */
+  inline const int size_z() const { return _size_z ; }
+
+  /**
+   * changes the size of the grid
+   * \param size_x width  of the grid
+   * \param size_y depth  of the grid
+   * \param size_z height of the grid
+   */
+  inline void set_resolution( const int size_x, const int size_y, const int size_z ) { _size_x = size_x ;  _size_y = size_y ;  _size_z = size_z ; }
+  /**
+   * selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes
+   * \param originalMC true for the original Marching Cubes
+   */
+  inline void set_method    ( const bool originalMC = false ) { _originalMC = originalMC ; }
+  /**
+   * selects to use data from another class
+   * \param data is the pointer to the external data, allocated as a size_x*size_y*size_z vector running in x first
+   */
+  inline void set_ext_data  ( real *data )
+  { if( !_ext_data ) delete [] _data ;  _ext_data = data != NULL ;  if( _ext_data ) _data = data ; }
+  /**
+   * selects to allocate data
+   */
+  inline void set_int_data  () { _ext_data = false ;  _data = NULL ; }
+
+  // Data access
+  /**
+   * accesses a specific cube of the grid
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline const real get_data  ( const int i, const int j, const int k ) const { return _data[ i + j*_size_x + k*_size_x*_size_y] ; }
+  /**
+   * sets a specific cube of the grid
+   * \param val new value for the cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline void  set_data  ( const real val, const int i, const int j, const int k ) { _data[ i + j*_size_x + k*_size_x*_size_y] = val ; }
+
+  // Data initialization
+  /** inits temporary structures (must set sizes before call) : the grid and the vertex index per cube */
+  void init_temps () ;
+  /** inits all structures (must set sizes before call) : the temporary structures and the mesh buffers */
+  void init_all   () ;
+  /** clears temporary structures : the grid and the main */
+  void clean_temps() ;
+  /** clears all structures : the temporary structures and the mesh buffers */
+  void clean_all  () ;
+
+
+//-----------------------------------------------------------------------------
+// Exportation
+public :
+  /**
+   * PLY exportation of the generated mesh
+   * \param fn  name of the PLY file to create
+   * \param bin if true, the PLY will be written in binary mode
+   */
+  void writePLY( const char *fn, bool bin = false ) ;
+
+  /**
+   * PLY importation of a mesh
+   * \param fn  name of the PLY file to read from
+   */
+  void readPLY( const char *fn ) ;
+
+  /**
+   * VRML / Open Inventor exportation of the generated mesh
+   * \param fn  name of the IV file to create
+   */
+  void writeIV ( const char *fn ) ;
+
+  /**
+   * ISO exportation of the input grid
+   * \param fn  name of the ISO file to create
+   */
+  void writeISO( const char *fn ) ;
+
+
+//-----------------------------------------------------------------------------
+// Algorithm
+public :
+  /**
+   * Main algorithm : must be called after init_all
+   * \param iso isovalue
+   */
+  void run( real iso = (real)0.0 ) ;
+
+protected :
+  /** tesselates one cube */
+  void process_cube ()             ;
+  /** tests if the components of the tesselation of the cube should be connected by the interior of an ambiguous face */
+  bool test_face    ( schar face ) ;
+  /** tests if the components of the tesselation of the cube should be connected through the interior of the cube */
+  bool test_interior( schar s )    ;
+
+
+//-----------------------------------------------------------------------------
+// Operations
+protected :
+  /**
+   * computes almost all the vertices of the mesh by interpolation along the cubes edges
+   * \param iso isovalue
+   */
+  void compute_intersection_points( real iso ) ;
+
+  /**
+   * routine to add a triangle to the mesh
+   * \param trig the code for the triangle as a sequence of edges index
+   * \param n    the number of triangles to produce
+   * \param v12  the index of the interior vertex to use, if necessary
+   */
+  void add_triangle ( const char* trig, char n, int v12 = -1 ) ;
+
+  /** tests and eventually doubles the vertex buffer capacity for a new vertex insertion */
+  void test_vertex_addition() ;
+  /** adds a vertex on the current horizontal edge */
+  int add_x_vertex() ;
+  /** adds a vertex on the current longitudinal edge */
+  int add_y_vertex() ;
+  /** adds a vertex on the current vertical edge */
+  int add_z_vertex() ;
+  /** adds a vertex inside the current cube */
+  int add_c_vertex() ;
+
+  /**
+   * interpolates the horizontal gradient of the implicit function at the lower vertex of the specified cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  real get_x_grad( const int i, const int j, const int k ) const ;
+  /**
+   * interpolates the longitudinal gradient of the implicit function at the lower vertex of the specified cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  real get_y_grad( const int i, const int j, const int k ) const ;
+  /**
+   * interpolates the vertical gradient of the implicit function at the lower vertex of the specified cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  real get_z_grad( const int i, const int j, const int k ) const ;
+
+  /**
+   * accesses the pre-computed vertex index on the lower horizontal edge of a specific cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline int   get_x_vert( const int i, const int j, const int k ) const { return _x_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
+  /**
+   * accesses the pre-computed vertex index on the lower longitudinal edge of a specific cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline int   get_y_vert( const int i, const int j, const int k ) const { return _y_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
+  /**
+   * accesses the pre-computed vertex index on the lower vertical edge of a specific cube
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline int   get_z_vert( const int i, const int j, const int k ) const { return _z_verts[ i + j*_size_x + k*_size_x*_size_y] ; }
+
+  /**
+   * sets the pre-computed vertex index on the lower horizontal edge of a specific cube
+   * \param val the index of the new vertex
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline void  set_x_vert( const int val, const int i, const int j, const int k ) { _x_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
+  /**
+   * sets the pre-computed vertex index on the lower longitudinal edge of a specific cube
+   * \param val the index of the new vertex
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline void  set_y_vert( const int val, const int i, const int j, const int k ) { _y_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
+  /**
+   * sets the pre-computed vertex index on the lower vertical edge of a specific cube
+   * \param val the index of the new vertex
+   * \param i abscisse of the cube
+   * \param j ordinate of the cube
+   * \param k height of the cube
+   */
+  inline void  set_z_vert( const int val, const int i, const int j, const int k ) { _z_verts[ i + j*_size_x + k*_size_x*_size_y] = val ; }
+
+  /** prints cube for debug */
+  void print_cube() ;
+
+//-----------------------------------------------------------------------------
+// Elements
+protected :
+  bool      _originalMC ;   /**< selects wether the algorithm will use the enhanced topologically controlled lookup table or the original MarchingCubes */
+  bool      _ext_data   ;   /**< selects wether to allocate data or use data from another class */
+
+  int       _size_x     ;  /**< width  of the grid */
+  int       _size_y     ;  /**< depth  of the grid */
+  int       _size_z     ;  /**< height of the grid */
+  real     *_data       ;  /**< implicit function values sampled on the grid */
+
+  int      *_x_verts    ;  /**< pre-computed vertex indices on the lower horizontal   edge of each cube */
+  int      *_y_verts    ;  /**< pre-computed vertex indices on the lower longitudinal edge of each cube */
+  int      *_z_verts    ;  /**< pre-computed vertex indices on the lower vertical     edge of each cube */
+
+  int       _nverts     ;  /**< number of allocated vertices  in the vertex   buffer */
+  int       _ntrigs     ;  /**< number of allocated triangles in the triangle buffer */
+  int       _Nverts     ;  /**< size of the vertex   buffer */
+  int       _Ntrigs     ;  /**< size of the triangle buffer */
+  Vertex   *_vertices   ;  /**< vertex   buffer */
+  Triangle *_triangles  ;  /**< triangle buffer */
+
+  int       _i          ;  /**< abscisse of the active cube */
+  int       _j          ;  /**< height of the active cube */
+  int       _k          ;  /**< ordinate of the active cube */
+
+  real      _cube[8]    ;  /**< values of the implicit function on the active cube */
+  uchar     _lut_entry  ;  /**< cube sign representation in [0..255] */
+  uchar     _case       ;  /**< case of the active cube in [0..15] */
+  uchar     _config     ;  /**< configuration of the active cube */
+  uchar     _subconfig  ;  /**< subconfiguration of the active cube */
+};
+//_____________________________________________________________________________
+
+
+#endif // _MARCHINGCUBES_H_
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c
new file mode 100755
index 0000000000000000000000000000000000000000..06c60f4dbb863fa79c88ac5336c3498adfecb99b
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.c
@@ -0,0 +1,3325 @@
+/*
+
+The interface routines for reading and writing PLY polygon files.
+
+Greg Turk
+
+---------------------------------------------------------------
+
+A PLY file contains a single polygonal _object_.
+
+An object is composed of lists of _elements_.  Typical elements are
+vertices, faces, edges and materials.
+
+Each type of element for a given object has one or more _properties_
+associated with the element type.  For instance, a vertex element may
+have as properties the floating-point values x,y,z and the three unsigned
+chars representing red, green and blue.
+
+-----------------------------------------------------------------------
+
+Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose is hereby granted without fee, provided
+that the above copyright notice and this permission notice appear in
+all copies of this software and that you do not sell the software.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "ply.h"
+
+char *type_names[]      = {  /* names of scalar types */
+"invalid",
+"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
+};
+
+char *old_type_names[]  = {  /* old names of types for backward compatability */
+"invalid",
+"char", "short", "int", "uchar", "ushort", "uint", "float", "double",
+};
+
+int   ply_type_size[]   = {
+0, 1, 2, 4, 1, 2, 4, 4, 8
+};
+
+#define NO_OTHER_PROPS  -1
+
+#define DONT_STORE_PROP  0
+#define STORE_PROP       1
+
+#define OTHER_PROP       0
+#define NAMED_PROP       1
+
+/* returns 1 if strings are equal, 0 if not */
+int           equal_strings( char * , char * );
+
+/* find an element in a plyfile's list */
+PlyElement   *find_element( PlyFile * , char * );
+
+/* find a property in an element's list */
+PlyProperty  *find_property( PlyElement * , char * , int * );
+
+/* write to a file the word describing a PLY file data type */
+void          write_scalar_type( FILE * , int );
+
+/* read a line from a file and break it up into separate words */
+char*        *get_words( FILE * , int * , char ** );
+
+/* write an item to a file */
+void          write_binary_item( FILE * , int, unsigned int, double, int );
+void          write_ascii_item( FILE * , int, unsigned int, double, int );
+
+/* add information to a PLY file descriptor */
+void          add_element( PlyFile * , char ** , int );
+void          add_property( PlyFile * , char ** , int );
+void          add_comment( PlyFile * , char * );
+void          add_obj_info( PlyFile * , char * );
+
+/* copy a property */
+void          copy_property( PlyProperty * , PlyProperty * );
+
+/* store a value into where a pointer and a type specify */
+void          store_item( char * , int, int, unsigned int, double );
+
+/* return the value of a stored item */
+void          get_stored_item( void * , int, int * , unsigned int * , double * );
+
+/* return the value stored in an item, given ptr to it and its type */
+double        get_item_value( char * , int );
+
+/* get binary or ascii item and store it according to ptr and type */
+void          get_ascii_item( char * , int, int * , unsigned int * , double * );
+void          get_binary_item( FILE * , int, int * , unsigned int * , double * );
+
+/* get a bunch of elements from a file */
+void          ascii_get_element( PlyFile * , char * );
+void          binary_get_element( PlyFile * , char * );
+
+/* memory allocation */
+static char  *my_alloc( int, int, char * );
+
+
+/*************/
+/*  Writing  */
+/*************/
+
+
+/******************************************************************************
+Given a file pointer, get ready to write PLY data to the file.
+
+Entry:
+fp         - the given file pointer
+nelems     - number of elements in object
+elem_names - list of element names
+file_type  - file type, either ascii or binary
+
+Exit:
+returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *ply_write( FILE *fp, int nelems, char **elem_names, int file_type )
+{
+  int         i;
+  PlyFile    *plyfile;
+  PlyElement *elem;
+
+  /* check for NULL file pointer */
+  if ( fp == NULL )
+    return ( NULL );
+
+  /* create a record for this object */
+
+  plyfile = ( PlyFile *  ) myalloc ( sizeof ( PlyFile ) );
+  plyfile->file_type = file_type;
+  plyfile->num_comments = 0;
+  plyfile->num_obj_info = 0;
+  plyfile->num_elem_types = nelems;
+  plyfile->version = 1.0;
+  plyfile->fp = fp;
+  plyfile->other_elems = NULL;
+
+  /* tuck aside the names of the elements */
+
+  plyfile->elems = ( PlyElement *  *  ) myalloc ( sizeof ( PlyElement *  ) * nelems );
+  for ( i = 0; i < nelems; i++ )
+  {
+    elem = ( PlyElement *  ) myalloc ( sizeof ( PlyElement ) );
+    plyfile->elems[i] = elem;
+    elem->name = strdup ( elem_names[i] );
+    elem->num = 0;
+    elem->nprops = 0;
+  }
+
+  /* return pointer to the file descriptor */
+  return ( plyfile );
+}
+
+
+/******************************************************************************
+Open a polygon file for writing.
+
+Entry:
+filename   - name of file to read from
+nelems     - number of elements in object
+elem_names - list of element names
+file_type  - file type, either ascii or binary
+
+Exit:
+returns a file identifier, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *open_for_writing_ply( char *filename, int nelems, char **elem_names, int file_type )
+{
+  PlyFile  *plyfile;
+  char     *name;
+  FILE     *fp;
+
+  /* tack on the extension .ply, if necessary */
+
+  name = ( char * ) myalloc ( sizeof ( char ) * ( strlen ( filename ) + 5 ) );
+  strcpy ( name, filename );
+  if ( strlen ( name ) < 4 || strcmp ( name + strlen ( name ) - 4, ".ply" ) != 0 )
+    strcat ( name, ".ply" );
+
+  /* open the file for writing */
+
+  fp = fopen ( name, "w" );
+  if ( fp == NULL )
+  {
+    return ( NULL );
+  }
+
+  /* create the actual PlyFile structure */
+
+  plyfile = ply_write ( fp, nelems, elem_names, file_type );
+  if ( plyfile == NULL )
+    return ( NULL );
+
+  /* return pointer to the file descriptor */
+  return ( plyfile );
+}
+
+
+/******************************************************************************
+Describe an element, including its properties and how many will be written
+to the file.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element that information is being specified about
+nelems    - number of elements of this type to be written
+nprops    - number of properties contained in the element
+prop_list - list of properties
+******************************************************************************/
+
+void element_layout_ply( PlyFile *plyfile, char *elem_name, int nelems, int nprops, PlyProperty *prop_list )
+{
+  int           i;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+
+  /* look for appropriate element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr,"element_layout_ply: can't find element '%s'\n",elem_name );
+    exit ( -1 );
+  }
+
+  elem->num = nelems;
+
+  /* copy the list of properties */
+
+  elem->nprops = nprops;
+  elem->props = ( PlyProperty *  *  ) myalloc ( sizeof ( PlyProperty *  ) * nprops );
+  elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * nprops );
+
+  for ( i = 0; i < nprops; i++ )
+  {
+    prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+    elem->props[i] = prop;
+    elem->store_prop[i] = NAMED_PROP;
+    copy_property ( prop, &prop_list[i] );
+  }
+}
+
+
+/******************************************************************************
+Describe a property of an element.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element that information is being specified about
+prop      - the new property
+******************************************************************************/
+
+void ply_describe_property( PlyFile *plyfile, char *elem_name, PlyProperty *prop )
+{
+  PlyElement   *elem;
+  PlyProperty  *elem_prop;
+
+  /* look for appropriate element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr, "ply_describe_property: can't find element '%s'\n",
+    elem_name );
+    return;
+  }
+
+  /* create room for new property */
+
+  if ( elem->nprops == 0 )
+  {
+    elem->props = ( PlyProperty *  *  ) myalloc ( sizeof ( PlyProperty *  ) );
+    elem->store_prop = ( char * ) myalloc ( sizeof ( char ) );
+    elem->nprops = 1;
+  }
+  else
+  {
+    elem->nprops++;
+    elem->props = ( PlyProperty *  *  )
+    realloc ( elem->props, sizeof ( PlyProperty *  ) * elem->nprops );
+    elem->store_prop = ( char * )
+    realloc ( elem->store_prop, sizeof ( char ) * elem->nprops );
+  }
+
+  /* copy the new property */
+
+  elem_prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+  elem->props[elem->nprops - 1] = elem_prop;
+  elem->store_prop[elem->nprops - 1] = NAMED_PROP;
+  copy_property ( elem_prop, prop );
+}
+
+
+/******************************************************************************
+State how many of a given element will be written.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element that information is being specified about
+nelems    - number of elements of this type to be written
+******************************************************************************/
+
+void element_count_ply( PlyFile *plyfile, char *elem_name, int nelems )
+{
+  PlyElement *elem;
+
+  /* look for appropriate element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr,"element_count_ply: can't find element '%s'\n",elem_name );
+    exit ( -1 );
+  }
+
+  elem->num = nelems;
+}
+
+
+/******************************************************************************
+Signal that we've described everything a PLY file's header and that the
+header should be written to the file.
+
+Entry:
+plyfile - file identifier
+******************************************************************************/
+
+void header_complete_ply( PlyFile *plyfile )
+{
+  int           i,j;
+  FILE         *fp  = plyfile->fp;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+
+  fprintf ( fp, "ply\n" );
+
+  switch ( plyfile->file_type )
+  {
+    case PLY_ASCII:
+      fprintf ( fp, "format ascii 1.0\n" );
+      break;
+    case PLY_BINARY_BE:
+      fprintf ( fp, "format binary_big_endian 1.0\n" );
+      break;
+    case PLY_BINARY_LE:
+      fprintf ( fp, "format binary_little_endian 1.0\n" );
+      break;
+    default:
+      fprintf ( stderr, "ply_header_complete: bad file type = %d\n",
+      plyfile->file_type );
+      exit ( -1 );
+  }
+
+  /* write out the comments */
+
+  for ( i = 0; i < plyfile->num_comments; i++ )
+    fprintf ( fp, "comment %s\n", plyfile->comments[i] );
+
+  /* write out object information */
+
+  for ( i = 0; i < plyfile->num_obj_info; i++ )
+    fprintf ( fp, "obj_info %s\n", plyfile->obj_info[i] );
+
+  /* write out information about each element */
+
+  for ( i = 0; i < plyfile->num_elem_types; i++ )
+  {
+    elem = plyfile->elems[i];
+    fprintf ( fp, "element %s %d\n", elem->name, elem->num );
+
+    /* write out each property */
+    for ( j = 0; j < elem->nprops; j++ )
+    {
+      prop = elem->props[j];
+      if ( prop->is_list == PLY_LIST )
+      {
+        fprintf ( fp, "property list " );
+        write_scalar_type ( fp, prop->count_external );
+        fprintf ( fp, " " );
+        write_scalar_type ( fp, prop->external_type );
+        fprintf ( fp, " %s\n", prop->name );
+      }
+      else if ( prop->is_list == PLY_STRING )
+      {
+        fprintf ( fp, "property string" );
+        fprintf ( fp, " %s\n", prop->name );
+      }
+      else
+      {
+        fprintf ( fp, "property " );
+        write_scalar_type ( fp, prop->external_type );
+        fprintf ( fp, " %s\n", prop->name );
+      }
+    }
+  }
+
+  fprintf ( fp, "end_header\n" );
+}
+
+
+/******************************************************************************
+Specify which elements are going to be written.  This should be called
+before a call to the routine ply_put_element().
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element we're talking about
+******************************************************************************/
+
+void put_element_setup_ply( PlyFile *plyfile, char *elem_name )
+{
+  PlyElement *elem;
+
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name );
+    exit ( -1 );
+  }
+
+  plyfile->which_elem = elem;
+}
+
+
+/******************************************************************************
+Write an element to the file.  This routine assumes that we're
+writing the type of element specified in the last call to the routine
+put_element_setup_ply().
+
+Entry:
+plyfile  - file identifier
+elem_ptr - pointer to the element
+******************************************************************************/
+
+void put_element_ply( PlyFile *plyfile, void *elem_ptr )
+{
+  int           j,k;
+  FILE         *fp  = plyfile->fp;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+  char         *item;
+  char         *elem_data;
+  char*        *item_ptr;
+  int           list_count;
+  int           item_size;
+  int           int_val;
+  unsigned int uint_val;
+  double  double_val;
+  char*  *other_ptr;
+
+  elem = plyfile->which_elem;
+  elem_data = ( char * ) elem_ptr;
+  other_ptr = ( char * *  ) ( ( ( char * ) elem_ptr ) + elem->other_offset );
+
+  /* write out either to an ascii or binary file */
+
+  if ( plyfile->file_type == PLY_ASCII )
+  {
+    /* write an ascii file */
+
+    /* write out each property of the element */
+    for ( j = 0; j < elem->nprops; j++ )
+    {
+      prop = elem->props[j];
+
+      if ( elem->store_prop[j] == OTHER_PROP )
+        elem_data = *other_ptr;
+      else
+        elem_data = ( char * ) elem_ptr;
+
+      if ( prop->is_list == PLY_LIST )
+      {
+        /* list */
+        item = elem_data + prop->count_offset;
+        get_stored_item ( ( void * ) item, prop->count_internal,
+        &int_val, &uint_val, &double_val );
+        write_ascii_item ( fp, int_val, uint_val, double_val,
+        prop->count_external );
+        list_count = uint_val;
+        item_ptr = ( char * *  ) ( elem_data + prop->offset );
+        item = item_ptr[0];
+        item_size = ply_type_size[prop->internal_type];
+        for ( k = 0; k < list_count; k++ )
+        {
+          get_stored_item ( ( void * ) item, prop->internal_type,
+          &int_val, &uint_val, &double_val );
+          write_ascii_item ( fp, int_val, uint_val, double_val,
+          prop->external_type );
+          item += item_size;
+        }
+      }
+      else if ( prop->is_list == PLY_STRING )
+      {
+        /* string */
+        char*  *str;
+        item = elem_data + prop->offset;
+        str = ( char * *  ) item;
+        fprintf ( fp, "\"%s\"", *str );
+      }
+      else
+      {
+        /* scalar */
+        item = elem_data + prop->offset;
+        get_stored_item ( ( void * ) item, prop->internal_type,
+        &int_val, &uint_val, &double_val );
+        write_ascii_item ( fp, int_val, uint_val, double_val,
+        prop->external_type );
+      }
+    }
+
+    fprintf ( fp, "\n" );
+  }
+  else
+  {
+    /* write a binary file */
+
+    /* write out each property of the element */
+    for ( j = 0; j < elem->nprops; j++ )
+    {
+      prop = elem->props[j];
+      if ( elem->store_prop[j] == OTHER_PROP )
+        elem_data = *other_ptr;
+      else
+        elem_data = ( char * ) elem_ptr;
+      if ( prop->is_list == PLY_LIST )
+      {
+        /* list */
+        item = elem_data + prop->count_offset;
+        item_size = ply_type_size[prop->count_internal];
+        get_stored_item ( ( void * ) item, prop->count_internal,
+        &int_val, &uint_val, &double_val );
+        write_binary_item ( fp, int_val, uint_val, double_val,
+        prop->count_external );
+        list_count = uint_val;
+        item_ptr = ( char * *  ) ( elem_data + prop->offset );
+        item = item_ptr[0];
+        item_size = ply_type_size[prop->internal_type];
+        for ( k = 0; k < list_count; k++ )
+        {
+          get_stored_item ( ( void * ) item, prop->internal_type,
+          &int_val, &uint_val, &double_val );
+          write_binary_item ( fp, int_val, uint_val, double_val,
+          prop->external_type );
+          item += item_size;
+        }
+      }
+      else if ( prop->is_list == PLY_STRING )
+      {
+        /* string */
+        int     len;
+        char*  *str;
+        item = elem_data + prop->offset;
+        str = ( char * *  ) item;
+
+        /* write the length */
+        len = strlen( *str ) + 1;
+        fwrite ( &len, sizeof( int ), 1, fp );
+
+        /* write the string, including the null character */
+        fwrite ( *str, len, 1, fp );
+      }
+      else
+      {
+        /* scalar */
+        item = elem_data + prop->offset;
+        item_size = ply_type_size[prop->internal_type];
+        get_stored_item ( ( void * ) item, prop->internal_type,
+        &int_val, &uint_val, &double_val );
+        write_binary_item ( fp, int_val, uint_val, double_val,
+        prop->external_type );
+      }
+    }
+  }
+}
+
+
+
+
+
+
+/*************/
+/*  Reading  */
+/*************/
+
+
+
+/******************************************************************************
+Given a file pointer, get ready to read PLY data from the file.
+
+Entry:
+fp - the given file pointer
+
+Exit:
+nelems     - number of elements in object
+elem_names - list of element names
+returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *ply_read( FILE *fp, int *nelems, char ***elem_names )
+{
+  int         i,j;
+  PlyFile    *plyfile;
+  int         nwords;
+  char*      *words;
+  int         found_format  = 0;
+  char*      *elist;
+  PlyElement *elem;
+  char       *orig_line;
+
+  /* check for NULL file pointer */
+  if ( fp == NULL )
+    return ( NULL );
+
+  /* create record for this object */
+
+  plyfile = ( PlyFile *  ) myalloc ( sizeof ( PlyFile ) );
+  plyfile->num_elem_types = 0;
+  plyfile->comments = NULL;
+  plyfile->num_comments = 0;
+  plyfile->obj_info = NULL;
+  plyfile->num_obj_info = 0;
+  plyfile->fp = fp;
+  plyfile->other_elems = NULL;
+  plyfile->rule_list = NULL;
+
+  /* read and parse the file's header */
+
+  words = get_words ( plyfile->fp, &nwords, &orig_line );
+  if ( !words || !equal_strings ( words[0], "ply" ) )
+    return ( NULL );
+
+  while ( words )
+  {
+    /* parse words */
+
+    if ( equal_strings ( words[0], "format" ) )
+    {
+      if ( nwords != 3 )
+        return ( NULL );
+      if ( equal_strings ( words[1], "ascii" ) )
+        plyfile->file_type = PLY_ASCII;
+      else if ( equal_strings ( words[1], "binary_big_endian" ) )
+        plyfile->file_type = PLY_BINARY_BE;
+      else if ( equal_strings ( words[1], "binary_little_endian" ) )
+        plyfile->file_type = PLY_BINARY_LE;
+      else
+        return ( NULL );
+      plyfile->version = ( float ) atof ( words[2] );
+      found_format = 1;
+    }
+    else if ( equal_strings ( words[0], "element" ) )
+      add_element ( plyfile, words, nwords );
+    else if ( equal_strings ( words[0], "property" ) )
+      add_property ( plyfile, words, nwords );
+    else if ( equal_strings ( words[0], "comment" ) )
+      add_comment ( plyfile, orig_line );
+    else if ( equal_strings ( words[0], "obj_info" ) )
+      add_obj_info ( plyfile, orig_line );
+    else if ( equal_strings ( words[0], "end_header" ) )
+      break;
+
+    /* free up words space */
+    free ( words );
+
+    words = get_words ( plyfile->fp, &nwords, &orig_line );
+  }
+
+  /* create tags for each property of each element, to be used */
+  /* later to say whether or not to store each property for the user */
+
+  for ( i = 0; i < plyfile->num_elem_types; i++ )
+  {
+    elem = plyfile->elems[i];
+    elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * elem->nprops );
+    for ( j = 0; j < elem->nprops; j++ )
+      elem->store_prop[j] = DONT_STORE_PROP;
+    elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
+  }
+
+  /* set return values about the elements */
+
+  elist = ( char * *  ) myalloc ( sizeof ( char * ) * plyfile->num_elem_types );
+  for ( i = 0; i < plyfile->num_elem_types; i++ )
+    elist[i] = strdup ( plyfile->elems[i]->name );
+
+  *elem_names = elist;
+  *nelems = plyfile->num_elem_types;
+
+  /* return a pointer to the file's information */
+
+  return ( plyfile );
+}
+
+
+/******************************************************************************
+Open a polygon file for reading.
+
+Entry:
+filename - name of file to read from
+
+Exit:
+nelems     - number of elements in object
+elem_names - list of element names
+file_type  - file type, either ascii or binary
+version    - version number of PLY file
+returns a file identifier, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *ply_open_for_reading( char *filename, int *nelems, char ***elem_names, int *file_type, float *version )
+{
+  FILE     *fp;
+  PlyFile  *plyfile;
+  char     *name;
+
+  /* tack on the extension .ply, if necessary */
+
+  name = ( char * ) myalloc ( sizeof ( char ) * ( strlen ( filename ) + 5 ) );
+  strcpy ( name, filename );
+  if ( strlen ( name ) < 4 || strcmp ( name + strlen ( name ) - 4, ".ply" ) != 0 )
+    strcat ( name, ".ply" );
+
+  /* open the file for reading */
+
+  fp = fopen ( name, "r" );
+  if ( fp == NULL )
+    return ( NULL );
+
+  /* create the PlyFile data structure */
+
+  plyfile = ply_read ( fp, nelems, elem_names );
+
+  /* determine the file type and version */
+
+  *file_type = plyfile->file_type;
+  *version = plyfile->version;
+
+  /* return a pointer to the file's information */
+
+  return ( plyfile );
+}
+
+
+/******************************************************************************
+Get information about a particular element.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element to get information about
+
+Exit:
+nelems   - number of elements of this type in the file
+nprops   - number of properties
+returns a list of properties, or NULL if the file doesn't contain that elem
+******************************************************************************/
+
+PlyProperty **get_element_description_ply( PlyFile *plyfile, char *elem_name, int *nelems, int *nprops )
+{
+  int             i;
+  PlyElement     *elem;
+  PlyProperty    *prop;
+  PlyProperty*   *prop_list;
+
+  /* find information about the element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+    return ( NULL );
+
+  *nelems = elem->num;
+  *nprops = elem->nprops;
+
+  /* make a copy of the element's property list */
+  prop_list = ( PlyProperty *  *  ) myalloc ( sizeof ( PlyProperty *  ) * elem->nprops );
+  for ( i = 0; i < elem->nprops; i++ )
+  {
+    prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+    copy_property ( prop, elem->props[i] );
+    prop_list[i] = prop;
+  }
+
+  /* return this duplicate property list */
+  return ( prop_list );
+}
+
+
+/******************************************************************************
+Specify which properties of an element are to be returned.  This should be
+called before a call to the routine get_element_ply().
+
+Entry:
+plyfile   - file identifier
+elem_name - which element we're talking about
+nprops    - number of properties
+prop_list - list of properties
+******************************************************************************/
+
+void get_element_setup_ply( PlyFile *plyfile, char *elem_name, int nprops, PlyProperty *prop_list )
+{
+  int           i;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+  int           index;
+
+  /* find information about the element */
+  elem = find_element ( plyfile, elem_name );
+  plyfile->which_elem = elem;
+
+  /* deposit the property information into the element's description */
+  for ( i = 0; i < nprops; i++ )
+  {
+    /* look for actual property */
+    prop = find_property ( elem, prop_list[i].name, &index );
+    if ( prop == NULL )
+    {
+      fprintf ( stderr, "Warning:  Can't find property '%s' in element '%s'\n",
+      prop_list[i].name, elem_name );
+      continue;
+    }
+
+    /* store its description */
+    prop->internal_type = prop_list[i].internal_type;
+    prop->offset = prop_list[i].offset;
+    prop->count_internal = prop_list[i].count_internal;
+    prop->count_offset = prop_list[i].count_offset;
+
+    /* specify that the user wants this property */
+    elem->store_prop[index] = STORE_PROP;
+  }
+}
+
+
+/******************************************************************************
+Specify a property of an element that is to be returned.  This should be
+called (usually multiple times) before a call to the routine ply_get_element().
+This routine should be used in preference to the less flexible old routine
+called ply_get_element_setup().
+
+Entry:
+plyfile   - file identifier
+elem_name - which element we're talking about
+prop      - property to add to those that will be returned
+******************************************************************************/
+
+void ply_get_property( PlyFile *plyfile, char *elem_name, PlyProperty *prop )
+{
+  PlyElement   *elem;
+  PlyProperty  *prop_ptr;
+  int           index;
+
+  /* find information about the element */
+  elem = find_element ( plyfile, elem_name );
+  plyfile->which_elem = elem;
+
+  /* deposit the property information into the element's description */
+
+  prop_ptr = find_property ( elem, prop->name, &index );
+  if ( prop_ptr == NULL )
+  {
+    fprintf ( stderr, "Warning:  Can't find property '%s' in element '%s'\n",
+    prop->name, elem_name );
+    return;
+  }
+  prop_ptr->internal_type = prop->internal_type;
+  prop_ptr->offset = prop->offset;
+  prop_ptr->count_internal = prop->count_internal;
+  prop_ptr->count_offset = prop->count_offset;
+
+  /* specify that the user wants this property */
+  elem->store_prop[index] = STORE_PROP;
+}
+
+
+/******************************************************************************
+Read one element from the file.  This routine assumes that we're reading
+the type of element specified in the last call to the routine
+ply_get_element_setup().
+
+Entry:
+plyfile  - file identifier
+elem_ptr - pointer to location where the element information should be put
+******************************************************************************/
+
+void ply_get_element( PlyFile *plyfile, void *elem_ptr )
+{
+  if ( plyfile->file_type == PLY_ASCII )
+    ascii_get_element ( plyfile, ( char * ) elem_ptr );
+  else
+    binary_get_element ( plyfile, ( char * ) elem_ptr );
+}
+
+
+/******************************************************************************
+Extract the comments from the header information of a PLY file.
+
+Entry:
+plyfile - file identifier
+
+Exit:
+num_comments - number of comments returned
+returns a pointer to a list of comments
+******************************************************************************/
+
+char **get_comments_ply( PlyFile *plyfile, int *num_comments )
+{
+  *num_comments = plyfile->num_comments;
+  return ( plyfile->comments );
+}
+
+
+/******************************************************************************
+Extract the object information (arbitrary text) from the header information
+of a PLY file.
+
+Entry:
+plyfile - file identifier
+
+Exit:
+num_obj_info - number of lines of text information returned
+returns a pointer to a list of object info lines
+******************************************************************************/
+
+char **get_obj_info_ply( PlyFile *plyfile, int *num_obj_info )
+{
+  *num_obj_info = plyfile->num_obj_info;
+  return ( plyfile->obj_info );
+}
+
+
+/******************************************************************************
+ake ready for "other" properties of an element-- those properties that
+the user has not explicitly asked for, but that are to be stashed away
+in a special structure to be carried along with the element's other
+information.
+
+Entry:
+plyfile - file identifier
+elem    - element for which we want to save away other properties
+******************************************************************************/
+
+void setup_other_props( PlyFile *plyfile, PlyElement *elem )
+{
+  int           i;
+  PlyProperty  *prop;
+  int           size  = 0;
+  int           type_size;
+
+  /* Examine each property in decreasing order of size. */
+  /* We do this so that all data types will be aligned by */
+  /* word, half-word, or whatever within the structure. */
+
+  for ( type_size = 8; type_size > 0; type_size /= 2 )
+  {
+    /* add up the space taken by each property, and save this information */
+    /* away in the property descriptor */
+
+    for ( i = 0; i < elem->nprops; i++ )
+    {
+      /* don't bother with properties we've been asked to store explicitly */
+      if ( elem->store_prop[i] )
+        continue;
+
+      prop = elem->props[i];
+
+      /* internal types will be same as external */
+      prop->internal_type = prop->external_type;
+      prop->count_internal = prop->count_external;
+
+      /* list case */
+      if ( prop->is_list == PLY_LIST )
+      {
+        /* pointer to list */
+        if ( type_size == sizeof ( void * ) )
+        {
+          prop->offset = size;
+          size += sizeof ( void * );    /* always use size of a pointer here */
+        }
+
+        /* count of number of list elements */
+        if ( type_size == ply_type_size[prop->count_external] )
+        {
+          prop->count_offset = size;
+          size += ply_type_size[prop->count_external];
+        }
+      }
+      /* string */
+      else if ( prop->is_list == PLY_STRING )
+      {
+        /* pointer to string */
+        if ( type_size == sizeof ( char * ) )
+        {
+          prop->offset = size;
+          size += sizeof ( char * );
+        }
+      }
+      /* scalar */
+      else if ( type_size == ply_type_size[prop->external_type] )
+      {
+        prop->offset = size;
+        size += ply_type_size[prop->external_type];
+      }
+    }
+  }
+
+  /* save the size for the other_props structure */
+  elem->other_size = size;
+}
+
+
+/******************************************************************************
+Specify that we want the "other" properties of an element to be tucked
+away within the user's structure.
+
+Entry:
+plyfile - file identifier
+elem    - the element that we want to store other_props in
+offset  - offset to where other_props will be stored inside user's structure
+
+Exit:
+returns pointer to structure containing description of other_props
+******************************************************************************/
+
+static PlyOtherProp *get_other_properties( PlyFile *plyfile, PlyElement *elem, int offset )
+{
+  int           i;
+  PlyOtherProp *other;
+  PlyProperty  *prop;
+  int           nprops;
+
+  /* remember that this is the "current" element */
+  plyfile->which_elem = elem;
+
+  /* save the offset to where to store the other_props */
+  elem->other_offset = offset;
+
+  /* place the appropriate pointers, etc. in the element's property list */
+  setup_other_props ( plyfile, elem );
+
+  /* create structure for describing other_props */
+  other = ( PlyOtherProp *  ) myalloc ( sizeof ( PlyOtherProp ) );
+  other->name = strdup ( elem->name );
+#if 0
+if (elem->other_offset == NO_OTHER_PROPS) {
+other->size = 0;
+other->props = NULL;
+other->nprops = 0;
+return (other);
+}
+#endif
+  other->size = elem->other_size;
+  other->props = ( PlyProperty *  *  ) myalloc ( sizeof( PlyProperty ) * elem->nprops );
+
+  /* save descriptions of each "other" property */
+  nprops = 0;
+  for ( i = 0; i < elem->nprops; i++ )
+  {
+    if ( elem->store_prop[i] )
+      continue;
+    prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+    copy_property ( prop, elem->props[i] );
+    other->props[nprops] = prop;
+    nprops++;
+  }
+  other->nprops = nprops;
+
+  /* set other_offset pointer appropriately if there are NO other properties */
+  if ( other->nprops == 0 )
+  {
+    elem->other_offset = NO_OTHER_PROPS;
+  }
+
+  /* return structure */
+  return ( other );
+}
+
+
+/******************************************************************************
+Specify that we want the "other" properties of an element to be tucked
+away within the user's structure.  The user needn't be concerned for how
+these properties are stored.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element that we want to store other_props in
+offset    - offset to where other_props will be stored inside user's structure
+
+Exit:
+returns pointer to structure containing description of other_props
+******************************************************************************/
+
+PlyOtherProp *ply_get_other_properties( PlyFile *plyfile, char *elem_name, int offset )
+{
+  PlyElement   *elem;
+  PlyOtherProp *other;
+
+  /* find information about the element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf ( stderr, "ply_get_other_properties: Can't find element '%s'\n",
+    elem_name );
+    return ( NULL );
+  }
+
+  other = get_other_properties ( plyfile, elem, offset );
+  return ( other );
+}
+
+
+
+
+/*************************/
+/*  Other Element Stuff  */
+/*************************/
+
+
+
+
+
+/******************************************************************************
+Grab all the data for the current element that a user does not want to
+explicitly read in.  Stores this in the PLY object's data structure.
+
+Entry:
+plyfile - pointer to file
+
+Exit:
+returns pointer to ALL the "other" element data for this PLY file
+******************************************************************************/
+
+PlyOtherElems *get_other_element_ply( PlyFile *plyfile )
+{
+  int             i;
+  PlyElement     *elem;
+  char           *elem_name;
+  int             elem_count;
+  PlyOtherElems  *other_elems;
+  OtherElem      *other;
+
+  elem = plyfile->which_elem;
+  elem_name = elem->name;
+  elem_count = elem->num;
+
+  /* create room for the new "other" element, initializing the */
+  /* other data structure if necessary */
+
+  if ( plyfile->other_elems == NULL )
+  {
+    plyfile->other_elems = ( PlyOtherElems *  ) myalloc ( sizeof ( PlyOtherElems ) );
+    other_elems = plyfile->other_elems;
+    other_elems->other_list = ( OtherElem *  ) myalloc ( sizeof ( OtherElem ) );
+    other = &( other_elems->other_list[0] );
+    other_elems->num_elems = 1;
+  }
+  else
+  {
+    other_elems = plyfile->other_elems;
+    other_elems->other_list = ( OtherElem *  ) realloc ( other_elems->other_list,
+    sizeof ( OtherElem ) * other_elems->num_elems + 1 );
+    other = &( other_elems->other_list[other_elems->num_elems] );
+    other_elems->num_elems++;
+  }
+
+  /* count of element instances in file */
+  other->elem_count = elem_count;
+
+  /* save name of element */
+  other->elem_name = strdup ( elem_name );
+
+  /* create a list to hold all the current elements */
+  other->other_data = ( OtherData *  *  )
+  malloc ( sizeof ( OtherData *  ) * other->elem_count );
+
+  /* set up for getting elements */
+  other->other_props = ply_get_other_properties ( plyfile, elem_name,
+  offsetof( OtherData,other_props ) );
+
+  /* grab all these elements */
+  for ( i = 0; i < other->elem_count; i++ )
+  {
+    /* grab and element from the file */
+    other->other_data[i] = ( OtherData *  ) malloc ( sizeof ( OtherData ) );
+    ply_get_element ( plyfile, ( void * ) other->other_data[i] );
+  }
+
+  /* return pointer to the other elements data */
+  return ( other_elems );
+}
+
+
+/******************************************************************************
+Write out the "other" elements specified for this PLY file.
+
+Entry:
+plyfile - pointer to PLY file to write out other elements for
+******************************************************************************/
+
+void put_other_elements_ply( PlyFile *plyfile )
+{
+  int         i,j;
+  OtherElem  *other;
+
+  /* make sure we have other elements to write */
+  if ( plyfile->other_elems == NULL )
+    return;
+
+  /* write out the data for each "other" element */
+
+  for ( i = 0; i < plyfile->other_elems->num_elems; i++ )
+  {
+    other = &( plyfile->other_elems->other_list[i] );
+    put_element_setup_ply ( plyfile, other->elem_name );
+
+    /* write out each instance of the current element */
+    for ( j = 0; j < other->elem_count; j++ )
+      put_element_ply ( plyfile, ( void * ) other->other_data[j] );
+  }
+}
+
+
+/******************************************************************************
+Free up storage used by an "other" elements data structure.
+
+Entry:
+other_elems - data structure to free up
+******************************************************************************/
+
+void free_other_elements_ply( PlyOtherElems *other_elems )
+{
+}
+
+
+
+/*******************/
+/*  Miscellaneous  */
+/*******************/
+
+
+
+/******************************************************************************
+Close a PLY file.
+
+Entry:
+plyfile - identifier of file to close
+******************************************************************************/
+
+void ply_close( PlyFile *plyfile )
+{
+  fclose ( plyfile->fp );
+
+  /* free up memory associated with the PLY file */
+  free ( plyfile );
+}
+
+
+/******************************************************************************
+Get version number and file type of a PlyFile.
+
+Entry:
+ply - pointer to PLY file
+
+Exit:
+version - version of the file
+file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
+******************************************************************************/
+
+void get_info_ply( PlyFile *ply, float *version, int *file_type )
+{
+  if ( ply == NULL )
+    return;
+
+  *version = ply->version;
+  *file_type = ply->file_type;
+}
+
+
+/******************************************************************************
+Compare two strings.  Returns 1 if they are the same, 0 if not.
+******************************************************************************/
+
+int equal_strings( char *s1, char *s2 )
+{
+  while ( *s1 && *s2 )
+    if ( *s1++ != *s2++ )
+      return ( 0 );
+
+  if ( *s1 != *s2 )
+    return ( 0 );
+  else
+    return ( 1 );
+}
+
+
+/******************************************************************************
+Re-create the command line that was used to invoke this program.
+
+Entry:
+argc - number of words in argv
+argv - array of words in command line
+******************************************************************************/
+
+char *recreate_command_line( int argc, char *argv[] )
+{
+  int   i;
+  char *line;
+  int   len = 0;
+
+  /* count total number of characters needed, including separating spaces */
+  for ( i = 0; i < argc; i++ )
+    len += strlen( argv[i] ) + 1;
+
+  /* create empty line */
+  line = ( char * ) malloc ( sizeof( char ) * len );
+  line[0] = '\0';
+
+  /* repeatedly append argv */
+  for ( i = 0; i < argc; i++ )
+  {
+    strcat ( line, argv[i] );
+    if ( i != argc - 1 )
+      strcat ( line, " " );
+  }
+
+  return ( line );
+}
+
+
+/******************************************************************************
+Find an element from the element list of a given PLY object.
+
+Entry:
+plyfile - file id for PLY file
+element - name of element we're looking for
+
+Exit:
+returns the element, or NULL if not found
+******************************************************************************/
+
+PlyElement *find_element( PlyFile *plyfile, char *element )
+{
+  int i;
+
+  for ( i = 0; i < plyfile->num_elem_types; i++ )
+    if ( equal_strings ( element, plyfile->elems[i]->name ) )
+      return ( plyfile->elems[i] );
+
+  return ( NULL );
+}
+
+
+/******************************************************************************
+Find a property in the list of properties of a given element.
+
+Entry:
+elem      - pointer to element in which we want to find the property
+prop_name - name of property to find
+
+Exit:
+index - index to position in list
+returns a pointer to the property, or NULL if not found
+******************************************************************************/
+
+PlyProperty *find_property( PlyElement *elem, char *prop_name, int *index )
+{
+  int i;
+
+  for ( i = 0; i < elem->nprops; i++ )
+    if ( equal_strings ( prop_name, elem->props[i]->name ) )
+    {
+      *index = i;
+      return ( elem->props[i] );
+    }
+
+  *index = -1;
+  return ( NULL );
+}
+
+
+/******************************************************************************
+Read an element from an ascii file.
+
+Entry:
+plyfile  - file identifier
+elem_ptr - pointer to element
+******************************************************************************/
+
+void ascii_get_element( PlyFile *plyfile, char *elem_ptr )
+{
+  int           j,k;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+  char*        *words;
+  int           nwords;
+  int           which_word;
+  char         *elem_data,*item;
+  char         *item_ptr;
+  int           item_size;
+  int           int_val;
+  unsigned int uint_val;
+  double  double_val;
+  int     list_count;
+  int     store_it;
+  char*  *store_array;
+  char   *orig_line;
+  char   *other_data;
+  int     other_flag;
+
+  item       = (char*) NULL ;
+  other_data = (char*) NULL ;
+
+  /* the kind of element we're reading currently */
+  elem = plyfile->which_elem;
+
+  /* do we need to setup for other_props? */
+
+  if ( elem->other_offset != NO_OTHER_PROPS )
+  {
+    char*  *ptr;
+    other_flag = 1;
+    /* make room for other_props */
+    other_data = ( char * ) myalloc ( elem->other_size );
+    /* store pointer in user's structure to the other_props */
+    ptr = ( char * *  ) ( elem_ptr + elem->other_offset );
+    *ptr = other_data;
+  }
+  else
+    other_flag = 0;
+
+  /* read in the element */
+
+  words = get_words ( plyfile->fp, &nwords, &orig_line );
+  if ( words == NULL )
+  {
+    fprintf ( stderr, "ply_get_element: unexpected end of file\n" );
+    exit ( -1 );
+  }
+
+  which_word = 0;
+
+  for ( j = 0; j < elem->nprops; j++ )
+  {
+    prop = elem->props[j];
+    store_it = ( elem->store_prop[j] | other_flag );
+
+    /* store either in the user's structure or in other_props */
+    if ( elem->store_prop[j] )
+      elem_data = elem_ptr;
+    else
+      elem_data = other_data;
+
+    if ( prop->is_list == PLY_LIST )
+    {
+      /* a list */
+
+      /* get and store the number of items in the list */
+      get_ascii_item ( words[which_word++], prop->count_external,
+      &int_val, &uint_val, &double_val );
+      if ( store_it )
+      {
+        item = elem_data + prop->count_offset;
+        store_item( item, prop->count_internal, int_val, uint_val, double_val );
+      }
+
+      /* allocate space for an array of items and store a ptr to the array */
+      list_count = int_val;
+      item_size = ply_type_size[prop->internal_type];
+      store_array = ( char * *  ) ( elem_data + prop->offset );
+
+      if ( list_count == 0 )
+      {
+        if ( store_it )
+          *store_array = NULL;
+      }
+      else
+      {
+        if ( store_it )
+        {
+          item_ptr = ( char * ) myalloc ( sizeof ( char ) * item_size * list_count );
+          item = item_ptr;
+          *store_array = item_ptr;
+        }
+
+        /* read items and store them into the array */
+        for ( k = 0; k < list_count; k++ )
+        {
+          get_ascii_item ( words[which_word++], prop->external_type,
+          &int_val, &uint_val, &double_val );
+          if ( store_it )
+          {
+            store_item ( item, prop->internal_type,
+            int_val, uint_val, double_val );
+            item += item_size;
+          }
+        }
+      }
+    }
+    else if ( prop->is_list == PLY_STRING )
+    {
+      /* a string */
+      if ( store_it )
+      {
+        char   *str;
+        char*  *str_ptr;
+        str = strdup ( words[which_word++] );
+        item = elem_data + prop->offset;
+        str_ptr = ( char * *  ) item;
+        *str_ptr = str;
+      }
+      else
+      {
+        which_word++;
+      }
+    }
+    else
+    {
+      /* a scalar */
+      get_ascii_item ( words[which_word++], prop->external_type,
+      &int_val, &uint_val, &double_val );
+      if ( store_it )
+      {
+        item = elem_data + prop->offset;
+        store_item ( item, prop->internal_type, int_val, uint_val, double_val );
+      }
+    }
+  }
+
+  free ( words );
+}
+
+
+/******************************************************************************
+Read an element from a binary file.
+
+Entry:
+plyfile  - file identifier
+elem_ptr - pointer to an element
+******************************************************************************/
+
+void binary_get_element( PlyFile *plyfile, char *elem_ptr )
+{
+  int           j,k;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+  FILE         *fp  = plyfile->fp;
+  char         *elem_data;
+  char         *item;
+  char         *item_ptr;
+  int           item_size;
+  int           int_val;
+  unsigned int uint_val;
+  double  double_val;
+  int     list_count;
+  int     store_it;
+  char*  *store_array;
+  char   *other_data;
+  int     other_flag;
+
+  item       = (char*) NULL ;
+  other_data = (char*) NULL ;
+
+  /* the kind of element we're reading currently */
+  elem = plyfile->which_elem;
+
+  /* do we need to setup for other_props? */
+
+  if ( elem->other_offset != NO_OTHER_PROPS )
+  {
+    char*  *ptr;
+    other_flag = 1;
+    /* make room for other_props */
+    other_data = ( char * ) myalloc ( elem->other_size );
+    /* store pointer in user's structure to the other_props */
+    ptr = ( char * *  ) ( elem_ptr + elem->other_offset );
+    *ptr = other_data;
+  }
+  else
+    other_flag = 0;
+
+  /* read in a number of elements */
+
+  for ( j = 0; j < elem->nprops; j++ )
+  {
+    prop = elem->props[j];
+    store_it = ( elem->store_prop[j] | other_flag );
+
+    /* store either in the user's structure or in other_props */
+    if ( elem->store_prop[j] )
+      elem_data = elem_ptr;
+    else
+      elem_data = other_data;
+
+    if ( prop->is_list == PLY_LIST )
+    {
+      /* list */
+
+      /* get and store the number of items in the list */
+      get_binary_item ( fp, prop->count_external,
+      &int_val, &uint_val, &double_val );
+      if ( store_it )
+      {
+        item = elem_data + prop->count_offset;
+        store_item( item, prop->count_internal, int_val, uint_val, double_val );
+      }
+
+      /* allocate space for an array of items and store a ptr to the array */
+      list_count = int_val;
+      item_size = ply_type_size[prop->internal_type];
+      store_array = ( char * *  ) ( elem_data + prop->offset );
+      if ( list_count == 0 )
+      {
+        if ( store_it )
+          *store_array = NULL;
+      }
+      else
+      {
+        if ( store_it )
+        {
+          item_ptr = ( char * ) myalloc ( sizeof ( char ) * item_size * list_count );
+          item = item_ptr;
+          *store_array = item_ptr;
+        }
+
+        /* read items and store them into the array */
+        for ( k = 0; k < list_count; k++ )
+        {
+          get_binary_item ( fp, prop->external_type,
+          &int_val, &uint_val, &double_val );
+          if ( store_it )
+          {
+            store_item ( item, prop->internal_type,
+            int_val, uint_val, double_val );
+            item += item_size;
+          }
+        }
+      }
+    }
+    else if ( prop->is_list == PLY_STRING )
+    {
+      /* string */
+      int   len;
+      char *str;
+      fread ( &len, sizeof( int ), 1, fp );
+      str = ( char * ) myalloc ( len );
+      fread ( str, len, 1, fp );
+      if ( store_it )
+      {
+        char*  *str_ptr;
+        item = elem_data + prop->offset;
+        str_ptr = ( char * *  ) item;
+        *str_ptr = str;
+      }
+    }
+    else
+    {
+      /* scalar */
+      get_binary_item ( fp, prop->external_type,
+      &int_val, &uint_val, &double_val );
+      if ( store_it )
+      {
+        item = elem_data + prop->offset;
+        store_item ( item, prop->internal_type, int_val, uint_val, double_val );
+      }
+    }
+  }
+}
+
+
+/******************************************************************************
+Write to a file the word that represents a PLY data type.
+
+Entry:
+fp   - file pointer
+code - code for type
+******************************************************************************/
+
+void write_scalar_type( FILE *fp, int code )
+{
+  /* make sure this is a valid code */
+
+  if ( code <= StartType || code >= EndType )
+  {
+    fprintf ( stderr, "write_scalar_type: bad data code = %d\n", code );
+    exit ( -1 );
+  }
+
+  /* write the code to a file */
+
+  fprintf ( fp, "%s", type_names[code] );
+}
+
+
+/******************************************************************************
+Get a text line from a file and break it up into words.
+
+IMPORTANT: The calling routine should call "free" on the returned pointer once
+finished with it.
+
+Entry:
+fp - file to read from
+
+Exit:
+nwords    - number of words returned
+orig_line - the original line of characters
+returns a list of words from the line, or NULL if end-of-file
+******************************************************************************/
+
+char **get_words( FILE *fp, int *nwords, char **orig_line )
+{
+#define BIG_STRING 4096
+  static char str[BIG_STRING];
+  static char str_copy[BIG_STRING];
+  char*      *words;
+  int         max_words = 10;
+  int         num_words = 0;
+  char       *ptr,*ptr2;
+  char       *result;
+
+  words = ( char * *  ) myalloc ( sizeof ( char * ) * max_words );
+
+  /* read in a line */
+  result = fgets ( str, BIG_STRING, fp );
+  if ( result == NULL )
+  {
+    *nwords = 0;
+    *orig_line = NULL;
+    return ( NULL );
+  }
+
+  /* convert line-feed and tabs into spaces */
+  /* (this guarentees that there will be a space before the */
+  /*  null character at the end of the string) */
+
+  str[BIG_STRING - 2] = ' ';
+  str[BIG_STRING - 1] = '\0';
+
+  for ( ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++ )
+  {
+    *ptr2 = *ptr;
+    if ( *ptr == '\t' )
+    {
+      *ptr = ' ';
+      *ptr2 = ' ';
+    }
+    else if ( *ptr == '\n' )
+    {
+      *ptr = ' ';
+      *ptr2 = ' ';
+      break;
+    }
+    else if ( *ptr == '\r' )
+    {
+      *ptr = ' ';
+      *ptr2 = '\0';
+    }
+  }
+
+  /* find the words in the line */
+
+  ptr = str;
+  while ( *ptr != '\0' )
+  {
+    /* jump over leading spaces */
+    while ( *ptr == ' ' )
+      ptr++;
+
+    /* break if we reach the end */
+    if ( *ptr == '\0' )
+      break;
+
+    /* allocate more room for words if necessary */
+    if ( num_words >= max_words )
+    {
+      max_words += 10;
+      words = ( char * *  ) realloc ( words, sizeof ( char * ) * max_words );
+    }
+
+    if ( *ptr == '\"' )
+    {
+      /* a quote indidicates that we have a string */
+
+      /* skip over leading quote */
+      ptr++;
+
+      /* save pointer to beginning of word */
+      words[num_words++] = ptr;
+
+      /* find trailing quote or end of line */
+      while ( *ptr != '\"' && *ptr != '\0' )
+        ptr++;
+
+      /* replace quote with a null character to mark the end of the word */
+      /* if we are not already at the end of the line */
+      if ( *ptr != '\0' )
+        *ptr++ = '\0';
+    }
+    else
+    {
+      /* non-string */
+
+      /* save pointer to beginning of word */
+      words[num_words++] = ptr;
+
+      /* jump over non-spaces */
+      while ( *ptr != ' ' )
+        ptr++;
+
+      /* place a null character here to mark the end of the word */
+      *ptr++ = '\0';
+    }
+  }
+
+  /* return the list of words */
+  *nwords = num_words;
+  *orig_line = str_copy;
+  return ( words );
+}
+
+
+/******************************************************************************
+Return the value of an item, given a pointer to it and its type.
+
+Entry:
+item - pointer to item
+type - data type that "item" points to
+
+Exit:
+returns a double-precision float that contains the value of the item
+******************************************************************************/
+
+double get_item_value( char *item, int type )
+{
+  unsigned char *puchar;
+  char       *pchar;
+  short int  *pshort;
+  unsigned short int *pushort;
+  int  *pint;
+  unsigned int *puint;
+  float  *pfloat;
+  double *pdouble;
+  int     int_value;
+  unsigned int uint_value;
+  double  double_value;
+
+  switch ( type )
+  {
+    case Int8:
+      pchar = ( char * ) item;
+      int_value = *pchar;
+      return ( ( double ) int_value );
+    case Uint8:
+      puchar = ( unsigned char * ) item;
+      int_value = *puchar;
+      return ( ( double ) int_value );
+    case Int16:
+      pshort = ( short int * ) item;
+      int_value = *pshort;
+      return ( ( double ) int_value );
+    case Uint16:
+      pushort = ( unsigned short int * ) item;
+      int_value = *pushort;
+      return ( ( double ) int_value );
+    case Int32:
+      pint = ( int * ) item;
+      int_value = *pint;
+      return ( ( double ) int_value );
+    case Uint32:
+      puint = ( unsigned int * ) item;
+      uint_value = *puint;
+      return ( ( double ) uint_value );
+    case Float32:
+      pfloat = ( float * ) item;
+      double_value = *pfloat;
+      return ( double_value );
+    case Float64:
+      pdouble = ( double * ) item;
+      double_value = *pdouble;
+      return ( double_value );
+    default:
+      fprintf ( stderr, "get_item_value: bad type = %d\n", type );
+      exit ( -1 );
+  }
+
+  return ( 0.0 );  /* never actually gets here */
+}
+
+
+/******************************************************************************
+Write out an item to a file as raw binary bytes.
+
+Entry:
+fp         - file to write to
+int_val    - integer version of item
+uint_val   - unsigned integer version of item
+double_val - double-precision float version of item
+type       - data type to write out
+******************************************************************************/
+
+void write_binary_item( FILE *fp, int int_val, unsigned int uint_val, double double_val, int type )
+{
+  unsigned char uchar_val;
+  char  char_val;
+  unsigned short ushort_val;
+  short short_val;
+  float float_val;
+
+  switch ( type )
+  {
+    case Int8:
+      char_val = int_val;
+      fwrite ( &char_val, 1, 1, fp );
+      break;
+    case Int16:
+      short_val = int_val;
+      fwrite ( &short_val, 2, 1, fp );
+      break;
+    case Int32:
+      fwrite ( &int_val, 4, 1, fp );
+      break;
+    case Uint8:
+      uchar_val = uint_val;
+      fwrite ( &uchar_val, 1, 1, fp );
+      break;
+    case Uint16:
+      ushort_val = uint_val;
+      fwrite ( &ushort_val, 2, 1, fp );
+      break;
+    case Uint32:
+      fwrite ( &uint_val, 4, 1, fp );
+      break;
+    case Float32:
+      float_val = ( float ) double_val;
+      fwrite ( &float_val, 4, 1, fp );
+      break;
+    case Float64:
+      fwrite ( &double_val, 8, 1, fp );
+      break;
+    default:
+      fprintf ( stderr, "write_binary_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Write out an item to a file as ascii characters.
+
+Entry:
+fp         - file to write to
+int_val    - integer version of item
+uint_val   - unsigned integer version of item
+double_val - double-precision float version of item
+type       - data type to write out
+******************************************************************************/
+
+void write_ascii_item( FILE *fp, int int_val, unsigned int uint_val, double double_val, int type )
+{
+  switch ( type )
+  {
+    case Int8:
+    case Int16:
+    case Int32:
+      fprintf ( fp, "%d ", int_val );
+      break;
+    case Uint8:
+    case Uint16:
+    case Uint32:
+      fprintf ( fp, "%u ", uint_val );
+      break;
+    case Float32:
+    case Float64:
+      fprintf ( fp, "%12f ", double_val );
+      break;
+    default:
+      fprintf ( stderr, "write_ascii_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Get the value of an item that is in memory, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+ptr  - pointer to the item
+type - data type supposedly in the item
+
+Exit:
+int_val    - integer value
+uint_val   - unsigned integer value
+double_val - double-precision floating point value
+******************************************************************************/
+
+void get_stored_item( void *ptr, int type, int *int_val, unsigned int *uint_val, double *double_val )
+{
+  switch ( type )
+  {
+    case Int8:
+      *int_val = *( ( char * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint8:
+      *uint_val = *( ( unsigned char * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Int16:
+      *int_val = *( ( short int * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint16:
+      *uint_val = *( ( unsigned short int * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Int32:
+      *int_val = *( ( int * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint32:
+      *uint_val = *( ( unsigned int * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Float32:
+      *double_val = *( ( float * ) ptr );
+      *int_val = ( int ) *double_val;
+      *uint_val = ( unsigned int ) *double_val;
+      break;
+    case Float64:
+      *double_val = *( ( double * ) ptr );
+      *int_val = ( int ) *double_val;
+      *uint_val = ( unsigned int ) *double_val;
+      break;
+    default:
+      fprintf ( stderr, "get_stored_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Get the value of an item from a binary file, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+fp   - file to get item from
+type - data type supposedly in the word
+
+Exit:
+int_val    - integer value
+uint_val   - unsigned integer value
+double_val - double-precision floating point value
+******************************************************************************/
+
+void get_binary_item( FILE *fp, int type, int *int_val, unsigned int *uint_val, double *double_val )
+{
+  char  c[8];
+  void *ptr;
+
+  ptr = ( void * ) c;
+
+  switch ( type )
+  {
+    case Int8:
+      fread ( ptr, 1, 1, fp );
+      *int_val = *( ( char * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint8:
+      fread ( ptr, 1, 1, fp );
+      *uint_val = *( ( unsigned char * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Int16:
+      fread ( ptr, 2, 1, fp );
+      *int_val = *( ( short int * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint16:
+      fread ( ptr, 2, 1, fp );
+      *uint_val = *( ( unsigned short int * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Int32:
+      fread ( ptr, 4, 1, fp );
+      *int_val = *( ( int * ) ptr );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+    case Uint32:
+      fread ( ptr, 4, 1, fp );
+      *uint_val = *( ( unsigned int * ) ptr );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+    case Float32:
+      fread ( ptr, 4, 1, fp );
+      *double_val = *( ( float * ) ptr );
+      *int_val = ( int ) *double_val;
+      *uint_val = ( unsigned int ) *double_val;
+      break;
+    case Float64:
+      fread ( ptr, 8, 1, fp );
+      *double_val = *( ( double * ) ptr );
+      *int_val = ( int ) *double_val;
+      *uint_val = ( unsigned int ) *double_val;
+      break;
+    default:
+      fprintf ( stderr, "get_binary_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Extract the value of an item from an ascii word, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+word - word to extract value from
+type - data type supposedly in the word
+
+Exit:
+int_val    - integer value
+uint_val   - unsigned integer value
+double_val - double-precision floating point value
+******************************************************************************/
+
+void get_ascii_item( char *word, int type, int *int_val, unsigned int *uint_val, double *double_val )
+{
+  switch ( type )
+  {
+    case Int8:
+    case Uint8:
+    case Int16:
+    case Uint16:
+    case Int32:
+      *int_val = atoi ( word );
+      *uint_val = *int_val;
+      *double_val = *int_val;
+      break;
+
+    case Uint32:
+      *uint_val = strtoul ( word, ( char * *  ) NULL, 10 );
+      *int_val = *uint_val;
+      *double_val = *uint_val;
+      break;
+
+    case Float32:
+    case Float64:
+      *double_val = atof ( word );
+      *int_val = ( int ) *double_val;
+      *uint_val = ( unsigned int ) *double_val;
+      break;
+
+    default:
+      fprintf ( stderr, "get_ascii_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Store a value into a place being pointed to, guided by a data type.
+
+Entry:
+item       - place to store value
+type       - data type
+int_val    - integer version of value
+uint_val   - unsigned integer version of value
+double_val - double version of value
+
+Exit:
+item - pointer to stored value
+******************************************************************************/
+
+void store_item( char *item, int type, int int_val, unsigned int uint_val, double double_val )
+{
+  unsigned char *puchar;
+  short int  *pshort;
+  unsigned short int *pushort;
+  int  *pint;
+  unsigned int *puint;
+  float  *pfloat;
+  double *pdouble;
+
+  switch ( type )
+  {
+    case Int8:
+      *item = int_val;
+      break;
+    case Uint8:
+      puchar = ( unsigned char * ) item;
+      *puchar = uint_val;
+      break;
+    case Int16:
+      pshort = ( short * ) item;
+      *pshort = int_val;
+      break;
+    case Uint16:
+      pushort = ( unsigned short * ) item;
+      *pushort = uint_val;
+      break;
+    case Int32:
+      pint = ( int * ) item;
+      *pint = int_val;
+      break;
+    case Uint32:
+      puint = ( unsigned int * ) item;
+      *puint = uint_val;
+      break;
+    case Float32:
+      pfloat = ( float * ) item;
+      *pfloat = ( float ) double_val;
+      break;
+    case Float64:
+      pdouble = ( double * ) item;
+      *pdouble = double_val;
+      break;
+    default:
+      fprintf ( stderr, "store_item: bad type = %d\n", type );
+      exit ( -1 );
+  }
+}
+
+
+/******************************************************************************
+Add an element to a PLY file descriptor.
+
+Entry:
+plyfile - PLY file descriptor
+words   - list of words describing the element
+nwords  - number of words in the list
+******************************************************************************/
+
+void add_element( PlyFile *plyfile, char **words, int nwords )
+{
+  PlyElement *elem;
+
+  /* create the new element */
+  elem = ( PlyElement *  ) myalloc ( sizeof ( PlyElement ) );
+  elem->name = strdup ( words[1] );
+  elem->num = atoi ( words[2] );
+  elem->nprops = 0;
+
+  /* make room for new element in the object's list of elements */
+  if ( plyfile->num_elem_types == 0 )
+    plyfile->elems = ( PlyElement *  *  ) myalloc ( sizeof ( PlyElement *  ) );
+  else
+    plyfile->elems = ( PlyElement *  *  ) realloc ( plyfile->elems,
+    sizeof ( PlyElement *  ) * ( plyfile->num_elem_types + 1 ) );
+
+  /* add the new element to the object's list */
+  plyfile->elems[plyfile->num_elem_types] = elem;
+  plyfile->num_elem_types++;
+}
+
+
+/******************************************************************************
+Return the type of a property, given the name of the property.
+
+Entry:
+name - name of property type
+
+Exit:
+returns integer code for property, or 0 if not found
+******************************************************************************/
+
+int get_prop_type( char *type_name )
+{
+  int i;
+
+  /* try to match the type name */
+  for ( i = StartType + 1; i < EndType; i++ )
+    if ( equal_strings ( type_name, type_names[i] ) )
+      return ( i );
+
+  /* see if we can match an old type name */
+  for ( i = StartType + 1; i < EndType; i++ )
+    if ( equal_strings ( type_name, old_type_names[i] ) )
+      return ( i );
+
+  /* if we get here, we didn't find the type */
+  return ( 0 );
+}
+
+
+/******************************************************************************
+Add a property to a PLY file descriptor.
+
+Entry:
+plyfile - PLY file descriptor
+words   - list of words describing the property
+nwords  - number of words in the list
+******************************************************************************/
+
+void add_property( PlyFile *plyfile, char **words, int nwords )
+{
+  PlyProperty  *prop;
+  PlyElement   *elem;
+
+  /* create the new property */
+
+  prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+
+  if ( equal_strings ( words[1], "list" ) )
+  {
+    /* list */
+    prop->count_external = get_prop_type ( words[2] );
+    prop->external_type = get_prop_type ( words[3] );
+    prop->name = strdup ( words[4] );
+    prop->is_list = PLY_LIST;
+  }
+  else if ( equal_strings ( words[1], "string" ) )
+  {
+    /* string */
+    prop->count_external = Int8;
+    prop->external_type = Int8;
+    prop->name = strdup ( words[2] );
+    prop->is_list = PLY_STRING;
+  }
+  else
+  {
+    /* scalar */
+    prop->external_type = get_prop_type ( words[1] );
+    prop->name = strdup ( words[2] );
+    prop->is_list = PLY_SCALAR;
+  }
+
+  /* add this property to the list of properties of the current element */
+
+  elem = plyfile->elems[plyfile->num_elem_types - 1];
+
+  if ( elem->nprops == 0 )
+    elem->props = ( PlyProperty *  *  ) myalloc ( sizeof ( PlyProperty *  ) );
+  else
+    elem->props = ( PlyProperty *  *  ) realloc ( elem->props,
+    sizeof ( PlyProperty *  ) * ( elem->nprops + 1 ) );
+
+  elem->props[elem->nprops] = prop;
+  elem->nprops++;
+}
+
+
+/******************************************************************************
+Add a comment to a PLY file descriptor.
+
+Entry:
+plyfile - PLY file descriptor
+line    - line containing comment
+******************************************************************************/
+
+void add_comment( PlyFile *plyfile, char *line )
+{
+  int i;
+
+  /* skip over "comment" and leading spaces and tabs */
+  i = 7;
+  while ( line[i] == ' ' || line[i] == '\t' )
+    i++;
+
+  append_comment_ply ( plyfile, &line[i] );
+}
+
+
+/******************************************************************************
+Add a some object information to a PLY file descriptor.
+
+Entry:
+plyfile - PLY file descriptor
+line    - line containing text info
+******************************************************************************/
+
+void add_obj_info( PlyFile *plyfile, char *line )
+{
+  int i;
+
+  /* skip over "obj_info" and leading spaces and tabs */
+  i = 8;
+  while ( line[i] == ' ' || line[i] == '\t' )
+    i++;
+
+  append_obj_info_ply ( plyfile, &line[i] );
+}
+
+
+/******************************************************************************
+Copy a property.
+******************************************************************************/
+
+void copy_property( PlyProperty *dest, PlyProperty *src )
+{
+  dest->name = strdup ( src->name );
+  dest->external_type = src->external_type;
+  dest->internal_type = src->internal_type;
+  dest->offset = src->offset;
+
+  dest->is_list = src->is_list;
+  dest->count_external = src->count_external;
+  dest->count_internal = src->count_internal;
+  dest->count_offset = src->count_offset;
+}
+
+
+/******************************************************************************
+Allocate some memory.
+
+Entry:
+size  - amount of memory requested (in bytes)
+lnum  - line number from which memory was requested
+fname - file name from which memory was requested
+******************************************************************************/
+
+static char *my_alloc( int size, int lnum, char *fname )
+{
+  char *ptr;
+
+  ptr = ( char * ) malloc ( size );
+
+  if ( ptr == 0 )
+  {
+    fprintf( stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname );
+  }
+
+  return ( ptr );
+}
+
+
+/**** NEW STUFF ****/
+/**** NEW STUFF ****/
+/**** NEW STUFF ****/
+/**** NEW STUFF ****/
+
+
+
+/******************************************************************************
+Given a file pointer, get ready to read PLY data from the file.
+
+Entry:
+fp - the given file pointer
+
+Exit:
+nelems     - number of elements in object
+elem_names - list of element names
+returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *read_ply( FILE *fp )
+{
+  PlyFile  *ply;
+  int       num_elems;
+  char*    *elem_names;
+
+  ply = ply_read ( fp, &num_elems, &elem_names );
+
+  return ( ply );
+}
+
+
+/******************************************************************************
+Given a file pointer, get ready to write PLY data to the file.
+
+Entry:
+fp         - the given file pointer
+nelems     - number of elements in object
+elem_names - list of element names
+file_type  - file type, either ascii or binary
+
+Exit:
+returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+PlyFile *write_ply( FILE *fp, int nelems, char **elem_names, int file_type )
+{
+  PlyFile  *ply;
+
+  ply = ply_write ( fp, nelems, elem_names, file_type );
+
+  return ( ply );
+}
+
+
+/******************************************************************************
+Return a list of the names of the elements in a particular PLY file.
+
+Entry:
+ply - PLY file whose element name list we want
+
+Exit:
+num_elems  - the number of element names in the list
+returns the list of names
+******************************************************************************/
+
+char **get_element_list_ply( PlyFile *ply, int *num_elems )
+{
+  int     i;
+  char*  *elist;
+
+  /* create the list of element names */
+
+  elist = ( char * *  ) myalloc ( sizeof ( char * ) * ply->num_elem_types );
+  for ( i = 0; i < ply->num_elem_types; i++ )
+    elist[i] = strdup ( ply->elems[i]->name );
+
+  /* return the number of elements and the list of element names */
+  *num_elems = ply->num_elem_types;
+  return ( elist );
+}
+
+
+/******************************************************************************
+Append a comment to a PLY file.
+
+Entry:
+ply     - file to append comment to
+comment - the comment to append
+******************************************************************************/
+
+void append_comment_ply( PlyFile *ply, char *comment )
+{
+  /* (re)allocate space for new comment */
+  if ( ply->num_comments == 0 )
+    ply->comments = ( char * *  ) myalloc ( sizeof ( char * ) );
+  else
+    ply->comments = ( char * *  ) realloc ( ply->comments,
+    sizeof ( char * ) * ( ply->num_comments + 1 ) );
+
+  /* add comment to list */
+  ply->comments[ply->num_comments] = strdup ( comment );
+  ply->num_comments++;
+}
+
+
+/******************************************************************************
+Copy the comments from one PLY file to another.
+
+Entry:
+out_ply - destination file to copy comments to
+in_ply  - the source of the comments
+******************************************************************************/
+
+void copy_comments_ply( PlyFile *out_ply, PlyFile *in_ply )
+{
+  int i;
+
+  for ( i = 0; i < in_ply->num_comments; i++ )
+    append_comment_ply ( out_ply, in_ply->comments[i] );
+}
+
+
+/******************************************************************************
+Append object information (arbitrary text) to a PLY file.
+
+Entry:
+ply      - file to append object info to
+obj_info - the object info to append
+******************************************************************************/
+
+void append_obj_info_ply( PlyFile *ply, char *obj_info )
+{
+  /* (re)allocate space for new info */
+  if ( ply->num_obj_info == 0 )
+    ply->obj_info = ( char * *  ) myalloc ( sizeof ( char * ) );
+  else
+    ply->obj_info = ( char * *  ) realloc ( ply->obj_info,
+    sizeof ( char * ) * ( ply->num_obj_info + 1 ) );
+
+  /* add info to list */
+  ply->obj_info[ply->num_obj_info] = strdup ( obj_info );
+  ply->num_obj_info++;
+}
+
+
+/******************************************************************************
+Copy the object information from one PLY file to another.
+
+Entry:
+out_ply - destination file to copy object information to
+in_ply  - the source of the object information
+******************************************************************************/
+
+void copy_obj_info_ply( PlyFile *out_ply, PlyFile *in_ply )
+{
+  int i;
+
+  for ( i = 0; i < in_ply->num_obj_info; i++ )
+    append_obj_info_ply ( out_ply, in_ply->obj_info[i] );
+}
+
+
+/******************************************************************************
+Close a PLY file.
+
+Entry:
+plyfile - identifier of file to close
+******************************************************************************/
+
+void close_ply( PlyFile *plyfile )
+{
+  fclose ( plyfile->fp );
+}
+
+
+/******************************************************************************
+Free the memory used by a PLY file.
+
+Entry:
+plyfile - identifier of file
+******************************************************************************/
+
+void free_ply( PlyFile *plyfile )
+{
+  /* free up memory associated with the PLY file */
+  free ( plyfile );
+}
+
+
+/******************************************************************************
+Specify the index of the next element to be read in from a PLY file.
+
+Entry:
+ply - file to read from
+index - index of the element to be read
+
+Exit:
+elem_count - the number of elements in the file
+returns pointer to the name of this next element
+******************************************************************************/
+
+char *setup_element_read_ply( PlyFile *ply, int index, int *elem_count )
+{
+  PlyElement *elem;
+
+  if ( index < 0 || index > ply->num_elem_types )
+  {
+    fprintf ( stderr, "Warning:  No element with index %d\n", index );
+    return ( 0 );
+  }
+
+  elem = ply->elems[index];
+
+  /* set this to be the current element */
+  ply->which_elem = elem;
+
+  /* return the number of such elements in the file and the element's name */
+  *elem_count = elem->num;
+  return ( elem->name );
+}
+
+
+/******************************************************************************
+Read one element from the file.  This routine assumes that we're reading
+the type of element specified in the last call to the routine
+setup_element_read_ply().
+
+Entry:
+plyfile  - file identifier
+elem_ptr - pointer to location where the element information should be put
+******************************************************************************/
+
+void get_element_ply( PlyFile *plyfile, void *elem_ptr )
+{
+  if ( plyfile->file_type == PLY_ASCII )
+    ascii_get_element ( plyfile, ( char * ) elem_ptr );
+  else
+    binary_get_element ( plyfile, ( char * ) elem_ptr );
+}
+
+
+/******************************************************************************
+Specify one of several properties of the current element that is to be
+read from a file.  This should be called (usually multiple times) before a
+call to the routine get_element_ply().
+
+Entry:
+plyfile - file identifier
+prop    - property to add to those that will be returned
+
+Exit:
+0 if the property has not been found
+1 if the property has been found
+******************************************************************************/
+
+int setup_property_ply( PlyFile *plyfile, PlyProperty *prop )
+{
+  PlyElement   *elem;
+  PlyProperty  *prop_ptr;
+  int           index;
+
+  elem = plyfile->which_elem;
+
+  /* deposit the property information into the element's description */
+
+  prop_ptr = find_property ( elem, prop->name, &index );
+  if ( prop_ptr == NULL )
+  {
+    fprintf ( stderr, "Warning:  Can't find property '%s' in element '%s'\n",
+    prop->name, elem->name );
+    return 0;
+  }
+  prop_ptr->internal_type = prop->internal_type;
+  prop_ptr->offset = prop->offset;
+  prop_ptr->count_internal = prop->count_internal;
+  prop_ptr->count_offset = prop->count_offset;
+
+  /* specify that the user wants this property */
+  elem->store_prop[index] = STORE_PROP;
+  return 1 ;
+}
+
+
+/******************************************************************************
+Specify that we want the "other" properties of the current element to be tucked
+away within the user's structure.
+
+Entry:
+plyfile - file identifier
+offset  - offset to where other_props will be stored inside user's structure
+
+Exit:
+returns pointer to structure containing description of other_props
+******************************************************************************/
+
+PlyOtherProp *get_other_properties_ply( PlyFile *plyfile, int offset )
+{
+  PlyOtherProp *other;
+
+  other = get_other_properties ( plyfile, plyfile->which_elem, offset );
+  return ( other );
+}
+
+
+/******************************************************************************
+Describe which element is to be written next and state how many of them will
+be written.
+
+Entry:
+plyfile   - file identifier
+elem_name - name of element that information is being described
+nelems    - number of elements of this type to be written
+******************************************************************************/
+
+void describe_element_ply( PlyFile *plyfile, char *elem_name, int nelems )
+{
+  PlyElement *elem;
+
+  /* look for appropriate element */
+  elem = find_element ( plyfile, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr,"describe_element_ply: can't find element '%s'\n",elem_name );
+    exit ( -1 );
+  }
+
+  elem->num = nelems;
+
+  /* now this element is the current element */
+  plyfile->which_elem = elem;
+}
+
+
+/******************************************************************************
+Describe a property of an element.
+
+Entry:
+plyfile   - file identifier
+prop      - the new property
+******************************************************************************/
+
+void describe_property_ply( PlyFile *plyfile, PlyProperty *prop )
+{
+  PlyElement   *elem;
+  PlyProperty  *elem_prop;
+
+  elem = plyfile->which_elem;
+
+  /* create room for new property */
+
+  if ( elem->nprops == 0 )
+  {
+    elem->props = ( PlyProperty *  *  ) myalloc ( sizeof ( PlyProperty *  ) );
+    elem->store_prop = ( char * ) myalloc ( sizeof ( char ) );
+    elem->nprops = 1;
+  }
+  else
+  {
+    elem->nprops++;
+    elem->props = ( PlyProperty *  *  )
+    realloc ( elem->props, sizeof ( PlyProperty *  ) * elem->nprops );
+    elem->store_prop = ( char * )
+    realloc ( elem->store_prop, sizeof ( char ) * elem->nprops );
+  }
+
+  /* copy the new property */
+
+  elem_prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+  elem->props[elem->nprops - 1] = elem_prop;
+  elem->store_prop[elem->nprops - 1] = NAMED_PROP;
+  copy_property ( elem_prop, prop );
+}
+
+
+/******************************************************************************
+Describe what the "other" properties are that are to be stored, and where
+they are in an element.
+******************************************************************************/
+
+void describe_other_properties_ply( PlyFile *plyfile, PlyOtherProp *other, int offset )
+{
+  int           i;
+  PlyElement   *elem;
+  PlyProperty  *prop;
+
+  /* look for appropriate element */
+  elem = find_element ( plyfile, other->name );
+  if ( elem == NULL )
+  {
+    fprintf( stderr, "describe_other_properties_ply: can't find element '%s'\n",
+    other->name );
+    return;
+  }
+
+  /* create room for other properties */
+
+  if ( elem->nprops == 0 )
+  {
+    elem->props = ( PlyProperty *  *  )
+    myalloc ( sizeof ( PlyProperty *  ) * other->nprops );
+    elem->store_prop = ( char * ) myalloc ( sizeof ( char ) * other->nprops );
+    elem->nprops = 0;
+  }
+  else
+  {
+    int newsize;
+    newsize = elem->nprops + other->nprops;
+    elem->props = ( PlyProperty *  *  )
+    realloc ( elem->props, sizeof ( PlyProperty *  ) * newsize );
+    elem->store_prop = ( char * )
+    realloc ( elem->store_prop, sizeof ( char ) * newsize );
+  }
+
+  /* copy the other properties */
+
+  for ( i = 0; i < other->nprops; i++ )
+  {
+    prop = ( PlyProperty *  ) myalloc ( sizeof ( PlyProperty ) );
+    copy_property ( prop, other->props[i] );
+    elem->props[elem->nprops] = prop;
+    elem->store_prop[elem->nprops] = OTHER_PROP;
+    elem->nprops++;
+  }
+
+  /* save other info about other properties */
+  elem->other_size = other->size;
+  elem->other_offset = offset;
+}
+
+
+/******************************************************************************
+Pass along a pointer to "other" elements that we want to save in a given
+PLY file.  These other elements were presumably read from another PLY file.
+
+Entry:
+plyfile     - file pointer in which to store this other element info
+other_elems - info about other elements that we want to store
+******************************************************************************/
+
+void describe_other_elements_ply( PlyFile *plyfile, PlyOtherElems *other_elems )
+{
+  int         i;
+  OtherElem  *other;
+
+  /* ignore this call if there is no other element */
+  if ( other_elems == NULL )
+    return;
+
+  /* save pointer to this information */
+  plyfile->other_elems = other_elems;
+
+  /* describe the other properties of this element */
+
+  for ( i = 0; i < other_elems->num_elems; i++ )
+  {
+    other = &( other_elems->other_list[i] );
+    element_count_ply ( plyfile, other->elem_name, other->elem_count );
+    describe_other_properties_ply ( plyfile, other->other_props,
+    offsetof( OtherData,other_props ) );
+  }
+}
+
+
+
+/**** Property Propagation Rules ****/
+
+
+typedef struct RuleName {
+int code;
+char *name;
+} RuleName;
+
+RuleName  rule_name_list[]  = {
+{AVERAGE_RULE, "avg"},
+{RANDOM_RULE, "rnd"},
+{MINIMUM_RULE, "max"},
+{MAXIMUM_RULE, "min"},
+{MAJORITY_RULE, "major"},
+{SAME_RULE, "same"},
+{-1, "end_marker"},
+};
+
+
+
+/******************************************************************************
+Initialize the property propagation rules for an element.  Default is to
+use averaging (AVERAGE_RULE) for creating all new properties.
+
+Entry:
+ply       - PLY object that this is for
+elem_name - name of the element that we're making the rules for
+
+Exit:
+returns pointer to the default rules
+******************************************************************************/
+
+PlyPropRules *init_rule_ply( PlyFile *ply, char *elem_name )
+{
+  int           i,j;
+  PlyElement   *elem;
+  PlyPropRules *rules;
+  PlyRuleList  *list;
+  int           found_prop;
+
+  elem = find_element ( ply, elem_name );
+  if ( elem == NULL )
+  {
+    fprintf ( stderr, "init_rule_ply: Can't find element '%s'\n", elem_name );
+    exit ( -1 );
+  }
+
+  rules = ( PlyPropRules *  ) myalloc ( sizeof ( PlyPropRules ) );
+  rules->elem = elem;
+  rules->rule_list = ( int * ) myalloc ( sizeof( int ) * elem->nprops );
+  rules->max_props = 0;
+  rules->nprops = 0;
+
+  /* default is to use averaging rule */
+  for ( i = 0; i < elem->nprops; i++ )
+    rules->rule_list[i] = AVERAGE_RULE;
+
+  /* see if there are other rules we should use */
+
+  if ( ply->rule_list == NULL )
+    return ( rules );
+
+  /* try to match the element, property and rule name */
+
+  for ( list = ply->rule_list; list != NULL; list = list->next )
+  {
+    if ( !equal_strings ( list->element, elem->name ) )
+      continue;
+
+    found_prop = 0;
+
+    for ( i = 0; i < elem->nprops; i++ )
+      if ( equal_strings ( list->property, elem->props[i]->name ) )
+      {
+        found_prop = 1;
+
+        /* look for matching rule name */
+        for ( j = 0; rule_name_list[j].code != -1; j++ )
+          if ( equal_strings ( list->name, rule_name_list[j].name ) )
+          {
+            rules->rule_list[i] = rule_name_list[j].code;
+            break;
+          }
+      }
+
+    if ( !found_prop )
+    {
+      fprintf ( stderr, "Can't find property '%s' for rule '%s'\n",
+      list->property, list->name );
+      continue;
+    }
+  }
+
+  return ( rules );
+}
+
+
+/******************************************************************************
+odify a property propagation rule.
+
+Entry:
+rules - rules for the element
+prop_name - name of the property whose rule we're modifying
+rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.)
+******************************************************************************/
+
+void modify_rule_ply( PlyPropRules *rules, char *prop_name, int rule_type )
+{
+  int         i;
+  PlyElement *elem  = rules->elem;
+
+  /* find the property and modify its rule type */
+
+  for ( i = 0; i < elem->nprops; i++ )
+    if ( equal_strings ( elem->props[i]->name, prop_name ) )
+    {
+      rules->rule_list[i] = rule_type;
+      return;
+    }
+
+  /* we didn't find the property if we get here */
+  fprintf ( stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name );
+  exit ( -1 );
+}
+
+
+/******************************************************************************
+Begin to create a set of properties from a set of propagation rules.
+
+Entry:
+ply   - PLY object whose rules we're preparing to use
+rules - rules for the element
+******************************************************************************/
+
+void start_props_ply( PlyFile *ply, PlyPropRules *rules )
+{
+  /*  PlyElement *elem  = rules->elem; */
+
+  /* save pointer to the rules in the PLY object */
+  ply->current_rules = rules;
+
+  /* get ready for new sets of properties to combine */
+  rules->nprops = 0;
+}
+
+
+/******************************************************************************
+Remember a set of properties and their weights for creating a new set of
+properties.
+
+Entry:
+weight      - weights for this set of properties
+other_props - the properties to use
+******************************************************************************/
+
+void weight_props_ply( PlyFile *ply, float weight, void *other_props )
+{
+  PlyPropRules *rules = ply->current_rules;
+
+  /* allocate space for properties and weights, if necessary */
+  if ( rules->max_props == 0 )
+  {
+    rules->max_props = 6;
+    rules->props = ( void * *  ) myalloc ( sizeof ( void * ) * rules->max_props );
+    rules->weights = ( float * ) myalloc ( sizeof ( float ) * rules->max_props );
+  }
+  if ( rules->nprops == rules->max_props )
+  {
+    rules->max_props *= 2;
+    rules->props = ( void * *  ) realloc ( rules->props,
+    sizeof ( void * ) * rules->max_props );
+    rules->weights = ( float * ) realloc ( rules->weights,
+    sizeof ( float ) * rules->max_props );
+  }
+
+  /* remember these new properties and their weights */
+
+  rules->props[rules->nprops] = other_props;
+  rules->weights[rules->nprops] = weight;
+  rules->nprops++;
+}
+
+
+/******************************************************************************
+Return a pointer to a new set of properties that have been created using
+a specified set of property combination rules and a given collection of
+"other" properties.
+
+Exit:
+returns a pointer to the new properties
+******************************************************************************/
+
+void *get_new_props_ply( PlyFile *ply )
+{
+  int             i,j;
+  static double  *vals;
+  static int      max_vals  = 0;
+  PlyPropRules   *rules     = ply->current_rules;
+  PlyElement     *elem      = rules->elem;
+  PlyProperty    *prop;
+  char           *data;
+  char           *new_data;
+  void           *ptr;
+  int             offset;
+  int             type;
+  double          double_val;
+  int             int_val;
+  unsigned int uint_val;
+  int random_pick;
+
+  /* return NULL if we've got no "other" properties */
+  if ( elem->other_size == 0 )
+  {
+    return ( NULL );
+  }
+
+  /* create room for combined other properties */
+  new_data = ( char * ) myalloc ( sizeof ( char ) * elem->other_size );
+
+  /* make sure there is enough room to store values we're to combine */
+
+  if ( max_vals == 0 )
+  {
+    max_vals = rules->nprops;
+    vals = ( double * ) myalloc ( sizeof ( double ) * rules->nprops );
+  }
+  if ( rules->nprops >= max_vals )
+  {
+    max_vals = rules->nprops;
+    vals = ( double * ) realloc ( vals, sizeof ( double ) * rules->nprops );
+  }
+
+  /* in case we need a random choice */
+  random_pick = ( int ) floor ( rules->nprops ); //* drand48());
+
+  /* calculate the combination for each "other" property of the element */
+
+  for ( i = 0; i < elem->nprops; i++ )
+  {
+    /* don't bother with properties we've been asked to store explicitly */
+    if ( elem->store_prop[i] )
+      continue;
+
+    prop = elem->props[i];
+    offset = prop->offset;
+    type = prop->external_type;
+
+    /* collect together all the values we're to combine */
+
+    for ( j = 0; j < rules->nprops; j++ )
+    {
+      data = ( char * ) rules->props[j];
+      ptr = ( void * ) ( data + offset );
+      get_stored_item ( ( void * ) ptr, type, &int_val, &uint_val, &double_val );
+      vals[j] = double_val;
+    }
+
+    /* calculate the combined value */
+
+    switch ( rules->rule_list[i] )
+    {
+      case AVERAGE_RULE:
+        {
+        double  sum         = 0;
+        double  weight_sum  = 0;
+        for ( j = 0; j < rules->nprops; j++ )
+        {
+          sum += vals[j] * rules->weights[j];
+          weight_sum += rules->weights[j];
+        }
+        double_val = sum / weight_sum;
+        break;
+      }
+      case MINIMUM_RULE:
+        {
+        double_val = vals[0];
+        for ( j = 1; j < rules->nprops; j++ )
+          if ( double_val > vals[j] )
+            double_val = vals[j];
+        break;
+      }
+      case MAXIMUM_RULE:
+        {
+        double_val = vals[0];
+        for ( j = 1; j < rules->nprops; j++ )
+          if ( double_val < vals[j] )
+            double_val = vals[j];
+        break;
+      }
+      case RANDOM_RULE:
+        {
+        double_val = vals[random_pick];
+        break;
+      }
+      case SAME_RULE:
+        {
+        double_val = vals[0];
+        for ( j = 1; j < rules->nprops; j++ )
+          if ( double_val != vals[j] )
+          {
+            fprintf ( stderr,
+            "get_new_props_ply: Error combining properties that should be the same.\n" );
+            exit ( -1 );
+          }
+        break;
+      }
+      default:
+        fprintf ( stderr, "get_new_props_ply: Bad rule = %d\n",
+        rules->rule_list[i] );
+        exit ( -1 );
+    }
+
+    /* store the combined value */
+
+    int_val = ( int ) double_val;
+    uint_val = ( unsigned int ) double_val;
+    ptr = ( void * ) ( new_data + offset );
+    store_item ( ( char * ) ptr, type, int_val, uint_val, double_val );
+  }
+
+  return ( ( void * ) new_data );
+}
+
+
+/******************************************************************************
+Set the list of user-specified property combination rules.
+******************************************************************************/
+
+void set_prop_rules_ply( PlyFile *ply, PlyRuleList *prop_rules )
+{
+  ply->rule_list = prop_rules;
+}
+
+
+/******************************************************************************
+Append a property rule to a growing list of user-specified rules.
+
+Entry:
+rule_list - current rule list
+name      - name of property combination rule
+property  - "element.property" says which property the rule affects
+
+Exit:
+returns pointer to the new rule list
+******************************************************************************/
+
+PlyRuleList *append_prop_rule( PlyRuleList *rule_list, char *name, char *property )
+{
+  PlyRuleList  *rule;
+  PlyRuleList  *rule_ptr;
+  char         *str,*str2;
+  char         *ptr;
+
+  /* find . */
+  str = strdup ( property );
+  for ( ptr = str; *ptr != '\0' && *ptr != '.'; ptr++ )
+    ;
+
+  /* split string at . */
+  if ( *ptr == '.' )
+  {
+    *ptr = '\0';
+    str2 = ptr + 1;
+  }
+  else
+  {
+    fprintf ( stderr, "Can't find property '%s' for rule '%s'\n",
+    property, name );
+    return ( rule_list );
+  }
+
+  rule = ( PlyRuleList *  ) malloc ( sizeof ( PlyRuleList ) );
+  rule->name = name;
+  rule->element = str;
+  rule->property = str2;
+  rule->next = NULL;
+
+  /* either start rule list or append to it */
+
+  if ( rule_list == NULL )
+    rule_list = rule;
+  else
+  {
+    /* append new rule to current list */
+    rule_ptr = rule_list;
+    while ( rule_ptr->next != NULL )
+      rule_ptr = rule_ptr->next;
+    rule_ptr->next = rule;
+  }
+
+  /* return pointer to list */
+
+  return ( rule_list );
+}
+
+
+/******************************************************************************
+See if a name matches the name of any property combination rules.
+
+Entry:
+name - name of rule we're trying to match
+
+Exit:
+returns 1 if we find a match, 0 if not
+******************************************************************************/
+
+int matches_rule_name( char *name )
+{
+  int i;
+
+  for ( i = 0; rule_name_list[i].code != -1; i++ )
+    if ( equal_strings ( rule_name_list[i].name, name ) )
+      return ( 1 );
+
+  return ( 0 );
+}
+
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h
new file mode 100755
index 0000000000000000000000000000000000000000..1925d5e584371f4713a93860f6cdfd93601d1ec4
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/MarchingCubes/ply.h
@@ -0,0 +1,233 @@
+/*
+
+Header for PLY polygon files.
+
+- Greg Turk
+
+A PLY file contains a single polygonal _object_.
+
+An object is composed of lists of _elements_.  Typical elements are
+vertices, faces, edges and materials.
+
+Each type of element for a given object has one or more _properties_
+associated with the element type.  For instance, a vertex element may
+have as properties three floating-point values x,y,z and three unsigned
+chars for red, green and blue.
+
+-----------------------------------------------------------------------
+
+Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose is hereby granted without fee, provided
+that the above copyright notice and this permission notice appear in
+all copies of this software and that you do not sell the software.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+#ifndef __PLY_H__
+#define __PLY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+
+#define PLY_ASCII      1        /* ascii PLY file */
+#define PLY_BINARY_BE  2        /* binary PLY file, big endian */
+#define PLY_BINARY_LE  3        /* binary PLY file, little endian */
+
+#define PLY_OKAY    0           /* ply routine worked okay */
+#define PLY_ERROR  -1           /* error in ply routine */
+
+/* scalar data types supported by PLY format */
+
+#define StartType  0
+#define Int8       1
+#define Int16      2
+#define Int32      3
+#define Uint8      4
+#define Uint16     5
+#define Uint32     6
+#define Float32    7
+#define Float64    8
+#define EndType    9
+
+#define  PLY_SCALAR  0
+#define  PLY_LIST    1
+#define  PLY_STRING  2
+
+
+typedef struct PlyProperty {    /* description of a property */
+
+char *name;                   /* property name */
+int external_type;            /* file's data type */
+int internal_type;            /* program's data type */
+int offset;                   /* offset bytes of prop in a struct */
+
+int is_list;                  /* 0 = scalar, 1 = list, 2 = char string */
+int count_external;           /* file's count type */
+int count_internal;           /* program's count type */
+int count_offset;             /* offset byte for list count */
+
+} PlyProperty;
+
+typedef struct PlyElement {     /* description of an element */
+char *name;                   /* element name */
+int num;                      /* number of elements in this object */
+int size;                     /* size of element (bytes) or -1 if variable */
+int nprops;                   /* number of properties for this element */
+PlyProperty **props;          /* list of properties in the file */
+char *store_prop;             /* flags: property wanted by user? */
+int other_offset;             /* offset to un-asked-for props, or -1 if none*/
+int other_size;               /* size of other_props structure */
+} PlyElement;
+
+typedef struct PlyOtherProp {   /* describes other properties in an element */
+char *name;                   /* element name */
+int size;                     /* size of other_props */
+int nprops;                   /* number of properties in other_props */
+PlyProperty **props;          /* list of properties in other_props */
+} PlyOtherProp;
+
+typedef struct OtherData { /* for storing other_props for an other element */
+void *other_props;
+} OtherData;
+
+typedef struct OtherElem {     /* data for one "other" element */
+char *elem_name;             /* names of other elements */
+int elem_count;              /* count of instances of each element */
+OtherData **other_data;      /* actual property data for the elements */
+PlyOtherProp *other_props;   /* description of the property data */
+} OtherElem;
+
+typedef struct PlyOtherElems {  /* "other" elements, not interpreted by user */
+int num_elems;                /* number of other elements */
+OtherElem *other_list;        /* list of data for other elements */
+} PlyOtherElems;
+
+#define AVERAGE_RULE  1
+#define MAJORITY_RULE 2
+#define MINIMUM_RULE  3
+#define MAXIMUM_RULE  4
+#define SAME_RULE     5
+#define RANDOM_RULE   6
+
+typedef struct PlyPropRules {   /* rules for combining "other" properties */
+PlyElement *elem;      /* element whose rules we are making */
+int *rule_list;        /* types of rules (AVERAGE_PLY, MAJORITY_PLY, etc.) */
+int nprops;            /* number of properties we're combining so far */
+int max_props;         /* maximum number of properties we have room for now */
+void **props;          /* list of properties we're combining */
+float *weights;        /* list of weights of the properties */
+} PlyPropRules;
+
+typedef struct PlyRuleList {
+char *name;                  /* name of the rule */
+char *element;               /* name of element that rule applies to */
+char *property;              /* name of property that rule applies to */
+struct PlyRuleList *next;    /* pointer for linked list of rules */
+} PlyRuleList;
+
+typedef struct PlyFile {        /* description of PLY file */
+FILE *fp;                     /* file pointer */
+int file_type;                /* ascii or binary */
+float version;                /* version number of file */
+int num_elem_types;           /* number of element types of object */
+PlyElement **elems;           /* list of elements */
+int num_comments;             /* number of comments */
+char **comments;              /* list of comments */
+int num_obj_info;             /* number of items of object information */
+char **obj_info;              /* list of object info items */
+PlyElement *which_elem;       /* element we're currently reading or writing */
+PlyOtherElems *other_elems;   /* "other" elements from a PLY file */
+PlyPropRules *current_rules;  /* current propagation rules */
+PlyRuleList *rule_list;       /* rule list from user */
+} PlyFile;
+
+/* memory allocation */
+/*
+extern char *my_alloc();
+*/
+#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
+
+
+/* old routines */
+
+#if 0
+extern PlyFile *ply_write(FILE *, int, char **, int);
+extern PlyFile *ply_read(FILE *, int *, char ***);
+extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *);
+extern void ply_close(PlyFile *);
+extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int);
+#endif
+
+extern void     ply_describe_property( PlyFile * , char * , PlyProperty * );
+extern void     ply_get_property( PlyFile * , char * , PlyProperty * );
+extern void     ply_get_element( PlyFile * , void * );
+
+
+/*** delcaration of routines ***/
+
+PlyOtherElems  *get_other_element_ply( PlyFile * );
+
+PlyFile        *read_ply( FILE * );
+PlyFile        *write_ply( FILE * , int, char ** , int );
+extern PlyFile *open_for_writing_ply( char * , int, char ** , int );
+void            close_ply( PlyFile * );
+void            free_ply( PlyFile * );
+
+void            get_info_ply( PlyFile * , float * , int * );
+void            free_other_elements_ply( PlyOtherElems * );
+
+void            append_comment_ply( PlyFile * , char * );
+void            append_obj_info_ply( PlyFile * , char * );
+void            copy_comments_ply( PlyFile * , PlyFile * );
+void            copy_obj_info_ply( PlyFile * , PlyFile * );
+char*          *get_comments_ply( PlyFile * , int * );
+char*          *get_obj_info_ply( PlyFile * , int * );
+
+char*          *get_element_list_ply( PlyFile * , int * );
+int             setup_property_ply( PlyFile * , PlyProperty * );
+void            get_element_ply( PlyFile * , void * );
+char           *setup_element_read_ply( PlyFile * , int, int * );
+PlyOtherProp   *get_other_properties_ply( PlyFile * , int );
+
+void            element_count_ply( PlyFile * , char * , int );
+void            describe_element_ply( PlyFile * , char * , int );
+void            describe_property_ply( PlyFile * , PlyProperty * );
+void            describe_other_properties_ply( PlyFile * , PlyOtherProp * , int );
+void            describe_other_elements_ply( PlyFile * , PlyOtherElems * );
+void            get_element_setup_ply( PlyFile * , char * , int, PlyProperty * );
+PlyProperty*   *get_element_description_ply( PlyFile * , char * , int * , int * );
+void            element_layout_ply( PlyFile * , char * , int, int, PlyProperty * );
+
+void            header_complete_ply( PlyFile * );
+void            put_element_setup_ply( PlyFile * , char * );
+void            put_element_ply( PlyFile * , void * );
+void            put_other_elements_ply( PlyFile * );
+
+PlyPropRules   *init_rule_ply( PlyFile * , char * );
+void            modify_rule_ply( PlyPropRules * , char * , int );
+void            start_props_ply( PlyFile * , PlyPropRules * );
+void            weight_props_ply( PlyFile * , float, void * );
+void           *get_new_props_ply( PlyFile * );
+void            set_prop_rules_ply( PlyFile * , PlyRuleList * );
+PlyRuleList    *append_prop_rule( PlyRuleList * , char * , char * );
+int             matches_rule_name( char * );
+
+int             equal_strings( char * , char * );
+char           *recreate_command_line( int, char *argv[] );
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !__PLY_H__ */
+
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C
new file mode 100644
index 0000000000000000000000000000000000000000..adc46f762378c75dafefa76bac50f125a5793b12
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/cvMeshSurfaceSimplify.C
@@ -0,0 +1,350 @@
+/*---------------------------------------------------------------------------*\
+ =========                   |
+ \\      /   F ield          | OpenFOAM: The Open Source CFD Toolbox
+  \\    /    O peration      |
+   \\  /     A nd            | Copyright (C) 2012 OpenFOAM Foundation
+    \\/      M anipulation   |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Application
+    cvMeshSurfaceSimplify
+
+Description
+    Simplifies surfaces by resampling.
+
+    Uses Thomas Lewiner's topology preserving MarchingCubes.
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "searchableSurfaces.H"
+#include "conformationSurfaces.H"
+#include "triSurfaceMesh.H"
+
+#include "MarchingCubes.h"
+
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::addNote
+    (
+        "Re-sample surfaces used in cvMesh operation"
+    );
+    //argList::validArgs.append("inputFile");
+    argList::validArgs.append("(nx ny nz)");
+    argList::validArgs.append("outputName");
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+    runTime.functionObjects().off();
+
+    const Vector<label> n(IStringStream(args.args()[1])());
+    const fileName exportName = args.args()[2];
+
+    Info<< "Reading surfaces as specified in the cvMeshDict and"
+        << " writing re-sampled " << n << " to " << exportName
+        << nl << endl;
+
+    cpuTime timer;
+
+    IOdictionary cvMeshDict
+    (
+        IOobject
+        (
+            "cvMeshDict",
+            runTime.system(),
+            runTime,
+            IOobject::MUST_READ_IF_MODIFIED,
+            IOobject::NO_WRITE
+        )
+    );
+
+    // Define/load all geometry
+    searchableSurfaces allGeometry
+    (
+        IOobject
+        (
+            "cvSearchableSurfaces",
+            runTime.constant(),
+            "triSurface",
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        ),
+        cvMeshDict.subDict("geometry")
+    );
+
+    Info<< "Geometry read in = "
+        << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+    Random rndGen(64293*Pstream::myProcNo());
+
+    conformationSurfaces geometryToConformTo
+    (
+        runTime,
+        rndGen,
+        allGeometry,
+        cvMeshDict.subDict("surfaceConformation")
+    );
+
+    Info<< "Set up geometry in = "
+        << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+
+    // Extend
+    treeBoundBox bb = geometryToConformTo.globalBounds();
+    {
+        const vector smallVec = 0.1*bb.span();
+        bb.min() -= smallVec;
+        bb.max() += smallVec;
+    }
+
+    Info<< "Meshing to bounding box " << bb << nl << endl;
+
+    const vector span(bb.span());
+    const vector d
+    (
+        span.x()/(n.x()-1),
+        span.y()/(n.y()-1),
+        span.z()/(n.z()-1)
+    );
+
+    MarchingCubes mc(span.x(), span.y(), span.z() ) ;
+    mc.set_resolution(n.x(), n.y(), n.z());
+    mc.init_all() ;
+
+
+    // Generate points
+    pointField points(mc.size_x()*mc.size_y()*mc.size_z());
+    label pointI = 0;
+
+    point pt;
+    for( int k = 0 ; k < mc.size_z() ; k++ )
+    {
+        pt.z() = bb.min().z() + k*d.z();
+        for( int j = 0 ; j < mc.size_y() ; j++ )
+        {
+            pt.y() = bb.min().y() + j*d.y();
+            for( int i = 0 ; i < mc.size_x() ; i++ )
+            {
+                pt.x() = bb.min().x() + i*d.x();
+                points[pointI++] = pt;
+            }
+        }
+    }
+
+    Info<< "Generated " << points.size() << " sampling points in = "
+        << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+    // Compute data
+    const searchableSurfaces& geometry = geometryToConformTo.geometry();
+    const labelList& surfaces = geometryToConformTo.surfaces();
+
+    scalarField signedDist;
+    labelList nearestSurfaces;
+    searchableSurfacesQueries::signedDistance
+    (
+        geometry,
+        surfaces,
+        points,
+        scalarField(points.size(), sqr(GREAT)),
+        nearestSurfaces,
+        signedDist
+    );
+
+    // Fill elements
+    pointI = 0;
+    for( int k = 0 ; k < mc.size_z() ; k++ )
+    {
+        for( int j = 0 ; j < mc.size_y() ; j++ )
+        {
+            for( int i = 0 ; i < mc.size_x() ; i++ )
+            {
+                mc.set_data(float(signedDist[pointI++]), i, j, k);
+            }
+        }
+    }
+
+    Info<< "Determined signed distance in = "
+        << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+    mc.run() ;
+
+    Info<< "Constructed iso surface in = "
+        << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+    mc.clean_temps() ;
+
+
+
+    // Write output file
+    if (mc.ntrigs() > 0)
+    {
+        Triangle* triangles = mc.triangles();
+        List<labelledTri> tris(mc.ntrigs());
+        forAll(tris, triI)
+        {
+            tris[triI] = labelledTri
+            (
+                triangles[triI].v1,
+                triangles[triI].v2,
+                triangles[triI].v3,
+                0                       // region
+            );
+        }
+
+
+        Vertex* vertices = mc.vertices();
+        pointField points(mc.nverts());
+        forAll(points, pointI)
+        {
+            Vertex& v = vertices[pointI];
+            points[pointI] = point
+            (
+                bb.min().x() + v.x*span.x()/mc.size_x(),
+                bb.min().y() + v.y*span.y()/mc.size_y(),
+                bb.min().z() + v.z*span.z()/mc.size_z()
+            );
+        }
+
+
+        // Find correspondence to original surfaces
+        labelList regionOffsets(surfaces.size());
+        label nRegions = 0;
+        forAll(surfaces, i)
+        {
+            const wordList& regions = geometry[surfaces[i]].regions();
+            regionOffsets[i] = nRegions;
+            nRegions += regions.size();
+        }
+
+
+        geometricSurfacePatchList patches(nRegions);
+        nRegions = 0;
+        forAll(surfaces, i)
+        {
+            const wordList& regions = geometry[surfaces[i]].regions();
+
+            forAll(regions, regionI)
+            {
+                patches[nRegions] = geometricSurfacePatch
+                (
+                    "patch",
+                    geometry[surfaces[i]].name() + "_" + regions[regionI],
+                    nRegions
+                );
+                nRegions++;
+            }
+        }
+
+        triSurface s(tris, patches, points, true);
+
+        Info<< "Extracted triSurface in = "
+            << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+
+        // Find out region on local surface of nearest point
+        {
+            List<pointIndexHit> hitInfo;
+            labelList hitSurfaces;
+            geometryToConformTo.findSurfaceNearest
+            (
+                s.faceCentres(),
+                scalarField(s.size(), sqr(GREAT)),
+                hitInfo,
+                hitSurfaces
+            );
+
+            // Get region
+            DynamicList<pointIndexHit> surfInfo(hitSurfaces.size());
+            DynamicList<label> surfIndices(hitSurfaces.size());
+
+            forAll(surfaces, surfI)
+            {
+                // Extract info on this surface
+                surfInfo.clear();
+                surfIndices.clear();
+                forAll(hitSurfaces, triI)
+                {
+                    if (hitSurfaces[triI] == surfI)
+                    {
+                        surfInfo.append(hitInfo[triI]);
+                        surfIndices.append(triI);
+                    }
+                }
+
+                // Calculate sideness of these surface points
+                labelList region;
+                geometry[surfaces[surfI]].getRegion(surfInfo, region);
+
+                forAll(region, i)
+                {
+                    label triI = surfIndices[i];
+                    s[triI].region() = regionOffsets[surfI]+region[i];
+                }
+            }
+        }
+
+        Info<< "Re-patched surface in = "
+            << timer.cpuTimeIncrement() << " s." << nl << endl;
+
+        triSurfaceMesh smesh
+        (
+            IOobject
+            (
+                exportName,
+                runTime.constant(), // instance
+                "triSurface",
+                runTime,            // registry
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            s
+        );
+
+        Info<< "writing surfMesh:\n  "
+            << smesh.searchableSurface::objectPath() << nl << endl;
+        smesh.searchableSurface::write();
+
+        Info<< "Written surface in = "
+            << timer.cpuTimeIncrement() << " s." << nl << endl;
+    }
+
+    mc.clean_all() ;
+
+
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip
new file mode 100644
index 0000000000000000000000000000000000000000..bb15279b270eb84738e70467383317685d53e425
Binary files /dev/null and b/applications/utilities/mesh/generation/cvMesh/cvMeshSurfaceSimplify/marching_cubes_jgt.zip differ
diff --git a/applications/utilities/postProcessing/sampling/sample/sampleDict b/applications/utilities/postProcessing/sampling/sample/sampleDict
index 8684d769326caccad8e9d16984e8129ec4fe54f4..b55b190bf71ce090805ab9f9a7dd3ff47a493573 100644
--- a/applications/utilities/postProcessing/sampling/sample/sampleDict
+++ b/applications/utilities/postProcessing/sampling/sample/sampleDict
@@ -272,10 +272,12 @@ surfaces
         // Distance to surface
         distance        0.0;
 
+        //cell            false;// optional: use isoSurface instead
+                                // of isoSurfaceCell
         interpolate     false;
-        regularise      false;       // Optional: do not simplify
-        // mergeTol        1e-10;    // Optional: fraction of mesh bounding box
-                                     // to merge points (default=1e-6)
+        regularise      false;  // Optional: do not simplify
+        // mergeTol 1e-10;      // Optional: fraction of mesh bounding box
+                                // to merge points (default=1e-6)
     }
 
     triSurfaceSampling
diff --git a/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.C b/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.C
index 17ef34fb6f710730e879bcdc4a2005d7b320bc07..024f7d27ecf4203c1684e3295bc7e20ad52692fc 100644
--- a/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.C
+++ b/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.C
@@ -379,6 +379,124 @@ Foam::label Foam::indexedOctree<Type>::compactContents
 }
 
 
+template <class Type>
+bool Foam::indexedOctree<Type>::quickCircumsphereRejection
+(
+    const label nodeI,
+    const point& cc,
+    const scalar crSqr,
+    const List<scalar>& nearestDistances
+) const
+{
+    const node& nod = nodes_[nodeI];
+
+    volumeType nodeType = volumeType(nodeTypes_.get(nodeI<<3));
+
+    //scalar boxDist = nearestDistances[nodeI] + 0.5*nod.bb_.mag();
+    scalar boxDist = crSqr + magSqr(cc - nod.bb_.midpoint());
+
+    if
+    (
+         nodeType == INSIDE
+      //&& (crSqr < sqr(boxDist))
+      && (boxDist < sqr(nearestDistances[nodeI]))
+    )
+    {
+        return true;
+    }
+    else
+    {
+        direction octant = nod.bb_.subOctant(cc);
+
+        labelBits index = nod.subNodes_[octant];
+
+        if (isNode(index))
+        {
+            return quickCircumsphereRejection
+            (
+                getNode(index),
+                cc,
+                crSqr,
+                nearestDistances
+            );
+        }
+        else
+        {
+            return false;
+        }
+    }
+}
+
+
+template <class Type>
+bool Foam::indexedOctree<Type>::quickCircumsphereRejection
+(
+    const point& cc,
+    const scalar crSqr,
+    const List<scalar>& nearestDistances
+) const
+{
+    if (nodes_.size())
+    {
+        return quickCircumsphereRejection
+        (
+            0,
+            cc,
+            crSqr,
+            nearestDistances
+        );
+    }
+
+    return false;
+}
+
+
+template <class Type>
+Foam::scalar
+Foam::indexedOctree<Type>::calcNearestDistance
+(
+    const label nodeI
+) const
+{
+    const node& nod = nodes_[nodeI];
+
+    const point& nodeCentre = nod.bb_.midpoint();
+
+    scalar nearestDistance = 0.0;
+
+    pointIndexHit pHit = findNearest(nodeCentre, sqr(GREAT));
+
+    if (pHit.hit())
+    {
+        nearestDistance = mag(pHit.hitPoint() - nodeCentre);
+    }
+    else
+    {
+        WarningIn("Foam::indexedOctree<Type>::calcNearestDistance(const label)")
+            << "Cannot calculate distance of nearest point on surface from "
+            << "the midpoint of the octree node. Returning distance of zero."
+            << endl;
+    }
+
+    return nearestDistance;
+}
+
+
+template <class Type>
+Foam::List<Foam::scalar>
+Foam::indexedOctree<Type>::calcNearestDistance() const
+{
+    List<scalar> nearestDistances(nodes_.size());
+
+    forAll(nearestDistances, nodeI)
+    {
+        nearestDistances[nodeI] = calcNearestDistance(nodeI);
+    }
+
+    return nearestDistances;
+}
+
+
 // Pre-calculates wherever possible the volume status per node/subnode.
 // Recurses to determine status of lowest level boxes. Level above is
 // combination of octants below.
@@ -540,6 +658,67 @@ Foam::indexedOctree<Type>::getSide
 // ~~~~~~~~~~~~~~
 //
 
+
+//template <class Type>
+//bool Foam::indexedOctree<Type>::findAnyOverlap
+//(
+//    const label nodeI,
+//    const point& sample,
+//    const scalar nearestDistSqr
+//) const
+//{
+//    const node& nod = nodes_[nodeI];
+//
+//    // Determine order to walk through octants
+//    FixedList<direction, 8> octantOrder;
+//    nod.bb_.searchOrder(sample, octantOrder);
+//
+//    // Go into all suboctants (one containing sample first) and update
+//    // nearest.
+//    for (direction i = 0; i < 8; i++)
+//    {
+//        direction octant = octantOrder[i];
+//
+//        labelBits index = nod.subNodes_[octant];
+//
+//        if (isNode(index))
+//        {
+//            label subNodeI = getNode(index);
+//
+//            const treeBoundBox& subBb = nodes_[subNodeI].bb_;
+//
+//            if (overlaps(subBb.min(), subBb.max(), nearestDistSqr, sample))
+//            {
+//                return findAnyOverlap
+//                (
+//                    subNodeI,
+//                    sample,
+//                    nearestDistSqr
+//                );
+//            }
+//        }
+//        else if (isContent(index))
+//        {
+//            if
+//            (
+//                overlaps
+//                (
+//                    nod.bb_,
+//                    octant,
+//                    nearestDistSqr,
+//                    sample
+//                )
+//            )
+//            {
+//                return true;
+//            }
+//        }
+//    }
+//
+//    return false;
+//}
+
+
 // Find nearest point starting from nodeI
 template <class Type>
 void Foam::indexedOctree<Type>::findNearest
@@ -1614,7 +1793,6 @@ void Foam::indexedOctree<Type>::traverseNode
         }
     }
 
-
     const node& nod = nodes_[nodeI];
 
     labelBits index = nod.subNodes_[octant];
@@ -1781,6 +1959,11 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
     label i = 0;
     for (; i < 100000; i++)
     {
+//        if (isLineInsideOrOutside(nodeI, treeStart, treeEnd))
+//        {
+//            return hitInfo;
+//        }
+
         // Ray-trace to end of current node. Updates point (either on triangle
         // in case of hit or on node bounding box in case of miss)
 
@@ -1935,6 +2118,38 @@ Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
 }
 
 
+//template <class Type>
+//bool Foam::indexedOctree<Type>::isLineInsideOrOutside
+//(
+//    const label nodeI,
+//    const point& start,
+//    const point& end
+//) const
+//{
+//    const node& nod = nodes_[nodeI];
+//
+//    direction startOctant = nod.bb_.subOctant(start);
+//    direction endOctant = nod.bb_.subOctant(end);
+//
+//    if (startOctant == endOctant)
+//    {
+//        volumeType startOctantType
+//            = volumeType(nodeTypes_.get((nodeI<<3) + startOctant));
+//
+//        if
+//        (
+//            startOctantType == INSIDE || startOctantType == OUTSIDE
+//        )
+//        {
+//            //Info<< nodeI << " | " << start << " " << end << endl;
+//            return true;
+//        }
+//    }
+//
+//    return false;
+//}
+
+
 // Find first intersection
 template <class Type>
 Foam::pointIndexHit Foam::indexedOctree<Type>::findLine
@@ -2559,6 +2774,27 @@ Foam::scalar& Foam::indexedOctree<Type>::perturbTol()
 }
 
 
+//template <class Type>
+//bool Foam::indexedOctree<Type>::findAnyOverlap
+//(
+//    const point& sample,
+//    const scalar startDistSqr
+//) const
+//{
+//    if (nodes_.size())
+//    {
+//        return findAnyOverlap
+//        (
+//            0,
+//            sample,
+//            startDistSqr
+//        );
+//    }
+//
+//    return false;
+//}
+
+
 template <class Type>
 Foam::pointIndexHit Foam::indexedOctree<Type>::findNearest
 (
diff --git a/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.H b/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.H
index aa493f34e92c40b7adb599d4a15dac0d0d55af1c..40ee7a8a32cf54d0403a53fd477c4046cecf5cbc 100644
--- a/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.H
+++ b/src/OpenFOAM/algorithms/indexedOctree/indexedOctree.H
@@ -201,6 +201,16 @@ private:
                 label& compactI
             );
 
+            scalar calcNearestDistance(const label nodeI) const;
+
+            bool quickCircumsphereRejection
+            (
+                const label nodeI,
+                const point& cc,
+                const scalar crSqr,
+                const List<scalar>& nearestDistances
+            ) const;
+
             //- Determine inside/outside per node (mixed if cannot be
             //  determined). Only valid for closed shapes.
             volumeType calcVolumeType(const label nodeI) const;
@@ -320,6 +330,13 @@ private:
                 const bool verbose = false
             ) const;
 
+//            bool isLineInsideOrOutside
+//            (
+//                const label nodeI,
+//                const point& start,
+//                const point& end
+//            ) const;
+
             //- Find any or nearest intersection of line between start and end.
             pointIndexHit findLine
             (
@@ -532,6 +549,19 @@ public:
                 const scalar nearestDistSqr
             ) const;
 
+//            bool findAnyOverlap
+//            (
+//                const point& sample,
+//                const scalar nearestDistSqr
+//            ) const;
+//
+//            bool findAnyOverlap
+//            (
+//                const label nodeI,
+//                const point& sample,
+//                const scalar nearestDistSqr
+//            ) const;
+
             //- Low level: calculate nearest starting from subnode.
             void findNearest
             (
@@ -628,6 +658,16 @@ public:
                 CompareOp& cop
             ) const;
 
+            //- Return a list containing the nearest distance of nodes to any
+            //  shapes
+            List<scalar> calcNearestDistance() const;
+
+            bool quickCircumsphereRejection
+            (
+                const point& cc,
+                const scalar crSqr,
+                const List<scalar>& nearestDistances
+            ) const;
 
         // Write
 
diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricBoundaryField.C b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricBoundaryField.C
index 0b2a45c473897ded3db69456b1ed73b6041817dd..448a009caba0396c33dfb38009d824e71d266113 100644
--- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricBoundaryField.C
+++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricBoundaryField.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -252,7 +252,7 @@ GeometricBoundaryField
     // Patch or patch-groups. (using non-wild card entries of dictionaries)
     forAllConstIter(dictionary, dict, iter)
     {
-        if (iter().isDict())
+        if (iter().isDict() && !iter().keyword().isPattern())
         {
             const labelList patchIDs = bmesh_.findIndices
             (
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C
index 2465c726968f48d6a27ab19039edce6012d8cc53..8a9136b68a55c5eb00db3a8600aebb3244bdaaf8 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C
@@ -555,9 +555,13 @@ Foam::List<Foam::tetIndices> Foam::polyMeshTetDecomposition::faceTetIndices
     {
         WarningIn
         (
-            "Foam::List<Foam::FixedList<Foam::label, 4> >"
-            "Foam::Cloud<ParticleType>::"
-            "faceTetIndices(label fI, label cI) const"
+            "Foam::List<Foam::tetIndices> "
+            "Foam::polyMeshTetDecomposition::faceTetIndices"
+            "("
+                "const polyMesh&, "
+                "label, "
+                "label"
+            ")"
         )
             << "No base point for face " << fI << ", " << f
             << ", produces a valid tet decomposition."
diff --git a/src/dynamicMesh/motionSmoother/motionSmoother.C b/src/dynamicMesh/motionSmoother/motionSmoother.C
index 4552d463200beb0b74551bf4224abd4a57011817..cace37690b88521f6927944fbb27617ca74f5d30 100644
--- a/src/dynamicMesh/motionSmoother/motionSmoother.C
+++ b/src/dynamicMesh/motionSmoother/motionSmoother.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -271,9 +271,28 @@ Foam::labelHashSet Foam::motionSmoother::getPoints
 }
 
 
+Foam::tmp<Foam::scalarField> Foam::motionSmoother::calcEdgeWeights
+(
+    const pointField& points
+) const
+{
+    const edgeList& edges = mesh_.edges();
+
+    tmp<scalarField> twght(new scalarField(edges.size()));
+    scalarField& wght = twght();
+
+    forAll(edges, edgeI)
+    {
+        wght[edgeI] = min(GREAT, 1.0/edges[edgeI].mag(points));
+    }
+    return twght;
+}
+
+
 // Smooth on selected points (usually patch points)
 void Foam::motionSmoother::minSmooth
 (
+    const scalarField& edgeWeights,
     const PackedBoolList& isAffectedPoint,
     const labelList& meshPoints,
     const pointScalarField& fld,
@@ -283,7 +302,7 @@ void Foam::motionSmoother::minSmooth
     tmp<pointScalarField> tavgFld = avg
     (
         fld,
-        scalarField(mesh_.nEdges(), 1.0)    // uniform weighting
+        edgeWeights //scalarField(mesh_.nEdges(), 1.0)    // uniform weighting
     );
     const pointScalarField& avgFld = tavgFld();
 
@@ -308,6 +327,7 @@ void Foam::motionSmoother::minSmooth
 // Smooth on all internal points
 void Foam::motionSmoother::minSmooth
 (
+    const scalarField& edgeWeights,
     const PackedBoolList& isAffectedPoint,
     const pointScalarField& fld,
     pointScalarField& newFld
@@ -316,7 +336,7 @@ void Foam::motionSmoother::minSmooth
     tmp<pointScalarField> tavgFld = avg
     (
         fld,
-        scalarField(mesh_.nEdges(), 1.0)    // uniform weighting
+        edgeWeights //scalarField(mesh_.nEdges(), 1.0)    // uniform weighting
     );
     const pointScalarField& avgFld = tavgFld();
 
@@ -337,7 +357,7 @@ void Foam::motionSmoother::minSmooth
 }
 
 
-// Scale on selected points
+// Scale on all internal points
 void Foam::motionSmoother::scaleField
 (
     const labelHashSet& pointLabels,
@@ -378,6 +398,47 @@ void Foam::motionSmoother::scaleField
 }
 
 
+// Lower on internal points
+void Foam::motionSmoother::subtractField
+(
+    const labelHashSet& pointLabels,
+    const scalar f,
+    pointScalarField& fld
+) const
+{
+    forAllConstIter(labelHashSet, pointLabels, iter)
+    {
+        if (isInternalPoint(iter.key()))
+        {
+            fld[iter.key()] = max(0.0, fld[iter.key()]-f);
+        }
+    }
+    fld.correctBoundaryConditions();
+    applyCornerConstraints(fld);
+}
+
+
+// Scale on selected points (usually patch points)
+void Foam::motionSmoother::subtractField
+(
+    const labelList& meshPoints,
+    const labelHashSet& pointLabels,
+    const scalar f,
+    pointScalarField& fld
+) const
+{
+    forAll(meshPoints, i)
+    {
+        label pointI = meshPoints[i];
+
+        if (pointLabels.found(pointI))
+        {
+            fld[pointI] = max(0.0, fld[pointI]-f);
+        }
+    }
+}
+
+
 bool Foam::motionSmoother::isInternalPoint(const label pointI) const
 {
     return isInternalPoint_.get(pointI) == 1;
@@ -1081,13 +1142,17 @@ bool Foam::motionSmoother::scaleMesh
         {
             // Scale conflicting patch points
             scaleField(pp_.meshPoints(), usedPoints, errorReduction, scale_);
+            //subtractField(pp_.meshPoints(), usedPoints, 0.1, scale_);
         }
         if (smoothMesh)
         {
             // Scale conflicting internal points
             scaleField(usedPoints, errorReduction, scale_);
+            //subtractField(usedPoints, 0.1, scale_);
         }
 
+        scalarField eWeights(calcEdgeWeights(oldPoints_));
+
         for (label i = 0; i < nSmoothScale; i++)
         {
             if (adaptPatchIDs_.size())
@@ -1096,6 +1161,7 @@ bool Foam::motionSmoother::scaleMesh
                 pointScalarField oldScale(scale_);
                 minSmooth
                 (
+                    eWeights,
                     isAffectedPoint,
                     pp_.meshPoints(),
                     oldScale,
@@ -1107,7 +1173,7 @@ bool Foam::motionSmoother::scaleMesh
             {
                 // Smooth internal values
                 pointScalarField oldScale(scale_);
-                minSmooth(isAffectedPoint, oldScale, scale_);
+                minSmooth(eWeights, isAffectedPoint, oldScale, scale_);
                 checkFld(scale_);
             }
         }
diff --git a/src/dynamicMesh/motionSmoother/motionSmoother.H b/src/dynamicMesh/motionSmoother/motionSmoother.H
index b9ce2b9fa770c40336bb80a120747f67cab11201..fe4073c1b5a450d4871b5663d57580f8b2a9d96e 100644
--- a/src/dynamicMesh/motionSmoother/motionSmoother.H
+++ b/src/dynamicMesh/motionSmoother/motionSmoother.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -229,9 +229,13 @@ class motionSmoother
         //- Get points used by given faces
         labelHashSet getPoints(const labelHashSet&) const;
 
+        //- Calculate per-edge weight
+        tmp<scalarField> calcEdgeWeights(const pointField&) const;
+
         //- explicit smoothing and min on all affected internal points
         void minSmooth
         (
+            const scalarField& edgeWeights,
             const PackedBoolList& isAffectedPoint,
             const pointScalarField& fld,
             pointScalarField& newFld
@@ -240,6 +244,7 @@ class motionSmoother
         //- same but only on selected points (usually patch points)
         void minSmooth
         (
+            const scalarField& edgeWeights,
             const PackedBoolList& isAffectedPoint,
             const labelList& meshPoints,
             const pointScalarField& fld,
@@ -264,6 +269,24 @@ class motionSmoother
             pointScalarField&
         ) const;
 
+        //- Lower on internal points
+        void subtractField
+        (
+            const labelHashSet& pointLabels,
+            const scalar f,
+            pointScalarField&
+        ) const;
+
+        //- As above but points have to be in meshPoints as well
+        //  (usually to scale patch points)
+        void subtractField
+        (
+            const labelList& meshPoints,
+            const labelHashSet& pointLabels,
+            const scalar scale,
+            pointScalarField&
+        ) const;
+
         //- Helper function. Is point internal?
         bool isInternalPoint(const label pointI) const;
 
diff --git a/src/edgeMesh/extendedFeatureEdgeMesh/extendedFeatureEdgeMesh.C b/src/edgeMesh/extendedFeatureEdgeMesh/extendedFeatureEdgeMesh.C
index 0ebb7b58ab6d0e54c7bc91092e02a51df9fadaa8..81f853aa417f1b3f2f0b264437bcc49ee47695d5 100644
--- a/src/edgeMesh/extendedFeatureEdgeMesh/extendedFeatureEdgeMesh.C
+++ b/src/edgeMesh/extendedFeatureEdgeMesh/extendedFeatureEdgeMesh.C
@@ -546,6 +546,49 @@ Foam::extendedFeatureEdgeMesh::extendedFeatureEdgeMesh
     }
 
     featurePointNormals_ = featurePointNormals;
+
+
+    // Create featurePointEdges_
+    // For each feature point, stores a list of edges which are arranged in
+    // order according to their connectivity
+
+//    featurePointEdges_.setSize(nonFeatureStart_);
+//
+//    Info<< sFeatEds.size() << " " << surf.pointEdges().size() << " "
+//        << edges().size() << endl;
+//
+//    forAll(sFeatEds, eI)
+//    {
+//        Info<< "Edge " << eI << " " << sFeatEds[eI] << " "
+//            << edges()[eI] << endl;
+//    }
+//
+//    const edgeList& edges = eds;
+//
+//    for (label i = 0; i < nonFeatureStart_; i++)
+//    {
+//        const labelList& ptEds = surf.pointEdges()[i];
+//
+//        DynamicList<label> tmpFtEdges;
+//
+//        forAll(ptEds, eI)
+//        {
+//            const label edgeI = ptEds[eI];
+//            const edge& e = sFeatEds[edgeI];
+//
+//            Info<< "Edges: " << edgeI << " " << e << endl;
+//
+//            forAll(sFeatEds, fEdgeI)
+//            {
+//                if (edges[fEdgeI] == e)
+//                {
+//                    tmpFtEdges.append(fEdgeI);
+//                }
+//            }
+//        }
+//
+//        featurePointEdges_[i] = tmpFtEdges;
+//    }
 }
 
 
@@ -821,7 +864,7 @@ void Foam::extendedFeatureEdgeMesh::allNearestFeatureEdges
 
             if (!hitPoint.hit())
             {
-                nearHit = pointIndexHit(true, hitPoint.missPoint(), hitIndex);
+                nearHit = pointIndexHit(false, hitPoint.missPoint(), hitIndex);
             }
             else
             {
diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C
index f70381471bda91d4c1a73244c5a1b2b68f2f2c64..c300cc53a71f8c4ecbc68b1da380e6e878154ecb 100644
--- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C
+++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriver.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -2067,8 +2067,10 @@ Foam::label Foam::autoLayerDriver::checkAndUnmark
         // The important thing, however, is that when only a few faces
         // are disabled, their coordinates are printed, and this should be
         // the case
-        label nReportLocal =
-            min
+        label nReportLocal = nChanged;
+        if (nChangedTotal > nReportMax)
+        {
+            nReportLocal = min
             (
                 max(nChangedTotal / Pstream::nProcs(), 1),
                 min
@@ -2077,11 +2079,15 @@ Foam::label Foam::autoLayerDriver::checkAndUnmark
                     max(nReportMax / Pstream::nProcs(), 1)
                 )
             );
+        }
 
-        Pout<< "Checked mesh with layers. Disabled extrusion at " << endl;
-        for (label i=0; i < nReportLocal; i++)
+        if (nReportLocal)
         {
-            Pout<< "    " << disabledFaceCentres[i] << endl;
+            Pout<< "Checked mesh with layers. Disabled extrusion at " << endl;
+            for (label i=0; i < nReportLocal; i++)
+            {
+                Pout<< "    " << disabledFaceCentres[i] << endl;
+            }
         }
 
         label nReportTotal = returnReduce(nReportLocal, sumOp<label>());
@@ -2546,7 +2552,7 @@ void Foam::autoLayerDriver::addLayers
             false
         ),
         meshMover().pMesh(),
-        dimensionedScalar("pointMedialDist", dimless, 0.0)
+        dimensionedScalar("pointMedialDist", dimLength, 0.0)
     );
 
     pointVectorField dispVec
@@ -2561,7 +2567,7 @@ void Foam::autoLayerDriver::addLayers
             false
         ),
         meshMover().pMesh(),
-        dimensionedVector("dispVec", dimless, vector::zero)
+        dimensionedVector("dispVec", dimLength, vector::zero)
     );
 
     pointScalarField medialRatio
diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C
index 5731562575b50d515d75b641459f4f1ddf200cab..b6a9e338aa63b18e6fb18798f991f5c2a1fe813b 100644
--- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C
+++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverShrink.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -49,6 +49,8 @@ void Foam::autoLayerDriver::sumWeights
     scalarField& invSumWeight
 ) const
 {
+    const pointField& pts = meshRefiner_.mesh().points();
+
     invSumWeight = 0;
 
     forAll(edges, edgeI)
@@ -57,7 +59,18 @@ void Foam::autoLayerDriver::sumWeights
         {
             const edge& e = edges[edgeI];
             //scalar eWeight = edgeWeights[edgeI];
-            scalar eWeight = 1.0;
+            //scalar eWeight = 1.0;
+
+            scalar eMag = max
+            (
+                VSMALL,
+                mag
+                (
+                    pts[meshPoints[e[1]]]
+                  - pts[meshPoints[e[0]]]
+                )
+            );
+            scalar eWeight = 1.0/eMag;
 
             invSumWeight[e[0]] += eWeight;
             invSumWeight[e[1]] += eWeight;
@@ -799,25 +812,54 @@ void Foam::autoLayerDriver::medialAxisSmoothingInfo
                 // Both end points of edge have very different nearest wall
                 // point. Mark both points as medial axis points.
                 const edge& e = edges[edgeI];
-
-                forAll(e, ep)
+                // Approximate medial axis location on edge.
+                //const point medialAxisPt = e.centre(points);
+                vector eVec = e.vec(mesh.points());
+                scalar eMag = mag(eVec);
+                if (eMag > VSMALL)
                 {
-                    label pointI = e[ep];
+                    eVec /= eMag;
 
-                    if (!pointMedialDist[pointI].valid(dummyTrackData))
+                    // Calculate distance along edge
+                    const point& p0 = points[e[0]];
+                    const point& p1 = points[e[1]];
+                    scalar dist0 = (p0-pointWallDist[e[0]].origin()) & eVec;
+                    scalar dist1 = (pointWallDist[e[1]].origin()-p1) & eVec;
+                    scalar s = 0.5*(dist1+eMag+dist0);
+
+                    point medialAxisPt;
+                    if (s <= dist0)
                     {
-                        maxPoints.append(pointI);
-                        maxInfo.append
-                        (
-                            pointData
+                        medialAxisPt = p0;
+                    }
+                    else if (s >= dist0+eMag)
+                    {
+                        medialAxisPt = p1;
+                    }
+                    else
+                    {
+                        medialAxisPt = p0+(s-dist0)*eVec;
+                    }
+
+                    forAll(e, ep)
+                    {
+                        label pointI = e[ep];
+
+                        if (!pointMedialDist[pointI].valid(dummyTrackData))
+                        {
+                            maxPoints.append(pointI);
+                            maxInfo.append
                             (
-                                points[pointI],
-                                0.0,
-                                pointI,         // passive data
-                                vector::zero    // passive data
-                            )
-                        );
-                        pointMedialDist[pointI] = maxInfo.last();
+                                pointData
+                                (
+                                    medialAxisPt,   //points[pointI],
+                                    magSqr(points[pointI]-medialAxisPt),//0.0,
+                                    pointI,         // passive data
+                                    vector::zero    // passive data
+                                )
+                            );
+                            pointMedialDist[pointI] = maxInfo.last();
+                        }
                     }
                 }
             }
@@ -887,6 +929,7 @@ void Foam::autoLayerDriver::medialAxisSmoothingInfo
         forAll(pointMedialDist, pointI)
         {
             medialDist[pointI] = Foam::sqrt(pointMedialDist[pointI].distSqr());
+            //medialVec[pointI] = pointMedialDist[pointI].origin();
         }
     }
 
@@ -923,11 +966,14 @@ void Foam::autoLayerDriver::medialAxisSmoothingInfo
             << " : normalised direction of nearest displacement" << nl
             << "    " << medialDist.name()
             << " : distance to medial axis" << nl
+            //<< "    " << medialVec.name()
+            //<< " : nearest point on medial axis" << nl
             << "    " << medialRatio.name()
             << " : ratio of medial distance to wall distance" << nl
             << endl;
         dispVec.write();
         medialDist.write();
+        //medialVec.write();
         medialRatio.write();
     }
 }
@@ -950,6 +996,7 @@ void Foam::autoLayerDriver::shrinkMeshMedialDistance
     const pointVectorField& dispVec,
     const pointScalarField& medialRatio,
     const pointScalarField& medialDist,
+    //const pointVectorField& medialVec,
 
     List<extrudeMode>& extrudeStatus,
     pointField& patchDisp,
@@ -1025,10 +1072,23 @@ void Foam::autoLayerDriver::shrinkMeshMedialDistance
         {
             label pointI = meshPoints[patchPointI];
 
+            //- Option 1: look only at extrusion thickness v.s. distance
+            //  to nearest (medial axis or static) point.
             scalar mDist = medialDist[pointI];
-
             scalar thicknessRatio = thickness[patchPointI]/(mDist+VSMALL);
 
+            //- Option 2: Look at component in the direction
+            //  of nearest (medial axis or static) point.
+            vector n =
+                patchDisp[patchPointI]
+              / (mag(patchDisp[patchPointI]) + VSMALL);
+            //vector mVec = mesh.points()[pointI]-medialVec[pointI];
+            //scalar mDist = mag(mVec);
+            //scalar thicknessRatio =
+            //    (n&mVec)
+            //   *thickness[patchPointI]
+            //   /(mDist+VSMALL);
+
             if (thicknessRatio > maxThicknessToMedialRatio)
             {
                 // Truncate thickness.
@@ -1043,16 +1103,16 @@ void Foam::autoLayerDriver::shrinkMeshMedialDistance
                                 minThickness[patchPointI]
                                +thickness[patchPointI]
                             )
+                        //<< " since near medial at:" << medialVec[pointI]
+                        //<< " with thicknessRatio:" << thicknessRatio
                         << endl;
                 }
 
                 thickness[patchPointI] =
                     0.5*(minThickness[patchPointI]+thickness[patchPointI]);
 
-                patchDisp[patchPointI] =
-                    thickness[patchPointI]
-                  * patchDisp[patchPointI]
-                  / (mag(patchDisp[patchPointI]) + VSMALL);
+                patchDisp[patchPointI] = thickness[patchPointI]*n;
+
                 numThicknessRatioExclude++;
 
                 if (str.valid())
diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C
index ddfe4ed4affeea39996ae282674fd037b4edddf0..afb66396c88747a2baac3b68632d19d90c1f9d53 100644
--- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C
+++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoLayerDriverTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -41,6 +41,8 @@ void Foam::autoLayerDriver::averageNeighbours
     Field<Type>& average
 )
 {
+    const pointField& pts = mesh.points();
+
     average = pTraits<Type>::zero;
 
     forAll(edges, edgeI)
@@ -49,7 +51,18 @@ void Foam::autoLayerDriver::averageNeighbours
         {
             const edge& e = edges[edgeI];
             //scalar eWeight = edgeWeights[edgeI];
-            scalar eWeight =  1.0;
+            //scalar eWeight =  1.0;
+            scalar eMag = max
+            (
+                VSMALL,
+                mag
+                (
+                    pts[meshPoints[e[1]]]
+                  - pts[meshPoints[e[0]]]
+                )
+            );
+            scalar eWeight = 1.0/eMag;
+
             label v0 = e[0];
             label v1 = e[1];
 
diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H
index 96d7958528b4a2219a727a8d02d62fb1e6ea56fa..71afd2fba648eb9ef22beea8b3b1259e42e0a29f 100644
--- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H
+++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H
@@ -244,6 +244,7 @@ protected:
             const label size
         );
 
+
 public:
 
     //- Runtime type information
@@ -319,6 +320,9 @@ public:
             //- Patch (only if NEARESTPATCHFACE)
             inline const word& samplePatch() const;
 
+            //- Return size of mapped mesh/patch/boundary
+            inline label sampleSize() const;
+
             //- Offset vector (from patch faces to destination mesh objects)
             inline const vector& offset() const;
 
diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H
index 5814a1e824e95b8de63276793f91b790f8620b0f..928fa86ad7ddf26b31e342cdaa16e4d15856525c 100644
--- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H
+++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -42,6 +42,37 @@ inline const Foam::word& Foam::mappedPatchBase::samplePatch() const
 }
 
 
+inline Foam::label Foam::mappedPatchBase::sampleSize() const
+{
+    switch (mode_)
+    {
+        case NEARESTPATCHFACEAMI:
+        {
+            return samplePolyPatch().size();
+        }
+        case NEARESTCELL:
+        {
+            return sampleMesh().nCells();
+        }
+        case NEARESTPATCHFACE:
+        {
+            return samplePolyPatch().size();
+        }
+        case NEARESTFACE:
+        {
+            const polyMesh& mesh = sampleMesh();
+            return mesh.nFaces() - mesh.nInternalFaces();
+        }
+        default:
+        {
+            FatalErrorIn("mappedPatchBase::sampleSize()")
+                << "problem." << abort(FatalError);
+            return -1;
+        }
+    }
+}
+
+
 inline const Foam::vector& Foam::mappedPatchBase::offset() const
 {
     return offset_;
diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseTemplates.C b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseTemplates.C
index 47067b00f66328ff0a7ad6ec561657563bcf6f19..a4e36ff4575aff7806297c4596ff8454e2210c27 100644
--- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseTemplates.C
+++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -89,8 +89,8 @@ void Foam::mappedPatchBase::reverseDistribute(List<Type>& lst) const
         }
         default:
         {
-            label cSize = patch_.size();
-            map().reverseDistribute(cSize, lst);
+            map().reverseDistribute(sampleSize(), lst);
+            break;
         }
     }
 }
@@ -116,7 +116,7 @@ void Foam::mappedPatchBase::reverseDistribute
         }
         default:
         {
-            label cSize = patch_.size();
+            label cSize = sampleSize();
             map().distribute
             (
                 Pstream::defaultCommsType,
@@ -128,6 +128,7 @@ void Foam::mappedPatchBase::reverseDistribute
                 bop,
                 pTraits<Type>::zero
             );
+            break;
         }
     }
 }
diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.C b/src/meshTools/searchableSurface/searchableSurfacesQueries.C
index bea97b328845bddfe22b078dddac7ab0fdd6ba7e..4db8f9acf37f58a13c9e874c657ab6aa9b7202a9 100644
--- a/src/meshTools/searchableSurface/searchableSurfacesQueries.C
+++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -27,6 +27,7 @@ License
 #include "ListOps.H"
 #include "OFstream.H"
 #include "meshTools.H"
+#include "DynamicField.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -686,6 +687,81 @@ void Foam::searchableSurfacesQueries::findNearest
 }
 
 
+void Foam::searchableSurfacesQueries::signedDistance
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    labelList& nearestSurfaces,
+    scalarField& distance
+)
+{
+    // Initialise
+    distance.setSize(samples.size());
+    distance = -GREAT;
+
+    // Find nearest
+    List<pointIndexHit> nearestInfo;
+    findNearest
+    (
+        allSurfaces,
+        surfacesToTest,
+        samples,
+        nearestDistSqr,
+        nearestSurfaces,
+        nearestInfo
+    );
+
+    // Determine sign of nearest. Sort by surface to do this.
+    DynamicField<point> surfPoints(samples.size());
+    DynamicList<label> surfIndices(samples.size());
+
+    forAll(surfacesToTest, testI)
+    {
+        // Extract samples on this surface
+        surfPoints.clear();
+        surfIndices.clear();
+        forAll(nearestSurfaces, i)
+        {
+            if (nearestSurfaces[i] == testI)
+            {
+                surfPoints.append(samples[i]);
+                surfIndices.append(i);
+            }
+        }
+
+        // Calculate sideness of these surface points
+        List<searchableSurface::volumeType> volType;
+        allSurfaces[surfacesToTest[testI]].getVolumeType(surfPoints, volType);
+
+        // Push back to original
+        forAll(volType, i)
+        {
+            label pointI = surfIndices[i];
+            scalar dist = mag(samples[pointI] - nearestInfo[pointI].hitPoint());
+
+            searchableSurface::volumeType vT = volType[i];
+
+            if (vT == searchableSurface::OUTSIDE)
+            {
+                distance[pointI] = dist;
+            }
+            else if (vT == searchableSurface::INSIDE)
+            {
+                distance[i] = -dist;
+            }
+            else
+            {
+                FatalErrorIn("signedDistance()")
+                    << "getVolumeType failure, neither INSIDE or OUTSIDE"
+                    << exit(FatalError);
+            }
+        }
+    }
+}
+
+
 Foam::boundBox Foam::searchableSurfacesQueries::bounds
 (
     const PtrList<searchableSurface>& allSurfaces,
diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.H b/src/meshTools/searchableSurface/searchableSurfacesQueries.H
index 6aa2245409707fdd96ce474ff7be0f07b7a8d3b2..a2dba23cb5d295a7b80338275a57d697ed670454 100644
--- a/src/meshTools/searchableSurface/searchableSurfacesQueries.H
+++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -184,6 +184,17 @@ public:
                 List<pointIndexHit>&
             );
 
+            //- Find signed distance to nearest surface
+            static void signedDistance
+            (
+                const PtrList<searchableSurface>& allSurfaces,
+                const labelList& surfacesToTest,
+                const pointField& samples,
+                const scalarField& nearestDistSqr,
+                labelList& nearestSurfaces,
+                scalarField& distance
+            );
+
             //- Find the boundBox of the selected surfaces
             static boundBox bounds
             (
diff --git a/src/regionModels/thermoBaffleModels/thermoBaffle2D/thermoBaffle2D.C b/src/regionModels/thermoBaffleModels/thermoBaffle2D/thermoBaffle2D.C
index 3e131d84b75cb66b9d9293da3ce05f8fd7781151..d251bc64e034fdcd28f8f59ba516d0f1e0ab0177 100644
--- a/src/regionModels/thermoBaffleModels/thermoBaffle2D/thermoBaffle2D.C
+++ b/src/regionModels/thermoBaffleModels/thermoBaffle2D/thermoBaffle2D.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -146,12 +146,12 @@ void thermoBaffle2D::solveEnergy()
         TEqn -= fvc::div(phiMesh);
     }
 
-    Info<< "T gas min/max   = " << min(T_).value() << ", "
-        << max(T_).value() << endl;
-
     TEqn.relax();
     TEqn.solve();
 
+    Info<< "T gas min/max   = " << min(T_).value() << ", "
+        << max(T_).value() << endl;
+
     thermo_->correct();
 }
 
@@ -362,7 +362,7 @@ void thermoBaffle2D::info() const
             (
                 mag(regionMesh().Sf().boundaryField()[patchI])
               * pT.snGrad()
-              * thermo_->K().boundaryField()[patchI]
+              * thermo_->K(patchI)
             ) << endl;
     }
 }
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
index 6b557df91844b2fce50573d970ddc6e85b496016..7d9c4eace454d7cd0bab0c351267530c03ab8cf5 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -49,6 +49,8 @@ void Foam::distanceSurface::createGeometry()
 
     // Clear any stored topologies
     facesPtr_.clear();
+    isoSurfCellPtr_.clear();
+    isoSurfPtr_.clear();
 
     // Clear derived data
     clearGeom();
@@ -265,24 +267,33 @@ void Foam::distanceSurface::createGeometry()
 
 
     //- Direct from cell field and point field.
-    isoSurfPtr_.reset
-    (
-        new isoSurface
+    if (cell_)
+    {
+        isoSurfCellPtr_.reset
         (
-            cellDistance,
-            pointDistance_,
-            distance_,
-            regularise_
-        )
-        //new isoSurfaceCell
-        //(
-        //    fvm,
-        //    cellDistance,
-        //    pointDistance_,
-        //    distance_,
-        //    regularise_
-        //)
-    );
+            new isoSurfaceCell
+            (
+                fvm,
+                cellDistance,
+                pointDistance_,
+                distance_,
+                regularise_
+            )
+        );
+    }
+    else
+    {
+        isoSurfPtr_.reset
+        (
+            new isoSurface
+            (
+                cellDistance,
+                pointDistance_,
+                distance_,
+                regularise_
+            )
+        );
+    }
 
     if (debug)
     {
@@ -321,10 +332,12 @@ Foam::distanceSurface::distanceSurface
     ),
     distance_(readScalar(dict.lookup("distance"))),
     signed_(readBool(dict.lookup("signed"))),
+    cell_(dict.lookupOrDefault("cell", true)),
     regularise_(dict.lookupOrDefault("regularise", true)),
     average_(dict.lookupOrDefault("average", false)),
     zoneKey_(keyType::null),
     needsUpdate_(true),
+    isoSurfCellPtr_(NULL),
     isoSurfPtr_(NULL),
     facesPtr_(NULL)
 {
@@ -338,6 +351,52 @@ Foam::distanceSurface::distanceSurface
 }
 
 
+
+Foam::distanceSurface::distanceSurface
+(
+    const word& name,
+    const polyMesh& mesh,
+    const bool interpolate,
+    const word& surfaceType,
+    const word& surfaceName,
+    const scalar distance,
+    const bool signedDistance,
+    const bool cell,
+    const Switch regularise,
+    const Switch average
+)
+:
+    sampledSurface(name, mesh, interpolate),
+    surfPtr_
+    (
+        searchableSurface::New
+        (
+            surfaceType,
+            IOobject
+            (
+                surfaceName,  // name
+                mesh.time().constant(),                     // directory
+                "triSurface",                               // instance
+                mesh.time(),                                // registry
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            ),
+            dictionary()
+        )
+    ),
+    distance_(distance),
+    signed_(signedDistance),
+    cell_(cell),
+    regularise_(regularise),
+    average_(average),
+    zoneKey_(keyType::null),
+    needsUpdate_(true),
+    isoSurfCellPtr_(NULL),
+    isoSurfPtr_(NULL),
+    facesPtr_(NULL)
+{}
+
+
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::distanceSurface::~distanceSurface()
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
index a7040ba7f8d96fa07e53c0160f2831fade41f1bd..2b971970872db59f58db19a885ac9d363a0fdd58 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -27,6 +27,8 @@ Class
 Description
     A sampledSurface defined by a distance to a surface.
 
+    Uses either isoSurfaceCell or isoSurface.
+
 SourceFiles
     distanceSurface.C
 
@@ -37,7 +39,7 @@ SourceFiles
 
 #include "sampledSurface.H"
 #include "searchableSurface.H"
-//#include "isoSurfaceCell.H"
+#include "isoSurfaceCell.H"
 #include "isoSurface.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -64,6 +66,9 @@ class distanceSurface
         //- signed distance
         const bool signed_;
 
+        //- Whether to use isoSurfaceCell or isoSurface
+        const bool cell_;
+
         //- Whether to coarsen
         const Switch regularise_;
 
@@ -84,7 +89,9 @@ class distanceSurface
         scalarField pointDistance_;
 
         //- Constructed iso surface
-        //autoPtr<isoSurfaceCell> isoSurfPtr_;
+        autoPtr<isoSurfaceCell> isoSurfCellPtr_;
+
+        //- Constructed iso surface
         autoPtr<isoSurface> isoSurfPtr_;
 
         //- triangles converted to faceList
@@ -125,6 +132,21 @@ public:
             const dictionary& dict
         );
 
+        //- Construct from components
+        distanceSurface
+        (
+            const word& name,
+            const polyMesh& mesh,
+            const bool interpolate,
+            const word& surfaceType,
+            const word& surfaceName,
+            const scalar distance,
+            const bool signedDistance,
+            const bool cell,
+            const Switch regularise,
+            const Switch average
+        );
+
 
     //- Destructor
     virtual ~distanceSurface();
@@ -167,11 +189,16 @@ public:
             return facesPtr_;
         }
 
-
-        //const isoSurfaceCell& surface() const
-        const isoSurface& surface() const
+        const triSurface& surface() const
         {
-            return isoSurfPtr_();
+            if (cell_)
+            {
+                return isoSurfCellPtr_();
+            }
+            else
+            {
+                return isoSurfPtr_();
+            }
         }
 
         //- sample field on surface
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C b/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
index 5701d09c24fcd49254ea126fdefa2f5fe28d0dba..d8871126ea71629c05d62e9a196ca6b7602fdfe8 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -37,7 +37,20 @@ Foam::distanceSurface::sampleField
     const GeometricField<Type, fvPatchField, volMesh>& vField
 ) const
 {
-    return tmp<Field<Type> >(new Field<Type>(vField, surface().meshCells()));
+    if (cell_)
+    {
+        return tmp<Field<Type> >
+        (
+            new Field<Type>(vField, isoSurfCellPtr_().meshCells())
+        );
+    }
+    else
+    {
+        return tmp<Field<Type> >
+        (
+            new Field<Type>(vField, isoSurfPtr_().meshCells())
+        );
+    }
 }
 
 
@@ -60,15 +73,30 @@ Foam::distanceSurface::interpolateField
     );
 
     // Sample.
-    return surface().interpolate
-    (
+    if (cell_)
+    {
+        return isoSurfCellPtr_().interpolate
         (
-            average_
-          ? pointAverage(pointFld())()
-          : volFld
-        ),
-        pointFld()
-    );
+            (
+                average_
+              ? pointAverage(pointFld())()
+              : volFld
+            ),
+            pointFld()
+        );
+    }
+    else
+    {
+        return isoSurfPtr_().interpolate
+        (
+            (
+                average_
+              ? pointAverage(pointFld())()
+              : volFld
+            ),
+            pointFld()
+        );
+    }
 }
 
 
diff --git a/src/sampling/sampledSurface/sampledSurface/sampledSurface.C b/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
index 0b812717fa6c27bc1d3a66fec9b43b892da9dfb3..5c7c5abb90c50b43d7c66f60adff1d1f7acd323a 100644
--- a/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
+++ b/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -152,12 +152,13 @@ Foam::autoPtr<Foam::sampledSurface> Foam::sampledSurface::New
 Foam::sampledSurface::sampledSurface
 (
     const word& name,
-    const polyMesh& mesh
+    const polyMesh& mesh,
+    const bool interpolate
 )
 :
     name_(name),
     mesh_(mesh),
-    interpolate_(false),
+    interpolate_(interpolate),
     SfPtr_(NULL),
     magSfPtr_(NULL),
     CfPtr_(NULL),
diff --git a/src/sampling/sampledSurface/sampledSurface/sampledSurface.H b/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
index 5b4683bee56516f235598a587e20a2465c851c70..9843143107269573d564d0223d7af14e8873ea37 100644
--- a/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
+++ b/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -81,7 +81,7 @@ class sampledSurface
         const polyMesh& mesh_;
 
         //- Do we intend to interpolate the information?
-        bool interpolate_;
+        const bool interpolate_;
 
 
     // Demand-driven data
@@ -197,7 +197,8 @@ public:
         sampledSurface
         (
             const word& name,
-            const polyMesh&
+            const polyMesh&,
+            const bool interpolate = false
         );
 
         //- Construct from dictionary
diff --git a/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.C b/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.C
index 2ecdd91b9eaafe51944559f0d1f63b326d762086..5e62a55eee3a7d5f12252385c9dde34b6498fe9d 100644
--- a/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -257,20 +257,6 @@ const Foam::volScalarField& Foam::basicSolidThermo::emissivity() const
 }
 
 
-const Foam::volScalarField&  Foam::basicSolidThermo::K() const
-{
-    notImplemented("basicSolidThermo::K()");
-    return volScalarField::null();
-}
-
-
-const Foam::volSymmTensorField& Foam::basicSolidThermo::directionalK() const
-{
-    notImplemented("basicSolidThermo::directionalK()");
-    return const_cast<volSymmTensorField&>(volSymmTensorField::null());
-}
-
-
 Foam::basicSolidMixture& Foam::basicSolidThermo::composition()
 {
     notImplemented("basicSolidThermo::composition()");
@@ -287,7 +273,7 @@ const Foam::basicSolidMixture& Foam::basicSolidThermo::composition() const
 
 Foam::tmp<Foam::volScalarField> Foam::basicSolidThermo::hs() const
 {
-    notImplemented("basicSolidThermo::hs()");
+    notImplemented("basicSolidThermo::hs() const");
     return volScalarField::null();
 }
 
@@ -295,31 +281,11 @@ Foam::tmp<Foam::volScalarField> Foam::basicSolidThermo::hs() const
 Foam::tmp<Foam::scalarField> Foam::basicSolidThermo::hs(const label patchI)
 const
 {
-    notImplemented("basicSolidThermo::hs(const label)");
-    return scalarField::null();
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::basicSolidThermo::K
-(
-    const label patchI
-)const
-{
-    notImplemented("basicSolidThermo::K(const label)");
+    notImplemented("basicSolidThermo::hs(const label) const");
     return scalarField::null();
 }
 
 
-Foam::tmp<Foam::symmTensorField> Foam::basicSolidThermo::directionalK
-(
-    const label
-)const
-{
-    notImplemented("basicSolidThermo::directionalK(const label)");
-    return symmTensorField::null();
-}
-
-
 bool Foam::basicSolidThermo::read()
 {
     return regIOobject::read();
diff --git a/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.H b/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.H
index 84ded7e35a23fd16d7505b60d593146b94ac0cf0..3def4a0ee5235ca1bfc12b09b0c9380458329567 100644
--- a/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/basicSolidThermo/basicSolidThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -144,35 +144,35 @@ public:
 
         // Access to thermodynamic state variables
 
-            //- Density [kg/m^3]
-            const volScalarField& rho() const;
+            //- Temperature [K]
+            virtual const volScalarField& T() const;
 
-            //- Thermal conductivity [W/m/K]
-            virtual const volScalarField& K() const;
+            //- non-const access for T
+            virtual volScalarField& T();
 
-            //- Thermal conductivity [W/m/K]
-            virtual const volSymmTensorField& directionalK() const;
+            //- Density [kg/m^3]
+            virtual const volScalarField& rho() const;
+
+            //- non-const access for rho
+            virtual volScalarField& rho();
 
             //- Absorption coefficient [1/m]
-            const volScalarField& kappa() const;
+            virtual const volScalarField& kappa() const;
 
             //- Emissivity coefficient
-            const volScalarField& sigmaS() const;
+            virtual const volScalarField& sigmaS() const;
 
             //- Emissivity coefficient [1/m]
-            const volScalarField& emissivity() const;
-
-            //- Temperature [K]
-            const volScalarField& T() const;
+            virtual const volScalarField& emissivity() const;
 
-            //- non-const access for T
-            volScalarField& T();
 
-            //- non-const access for rho
-            volScalarField& rho();
+        // Derived thermal properties
 
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volScalarField> K() const = 0;
 
-        // Derived thermal properties
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volSymmTensorField> directionalK() const = 0;
 
             //- Specific heat capacity [J/kg/K]
             virtual tmp<volScalarField> Cp() const = 0;
@@ -186,8 +186,11 @@ public:
 
         // Per patch calculation
 
-            //- Density [kg/m3]
-            virtual tmp<scalarField> rho(const label patchI) const = 0;
+            //- Thermal conductivity [W//m/K]
+            virtual tmp<scalarField> K(const label patchI) const = 0;
+
+            //- Thermal conductivity [W//m/K]
+            virtual tmp<symmTensorField> directionalK(const label) const = 0;
 
             //- Specific heat capacity [J/kg/K)]
             virtual tmp<scalarField> Cp(const label patchI) const = 0;
@@ -195,24 +198,9 @@ public:
             //- Sensible enthalpy [J/kg]
             virtual tmp<scalarField> hs(const label patchI) const;
 
-            //- Thermal conductivity [W//m/K]
-            virtual tmp<scalarField> K(const label patchI) const;
-
-            //- Thermal conductivity [W//m/K]
-            virtual tmp<symmTensorField> directionalK(const label) const;
-
             //- Heat of formation [J/kg]
             virtual tmp<scalarField> Hf(const label patchI) const = 0;
 
-            //- Scatter coefficient [1/m]
-            virtual tmp<scalarField> sigmaS(const label) const = 0;
-
-            //- Absorption coefficient [1/m]
-            virtual tmp<scalarField> kappa(const label) const = 0;
-
-            //- Emissivity []
-            virtual tmp<scalarField> emissivity(const label) const = 0;
-
     // I-O
 
         //- Write the basicSolidThermo properties
diff --git a/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.C b/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.C
index 2434d959c3ffcda671e66719a53d8becf77fcc3a..ee20901aac3a79685207ccb86372e9696093dca5 100644
--- a/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -132,34 +132,13 @@ void Foam::constSolidThermo::correct()
 {}
 
 
-Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::Cp() const
-{
-    return tmp<volScalarField>
-    (
-        new volScalarField
-        (
-            IOobject
-            (
-                "Cp",
-                mesh_.time().timeName(),
-                mesh_,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            mesh_,
-            constCp_
-        )
-    );
-}
-
-
-const Foam::volScalarField& Foam::constSolidThermo::K() const
+Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::K() const
 {
     return K_;
 }
 
 
-const Foam::volSymmTensorField& Foam::constSolidThermo::directionalK() const
+Foam::tmp<Foam::volSymmTensorField> Foam::constSolidThermo::directionalK() const
 {
     dimensionedSymmTensor t
     (
@@ -194,7 +173,7 @@ const Foam::volSymmTensorField& Foam::constSolidThermo::directionalK() const
 }
 
 
-Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::Hf() const
+Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::Cp() const
 {
     return tmp<volScalarField>
     (
@@ -202,46 +181,35 @@ Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::Hf() const
         (
             IOobject
             (
-                "Hf",
+                "Cp",
                 mesh_.time().timeName(),
                 mesh_,
                 IOobject::NO_READ,
                 IOobject::NO_WRITE
             ),
             mesh_,
-            constHf_
-        )
-    );
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::rho
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            T_.boundaryField()[patchI].size(),
-            constRho_.value()
+            constCp_
         )
     );
 }
 
 
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::Cp
-(
-    const label patchI
-) const
+Foam::tmp<Foam::volScalarField> Foam::constSolidThermo::Hf() const
 {
-    return tmp<scalarField>
+    return tmp<volScalarField>
     (
-        new scalarField
+        new volScalarField
         (
-            T_.boundaryField()[patchI].size(),
-            constCp_.value()
+            IOobject
+            (
+                "Hf",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            constHf_
         )
     );
 }
@@ -281,39 +249,7 @@ Foam::tmp<Foam::symmTensorField> Foam::constSolidThermo::directionalK
 }
 
 
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::Hf
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            T_.boundaryField()[patchI].size(),
-            constHf_.value()
-        )
-    );
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::emissivity
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            T_.boundaryField()[patchI].size(),
-            constEmissivity_.value()
-        )
-    );
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::kappa
+Foam::tmp<Foam::scalarField> Foam::constSolidThermo::Cp
 (
     const label patchI
 ) const
@@ -323,13 +259,13 @@ Foam::tmp<Foam::scalarField> Foam::constSolidThermo::kappa
         new scalarField
         (
             T_.boundaryField()[patchI].size(),
-            constKappa_.value()
+            constCp_.value()
         )
     );
 }
 
 
-Foam::tmp<Foam::scalarField> Foam::constSolidThermo::sigmaS
+Foam::tmp<Foam::scalarField> Foam::constSolidThermo::Hf
 (
     const label patchI
 ) const
@@ -339,7 +275,7 @@ Foam::tmp<Foam::scalarField> Foam::constSolidThermo::sigmaS
         new scalarField
         (
             T_.boundaryField()[patchI].size(),
-            constSigmaS_.value()
+            constHf_.value()
         )
     );
 }
diff --git a/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.H b/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.H
index cba0bda908a26a07662dfcc9319f2d0020313053..75a5068552d0ed377cabc600d598e98a003db418 100644
--- a/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/constSolidThermo/constSolidThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -107,16 +107,13 @@ public:
         virtual void correct();
 
 
-    // Acces functions
+        // Derived thermal properties
 
-        //- Constant access to K
-        virtual const volScalarField& K() const;
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volScalarField> K() const;
 
-        //- Thermal conductivity [W/(m.K)]
-        virtual const volSymmTensorField& directionalK() const;
-
-
-        // Derived properties
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volSymmTensorField> directionalK() const;
 
             //- Specific heat capacity [J/(kg.K)]
             virtual tmp<volScalarField> Cp() const;
@@ -127,29 +124,18 @@ public:
 
         // Per patch calculation
 
-            //- Density [kg/m3]
-            virtual tmp<scalarField> rho(const label patchI) const;
-
-            //- Specific heat capacity [J/kg/K)]
-            virtual tmp<scalarField> Cp(const label patchI) const;
-
             //- Thermal conductivity [W//m/K]
             virtual tmp<scalarField> K(const label patchI) const;
 
             //- Thermal conductivity [W//m/K]
             virtual tmp<symmTensorField>directionalK(const label) const;
 
+            //- Specific heat capacity [J/kg/K)]
+            virtual tmp<scalarField> Cp(const label patchI) const;
+
             //- Heat of formation [J/kg]
             virtual tmp<scalarField> Hf(const label patchI) const;
 
-            //- Scatter coefficient [1/m]
-            virtual tmp<scalarField> sigmaS(const label) const;
-
-            //- Absorption coefficient [1/m]
-            virtual tmp<scalarField> kappa(const label) const;
-
-             //- Emissivity []
-            virtual tmp<scalarField> emissivity(const label) const;
 
 
         // I-O
diff --git a/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.C b/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.C
index c6a4de63dd41c317e253d486a96289a91bf3b472..e2185e45f5883c381a2cb9e902322e40769a9fa0 100644
--- a/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -136,12 +136,10 @@ void Foam::directionalKSolidThermo::init()
 {
     KValues_ = Field<vector>(subDict(typeName + "Coeffs").lookup("KValues"));
 
-    const fvMesh& mesh = K().mesh();
-
     // Determine transforms for cell centres
-    forAll(mesh.C(), cellI)
+    forAll(mesh_.C(), cellI)
     {
-        vector dir = mesh.C()[cellI] - coordSys_.origin();
+        vector dir = mesh_.C()[cellI] - coordSys_.origin();
         dir /= mag(dir);
 
         // Define local coordinate system with
@@ -158,9 +156,9 @@ void Foam::directionalKSolidThermo::init()
         ccTransforms_[cellI] = cs.R();
     }
 
-    forAll(mesh.C().boundaryField(), patchI)
+    forAll(mesh_.C().boundaryField(), patchI)
     {
-        const fvPatchVectorField& patchC = mesh.C().boundaryField()[patchI];
+        const fvPatchVectorField& patchC = mesh_.C().boundaryField()[patchI];
         fvPatchTensorField& patchT = ccTransforms_.boundaryField()[patchI];
 
         tensorField tc(patchT.size());
@@ -192,13 +190,13 @@ void Foam::directionalKSolidThermo::init()
                 IOobject
                 (
                     "Kxx",
-                    mesh.time().timeName(),
-                    mesh,
+                    mesh_.time().timeName(),
+                    mesh_,
                     IOobject::NO_READ,
                     IOobject::AUTO_WRITE,
                     false
                 ),
-                mesh,
+                mesh_,
                 dimless
             );
             Kxx.internalField() = transform
@@ -230,13 +228,13 @@ void Foam::directionalKSolidThermo::init()
                 IOobject
                 (
                     "Kyy",
-                    mesh.time().timeName(),
-                    mesh,
+                    mesh_.time().timeName(),
+                    mesh_,
                     IOobject::NO_READ,
                     IOobject::AUTO_WRITE,
                     false
                 ),
-                mesh,
+                mesh_,
                 dimless
             );
             Kyy.internalField() = transform
@@ -268,13 +266,13 @@ void Foam::directionalKSolidThermo::init()
                 IOobject
                 (
                     "Kzz",
-                    mesh.time().timeName(),
-                    mesh,
+                    mesh_.time().timeName(),
+                    mesh_,
                     IOobject::NO_READ,
                     IOobject::AUTO_WRITE,
                     false
                 ),
-                mesh,
+                mesh_,
                 dimless
             );
             Kzz.internalField() = transform
@@ -363,7 +361,7 @@ void Foam::directionalKSolidThermo::correct()
 }
 
 
-const Foam::volSymmTensorField&
+Foam::tmp<Foam::volSymmTensorField>
 Foam::directionalKSolidThermo::directionalK() const
 {
     return directionalK_;
@@ -398,105 +396,6 @@ void Foam::directionalKSolidThermo::calculate()
 }
 
 
-const Foam::volScalarField& Foam::directionalKSolidThermo::K() const
-{
-    forAll(KValues_, i)
-    {
-        const vector& v = KValues_[i];
-        if
-        (
-            v.x() != v.y()
-         || v.x() != v.z()
-         || v.y() != v.z()
-        )
-        {
-            FatalErrorIn("directionalKSolidThermo::K() const")
-                << "Supplied K values " << KValues_
-                << " are not isotropic." << exit(FatalError);
-        }
-    }
-
-    // Get temperature interpolated properties (principal directions)
-    Field<vector> localK
-    (
-        interpolateXY
-        (
-            T_.internalField(),
-            TValues_,
-            KValues_
-        )
-    );
-
-    tmp<volScalarField> tK
-    (
-        new volScalarField
-        (
-            IOobject
-            (
-                "K",
-                mesh_.time().timeName(),
-                mesh_,
-                IOobject::NO_READ,
-                IOobject::NO_WRITE
-            ),
-            mesh_,
-            dimEnergy/dimTime/(dimLength*dimTemperature)
-        )
-    );
-    volScalarField& K = tK();
-
-    K.internalField() = interpolateXY
-    (
-        T_.internalField(),
-        TValues_,
-        KValues_.component(0)()
-    );
-
-    forAll(K.boundaryField(), patchI)
-    {
-        K.boundaryField()[patchI] == this->K(patchI)();
-    }
-
-    return tK;
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::directionalKSolidThermo::K
-(
-    const label patchI
-) const
-{
-    forAll(KValues_, i)
-    {
-        const vector& v = KValues_[i];
-        if
-        (
-            v.x() != v.y()
-         || v.x() != v.z()
-         || v.y() != v.z()
-        )
-        {
-            FatalErrorIn("directionalKSolidThermo::K() const")
-                << "Supplied K values " << KValues_
-                << " are not isotropic." << exit(FatalError);
-        }
-    }
-
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                KValues_.component(0)()
-            )
-        )
-    );
-}
-
-
 Foam::tmp<Foam::symmTensorField> Foam::directionalKSolidThermo::directionalK
 (
     const label patchI
diff --git a/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.H b/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.H
index 6872bec26f5ecd06649d54237d86e4ef14fcdd53..c5c8ad9cc8288a1adfc7c72e103fe4d13b38ee52 100644
--- a/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/directionalKSolidThermo/directionalKSolidThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -116,16 +116,24 @@ public:
 
         //- Access functions
 
-            //- Thermal conductivity [W/(m.K)]
-            virtual const volSymmTensorField& directionalK() const;
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volScalarField> K() const
+            {
+                notImplemented("directionalKSolidThermo::K() const");
+                return tmp<volScalarField>(NULL);
+            }
 
-            //- Iostropic thermal conductivity [W/(m.K)]
-            virtual const volScalarField& K() const;
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volSymmTensorField> directionalK() const;
 
-        // Per patch calculation
+         // Per patch calculation
 
             //- Thermal conductivity [W//m/K]
-            virtual tmp<scalarField> K(const label patchI) const;
+            virtual tmp<scalarField> K(const label patchI) const
+            {
+                notImplemented("directionalKSolidThermo::K(const label) const");
+                return tmp<scalarField>(NULL);
+            }
 
             //- Thermal conductivity [W//m/K]
             virtual tmp<symmTensorField> directionalK(const label) const;
diff --git a/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.C b/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.C
index bfabc2ed603b1728328aee1aedd25ebee3bc41da..def8dc6160e2df77d25ec775da1da57d3d801f01 100644
--- a/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -27,6 +27,88 @@ License
 #include "interpolateXY.H"
 
 
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::rho
+(
+    const label patchI
+) const
+{
+    return tmp<scalarField>
+    (
+        new scalarField
+        (
+            interpolateXY
+            (
+                T_.boundaryField()[patchI],
+                TValues_,
+                rhoValues_
+            )
+        )
+    );
+}
+
+
+Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::emissivity
+(
+    const label patchI
+) const
+{
+    return tmp<scalarField>
+    (
+        new scalarField
+        (
+            interpolateXY
+            (
+                T_.boundaryField()[patchI],
+                TValues_,
+                emissivityValues_
+            )
+        )
+    );
+}
+
+
+Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::kappa
+(
+    const label patchI
+) const
+{
+    return tmp<scalarField>
+    (
+        new scalarField
+        (
+            interpolateXY
+            (
+                T_.boundaryField()[patchI],
+                TValues_,
+                kappaValues_
+            )
+        )
+    );
+}
+
+
+Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::sigmaS
+(
+    const label patchI
+) const
+{
+    return tmp<scalarField>
+    (
+        new scalarField
+        (
+            interpolateXY
+            (
+                T_.boundaryField()[patchI],
+                TValues_,
+                sigmaSValues_
+            )
+        )
+    );
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::interpolatedSolidThermo::interpolatedSolidThermo
@@ -57,6 +139,7 @@ Foam::interpolatedSolidThermo::interpolatedSolidThermo
     calculate();
 }
 
+
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::interpolatedSolidThermo::~interpolatedSolidThermo()
@@ -195,26 +278,6 @@ Foam::tmp<Foam::volScalarField> Foam::interpolatedSolidThermo::Hf() const
 }
 
 
-Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::rho
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                rhoValues_
-            )
-        )
-    );
-}
-
-
 Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::Cp
 (
     const label patchI
@@ -255,66 +318,6 @@ Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::Hf
 }
 
 
-Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::emissivity
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                emissivityValues_
-            )
-        )
-    );
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::kappa
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                kappaValues_
-            )
-        )
-    );
-}
-
-
-Foam::tmp<Foam::scalarField> Foam::interpolatedSolidThermo::sigmaS
-(
-    const label patchI
-) const
-{
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                sigmaSValues_
-            )
-        )
-    );
-}
-
-
 bool Foam::interpolatedSolidThermo::read()
 {
     return read(dict_);
diff --git a/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.H b/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.H
index 15899c29a091cfb53e4a51d36e624a504d82b5a4..23e112db5a44159ef8cf65dc8eb99ed4d8fb7086 100644
--- a/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/interpolatedSolidThermo/interpolatedSolidThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -60,6 +60,21 @@ private:
         const dictionary dict_;
 
 
+        // Helper functions
+
+            //- Density [kg/m3]
+            tmp<scalarField> rho(const label patchI) const;
+
+            //- Scatter coefficient [1/m]
+            tmp<scalarField> sigmaS(const label) const;
+
+            //- Absorption coefficient [1/m]
+            tmp<scalarField> kappa(const label) const;
+
+             //- Emissivity []
+            tmp<scalarField> emissivity(const label) const;
+
+
 public:
 
     // Constructors
@@ -98,24 +113,12 @@ public:
 
         // Per patch calculation
 
-            //- Density [kg/m3]
-            virtual tmp<scalarField> rho(const label patchI) const;
-
             //- Specific heat capacity [J/kg/K)]
             virtual tmp<scalarField> Cp(const label patchI) const;
 
             //- Heat of formation [J/kg]
             virtual tmp<scalarField> Hf(const label patchI) const;
 
-            //- Scatter coefficient [1/m]
-            virtual tmp<scalarField> sigmaS(const label) const;
-
-            //- Absorption coefficient [1/m]
-            virtual tmp<scalarField> kappa(const label) const;
-
-             //- Emissivity []
-            virtual tmp<scalarField> emissivity(const label) const;
-
 
         // I-O
 
diff --git a/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.C b/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.C
index 7a8b659b88dd5bb784c8ebd9abd090457d21d9d4..1b15c88946923e6523bcb55e875acd813b4fda3e 100644
--- a/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -100,7 +100,6 @@ Foam::isotropicKSolidThermo::isotropicKSolidThermo(const fvMesh& mesh)
 
 void Foam::isotropicKSolidThermo::correct()
 {
-
     // Correct K
     K_.internalField() = interpolateXY
     (
@@ -111,31 +110,30 @@ void Foam::isotropicKSolidThermo::correct()
 
     forAll(K_.boundaryField(), patchI)
     {
-        K_.boundaryField()[patchI] == this->K(patchI)();
+        K_.boundaryField()[patchI] == interpolateXY
+        (
+            T_.boundaryField()[patchI],
+            TValues_,
+            KValues_
+        );
     }
 
     interpolatedSolidThermo::calculate();
 }
 
 
+Foam::tmp<Foam::volScalarField> Foam::isotropicKSolidThermo::K() const
+{
+    return K_;
+}
+
+
 Foam::tmp<Foam::scalarField> Foam::isotropicKSolidThermo::K
 (
     const label patchI
 ) const
 {
-
-    return tmp<scalarField>
-    (
-        new scalarField
-        (
-            interpolateXY
-            (
-                T_.boundaryField()[patchI],
-                TValues_,
-                KValues_
-            )
-        )
-    );
+    return K_.boundaryField()[patchI];
 }
 
 
@@ -154,6 +152,7 @@ bool Foam::isotropicKSolidThermo::writeData(Ostream& os) const
     return ok && os.good();
 }
 
+
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::isotropicKSolidThermo::~isotropicKSolidThermo()
diff --git a/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.H b/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.H
index 77f84f3ba63e39c4484b4d3f3e974d898d188490..d6acac3e91c1654837ef9e3b3b2052b2ad8e7c24 100644
--- a/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/isotropicKSolidThermo/isotropicKSolidThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -87,17 +87,30 @@ public:
         // Access functions
 
             //- Constant access to K
-            virtual const volScalarField& K() const
+            virtual tmp<volScalarField> K() const;
+
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volSymmTensorField> directionalK() const
             {
-                return K_;
+                notImplemented("directionalKSolidThermo::directionalK() const");
+                return tmp<volSymmTensorField>(NULL);
             }
 
-
         // Per patch calculation
 
             //- Thermal conductivity [W//m/K]
             virtual tmp<scalarField> K(const label patchI) const;
 
+            //- Thermal conductivity [W//m/K]
+            virtual tmp<symmTensorField> directionalK(const label) const
+            {
+                notImplemented
+                (
+                    "directionalKSolidThermo::directionalK(const label) const"
+                );
+                return tmp<symmTensorField>(NULL);
+            }
+
 
     // I-O
 
diff --git a/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.C b/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.C
index 024f6cfcedb8df8391a9742028f9e4cecabbe24d..0f78d32337846755d44d386e49bd5466ab32bde9 100644
--- a/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.C
+++ b/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -63,6 +63,96 @@ void Foam::solidMixtureThermo<MixtureType>::calculate()
 }
 
 
+template<class MixtureType>
+Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::rho
+(
+    const label patchI
+) const
+{
+    const scalarField& patchT = T_.boundaryField()[patchI];
+    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
+    const labelUList& cells = pp.faceCells();
+
+    tmp<scalarField> tRho(new scalarField(patchT.size()));
+    scalarField& Rho = tRho();
+
+    forAll(patchT, celli)
+    {
+        Rho[celli] = MixtureType::rho(patchT[celli], cells[celli]);
+    }
+
+    return tRho;
+}
+
+
+template<class MixtureType>
+Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::sigmaS
+(
+    const label patchI
+) const
+{
+    const scalarField& patchT = T_.boundaryField()[patchI];
+    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
+    const labelUList& cells = pp.faceCells();
+
+    tmp<scalarField> tsigmaS(new scalarField(patchT.size()));
+    scalarField& sigmaS = tsigmaS();
+
+    forAll(patchT, celli)
+    {
+        sigmaS[celli] =
+            MixtureType::sigmaS(patchT[celli], cells[celli]);
+    }
+
+    return tsigmaS;
+}
+
+
+template<class MixtureType>
+Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::kappa
+(
+    const label patchI
+) const
+{
+    const scalarField& patchT = T_.boundaryField()[patchI];
+   const polyPatch& pp = mesh_.boundaryMesh()[patchI];
+    const labelUList& cells = pp.faceCells();
+
+    tmp<scalarField> tKappa(new scalarField(patchT.size()));
+    scalarField& kappa = tKappa();
+
+    forAll(patchT, celli)
+    {
+        kappa[celli] =
+            MixtureType::kappa(patchT[celli], cells[celli]);
+    }
+
+    return tKappa;
+}
+
+
+template<class MixtureType>
+Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::emissivity
+(
+    const label patchI
+) const
+{
+    const scalarField& patchT = T_.boundaryField()[patchI];
+    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
+    const labelUList& cells = pp.faceCells();
+
+    tmp<scalarField> te(new scalarField(patchT.size()));
+    scalarField& e = te();
+
+    forAll(patchT, celli)
+    {
+        e[celli] = MixtureType::emissivity(patchT[celli], cells[celli]);
+    }
+
+    return te;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class MixtureType>
@@ -117,6 +207,7 @@ Foam::solidMixtureThermo<MixtureType>::solidMixtureThermo
     calculate();
 }
 
+
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 template<class MixtureType>
@@ -134,7 +225,7 @@ void Foam::solidMixtureThermo<MixtureType>::correct()
 
 
 template<class MixtureType>
-const Foam::volScalarField& Foam::solidMixtureThermo<MixtureType>::K() const
+Foam::tmp<Foam::volScalarField> Foam::solidMixtureThermo<MixtureType>::K() const
 {
     return K_;
 }
@@ -261,7 +352,7 @@ Foam::solidMixtureThermo<MixtureType>::Hf() const
 
 
 template<class MixtureType>
-Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::rho
+Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::K
 (
     const label patchI
 ) const
@@ -270,15 +361,15 @@ Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::rho
     const polyPatch& pp = mesh_.boundaryMesh()[patchI];
     const labelUList& cells = pp.faceCells();
 
-    tmp<scalarField> tRho(new scalarField(patchT.size()));
-    scalarField& Rho = tRho();
+    tmp<scalarField> tK(new scalarField(patchT.size()));
+    scalarField& K = tK();
 
     forAll(patchT, celli)
     {
-        Rho[celli] = MixtureType::rho(patchT[celli], cells[celli]);
+        K[celli] = MixtureType::K(patchT[celli], cells[celli]);
     }
 
-    return tRho;
+    return tK;
 }
 
 
@@ -326,28 +417,6 @@ Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::hs
 }
 
 
-template<class MixtureType>
-Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::K
-(
-    const label patchI
-) const
-{
-    const scalarField& patchT = T_.boundaryField()[patchI];
-    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
-    const labelUList& cells = pp.faceCells();
-
-    tmp<scalarField> tK(new scalarField(patchT.size()));
-    scalarField& K = tK();
-
-    forAll(patchT, celli)
-    {
-        K[celli] = MixtureType::K(patchT[celli], cells[celli]);
-    }
-
-    return tK;
-}
-
-
 template<class MixtureType>
 Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::Hf
 (
@@ -370,74 +439,6 @@ Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::Hf
 }
 
 
-template<class MixtureType>
-Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::sigmaS
-(
-    const label patchI
-) const
-{
-    const scalarField& patchT = T_.boundaryField()[patchI];
-    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
-    const labelUList& cells = pp.faceCells();
-
-    tmp<scalarField> tsigmaS(new scalarField(patchT.size()));
-    scalarField& sigmaS = tsigmaS();
-
-    forAll(patchT, celli)
-    {
-        sigmaS[celli] =
-            MixtureType::sigmaS(patchT[celli], cells[celli]);
-    }
-
-    return tsigmaS;
-}
-
-
-template<class MixtureType>
-Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::kappa
-(
-    const label patchI
-) const
-{
-    const scalarField& patchT = T_.boundaryField()[patchI];
-   const polyPatch& pp = mesh_.boundaryMesh()[patchI];
-    const labelUList& cells = pp.faceCells();
-
-    tmp<scalarField> tKappa(new scalarField(patchT.size()));
-    scalarField& kappa = tKappa();
-
-    forAll(patchT, celli)
-    {
-        kappa[celli] =
-            MixtureType::kappa(patchT[celli], cells[celli]);
-    }
-
-    return tKappa;
-}
-
-
-template<class MixtureType>
-Foam::tmp<Foam::scalarField> Foam::solidMixtureThermo<MixtureType>::emissivity
-(
-    const label patchI
-) const
-{
-    const scalarField& patchT = T_.boundaryField()[patchI];
-    const polyPatch& pp = mesh_.boundaryMesh()[patchI];
-    const labelUList& cells = pp.faceCells();
-
-    tmp<scalarField> te(new scalarField(patchT.size()));
-    scalarField& e = te();
-
-    forAll(patchT, celli)
-    {
-        e[celli] = MixtureType::emissivity(patchT[celli], cells[celli]);
-    }
-
-    return te;
-}
-
-
 template<class MixtureType>
 bool Foam::solidMixtureThermo<MixtureType>::read()
 {
diff --git a/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.H b/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.H
index 1e77c79a6b4a4c2894d18ec3063b8db682719ffd..100d371b99a8d9bd5c3c87c8196d6081a98472ae 100644
--- a/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.H
+++ b/src/thermophysicalModels/basicSolidThermo/solidMixtureThermo/solidMixtureThermo/solidMixtureThermo.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -68,6 +68,16 @@ private:
         void calculate();
 
 
+        // Per patch helpers to get mixture properties on a patch
+
+            tmp<scalarField> rho(const label patchI) const;
+
+            tmp<scalarField> sigmaS(const label patchI) const;
+
+            tmp<scalarField> kappa(const label patchI) const;
+
+            tmp<scalarField> emissivity(const label patchI) const;
+
 public:
 
     //- Runtime type information
@@ -89,6 +99,9 @@ public:
 
     // Member functions
 
+        //- Update properties
+        virtual void correct();
+
         //- Return the compostion of the solid mixture
         virtual MixtureType& composition()
         {
@@ -101,32 +114,44 @@ public:
             return *this;
         }
 
-        //- Update properties
-        virtual void correct();
 
-        // Access functions
+        // Derived thermal properties
 
             //- Thermal conductivity [W/m/K]
-            virtual const volScalarField& K() const;
+            virtual tmp<volScalarField> K() const;
 
+            //- Thermal conductivity [W/m/K]
+            virtual tmp<volSymmTensorField> directionalK() const
+            {
+                notImplemented("solidMixtureThermo::directionalK() const");
+                return tmp<volSymmTensorField>(NULL);
+            }
 
-            // Derived properties
+            //- Specific heat capacity [J/(kg.K)]
+            virtual tmp<volScalarField> Cp() const;
 
-                //- Specific heat capacity [J/(kg.K)]
-                virtual tmp<volScalarField> Cp() const;
+            //- Sensible enthalpy [J/(kg.K)]
+            virtual tmp<volScalarField> hs() const;
 
-                //- Heat of formation [J/kg]
-                virtual tmp<volScalarField> Hf() const;
+            //- Heat of formation [J/kg]
+            virtual tmp<volScalarField> Hf() const;
 
-                //- Sensible enthalpy [J/(kg.K)]
-                virtual tmp<volScalarField> hs() const;
 
+        // Per patch calculation
 
-        // Patches variables
+            //- Thermal conductivity [W/(m.K)]
+            virtual tmp<scalarField> K(const label patchI) const;
 
+            //- Thermal conductivity [W/(m.K)]
+            virtual tmp<symmTensorField> directionalK(const label) const
+            {
+                notImplemented
+                (
+                    "solidMixtureThermo::directionalK(const label) const"
+                );
+                return tmp<symmTensorField>(NULL);
+            }
 
-            //- Density [kg/m3]
-            virtual tmp<scalarField> rho(const label patchI) const;
 
             //- Specific heat capacity [J/(kg.K)]
             virtual tmp<scalarField> Cp(const label patchI) const;
@@ -134,21 +159,9 @@ public:
             //- Sensible enthalpy [J/(kg.K)]
             virtual tmp<scalarField> hs(const label patchI) const;
 
-            //- Thermal conductivity [W/(m.K)]
-            virtual tmp<scalarField> K(const label patchI) const;
-
             //- Heat of formation [J/kg]
             virtual tmp<scalarField> Hf(const label patchI) const;
 
-            //- Scatter coefficient [1/m]
-            virtual tmp<scalarField> sigmaS(const label patchI) const;
-
-            //- Absorptivity [1/m]
-            virtual tmp<scalarField> kappa(const label patchI) const;
-
-            //- Emissivity []
-            virtual tmp<scalarField> emissivity(const label patchI) const;
-
 
         //- Read thermophysicalProperties dictionary
         virtual bool read();
diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/Allrun b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/Allrun
index 6e1c645ec0268f71fc520897dba3ad8cab0876b2..762810a181ef3c95bb62f1e7f85afc67ab37ab8b 100755
--- a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/Allrun
+++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/Allrun
@@ -42,7 +42,7 @@ runParallel `getApplication` 4
 # Reconstruct
 for i in bottomWater topAir heater leftSolid rightSolid
 do
-   reconstructPar -region $i > log.reconstructPar.$i2 >&1
+   reconstructPar -region $i > log.reconstructPar.$i 2>&1
 done
 
 
diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/README.txt b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8462b44418512ac3e5ff8ebd26a3429502f7b9aa
--- /dev/null
+++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionLiquidHeater/README.txt
@@ -0,0 +1,16 @@
+To run with directional thermo:
+
+- compile chtMultiRegionFoam/solid/setRegionSolidFields.H with
+
+    tmp<volSymmTensorField> tkappa = thermo.directionalK();
+    const volSymmTensorField& kappa = tkappa();
+
+- change in e.g. heater:
+
+    - in constant/heater/solidThermophysicalProperties:
+
+        thermoType directionalKSolidThermo;
+
+    - in 0/heater/T:
+
+        K               directionalSolidThermo;