diff --git a/applications/test/vectorTools/Make/files b/applications/test/vectorTools/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..0b30b98f8f3b0c0c1048846c8e90a62733a12dda
--- /dev/null
+++ b/applications/test/vectorTools/Make/files
@@ -0,0 +1,3 @@
+Test-vectorTools.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-vectorTools
diff --git a/applications/test/vectorTools/Make/options b/applications/test/vectorTools/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..9e015e6078873ee32ae6d53ac1590010819dcb69
--- /dev/null
+++ b/applications/test/vectorTools/Make/options
@@ -0,0 +1 @@
+EXE_INC = -I$(FOAM_APP)/utilities/mesh/generation/cvMesh/vectorTools
diff --git a/applications/test/vectorTools/Test-vectorTools.C b/applications/test/vectorTools/Test-vectorTools.C
new file mode 100644
index 0000000000000000000000000000000000000000..0c85ac935bcfbe7aaa654be653ecb9635cdaa356
--- /dev/null
+++ b/applications/test/vectorTools/Test-vectorTools.C
@@ -0,0 +1,71 @@
+#include "vector.H"
+#include "IOstreams.H"
+#include "vectorTools.H"
+#include "unitConversion.H"
+
+using namespace Foam;
+
+
+void test(const vector& a, const vector& b, const scalar tolerance)
+{
+    Info<< "Vectors " << a << " and " << b 
+        << " are (to tolerance of " << tolerance << "): ";
+
+    if (vectorTools::areParallel(a, b, tolerance))
+        Info<< " parallel ";
+
+    if (vectorTools::areOrthogonal(a, b, tolerance))
+        Info<< " orthogonal ";
+
+    if (vectorTools::areAcute(a, b))
+        Info<< " acute ";
+
+    if (vectorTools::areObtuse(a, b))
+        Info<< " obtuse ";
+
+    Info<< ", angle = " << vectorTools::degAngleBetween(a, b);
+
+    Info<< endl;
+}
+
+
+int main()
+{
+    vector a(1.0, 1.0, 1.0);
+    vector b(2.0, 2.0, 2.0);
+
+    test(a, b, 0.0);
+    test(a, b, VSMALL);
+    test(a, b, SMALL);
+    test(a, b, 1e-3);
+    test(a, b, 1e-1);
+
+    a = vector(1,0,0);
+    b = vector(0,2,0);
+
+    test(a, b, 0.0);
+    test(a, b, VSMALL);
+    test(a, b, SMALL);
+    test(a, b, 1e-3);
+    test(a, b, 1e-1);
+
+    a = vector(1,0,0);
+    b = vector(-1,0,0);
+
+    test(a, b, 0.0);
+    test(a, b, VSMALL);
+    test(a, b, SMALL);
+    test(a, b, 1e-3);
+    test(a, b, 1e-1);
+
+    a = vector(1,0,0);
+    b = vector(-1,2,0);
+
+    test(a, b, 0.0);
+    test(a, b, VSMALL);
+    test(a, b, SMALL);
+    test(a, b, 1e-3);
+    test(a, b, 1e-1);
+
+    return 0;
+}
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files
index 29305c3320e3620372a63a9bea4c126aea8bed4b..217ec9d12e939f51c72fc6c3423b738f3d9c004a 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files
@@ -4,6 +4,7 @@ conformalVoronoiMesh/conformalVoronoiMesh.C
 conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
 conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
 conformalVoronoiMesh/conformalVoronoiMeshIO.C
+conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C
 conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C
 
 cvControls/cvControls.C
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options
index 711e4ae7738e8eacbef824ea378241d33bebcd97..1a1902b559ddda2a3ff6c37acca1316f89b6b7ea 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options
@@ -14,7 +14,8 @@ EXE_INC = \
     -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
     -I$(LIB_SRC)/edgeMesh/lnInclude \
     -I$(LIB_SRC)/dynamicMesh/lnInclude \
-    -I$(LIB_SRC)/triSurface/lnInclude
+    -I$(LIB_SRC)/triSurface/lnInclude \
+    -I../vectorTools
 
 EXE_LIBS = \
     -lmeshTools \
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H
index 8efb9ec71126115c8f79fff2b2142775092201b7..3176e4dec42543fc4fdf9d49b9ef1178ec4e81a2 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H
@@ -72,6 +72,48 @@ typedef Delaunay::Cell_handle      Cell_handle;
 typedef Delaunay::Point            Point;
 
 
+//- Spatial sort traits to use with a pair of point pointers and an integer.
+//  Taken from a post on the CGAL lists: 2010-01/msg00004.html by
+//  Sebastien Loriot (Geometry Factory).
+template<class Triangulation>
+struct Traits_for_spatial_sort
+:
+    public Triangulation::Geom_traits
+{
+    typedef typename Triangulation::Geom_traits Gt;
+
+    typedef std::pair<const typename Triangulation::Point*, int> Point_3;
+
+    struct Less_x_3
+    {
+        bool operator()(const Point_3& p, const Point_3& q) const
+        {
+            return typename Gt::Less_x_3()(*(p.first), *(q.first));
+        }
+    };
+
+    struct Less_y_3
+    {
+        bool operator()(const Point_3& p, const Point_3& q) const
+        {
+            return typename Gt::Less_y_3()(*(p.first), *(q.first));
+        }
+    };
+
+    struct Less_z_3
+    {
+        bool operator()(const Point_3& p, const Point_3& q) const
+        {
+            return typename Gt::Less_z_3()(*(p.first), *(q.first));
+        }
+    };
+
+    Less_x_3  less_x_3_object () const {return Less_x_3();}
+    Less_y_3  less_y_3_object () const {return Less_y_3();}
+    Less_z_3  less_z_3_object () const {return Less_z_3();}
+};
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
index dd58fc5141707e9f78bad63d01d6bb5ecf5bd1b6..4e97af7a7a7583dea1535bae83092571ea12bbb0 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C
@@ -39,6 +39,8 @@ defineTypeNameAndDebug(conformalVoronoiMesh, 0);
 
 }
 
+const Foam::scalar Foam::conformalVoronoiMesh::tolParallel = 1e-3;
+
 
 // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
 
@@ -78,17 +80,17 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment
         norm
     );
 
-    vector np = norm[0];
+    const vector np = norm[0];
 
     // Generate equally spaced 'spokes' in a circle normal to the
     // direction from the vertex to the closest point on the surface
     // and look for a secondary intersection.
 
-    vector d = surfHit.hitPoint() - pt;
+    const vector d = surfHit.hitPoint() - pt;
 
-    tensor Rp = rotationTensor(vector(0,0,1), np);
+    const tensor Rp = rotationTensor(vector(0,0,1), np);
 
-    label s = cvMeshControls().alignmentSearchSpokes();
+    const label s = cvMeshControls().alignmentSearchSpokes();
 
     scalar closestSpokeHitDistance = GREAT;
 
@@ -96,7 +98,7 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment
 
     label closestSpokeSurface = -1;
 
-    scalar spanMag = geometryToConformTo_.globalBounds().mag();
+    const scalar spanMag = geometryToConformTo_.globalBounds().mag();
 
     for (label i = 0; i < s; i++)
     {
@@ -176,8 +178,7 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment
             "("
                 "const Foam::point& pt"
             ") const"
-        )
-            << "No secondary surface hit found in spoke search "
+        )   << "No secondary surface hit found in spoke search "
             << "using " << s
             << " spokes, try increasing alignmentSearchSpokes."
             << endl;
@@ -198,7 +199,7 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment
     // Secondary alignment
     vector ns = np ^ na;
 
-    if (mag(ns) <  SMALL)
+    if (mag(ns) < SMALL)
     {
         FatalErrorIn("conformalVoronoiMesh::requiredAlignment")
             << "Parallel normals detected in spoke search." << nl
@@ -220,7 +221,7 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment
 
 void Foam::conformalVoronoiMesh::insertPoints
 (
-    std::list<Point>& points,
+    List<Point>& points,
     bool distribute
 )
 {
@@ -241,11 +242,13 @@ void Foam::conformalVoronoiMesh::insertPoints
 
         DynamicList<Foam::point> transferPoints;
 
+        List<Point> pointsOnProcessor;
+
         for
         (
-            std::list<Point>::iterator pit=points.begin();
+            List<Point>::iterator pit = points.begin();
             pit != points.end();
-            // No action
+            ++pit
         )
         {
             Foam::point p(topoint(*pit));
@@ -253,15 +256,20 @@ void Foam::conformalVoronoiMesh::insertPoints
             if (!positionOnThisProc(p))
             {
                 transferPoints.append(p);
-
-                pit = points.erase(pit);
             }
             else
             {
-                ++pit;
+                pointsOnProcessor.append(*pit);
             }
         }
 
+        points.setSize(pointsOnProcessor.size());
+        forAll(pointsOnProcessor, pI)
+        {
+            points[pI] = pointsOnProcessor[pI];
+        }
+        pointsOnProcessor.clear();
+
         // Send the points that are not on this processor to the appropriate
         // place
         Foam::autoPtr<Foam::mapDistribute> map
@@ -271,7 +279,7 @@ void Foam::conformalVoronoiMesh::insertPoints
 
         forAll(transferPoints, tPI)
         {
-            points.push_back(toPoint(transferPoints[tPI]));
+            points.append(toPoint(transferPoints[tPI]));
         }
 
         label sizeChange = preDistributionSize - label(points.size());
@@ -307,16 +315,16 @@ void Foam::conformalVoronoiMesh::insertPoints
     // using the range insert (faster than inserting points one by one)
     insert(points.begin(), points.end());
 
-    // Info<< "USING INDIVIDUAL INSERTION TO DETECT FAILURE" << endl;
-    // for
-    // (
-    //     std::list<Point>::iterator pit=points.begin();
-    //     pit != points.end();
-    //     ++pit
-    // )
-    // {
-    //     insertPoint(topoint(*pit), Vb::vtInternal);
-    // }
+//     Info<< "USING INDIVIDUAL INSERTION TO DETECT FAILURE" << endl;
+//     for
+//     (
+//         List<Point>::iterator pit=points.begin();
+//         pit != points.end();
+//         ++pit
+//     )
+//     {
+//         insertPoint(topoint(*pit), Vb::vtInternal);
+//     }
 
     label nInserted(number_of_vertices() - preInsertionSize);
 
@@ -386,31 +394,14 @@ void Foam::conformalVoronoiMesh::insertPoints
         //     << " points in total" << endl;
     }
 
-    // Using index is actually pointless, it is always zero.  Keep for clarity
-    // of code.
-
-    forAll(pts, pI)
-    {
-        // creation of points and indices is done assuming that it will be
-        // relative to the instantaneous number_of_vertices() at insertion.
-
-        label type = types[pI];
-
-        if (type > Vb::vtFar)
-        {
-            // This is a member of a point pair, don't use the type directly
-            // (note that this routine never gets called for referredPoints
-            //  so type will never be -procI)
-            type += number_of_vertices();
-        }
-
-        insertPoint
-        (
-            pts[pI],
-            indices[pI] + number_of_vertices(),
-            type
-        );
-    }
+    rangeInsertWithInfo
+    (
+        pts.begin(),
+        pts.end(),
+        *this,
+        indices,
+        types
+    );
 }
 
 
@@ -507,734 +498,6 @@ void Foam::conformalVoronoiMesh::insertEdgePointGroups
 }
 
 
-void Foam::conformalVoronoiMesh::createEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    label edgeI = edHit.index();
-
-    extendedFeatureEdgeMesh::edgeStatus edStatus = feMesh.getEdgeStatus(edgeI);
-
-    switch (edStatus)
-    {
-        case extendedFeatureEdgeMesh::EXTERNAL:
-        {
-            createExternalEdgePointGroup(feMesh, edHit, pts, indices, types);
-            break;
-        }
-        case extendedFeatureEdgeMesh::INTERNAL:
-        {
-            createInternalEdgePointGroup(feMesh, edHit, pts, indices, types);
-            break;
-        }
-        case extendedFeatureEdgeMesh::FLAT:
-        {
-            createFlatEdgePointGroup(feMesh, edHit, pts, indices, types);
-            break;
-        }
-        case extendedFeatureEdgeMesh::OPEN:
-        {
-            createOpenEdgePointGroup(feMesh, edHit, pts, indices, types);
-            break;
-        }
-        case extendedFeatureEdgeMesh::MULTIPLE:
-        {
-            createMultipleEdgePointGroup(feMesh, edHit, pts, indices, types);
-            break;
-        }
-        case extendedFeatureEdgeMesh::NONE:
-        {
-            break;
-        }
-    }
-}
-
-
-void Foam::conformalVoronoiMesh::createExternalEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    const Foam::point& edgePt = edHit.hitPoint();
-
-    scalar ppDist = pointPairDistance(edgePt);
-
-    const vectorField& feNormals = feMesh.normals();
-    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
-
-    // As this is an external edge, there are two normals by definition
-    const vector& nA = feNormals[edNormalIs[0]];
-    const vector& nB = feNormals[edNormalIs[1]];
-
-    if (mag(nA & nB) > 1 - SMALL)
-    {
-        // The normals are nearly parallel, so this is too sharp a feature to
-        // conform to.
-
-        return;
-    }
-
-    // Normalised distance of reference point from edge point
-    vector refVec((nA + nB)/(1 + (nA & nB)));
-
-    if (magSqr(refVec) > sqr(5.0))
-    {
-        // Limit the size of the conformation
-        ppDist *= 5.0/mag(refVec);
-
-        // Pout<< nl << "createExternalEdgePointGroup limit "
-        //     << "edgePt " << edgePt << nl
-        //     << "refVec " << refVec << nl
-        //     << "mag(refVec) " << mag(refVec) << nl
-        //     << "ppDist " << ppDist << nl
-        //     << "nA " << nA << nl
-        //     << "nB " << nB << nl
-        //     << "(nA & nB) " << (nA & nB) << nl
-        //     << endl;
-    }
-
-    // Convex. So refPt will be inside domain and hence a master point
-    Foam::point refPt = edgePt - ppDist*refVec;
-
-    // Result when the points are eventually inserted.
-    // Add number_of_vertices() at insertion of first vertex to all numbers:
-    // pt           index type
-    // refPt        0     1
-    // reflectedA   1     0
-    // reflectedB   2     0
-
-    // Insert the master point pairing the the first slave
-
-    pts.append(refPt);
-    indices.append(0);
-    types.append(1);
-
-    // Insert the slave points by reflecting refPt in both faces.
-    // with each slave refering to the master
-
-    Foam::point reflectedA = refPt + 2*ppDist*nA;
-    pts.append(reflectedA);
-    indices.append(0);
-    types.append(-1);
-
-    Foam::point reflectedB = refPt + 2*ppDist*nB;
-    pts.append(reflectedB);
-    indices.append(0);
-    types.append(-2);
-}
-
-
-void Foam::conformalVoronoiMesh::createInternalEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    const Foam::point& edgePt = edHit.hitPoint();
-
-    scalar ppDist = pointPairDistance(edgePt);
-
-    const vectorField& feNormals = feMesh.normals();
-    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
-
-    // As this is an external edge, there are two normals by definition
-    const vector& nA = feNormals[edNormalIs[0]];
-    const vector& nB = feNormals[edNormalIs[1]];
-
-    if (mag(nA & nB) > 1 - SMALL)
-    {
-        // The normals are nearly parallel, so this is too sharp a feature to
-        // conform to.
-
-        return;
-    }
-
-    // Normalised distance of reference point from edge point
-    vector refVec((nA + nB)/(1 + (nA & nB)));
-
-    if (magSqr(refVec) > sqr(5.0))
-    {
-        // Limit the size of the conformation
-        ppDist *= 5.0/mag(refVec);
-
-        // Pout<< nl << "createInternalEdgePointGroup limit "
-        //     << "edgePt " << edgePt << nl
-        //     << "refVec " << refVec << nl
-        //     << "mag(refVec) " << mag(refVec) << nl
-        //     << "ppDist " << ppDist << nl
-        //     << "nA " << nA << nl
-        //     << "nB " << nB << nl
-        //     << "(nA & nB) " << (nA & nB) << nl
-        //     << endl;
-    }
-
-    // Concave. master and reflected points inside the domain.
-    Foam::point refPt = edgePt - ppDist*refVec;
-
-    // Generate reflected master to be outside.
-    Foam::point reflMasterPt = refPt + 2*(edgePt - refPt);
-
-    // Reflect reflMasterPt in both faces.
-    Foam::point reflectedA = reflMasterPt - 2*ppDist*nA;
-
-    Foam::point reflectedB = reflMasterPt - 2*ppDist*nB;
-
-    scalar totalAngle =
-        radToDeg(constant::mathematical::pi + acos(nA & nB));
-
-    // Number of quadrants the angle should be split into
-    int nQuads = int(totalAngle/cvMeshControls().maxQuadAngle()) + 1;
-
-    // The number of additional master points needed to obtain the
-    // required number of quadrants.
-    int nAddPoints = min(max(nQuads - 2, 0), 2);
-
-    // index of reflMaster
-    label reflectedMaster = 2 + nAddPoints;
-
-    // Add number_of_vertices() at insertion of first vertex to all numbers:
-    // Result for nAddPoints 1 when the points are eventually inserted
-    // pt           index type
-    // reflectedA   0     2
-    // reflectedB   1     2
-    // reflMasterPt 2     0
-
-    // Result for nAddPoints 1 when the points are eventually inserted
-    // pt           index type
-    // reflectedA   0     3
-    // reflectedB   1     3
-    // refPt        2     3
-    // reflMasterPt 3     0
-
-    // Result for nAddPoints 2 when the points are eventually inserted
-    // pt           index type
-    // reflectedA   0     4
-    // reflectedB   1     4
-    // reflectedAa  2     4
-    // reflectedBb  3     4
-    // reflMasterPt 4     0
-
-    // Master A is inside.
-    pts.append(reflectedA);
-    indices.append(0);
-    types.append(reflectedMaster--);
-
-    // Master B is inside.
-    pts.append(reflectedB);
-    indices.append(0);
-    types.append(reflectedMaster--);
-
-    if (nAddPoints == 1)
-    {
-        // One additinal point is the reflection of the slave point,
-        // i.e. the original reference point
-        pts.append(refPt);
-        indices.append(0);
-        types.append(reflectedMaster--);
-    }
-    else if (nAddPoints == 2)
-    {
-        Foam::point reflectedAa = refPt + ppDist*nB;
-        pts.append(reflectedAa);
-        indices.append(0);
-        types.append(reflectedMaster--);
-
-        Foam::point reflectedBb = refPt + ppDist*nA;
-        pts.append(reflectedBb);
-        indices.append(0);
-        types.append(reflectedMaster--);
-    }
-
-    // Slave is outside.
-    pts.append(reflMasterPt);
-    indices.append(0);
-    types.append(-(nAddPoints + 2));
-}
-
-
-void Foam::conformalVoronoiMesh::createFlatEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    const Foam::point& edgePt = edHit.hitPoint();
-
-    scalar ppDist = pointPairDistance(edgePt);
-
-    const vectorField& feNormals = feMesh.normals();
-    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
-
-    // As this is a flat edge, there are two normals by definition
-    const vector& nA = feNormals[edNormalIs[0]];
-    const vector& nB = feNormals[edNormalIs[1]];
-
-    // Average normal to remove any bias to one side, although as this
-    // is a flat edge, the normals should be essentially the same
-    vector n = 0.5*(nA + nB);
-
-    // Direction along the surface to the control point, sense of edge
-    // direction not important, as +s and -s can be used because this
-    // is a flat edge
-    vector s = 2.0*ppDist*(feMesh.edgeDirections()[edHit.index()] ^ n);
-
-    createPointPair(ppDist, edgePt + s, n, pts, indices, types);
-    createPointPair(ppDist, edgePt - s, n, pts, indices, types);
-}
-
-
-void Foam::conformalVoronoiMesh::createOpenEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    Info<< "NOT INSERTING OPEN EDGE POINT GROUP, NOT IMPLEMENTED" << endl;
-}
-
-
-void Foam::conformalVoronoiMesh::createMultipleEdgePointGroup
-(
-    const extendedFeatureEdgeMesh& feMesh,
-    const pointIndexHit& edHit,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    Info<< "NOT INSERTING MULTIPLE EDGE POINT GROUP, NOT IMPLEMENTED"
-        << endl;
-}
-
-
-void Foam::conformalVoronoiMesh::insertFeaturePoints()
-{
-    Info<< nl << "Conforming to feature points" << endl;
-
-    DynamicList<Foam::point> pts;
-    DynamicList<label> indices;
-    DynamicList<label> types;
-
-    label preFeaturePointSize = number_of_vertices();
-
-    createConvexFeaturePoints(pts, indices, types);
-
-    createConcaveFeaturePoints(pts, indices, types);
-
-    createMixedFeaturePoints(pts, indices, types);
-
-    // Insert the created points, distributing to the appropriate processor
-    insertPoints(pts, indices, types, true);
-
-    if (cvMeshControls().objOutput())
-    {
-        writePoints("featureVertices.obj", pts);
-    }
-
-    label nFeatureVertices = number_of_vertices() - preFeaturePointSize;
-
-    if (Pstream::parRun())
-    {
-        reduce(nFeatureVertices, sumOp<label>());
-    }
-
-    if (nFeatureVertices > 0)
-    {
-        Info<< "    Inserted " << nFeatureVertices
-            << " feature vertices" << endl;
-    }
-
-    featureVertices_.clear();
-
-    forAll(pts, pI)
-    {
-        featureVertices_.push_back
-        (
-            Vb(toPoint(pts[pI]), indices[pI], types[pI])
-        );
-    }
-
-    constructFeaturePointLocations();
-}
-
-
-void Foam::conformalVoronoiMesh::createConvexFeaturePoints
-(
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    const PtrList<extendedFeatureEdgeMesh>& feMeshes
-    (
-        geometryToConformTo_.features()
-    );
-
-    forAll(feMeshes, i)
-    {
-        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
-
-        for
-        (
-            label ptI = feMesh.convexStart();
-            ptI < feMesh.concaveStart();
-            ptI++
-        )
-        {
-            const Foam::point& featPt = feMesh.points()[ptI];
-
-            if (!positionOnThisProc(featPt))
-            {
-                continue;
-            }
-
-            vectorField featPtNormals = feMesh.featurePointNormals(ptI);
-
-            vector cornerNormal = sum(featPtNormals);
-            cornerNormal /= mag(cornerNormal);
-
-            Foam::point internalPt =
-                featPt - pointPairDistance(featPt)*cornerNormal;
-
-            // Result when the points are eventually inserted (example n = 4)
-            // Add number_of_vertices() at insertion of first vertex to all
-            // numbers:
-            // pt           index type
-            // internalPt   0     1
-            // externalPt0  1     0
-            // externalPt1  2     0
-            // externalPt2  3     0
-            // externalPt3  4     0
-
-            pts.append(internalPt);
-            indices.append(0);
-            types.append(1);
-
-            label internalPtIndex = -1;
-
-            forAll(featPtNormals, nI)
-            {
-                const vector& n = featPtNormals[nI];
-
-                plane planeN = plane(featPt, n);
-
-                Foam::point externalPt =
-                    internalPt + 2.0 * planeN.distance(internalPt) * n;
-
-                pts.append(externalPt);
-                indices.append(0);
-                types.append(internalPtIndex--);
-            }
-        }
-    }
-}
-
-
-void Foam::conformalVoronoiMesh::createConcaveFeaturePoints
-(
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    const PtrList<extendedFeatureEdgeMesh>& feMeshes
-    (
-        geometryToConformTo_.features()
-    );
-
-    forAll(feMeshes, i)
-    {
-        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
-
-        for
-        (
-            label ptI = feMesh.concaveStart();
-            ptI < feMesh.mixedStart();
-            ptI++
-        )
-        {
-            const Foam::point& featPt = feMesh.points()[ptI];
-
-            if (!positionOnThisProc(featPt))
-            {
-                continue;
-            }
-
-            vectorField featPtNormals = feMesh.featurePointNormals(ptI);
-
-            vector cornerNormal = sum(featPtNormals);
-            cornerNormal /= mag(cornerNormal);
-
-            Foam::point externalPt =
-                featPt + pointPairDistance(featPt)*cornerNormal;
-
-            label externalPtIndex = featPtNormals.size();
-
-            // Result when the points are eventually inserted (example n = 5)
-            // Add number_of_vertices() at insertion of first vertex to all
-            // numbers:
-            // pt           index type
-            // internalPt0  0     5
-            // internalPt1  1     5
-            // internalPt2  2     5
-            // internalPt3  3     5
-            // internalPt4  4     5
-            // externalPt   5     4
-
-            forAll(featPtNormals, nI)
-            {
-                const vector& n = featPtNormals[nI];
-
-                plane planeN = plane(featPt, n);
-
-                Foam::point internalPt =
-                    externalPt - 2.0 * planeN.distance(externalPt) * n;
-
-                pts.append(internalPt);
-                indices.append(0);
-                types.append(externalPtIndex--);
-            }
-
-            pts.append(externalPt);
-            indices.append(0);
-            types.append(-1);
-        }
-    }
-}
-
-
-void Foam::conformalVoronoiMesh::createMixedFeaturePoints
-(
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
-)
-{
-    if (cvMeshControls().mixedFeaturePointPPDistanceCoeff() < 0)
-    {
-        Info<<nl << "Skipping specialised handling for mixed feature points"
-            << endl;
-        return;
-    }
-
-    const PtrList<extendedFeatureEdgeMesh>& feMeshes
-    (
-        geometryToConformTo_.features()
-    );
-
-    forAll(feMeshes, i)
-    {
-        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
-
-        for
-        (
-            label ptI = feMesh.mixedStart();
-            ptI < feMesh.nonFeatureStart();
-            ptI++
-        )
-        {
-            if
-            (
-                !createSpecialisedFeaturePoint(feMesh, ptI, pts, indices, types)
-            )
-            {
-                // Specialisations available for some mixed feature points.  For
-                // non-specialised feature points, inserting mixed internal and
-                // external edge groups at feature point.
-
-                const labelList& pEds(feMesh.pointEdges()[ptI]);
-
-                // Skipping unsupported mixed feature point types
-
-                bool skipEdge = false;
-
-                forAll(pEds, e)
-                {
-                    label edgeI = pEds[e];
-
-                    extendedFeatureEdgeMesh::edgeStatus edStatus =
-                        feMesh.getEdgeStatus(edgeI);
-
-                    if
-                    (
-                        edStatus == extendedFeatureEdgeMesh::OPEN
-                     || edStatus == extendedFeatureEdgeMesh::MULTIPLE
-                    )
-                    {
-                        Info<< "Edge type " << edStatus
-                            << " found for mixed feature point " << ptI
-                            << ". Not supported."
-                            << endl;
-
-                        skipEdge = true;
-                    }
-                }
-
-                if (skipEdge)
-                {
-                    Info<< "Skipping point " << ptI << nl << endl;
-
-                    continue;
-                }
-
-                const Foam::point& pt(feMesh.points()[ptI]);
-
-                if (!positionOnThisProc(pt))
-                {
-                    continue;
-                }
-
-                scalar edgeGroupDistance = mixedFeaturePointDistance(pt);
-
-                forAll(pEds, e)
-                {
-                    label edgeI = pEds[e];
-
-                    Foam::point edgePt =
-                        pt + edgeGroupDistance*feMesh.edgeDirection(edgeI, ptI);
-
-                    pointIndexHit edgeHit(true, edgePt, edgeI);
-
-                    createEdgePointGroup(feMesh, edgeHit, pts, indices, types);
-                }
-            }
-        }
-    }
-}
-
-
-void Foam::conformalVoronoiMesh::constructFeaturePointLocations()
-{
-    DynamicList<Foam::point> ftPtLocs;
-
-    const PtrList<extendedFeatureEdgeMesh>& feMeshes
-    (
-        geometryToConformTo_.features()
-    );
-
-    forAll(feMeshes, i)
-    {
-        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
-
-
-        if (cvMeshControls().mixedFeaturePointPPDistanceCoeff() < 0)
-        {
-            // Ignoring mixed feature points
-            for
-            (
-                label ptI = feMesh.convexStart();
-                ptI < feMesh.mixedStart();
-                ptI++
-            )
-            {
-                ftPtLocs.append(feMesh.points()[ptI]);
-            }
-        }
-        else
-        {
-            for
-            (
-                label ptI = feMesh.convexStart();
-                ptI < feMesh.nonFeatureStart();
-                ptI++
-            )
-            {
-                ftPtLocs.append(feMesh.points()[ptI]);
-            }
-        }
-    }
-
-    featurePointLocations_.transfer(ftPtLocs);
-}
-
-
-void Foam::conformalVoronoiMesh::reinsertFeaturePoints(bool distribute)
-{
-    Info<< nl << "Reinserting stored feature points" << endl;
-
-    label preReinsertionSize(number_of_vertices());
-
-    if (distribute)
-    {
-        DynamicList<Foam::point> pointsToInsert;
-        DynamicList<label> indices;
-        DynamicList<label> types;
-
-        for
-        (
-            std::list<Vb>::iterator vit=featureVertices_.begin();
-            vit != featureVertices_.end();
-            ++vit
-        )
-        {
-            pointsToInsert.append(topoint(vit->point()));
-            indices.append(vit->index());
-            types.append(vit->type());
-        }
-
-        // Insert distributed points
-        insertPoints(pointsToInsert, indices, types, true);
-
-        // Save points in new distribution
-        featureVertices_.clear();
-
-        forAll(pointsToInsert, pI)
-        {
-            featureVertices_.push_back
-            (
-                Vb(toPoint(pointsToInsert[pI]), indices[pI], types[pI])
-            );
-        }
-    }
-    else
-    {
-        for
-        (
-            std::list<Vb>::iterator vit=featureVertices_.begin();
-            vit != featureVertices_.end();
-            ++vit
-        )
-        {
-            // Assuming that all of the reinsertions are pair points, and that
-            // the index and type are relative, i.e. index 0 and type relative
-            // to it.
-            insertPoint
-            (
-                vit->point(),
-                vit->index() + number_of_vertices(),
-                vit->type() + number_of_vertices()
-            );
-        }
-    }
-
-    Info<< "    Reinserted "
-        << returnReduce
-        (
-            label(number_of_vertices()) - preReinsertionSize,
-            sumOp<label>()
-        )
-        << " vertices" << endl;
-}
-
-
 const Foam::indexedOctree<Foam::treeDataPoint>&
 Foam::conformalVoronoiMesh::featurePointTree() const
 {
@@ -1277,33 +540,17 @@ bool Foam::conformalVoronoiMesh::nearFeaturePt(const Foam::point& pt) const
 }
 
 
-void Foam::conformalVoronoiMesh::reset()
+void Foam::conformalVoronoiMesh::reset(const bool distribute)
 {
     this->clear();
 
-    insertBoundingPoints();
-}
-
-
-void Foam::conformalVoronoiMesh::insertBoundingPoints()
-{
-    pointField farPts = geometryToConformTo_.globalBounds().points();
+    reinsertBoundingPoints();
 
-    // Shift corners of bounds relative to origin
-    farPts -= geometryToConformTo_.globalBounds().midpoint();
+    // Reinsert feature points, distributing them as necessary.
+    reinsertFeaturePoints(distribute);
+    //insertFeaturePoints();
 
-    // Scale the box up
-    farPts *= 10.0;
-
-    // Shift corners of bounds back to be relative to midpoint
-    farPts += geometryToConformTo_.globalBounds().midpoint();
-
-    limitBounds_ = treeBoundBox(farPts);
-
-    forAll(farPts, fPI)
-    {
-        insertPoint(farPts[fPI], Vb::vtFar);
-    }
+    startOfInternalPoints_ = number_of_vertices();
 }
 
 
@@ -1313,7 +560,7 @@ void Foam::conformalVoronoiMesh::insertInitialPoints()
 
     timeCheck("Before initial points call");
 
-    std::list<Point> initPts = initialPointsMethod_->initialPoints();
+    List<Point> initPts = initialPointsMethod_->initialPoints();
 
     timeCheck("After initial points call");
 
@@ -1466,13 +713,8 @@ bool Foam::conformalVoronoiMesh::distributeBackground()
             cellVertexTypes
         );
 
-        // Remove the entire tessellation
-        reset();
-
-        // Reinsert feature points, distributing them as necessary.
-        reinsertFeaturePoints(true);
-
-        startOfInternalPoints_ = number_of_vertices();
+        // Reset the entire tessellation
+        reset(true);
 
         timeCheck("Distribution performed");
 
@@ -1533,7 +775,7 @@ bool Foam::conformalVoronoiMesh::distributeBackground()
 
 void Foam::conformalVoronoiMesh::storeSizesAndAlignments()
 {
-    std::list<Point> storePts;
+    DynamicList<Point> storePts(number_of_vertices());
 
     for
     (
@@ -1544,17 +786,19 @@ void Foam::conformalVoronoiMesh::storeSizesAndAlignments()
     {
         if (vit->internalPoint())
         {
-            storePts.push_back(vit->point());
+            storePts.append(vit->point());
         }
     }
 
+    storePts.shrink();
+
     storeSizesAndAlignments(storePts);
 }
 
 
 void Foam::conformalVoronoiMesh::storeSizesAndAlignments
 (
-    const std::list<Point>& storePts
+    const List<Point>& storePts
 )
 {
     timeCheck("Start of storeSizesAndAlignments");
@@ -1571,7 +815,7 @@ void Foam::conformalVoronoiMesh::storeSizesAndAlignments
 
     for
     (
-        std::list<Point>::const_iterator pit=storePts.begin();
+        List<Point>::const_iterator pit = storePts.begin();
         pit != storePts.end();
         ++pit
     )
@@ -1598,7 +842,7 @@ void Foam::conformalVoronoiMesh::storeSizesAndAlignments
 
 void Foam::conformalVoronoiMesh::updateSizesAndAlignments
 (
-    const std::list<Point>& storePts
+    const List<Point>& storePts
 )
 {
     // This function is only used in serial, the background redistribution
@@ -1909,7 +1153,7 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh
     Delaunay(),
     runTime_(runTime),
     rndGen_(64293*Pstream::myProcNo()),
-    cvMeshControls_(*this, cvMeshDict),
+    cvMeshControls_(cvMeshDict),
     allGeometry_
     (
         IOobject
@@ -1940,6 +1184,8 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh
     featureVertices_(),
     featurePointLocations_(),
     featurePointTreePtr_(),
+    edgeLocationTreePtr_(),
+    surfacePtLocationTreePtr_(),
     sizeAndAlignmentLocations_(),
     storedSizes_(),
     storedAlignments_(),
@@ -1965,8 +1211,7 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh
     (
         faceAreaWeightModel::New
         (
-            cvMeshDict.subDict("motionControl"),
-            *this
+            cvMeshDict.subDict("motionControl")
         )
     ),
     decomposition_()
@@ -2100,7 +1345,7 @@ void Foam::conformalVoronoiMesh::move()
         true
     );
 
-    std::list<Point> pointsToInsert;
+    DynamicList<Point> pointsToInsert(number_of_vertices());
 
     for
     (
@@ -2137,15 +1382,15 @@ void Foam::conformalVoronoiMesh::move()
 
             forAll(alignmentDirsA, aA)
             {
-                const vector& a(alignmentDirsA[aA]);
+                const vector& a = alignmentDirsA[aA];
 
                 scalar maxDotProduct = 0.0;
 
                 forAll(alignmentDirsB, aB)
                 {
-                    const vector& b(alignmentDirsB[aB]);
+                    const vector& b = alignmentDirsB[aB];
 
-                    scalar dotProduct = a & b;
+                    const scalar dotProduct = a & b;
 
                     if (mag(dotProduct) > maxDotProduct)
                     {
@@ -2179,7 +1424,7 @@ void Foam::conformalVoronoiMesh::move()
                      && pointToBeRetained[vB->index()] == true
                     )
                     {
-                        pointsToInsert.push_back
+                        pointsToInsert.append
                         (
                             toPoint(0.5*(dVA + dVB))
                         );
@@ -2212,7 +1457,7 @@ void Foam::conformalVoronoiMesh::move()
                     alignmentDir *= -1;
                 }
 
-                scalar alignmentDotProd = ((rAB/rABMag) & alignmentDir);
+                const scalar alignmentDotProd = ((rAB/rABMag) & alignmentDir);
 
                 if
                 (
@@ -2220,9 +1465,9 @@ void Foam::conformalVoronoiMesh::move()
                   > cvMeshControls().cosAlignmentAcceptanceAngle()
                 )
                 {
-                    scalar targetCellSize = averageCellSize(vA, vB);
+                    const scalar targetCellSize = averageCellSize(vA, vB);
 
-                    scalar targetFaceArea = sqr(targetCellSize);
+                    const scalar targetFaceArea = sqr(targetCellSize);
 
                     alignmentDir *= 0.5*targetCellSize;
 
@@ -2231,7 +1476,7 @@ void Foam::conformalVoronoiMesh::move()
                     // directions.
                     vector delta = alignmentDir - 0.5*rAB;
 
-                    scalar faceArea = dualFace.mag(dualVertices);
+                    const scalar faceArea = dualFace.mag(dualVertices);
 
                     delta *= faceAreaWeightModel_->faceAreaWeight
                     (
@@ -2262,8 +1507,7 @@ void Foam::conformalVoronoiMesh::move()
                         )
                         {
                             // Prevent insertions spanning surfaces
-
-                            pointsToInsert.push_back
+                            pointsToInsert.append
                             (
                                 toPoint(0.5*(dVA + dVB))
                             );
@@ -2285,14 +1529,13 @@ void Foam::conformalVoronoiMesh::move()
                             // the short edge if neither attached
                             // point has already been identified to be
                             // removed.
-
                             if
                             (
                                 pointToBeRetained[vA->index()] == true
                              && pointToBeRetained[vB->index()] == true
                             )
                             {
-                                pointsToInsert.push_back
+                                pointsToInsert.append
                                 (
                                     toPoint(0.5*(dVA + dVB))
                                 );
@@ -2371,7 +1614,7 @@ void Foam::conformalVoronoiMesh::move()
                 // Only necessary if using an exact constructions kernel
                 // (extended precision)
 
-                pointsToInsert.push_back
+                pointsToInsert.append
                 (
                     toPoint
                     (
@@ -2383,12 +1626,44 @@ void Foam::conformalVoronoiMesh::move()
         }
     }
 
+    pointsToInsert.shrink();
+
+    // Save displacements to file.
+    if (cvMeshControls().objOutput() && runTime_.outputTime())
+    {
+        Pout<< "Writing point displacement vectors to file." << endl;
+        OFstream str("displacements_" + runTime_.timeName() + ".obj");
+
+        for
+        (
+            Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+            vit != finite_vertices_end();
+            ++vit
+        )
+        {
+            if (vit->internalPoint())
+            {
+                if (pointToBeRetained[vit->index()] == true)
+                {
+                    meshTools::writeOBJ(str, topoint(vit->point()));
+
+                    str << "vn "
+                        << displacementAccumulator[vit->index()][0] << " "
+                        << displacementAccumulator[vit->index()][1] << " "
+                        << displacementAccumulator[vit->index()][2] << " "
+                        << endl;
+                }
+            }
+        }
+    }
+
     // Remove the entire tessellation
     reset();
 
-    reinsertFeaturePoints();
-
-    startOfInternalPoints_ = number_of_vertices();
+    if (cvMeshControls().objOutput() && runTime_.outputTime())
+    {
+        writePoints("featurePoints_" + runTime_.timeName() + ".obj", false);
+    }
 
     timeCheck("Displacement calculated");
 
@@ -2396,13 +1671,21 @@ void Foam::conformalVoronoiMesh::move()
 
     insertPoints(pointsToInsert);
 
+    if (cvMeshControls().objOutput() && runTime_.outputTime())
+    {
+        writePoints("points_" + runTime_.timeName() + ".obj", false);
+    }
+
     timeCheck("Internal points inserted");
 
     conformToSurface();
 
-    timeCheck("After conformToSurface");
+    if (cvMeshControls().objOutput() && runTime_.outputTime())
+    {
+        writeBoundaryPoints("boundaryPoints_" + runTime_.timeName() + ".obj");
+    }
 
-    updateSizesAndAlignments(pointsToInsert);
+    timeCheck("After conformToSurface");
 
     // Write the intermediate mesh, do not filter the dual faces.
     if (runTime_.outputTime())
@@ -2410,6 +1693,8 @@ void Foam::conformalVoronoiMesh::move()
         writeMesh(runTime_.timeName(), false);
     }
 
+    updateSizesAndAlignments(pointsToInsert);
+
     Info<< nl
         << "Total displacement = " << totalDisp << nl
         << "Total distance = " << totalDist << nl
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
index 53b56da7b20d734760541d8d9b892f0dc2fafdfa..4ee0b2a42d6ab720f3a3b81d46fecf4119cb6140 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H
@@ -35,6 +35,10 @@ SourceFiles
     conformalVoronoiMeshI.H
     conformalVoronoiMesh.C
     conformalVoronoiMeshIO.C
+    conformalVoronoiMeshConformToSurface.C
+    conformalVoronoiMeshFeaturePoints.C
+    conformalVoronoiMeshFeaturePointSpecialisations.C
+    conformalVoronoiMeshCalcDualMesh.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -44,6 +48,7 @@ SourceFiles
 #define CGAL_INEXACT
 
 #include "CGALTriangulation3Ddefs.H"
+#include <CGAL/Spatial_sort_traits_adapter_3.h>
 #include "uint.H"
 #include "ulong.H"
 #include "searchableSurfaces.H"
@@ -57,6 +62,8 @@ SourceFiles
 #include "plane.H"
 #include "SortableList.H"
 #include "meshTools.H"
+#include "dynamicIndexedOctree.H"
+#include "dynamicTreeDataPoint.H"
 #include "indexedOctree.H"
 #include "treeDataPoint.H"
 #include "unitConversion.H"
@@ -73,6 +80,7 @@ SourceFiles
 #include "processorPolyPatch.H"
 #include "zeroGradientFvPatchFields.H"
 #include "globalIndex.H"
+#include "pointFeatureEdgesTypes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -116,6 +124,15 @@ public:
 
 private:
 
+    // Static data
+
+        static const scalar tolParallel;
+
+        static const scalar searchConeAngle;
+
+        static const scalar searchAngleOppositeSurface;
+
+
     // Private data
 
         //- The time registry of the application
@@ -146,7 +163,7 @@ private:
 
         //- Store the feature constraining points to be reinserted after a
         //  triangulation clear. Maintained with relative types and indices.
-        std::list<Vb> featureVertices_;
+        List<Vb> featureVertices_;
 
         //- Storing the locations of all of the features to be conformed to.
         //  Single pointField required by the featurePointTree.
@@ -155,6 +172,14 @@ private:
         //- Search tree for feature point locations
         mutable autoPtr<indexedOctree<treeDataPoint> > featurePointTreePtr_;
 
+        //- Search tree for edge point locations
+        mutable autoPtr<dynamicIndexedOctree<dynamicTreeDataPoint> >
+        edgeLocationTreePtr_;
+
+        //- Search tree for surface point locations
+        mutable autoPtr<dynamicIndexedOctree<dynamicTreeDataPoint> >
+        surfacePtLocationTreePtr_;
+
         //- Store locations where the cell size and alignments will be
         //  pre-calculated and looked up
         pointField sizeAndAlignmentLocations_;
@@ -170,7 +195,7 @@ private:
 
         //- Store the surface and feature edge conformation locations to be
         //  reinserted
-        std::list<Vb> surfaceConformationVertices_;
+        List<Vb> surfaceConformationVertices_;
 
         //- Method for inserting initial points.  Runtime selectable.
         autoPtr<initialPointsMethod> initialPointsMethod_;
@@ -235,6 +260,12 @@ private:
             const Foam::point& pt
         ) const;
 
+        //- Return the square of the local surface point exclusion distance
+        inline scalar surfacePtExclusionDistanceSqr
+        (
+            const Foam::point& pt
+        ) const;
+
         //- Return the square of the local surface search distance
         inline scalar surfaceSearchDistanceSqr(const Foam::point& pt) const;
 
@@ -279,7 +310,7 @@ private:
         //  processors
         void insertPoints
         (
-            std::list<Point>& points,
+            List<Point>& points,
             bool distribute = true
         );
 
@@ -396,6 +427,8 @@ private:
         //- Determine and insert point groups at the feature points
         void insertFeaturePoints();
 
+        bool edgesShareNormal(const label e1, const label e2) const;
+
         //- Create point groups at convex feature points
         void createConvexFeaturePoints
         (
@@ -420,12 +453,24 @@ private:
             DynamicList<label>& types
         );
 
+        //- Fill the pointFeatureEdgesType struct with the types of feature
+        //  edges that are attached to the point.
+        List<extendedFeatureEdgeMesh::edgeStatus> calcPointFeatureEdgesTypes
+        (
+            const extendedFeatureEdgeMesh& feMesh,
+            const labelList& pEds,
+            pointFeatureEdgesTypes& pFEdgeTypes
+        );
+
         //- Create feature point groups if a specialisation exists for the
         //  structure
         bool createSpecialisedFeaturePoint
         (
             const extendedFeatureEdgeMesh& feMesh,
-            label ptI,
+            const labelList& pEds,
+            const pointFeatureEdgesTypes& pFEdgeTypes,
+            const List<extendedFeatureEdgeMesh::edgeStatus>& allEdStat,
+            const label ptI,
             DynamicList<Foam::point>& pts,
             DynamicList<label>& indices,
             DynamicList<label>& types
@@ -434,6 +479,11 @@ private:
         //- Store the locations of all of the features to be conformed to
         void constructFeaturePointLocations();
 
+        List<pointIndexHit> findSurfacePtLocationsNearFeaturePoint
+        (
+            const Foam::point& featurePoint
+        ) const;
+
         //- Reinsert stored feature point defining points
         void reinsertFeaturePoints(bool distribute = false);
 
@@ -443,13 +493,18 @@ private:
         //- Check if a location is in exclusion range around a feature point
         bool nearFeaturePt(const Foam::point& pt) const;
 
-        //- Clear the entire tesselation and insert bounding points
-        void reset();
+        //- Clear the entire tesselation
+        //  Reinsert bounding points, feature points and recalculate
+        //  startOfInternalPoints_
+        void reset(const bool distribute = false);
 
         //- Insert far points in a large bounding box to avoid dual edges
         //  spanning huge distances
         void insertBoundingPoints();
 
+        //- Reinsert the bounding points
+        void reinsertBoundingPoints();
+
         //- Insert the initial points into the triangulation, based on the
         //  initialPointsMethod
         void insertInitialPoints();
@@ -468,10 +523,10 @@ private:
 
         //- Store data for sizeAndAlignmentLocations_, storedSizes_ and
         //  storedAlignments_ and initialise the sizeAndAlignmentTreePtr_
-        void storeSizesAndAlignments(const std::list<Point>& storePts);
+        void storeSizesAndAlignments(const List<Point>& storePts);
 
         //- Restore the sizes and alignments if required
-        void updateSizesAndAlignments(const std::list<Point>& storePts);
+        void updateSizesAndAlignments(const List<Point>& storePts);
 
         //- Demand driven construction of octree for and alignment points
         const indexedOctree<treeDataPoint>& sizeAndAlignmentTree() const;
@@ -526,6 +581,14 @@ private:
             const Delaunay::Finite_vertices_iterator& vit
         ) const;
 
+        //- Return all intersections
+        bool dualCellSurfaceAllIntersections
+        (
+            const Delaunay::Finite_vertices_iterator& vit,
+            DynamicList<pointIndexHit>& info,
+            DynamicList<label>& hitSurface
+        ) const;
+
         //- Return false if the line is entirely outside the current processor
         //  domain, true is either point is inside, or the processor domain
         //  bounadry is intersected (i.e. the points are box outside but the
@@ -533,6 +596,7 @@ private:
         //  intersect.
         bool clipLineToProc
         (
+            const Foam::point& pt,
             Foam::point& a,
             Foam::point& b
         ) const;
@@ -624,21 +688,67 @@ private:
             label callCount = 0
         ) const;
 
+        //- Find angle between the normals of two close surface points.
+        scalar angleBetweenSurfacePoints(Foam::point pA, Foam::point pB) const;
+
+        //- Check if a surface point is near another.
+        bool nearSurfacePoint
+        (
+            pointIndexHit& pHit,
+            label& surfaceHit,
+            DynamicList<Foam::point>& existingSurfacePtLocations
+        ) const;
+
+        //- Append a point to the surface point tree and the existing list
+        bool appendToSurfacePtTree
+        (
+            const Foam::point& pt,
+            DynamicList<Foam::point>& existingSurfacePtLocations
+        ) const;
+
+        //- Append a point to the edge location tree and the existing list
+        bool appendToEdgeLocationTree
+        (
+            const Foam::point& pt,
+            DynamicList<Foam::point>& existingEdgeLocations
+        ) const;
+
+        //- Check if a point is near any feature edge points.
+        bool pointIsNearFeatureEdgeLocation(const Foam::point& pt) const;
+
+        bool pointIsNearFeatureEdgeLocation
+        (
+            const Foam::point& pt,
+            pointIndexHit& info
+        ) const;
+
+        //- Check if a point is near any surface conformation points.
+        bool pointIsNearSurfaceLocation(const Foam::point& pt) const;
+
+        bool pointIsNearSurfaceLocation
+        (
+            const Foam::point& pt,
+            pointIndexHit& info
+        ) const;
+
         //- Check if a location is in the exclusion range of an existing feature
         //- edge conformation location
         bool nearFeatureEdgeLocation
         (
-            const Foam::point& pt,
-            DynamicList<Foam::point>& newEdgeLocations,
-            pointField& existingEdgeLocations,
-            autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree
+            pointIndexHit& pHit,
+            DynamicList<Foam::point>& existingEdgeLocations
         ) const;
 
-        //- Build or rebuild the edgeLocationTree
+        //- Build or rebuild the edge location tree
         void buildEdgeLocationTree
         (
-            autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree,
-            const pointField& existingEdgeLocations
+            const DynamicList<Foam::point>& existingEdgeLocations
+        ) const;
+
+        //- Build or rebuild the surface point location tree
+        void buildSurfacePtLocationTree
+        (
+            const DynamicList<Foam::point>& existingSurfacePtLocations
         ) const;
 
         //- Build or rebuild the sizeAndAlignmentTree
@@ -650,8 +760,8 @@ private:
         (
             const Delaunay::Finite_vertices_iterator& vit,
             const Foam::point& vert,
-            const pointIndexHit& surfHit,
-            label hitSurface,
+            const DynamicList<pointIndexHit>& surfHit,
+            const DynamicList<label>& hitSurface,
             scalar surfacePtReplaceDistCoeffSqr,
             scalar edgeSearchDistCoeffSqr,
             DynamicList<pointIndexHit>& surfaceHits,
@@ -659,8 +769,8 @@ private:
             DynamicList<pointIndexHit>& featureEdgeHits,
             DynamicList<label>& featureEdgeFeaturesHit,
             DynamicList<Foam::point>& newEdgeLocations,
-            pointField& existingEdgeLocations,
-            autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree
+            DynamicList<Foam::point>& existingEdgeLocations,
+            DynamicList<Foam::point>& existingSurfacePtLocations
         ) const;
 
         //- Store the surface conformation with the indices offset to be
@@ -996,6 +1106,9 @@ public:
             //- Write Delaunay points to .obj file
             void writePoints(const fileName& fName, bool internalOnly) const;
 
+            //- Write the boundary Delaunay points to .obj file
+            void writeBoundaryPoints(const fileName& fName) const;
+
             //- Write list of points to file
             void writePoints
             (
@@ -1045,9 +1158,93 @@ public:
             //  actual cell size (cbrt(actual cell volume)).
             void writeCellSizes(const fvMesh& mesh) const;
 
+            //- Calculate and write the cell centres.
+            void writeCellCentres(const fvMesh& mesh) const;
+
             //- Find the cellSet of the boundary cells which have points that
             //  protrude out of the surface beyond a tolerance.
             void findRemainingProtrusionSet(const fvMesh& mesh) const;
+
+
+            //- Function inserting points into a triangulation and setting the
+            //  index and type data of the point in the correct order. This is
+            //  faster than inserting points individually.
+            //
+            //  Adapted from a post on the CGAL lists: 2010-01/msg00004.html by
+            //  Sebastien Loriot (Geometry Factory).
+            //
+            //  @todo problems putting declaration in the .C file. Function
+            //        prototype is not recognised.
+            template<class Triangulation, class Point_iterator>
+            void rangeInsertWithInfo
+            (
+                Point_iterator begin,
+                Point_iterator end,
+                Triangulation& T,
+                DynamicList<label>& indices,
+                DynamicList<label>& types
+            )
+            {
+                typedef std::vector
+                <
+                    std::pair<const typename Triangulation::Point*, label>
+                > vectorPairPointIndex;
+
+                vectorPairPointIndex points;
+                label index = 0;
+
+                for (Point_iterator it = begin; it != end; ++it)
+                {
+                    points.push_back
+                    (
+                        std::make_pair(&(toPoint(*it)), index++)
+                    );
+                }
+
+                std::random_shuffle(points.begin(), points.end());
+
+                spatial_sort
+                (
+                    points.begin(),
+                    points.end(),
+                    Traits_for_spatial_sort<Triangulation>()
+                );
+
+                typename Triangulation::Cell_handle hint;
+
+                for
+                (
+                    typename vectorPairPointIndex::const_iterator
+                    p = points.begin();
+                    p != points.end();
+                    ++p
+                )
+                {
+                    typename Triangulation::Locate_type lt;
+                    typename Triangulation::Cell_handle c;
+                    label li, lj;
+
+                    c = T.locate(*(p->first), lt, li, lj, hint);
+
+                    typename Triangulation::Vertex_handle v
+                        = T.insert(*(p->first), lt, c, li, lj);
+
+                    label oldIndex = p->second;
+
+                    label type = types[oldIndex];
+
+                    if (type > Vb::vtFar)
+                    {
+                        // This is a member of a point pair, don't use the type
+                        // directly (note that this routine never gets called
+                        // for referredPoints so type will never be -procI)
+                        type += T.number_of_vertices() - 1;
+                    }
+
+                    v->index() = indices[oldIndex] + T.number_of_vertices() - 1;
+                    v->type() = type;
+                }
+            }
 };
 
 
@@ -1059,6 +1256,10 @@ public:
 
 #include "conformalVoronoiMeshI.H"
 
+//#ifdef NoRepository
+//#   include "conformalVoronoiMeshTemplates.C"
+//#endif
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
index e764923699bf3ebfa50f76032db0893d6336128a..d2c23eef51c8c066db1cf1ac04ff4007489a1445 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C
@@ -79,53 +79,59 @@ void Foam::conformalVoronoiMesh::calcDualMesh
         }
     }
 
-    for
-    (
-        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
-        vit != finite_vertices_end();
-        vit++
-    )
-    {
-        std::list<Cell_handle> cells;
-        incident_cells(vit, std::back_inserter(cells));
-
-        bool hasProcPt = false;
-
-        for
-        (
-            std::list<Cell_handle>::iterator cit=cells.begin();
-            cit != cells.end();
-            ++cit
-        )
-        {
-            if
-            (
-                !(*cit)->vertex(0)->real()
-             || !(*cit)->vertex(1)->real()
-             || !(*cit)->vertex(2)->real()
-             || !(*cit)->vertex(3)->real()
-            )
-            {
-                hasProcPt = true;
-
-                break;
-            }
-        }
-
-        if (hasProcPt)
-        {
-            for
-            (
-                std::list<Cell_handle>::iterator cit=cells.begin();
-                cit != cells.end();
-                ++cit
-            )
-            {
-                (*cit)->filterCount() =
-                     cvMeshControls().filterCountSkipThreshold() + 1;
-            }
-        }
-    }
+// REMOVED BECAUSE THIS CODE STOPS ALL FACES NEAR ANY BOUNDARY (PROC OR REAL)
+// FROM BEING FILTERED.
+//
+//    for
+//    (
+//        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+//        vit != finite_vertices_end();
+//        vit++
+//    )
+//    {
+//        std::list<Cell_handle> cells;
+//        incident_cells(vit, std::back_inserter(cells));
+//
+//        bool hasProcPt = false;
+//
+//        for
+//        (
+//            std::list<Cell_handle>::iterator cit = cells.begin();
+//            cit != cells.end();
+//            ++cit
+//        )
+//        {
+//            // Allow filtering if any vertices are far points. Otherwise faces
+//            // with boundary points attached to a cell with a far point will not
+//            // be filtered.
+//            if
+//            (
+//                ( !(*cit)->vertex(0)->real() && !(*cit)->vertex(0)->farPoint() )
+//             || ( !(*cit)->vertex(1)->real() && !(*cit)->vertex(1)->farPoint() )
+//             || ( !(*cit)->vertex(2)->real() && !(*cit)->vertex(2)->farPoint() )
+//             || ( !(*cit)->vertex(3)->real() && !(*cit)->vertex(3)->farPoint() )
+//            )
+//            {
+//                hasProcPt = true;
+//
+//                break;
+//            }
+//        }
+//
+//        if (hasProcPt)
+//        {
+//            for
+//            (
+//                std::list<Cell_handle>::iterator cit = cells.begin();
+//                cit != cells.end();
+//                ++cit
+//            )
+//            {
+//                (*cit)->filterCount() =
+//                     cvMeshControls().filterCountSkipThreshold() + 1;
+//            }
+//        }
+//    }
 
     PackedBoolList boundaryPts(number_of_cells(), false);
 
@@ -250,7 +256,7 @@ void Foam::conformalVoronoiMesh::calcDualMesh
 
                 timeCheck("End of filtering iteration");
 
-            } while (nBadQualityFaces > nInitialBadQualityFaces);
+            } while (nBadQualityFaces > 0); //nInitialBadQualityFaces);
         }
     }
 
@@ -987,7 +993,6 @@ Foam::label Foam::conformalVoronoiMesh::collapseFaces
 
             if (dualFace.size() < 3)
             {
-                // This face has been collapsed already
                 continue;
             }
 
@@ -995,8 +1000,6 @@ Foam::label Foam::conformalVoronoiMesh::collapseFaces
 
             if (maxFC > cvMeshControls().filterCountSkipThreshold())
             {
-                // A vertex on this face has been limited too many
-                // times, skip
                 continue;
             }
 
@@ -1900,7 +1903,6 @@ void Foam::conformalVoronoiMesh::indexDualVertices
             )
             {
                 // This is a boundary dual vertex
-
                 boundaryPts[dualVertI] = true;
             }
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
index e65a5beefa2daa974addc6fea9a0c5faff76c9c6..925a19c099c057fa710b77bca13264838251740f 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C
@@ -25,6 +25,15 @@ License
 
 #include "conformalVoronoiMesh.H"
 #include "backgroundMeshDecomposition.H"
+#include "vectorTools.H"
+
+using namespace Foam::vectorTools;
+
+const Foam::scalar Foam::conformalVoronoiMesh::searchConeAngle
+    = Foam::cos(degToRad(30));
+
+const Foam::scalar Foam::conformalVoronoiMesh::searchAngleOppositeSurface
+    = Foam::cos(degToRad(150));
 
 // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
 
@@ -125,12 +134,15 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
     // Initialise containers to store the edge conformation locations
     DynamicList<Foam::point> newEdgeLocations;
 
-    pointField existingEdgeLocations(0);
+    DynamicList<Foam::point> existingEdgeLocations;
+    DynamicList<Foam::point> existingSurfacePtLocations;
+
+    buildEdgeLocationTree(existingEdgeLocations);
+    buildSurfacePtLocationTree(existingSurfacePtLocations);
 
-    autoPtr<indexedOctree<treeDataPoint> > edgeLocationTree;
 
     // Initialise the edgeLocationTree
-    buildEdgeLocationTree(edgeLocationTree, existingEdgeLocations);
+    //buildEdgeLocationTree(edgeLocationTree, existingEdgeLocations);
 
     label initialTotalHits = 0;
 
@@ -167,10 +179,10 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
 
     // Initial surface protrusion conformation - nearest surface point
     {
-        scalar edgeSearchDistCoeffSqr =
+        const scalar edgeSearchDistCoeffSqr =
             cvMeshControls().edgeSearchDistCoeffSqrInitial(reconfMode);
 
-        scalar surfacePtReplaceDistCoeffSqr =
+        const scalar surfacePtReplaceDistCoeffSqr =
             cvMeshControls().surfacePtReplaceDistCoeffSqrInitial(reconfMode);
 
         DynamicList<pointIndexHit> surfaceHits;
@@ -188,46 +200,51 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
         {
             if (vit->internalPoint())
             {
-                Foam::point vert(topoint(vit->point()));
-                scalar searchDistanceSqr = surfaceSearchDistanceSqr(vert);
-                pointIndexHit surfHit;
-                label hitSurface;
+                const Foam::point vert = topoint(vit->point());
 
-                geometryToConformTo_.findSurfaceNearest
-                (
-                    vert,
-                    searchDistanceSqr,
-                    surfHit,
-                    hitSurface
-                );
+                if (!positionOnThisProc(vert))
+                {
+                    continue;
+                }
 
-                if (surfHit.hit())
+                DynamicList<pointIndexHit> surfHitList;
+                DynamicList<label> hitSurfaceList;
+
+                if
+                (
+                    dualCellSurfaceAllIntersections
+                    (
+                        vit,
+                        surfHitList,
+                        hitSurfaceList
+                    )
+                )
                 {
+                    // This used to be just before this if statement.
+                    // Moved because a point is only near the boundary if
+                    // the dual cell intersects the surface.
                     vit->setNearBoundary();
 
-                    if (dualCellSurfaceAnyIntersection(vit))
-                    {
-                        // meshTools::writeOBJ(Pout, vert);
-                        // meshTools::writeOBJ(Pout, surfHit.hitPoint());
-                        // Pout<< "l cr0 cr1" << endl;
+                    // meshTools::writeOBJ(Pout, vert);
+                    // meshTools::writeOBJ(Pout, surfHit.hitPoint());
+                    // Pout<< "l cr0 cr1" << endl;
 
-                        addSurfaceAndEdgeHits
-                        (
-                            vit,
-                            vert,
-                            surfHit,
-                            hitSurface,
-                            surfacePtReplaceDistCoeffSqr,
-                            edgeSearchDistCoeffSqr,
-                            surfaceHits,
-                            hitSurfaces,
-                            featureEdgeHits,
-                            featureEdgeFeaturesHit,
-                            newEdgeLocations,
-                            existingEdgeLocations,
-                            edgeLocationTree
-                        );
-                    }
+                    addSurfaceAndEdgeHits
+                    (
+                        vit,
+                        vert,
+                        surfHitList,
+                        hitSurfaceList,
+                        surfacePtReplaceDistCoeffSqr,
+                        edgeSearchDistCoeffSqr,
+                        surfaceHits,
+                        hitSurfaces,
+                        featureEdgeHits,
+                        featureEdgeFeaturesHit,
+                        newEdgeLocations,
+                        existingEdgeLocations,
+                        existingSurfacePtLocations
+                    );
                 }
             }
         }
@@ -339,7 +356,8 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
              || vit->referredInternalOrBoundaryPoint()
             )
             {
-                Foam::point vert(topoint(vit->point()));
+                const Foam::point vert = topoint(vit->point());
+
                 pointIndexHit surfHit;
                 label hitSurface;
 
@@ -349,12 +367,18 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
 
                 if (surfHit.hit())
                 {
+                    DynamicList<pointIndexHit> tmpPIH;
+                    tmpPIH.append(surfHit);
+
+                    DynamicList<label> tmpHS;
+                    tmpHS.append(hitSurface);
+
                     addSurfaceAndEdgeHits
                     (
                         vit,
                         vert,
-                        surfHit,
-                        hitSurface,
+                        tmpPIH,
+                        tmpHS,
                         surfacePtReplaceDistCoeffSqr,
                         edgeSearchDistCoeffSqr,
                         surfaceHits,
@@ -363,13 +387,14 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
                         featureEdgeFeaturesHit,
                         newEdgeLocations,
                         existingEdgeLocations,
-                        edgeLocationTree
+                        existingSurfacePtLocations
                     );
                 }
             }
             else if (vit->ppSlave() || vit->referredExternal())
             {
-                Foam::point vert(topoint(vit->point()));
+                const Foam::point vert = topoint(vit->point());
+
                 pointIndexHit surfHit;
                 label hitSurface;
 
@@ -379,12 +404,18 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
 
                 if (surfHit.hit())
                 {
+                    DynamicList<pointIndexHit> tmpPIH;
+                    tmpPIH.append(surfHit);
+
+                    DynamicList<label> tmpHS;
+                    tmpHS.append(hitSurface);
+
                     addSurfaceAndEdgeHits
                     (
                         vit,
                         vert,
-                        surfHit,
-                        hitSurface,
+                        tmpPIH,
+                        tmpHS,
                         surfacePtReplaceDistCoeffSqr,
                         edgeSearchDistCoeffSqr,
                         surfaceHits,
@@ -393,7 +424,7 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation
                         featureEdgeFeaturesHit,
                         newEdgeLocations,
                         existingEdgeLocations,
-                        edgeLocationTree
+                        existingSurfacePtLocations
                     );
                 }
             }
@@ -497,10 +528,10 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAnyIntersection
 
         if (Pstream::parRun())
         {
-            Foam::point a = dE0;
-            Foam::point b = dE1;
+            Foam::point& a = dE0;
+            Foam::point& b = dE1;
 
-            bool inProc = clipLineToProc(a, b);
+            bool inProc = clipLineToProc(topoint(vit->point()), a, b);
 
             // Check for the edge passing through a surface
             if
@@ -530,74 +561,185 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAnyIntersection
 }
 
 
-bool Foam::conformalVoronoiMesh::clipLineToProc
+bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections
 (
-    Foam::point& a,
-    Foam::point& b
+    const Delaunay::Finite_vertices_iterator& vit,
+    DynamicList<pointIndexHit>& infoList,
+    DynamicList<label>& hitSurfaceList
 ) const
 {
-    bool intersects = false;
+    bool flagIntersection = false;
 
-    if (decomposition_().positionOnThisProcessor(a))
-    {
-        // a is inside this processor
+    std::list<Facet> facets;
+    incident_facets(vit, std::back_inserter(facets));
 
-        if (decomposition_().positionOnThisProcessor(b))
+    for
+    (
+        std::list<Facet>::iterator fit = facets.begin();
+        fit != facets.end();
+        ++fit
+    )
+    {
+        if
+        (
+            is_infinite(fit->first)
+         || is_infinite(fit->first->neighbor(fit->second))
+        )
         {
-            // both a and b inside, no clip required
-            intersects = true;
+            continue;
         }
-        else
-        {
-            // b is outside, clip b to bounding box.
 
-            pointIndexHit info = decomposition_().findLine(b, a);
+        // 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)));
 
-            if (info.hit())
-            {
-                intersects = true;
-                b = info.hitPoint();
-            }
-        }
-    }
-    else
-    {
-        // a is outside this processor
+        pointIndexHit infoIntersection;
+        label hitSurfaceIntersection = -1;
 
-        if (decomposition_().positionOnThisProcessor(b))
+        if (Pstream::parRun())
         {
-            // b is inside this processor, clip a to processor
+            bool inProc = clipLineToProc(topoint(vit->point()), dE0, dE1);
 
-            pointIndexHit info = decomposition_().findLine(a, b);
-
-            if (info.hit())
+            if (!inProc)
             {
-                intersects = true;
-                a = info.hitPoint();
+                continue;
             }
         }
-        else
+
+        geometryToConformTo_.findSurfaceNearestIntersection
+        (
+            dE0,
+            dE1,
+            infoIntersection,
+            hitSurfaceIntersection
+        );
+
+        if (infoIntersection.hit())
         {
-            // both a and b outside, but they can still intersect the processor
+            vectorField norm(1);
+
+            allGeometry_[hitSurfaceIntersection].getNormal
+            (
+                List<pointIndexHit>(1, infoIntersection),
+                norm
+            );
+
+            const vector& n = norm[0];
+
+            const Foam::point vertex = topoint(vit->point());
+
+            const plane p(infoIntersection.hitPoint(), n);
+
+            const plane::ray r(vertex, n);
+
+            const scalar d = p.normalIntersect(r);
 
-            pointIndexHit info = decomposition_().findLine(a, b);
+            const Foam::point newPoint = vertex + d*n;
+
+            pointIndexHit info;
+            label hitSurface = -1;
+
+            geometryToConformTo_.findSurfaceNearest
+            (
+                newPoint,
+                surfaceSearchDistanceSqr(newPoint),
+                info,
+                hitSurface
+            );
+
+            bool rejectPoint = false;
 
             if (info.hit())
             {
-                intersects = true;
-                a = info.hitPoint();
+                if (!infoList.empty())
+                {
+                    forAll(infoList, hitI)
+                    {
+                        // Reject point if the point is already added
+                        if (infoList[hitI].index() == info.index())
+                        {
+                            rejectPoint = true;
+                            break;
+                        }
 
-                info = decomposition_().findLine(b, a);
+                        const Foam::point& p = infoList[hitI].hitPoint();
 
-                if (info.hit())
-                {
-                    b = info.hitPoint();
+                        const scalar separationDistance
+                            = mag(p - info.hitPoint());
+
+                        const scalar minSepDist
+                            = sqr(cvMeshControls().removalDistCoeff()
+                             *targetCellSize(p));
+
+                        // Reject the point if it is too close to another
+                        // surface point.
+                        // Could merge the points?
+                        if (separationDistance < minSepDist)
+                        {
+                            rejectPoint = true;
+                            break;
+                        }
+                    }
                 }
             }
+
+            // The normal ray from the vertex will not always result in a hit
+            // because another surface may be in the way.
+            if (!rejectPoint && info.hit())
+            {
+                flagIntersection = true;
+                infoList.append(info);
+                hitSurfaceList.append(hitSurface);
+            }
         }
     }
 
-    return intersects;
+    return flagIntersection;
+}
+
+
+bool Foam::conformalVoronoiMesh::clipLineToProc
+(
+    const Foam::point& pt,
+    Foam::point& a,
+    Foam::point& b
+) const
+{
+    bool inProc = false;
+
+    pointIndexHit findAnyIntersection = decomposition_().findLine(a, b);
+
+    if (!findAnyIntersection.hit())
+    {
+        pointIndexHit info = decomposition_().findLine(a, pt);
+
+        if (!info.hit())
+        {
+            inProc = true;
+        }
+        else
+        {
+            inProc = false;
+        }
+    }
+    else
+    {
+        pointIndexHit info = decomposition_().findLine(a, pt);
+
+        if (!info.hit())
+        {
+            inProc = true;
+            b = findAnyIntersection.hitPoint();
+        }
+        else
+        {
+            inProc = true;
+            a = findAnyIntersection.hitPoint();
+        }
+    }
+
+    return inProc;
 }
 
 
@@ -1213,13 +1355,13 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion
     std::list<Facet> facets;
     incident_facets(vit, std::back_inserter(facets));
 
-    Foam::point vert(topoint(vit->point()));
+    const Foam::point vert = topoint(vit->point());
 
     scalar maxProtrusionDistance = maxSurfaceProtrusion(vert);
 
     for
     (
-        std::list<Facet>::iterator fit=facets.begin();
+        std::list<Facet>::iterator fit = facets.begin();
         fit != facets.end();
         ++fit
     )
@@ -1230,7 +1372,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion
          && !is_infinite(fit->first->neighbor(fit->second))
         )
         {
-            Foam::point edgeMid =
+            const Foam::point edgeMid =
                 0.5
                *(
                     topoint(dual(fit->first))
@@ -1260,7 +1402,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion
 
                 const vector& n = norm[0];
 
-                scalar normalProtrusionDistance =
+                const scalar normalProtrusionDistance =
                     (edgeMid - surfHit.hitPoint()) & n;
 
                 if (normalProtrusionDistance > maxProtrusionDistance)
@@ -1311,7 +1453,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceIncursion
 
     for
     (
-        std::list<Facet>::iterator fit=facets.begin();
+        std::list<Facet>::iterator fit = facets.begin();
         fit != facets.end();
         ++fit
     )
@@ -1592,56 +1734,339 @@ void Foam::conformalVoronoiMesh::limitDisplacement
 }
 
 
-bool Foam::conformalVoronoiMesh::nearFeatureEdgeLocation
+Foam::scalar Foam::conformalVoronoiMesh::angleBetweenSurfacePoints
 (
-    const Foam::point& pt,
-    DynamicList<Foam::point>& newEdgeLocations,
-    pointField& existingEdgeLocations,
-    autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree
+    Foam::point pA,
+    Foam::point pB
 ) const
 {
-    scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
+    pointIndexHit pAhit;
+    label pAsurfaceHit = -1;
 
-    // 0.01 and 1000 determined from speed tests, varying the indexedOctree
-    // rebuild frequency and balance of additions to queries.
+    const scalar searchDist = 5.0*targetCellSize(pA);
 
-    if
+    geometryToConformTo_.findSurfaceNearest
     (
-        newEdgeLocations.size()
-     >= max(0.01*existingEdgeLocations.size(), 1000)
-    )
+        pA,
+        searchDist,
+        pAhit,
+        pAsurfaceHit
+    );
+
+    vectorField norm(1);
+
+    allGeometry_[pAsurfaceHit].getNormal
+    (
+        List<pointIndexHit>(1, pAhit),
+        norm
+    );
+
+    const vector nA = norm[0];
+
+    pointIndexHit pBhit;
+    label pBsurfaceHit = -1;
+
+    geometryToConformTo_.findSurfaceNearest
+    (
+        pB,
+        searchDist,
+        pBhit,
+        pBsurfaceHit
+    );
+
+    allGeometry_[pBsurfaceHit].getNormal
+    (
+        List<pointIndexHit>(1, pBhit),
+        norm
+    );
+
+    const vector nB = norm[0];
+
+    return vectorTools::cosPhi(nA, nB);
+}
+
+
+bool Foam::conformalVoronoiMesh::nearSurfacePoint
+(
+    pointIndexHit& pHit,
+    label& surfaceHit,
+    DynamicList<Foam::point>& existingSurfacePtLocations
+) const
+{
+    const Foam::point& pt = pHit.hitPoint();
+
+    pointIndexHit closePoint;
+
+    const bool closeToSurfacePt = pointIsNearSurfaceLocation(pt, closePoint);
+
+    if (closeToSurfacePt)
+    {
+        const scalar cosAngle
+            = angleBetweenSurfacePoints(pt, closePoint.hitPoint());
+
+        // @todo make this tolerance run-time selectable?
+        if (cosAngle < searchAngleOppositeSurface)
+        {
+            pointIndexHit pCloseHit;
+            label pCloseSurfaceHit = -1;
+
+            const scalar searchDist = targetCellSize(closePoint.hitPoint());
+
+            geometryToConformTo_.findSurfaceNearest
+            (
+                closePoint.hitPoint(),
+                searchDist,
+                pCloseHit,
+                pCloseSurfaceHit
+            );
+
+            vectorField norm(1);
+
+            allGeometry_[pCloseSurfaceHit].getNormal
+            (
+                List<pointIndexHit>(1, pCloseHit),
+                norm
+            );
+
+            const vector nA = norm[0];
+
+            pointIndexHit oppositeHit;
+            label oppositeSurfaceHit = -1;
+
+            geometryToConformTo_.findSurfaceNearestIntersection
+            (
+                closePoint.hitPoint() + SMALL*nA,
+                closePoint.hitPoint() + mag(pt - closePoint.hitPoint())*nA,
+                oppositeHit,
+                oppositeSurfaceHit
+            );
+
+            if (oppositeHit.hit())
+            {
+                // Replace point
+                pHit = oppositeHit;
+                surfaceHit = oppositeSurfaceHit;
+
+                Foam::point newPt = oppositeHit.hitPoint();
+
+                appendToSurfacePtTree(newPt, existingSurfacePtLocations);
+
+                return !closeToSurfacePt;
+
+                if (debug)
+                {
+                    Info<< "Point " << pt
+                        << " is close to " << closePoint.hitPoint()
+                        << " so will be moved to " << oppositeHit.hitPoint()
+                        << endl;
+                }
+            }
+        }
+    }
+    else
     {
-        existingEdgeLocations.append(newEdgeLocations);
+        appendToSurfacePtTree(pt, existingSurfacePtLocations);
+    }
+
+    return closeToSurfacePt;
+}
+
+
+bool Foam::conformalVoronoiMesh::appendToSurfacePtTree
+(
+    const Foam::point& pt,
+    DynamicList<Foam::point>& existingSurfacePtLocations
+) const
+{
+   label startIndex = existingSurfacePtLocations.size();
+
+   existingSurfacePtLocations.append(pt);
+
+   label endIndex = existingSurfacePtLocations.size();
+
+   return surfacePtLocationTreePtr_().insert(startIndex, endIndex);
+}
+
+
+bool Foam::conformalVoronoiMesh::appendToEdgeLocationTree
+(
+    const Foam::point& pt,
+    DynamicList<Foam::point>& existingEdgeLocations
+) const
+{
+   label startIndex = existingEdgeLocations.size();
+
+   existingEdgeLocations.append(pt);
+
+   label endIndex = existingEdgeLocations.size();
+
+   return edgeLocationTreePtr_().insert(startIndex, endIndex);
+}
+
+
+bool Foam::conformalVoronoiMesh::pointIsNearFeatureEdgeLocation
+(
+    const Foam::point& pt
+) const
+{
+    const scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
+
+    pointIndexHit info
+        = edgeLocationTreePtr_().findNearest(pt, exclusionRangeSqr);
+
+    return info.hit();
+}
+
+
+bool Foam::conformalVoronoiMesh::pointIsNearFeatureEdgeLocation
+(
+    const Foam::point& pt,
+    pointIndexHit& info
+) const
+{
+    const scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
+
+    info = edgeLocationTreePtr_().findNearest(pt, exclusionRangeSqr);
+
+    return info.hit();
+}
+
+
+bool Foam::conformalVoronoiMesh::pointIsNearSurfaceLocation
+(
+    const Foam::point& pt
+) const
+{
+    pointIndexHit info;
+
+    pointIsNearSurfaceLocation(pt, info);
+
+    return info.hit();
+}
+
+
+bool Foam::conformalVoronoiMesh::pointIsNearSurfaceLocation
+(
+    const Foam::point& pt,
+    pointIndexHit& info
+) const
+{
+    const scalar exclusionRangeSqr = surfacePtExclusionDistanceSqr(pt);
+
+    info = surfacePtLocationTreePtr_().findNearest(pt, exclusionRangeSqr);
+
+    return info.hit();
+}
+
+
+bool Foam::conformalVoronoiMesh::nearFeatureEdgeLocation
+(
+    pointIndexHit& pHit,
+    DynamicList<Foam::point>& existingEdgeLocations
+) const
+{
+    const Foam::point pt = pHit.hitPoint();
+
+    const scalar exclusionRangeSqr = featureEdgeExclusionDistanceSqr(pt);
 
-        buildEdgeLocationTree(edgeLocationTree, existingEdgeLocations);
+    pointIndexHit info;
 
-        newEdgeLocations.clear();
+    bool closeToFeatureEdge = pointIsNearFeatureEdgeLocation(pt, info);
+
+    if (!closeToFeatureEdge)
+    {
+        appendToEdgeLocationTree(pt, existingEdgeLocations);
     }
     else
     {
-        // Search for the nearest point in newEdgeLocations.
-        // Searching here first, because the intention is that the value of
-        // newEdgeLocationsSizeLimit should make this faster by design.
+        // 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;
+
+        geometryToConformTo_.findEdgeNearest
+        (
+            pt,
+            exclusionRangeSqr,
+            edgeHit,
+            featureHit
+        );
+
+        const extendedFeatureEdgeMesh& eMesh
+            = geometryToConformTo_.features()[featureHit];
 
-        if (min(magSqr(newEdgeLocations - pt)) <= exclusionRangeSqr)
+        const vector& edgeDir = eMesh.edgeDirections()[edgeHit.index()];
+
+        const vector lineBetweenPoints = pt - info.hitPoint();
+
+        const scalar cosAngle = vectorTools::cosPhi(edgeDir, lineBetweenPoints);
+
+        // 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
+        )
         {
-            return true;
+            closeToFeatureEdge = false;
+            appendToEdgeLocationTree(pt, existingEdgeLocations);
         }
     }
 
+    return closeToFeatureEdge;
+
     // Searching for the nearest point in existingEdgeLocations using the
     // indexedOctree
 
-    pointIndexHit info = edgeLocationTree().findNearest(pt, exclusionRangeSqr);
+    // 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();
+//    }
 
-    return info.hit();
 }
 
 
 void Foam::conformalVoronoiMesh::buildEdgeLocationTree
 (
-    autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree,
-    const pointField& existingEdgeLocations
+    const DynamicList<Foam::point>& existingEdgeLocations
 ) const
 {
     treeBoundBox overallBb
@@ -1652,14 +2077,41 @@ void Foam::conformalVoronoiMesh::buildEdgeLocationTree
     overallBb.min() -= Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
     overallBb.max() += Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
 
-    edgeLocationTree.reset
+    edgeLocationTreePtr_.reset
     (
-        new indexedOctree<treeDataPoint>
+        new dynamicIndexedOctree<dynamicTreeDataPoint>
         (
-            treeDataPoint(existingEdgeLocations),
+            dynamicTreeDataPoint(existingEdgeLocations),
             overallBb,  // overall search domain
-            10,         // max levels
-            10.0,       // maximum ratio of cubes v.s. cells
+            10,         // max levels, n/a
+            20.0,       // maximum ratio of cubes v.s. cells
+            100.0       // max. duplicity; n/a since no bounding boxes.
+        )
+    );
+}
+
+
+void Foam::conformalVoronoiMesh::buildSurfacePtLocationTree
+(
+    const DynamicList<Foam::point>& existingSurfacePtLocations
+) const
+{
+    treeBoundBox overallBb
+    (
+        geometryToConformTo_.globalBounds().extend(rndGen_, 1e-4)
+    );
+
+    overallBb.min() -= Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
+    overallBb.max() += Foam::point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
+
+    surfacePtLocationTreePtr_.reset
+    (
+        new dynamicIndexedOctree<dynamicTreeDataPoint>
+        (
+            dynamicTreeDataPoint(existingSurfacePtLocations),
+            overallBb,  // overall search domain
+            10,         // max levels, n/a
+            20.0,       // maximum ratio of cubes v.s. cells
             100.0       // max. duplicity; n/a since no bounding boxes.
         )
     );
@@ -1702,8 +2154,8 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits
 (
     const Delaunay::Finite_vertices_iterator& vit,
     const Foam::point& vert,
-    const pointIndexHit& surfHit,
-    label hitSurface,
+    const DynamicList<pointIndexHit>& surfHit,
+    const DynamicList<label>& hitSurface,
     scalar surfacePtReplaceDistCoeffSqr,
     scalar edgeSearchDistCoeffSqr,
     DynamicList<pointIndexHit>& surfaceHits,
@@ -1711,104 +2163,123 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits
     DynamicList<pointIndexHit>& featureEdgeHits,
     DynamicList<label>& featureEdgeFeaturesHit,
     DynamicList<Foam::point>& newEdgeLocations,
-    pointField& existingEdgeLocations,
-    autoPtr<indexedOctree<treeDataPoint> >& edgeLocationTree
+    DynamicList<Foam::point>& existingEdgeLocations,
+    DynamicList<Foam::point>& existingSurfacePtLocations
 ) const
 {
     bool keepSurfacePoint = true;
 
-    if (nearFeaturePt(surfHit.hitPoint()))
+    const scalar cellSize = targetCellSize(vert);
+    const scalar cellSizeSqr = sqr(cellSize);
+
+    forAll(surfHit, sI)
     {
-        keepSurfacePoint = false;
+        pointIndexHit surfHitI = surfHit[sI];
+        label hitSurfaceI = hitSurface[sI];
 
-        // If the triggering Vertex is part of a feature point, allow it to
-        // conform to the surface
-        if (vit->index() < startOfInternalPoints_)
+        if (!surfHitI.hit())
         {
-            surfaceHits.append(surfHit);
-
-            hitSurfaces.append(hitSurface);
+            continue;
         }
-    }
 
-    List<pointIndexHit> edHits;
+        bool isNearFeaturePt = nearFeaturePt(surfHitI.hitPoint());
 
-    labelList featuresHit;
+        bool isNearSurfacePt = nearSurfacePoint
+        (
+            surfHitI,
+            hitSurfaceI,
+            existingSurfacePtLocations
+        );
 
-    scalar targetCellSizeSqr = sqr(targetCellSize(vert));
+        if (isNearFeaturePt || isNearSurfacePt)
+        {
+            keepSurfacePoint = false;
 
-    geometryToConformTo_.findEdgeNearestByType
-    (
-        surfHit.hitPoint(),
-        edgeSearchDistCoeffSqr*targetCellSizeSqr,
-        edHits,
-        featuresHit
-    );
+            // If the triggering Vertex is part of a feature point, allow it to
+            // conform to the surface.
+            // @todo Is this needed?! Shouldn't be any feature points here...
+            if (vit->index() < startOfInternalPoints_)
+            {
+                surfaceHits.append(surfHitI);
 
-    // 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.
+                hitSurfaces.append(hitSurfaceI);
+            }
+        }
 
-    DynamicList<Foam::point> currentEdgeLocations;
+        List<List<pointIndexHit> > edHitsByFeature;
 
-    forAll(edHits, i)
-    {
-        const pointIndexHit& edHit(edHits[i]);
+        labelList featuresHit;
 
-        label featureHit = featuresHit[i];
+        const scalar searchRadiusSqr = edgeSearchDistCoeffSqr*cellSizeSqr;
 
-        if (edHit.hit())
+        geometryToConformTo_.findAllNearestEdges
+        (
+            surfHitI.hitPoint(),
+            searchRadiusSqr,
+            edHitsByFeature,
+            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)
         {
-            if (!positionOnThisProc(edHit.hitPoint()))
-            {
-                continue;
-            }
+            const label featureHit = featuresHit[i];
+
+            List<pointIndexHit>& edHits = edHitsByFeature[i];
 
-            if (!nearFeaturePt(edHit.hitPoint()))
+            forAll(edHits, eHitI)
             {
-                if
-                (
-                    magSqr(edHit.hitPoint() - surfHit.hitPoint())
-                  < surfacePtReplaceDistCoeffSqr*targetCellSizeSqr
-                )
+                pointIndexHit& edHit = edHits[eHitI];
+
+                if (!nearFeaturePt(edHit.hitPoint()) && keepSurfacePoint)
                 {
-                    // 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;
 
-                if
-                (
-                    !nearFeatureEdgeLocation
+                        // NEED TO REMOVE FROM THE SURFACE TREE...
+                    }
+
+                    if
                     (
-                        edHit.hitPoint(),
-                        newEdgeLocations,
-                        existingEdgeLocations,
-                        edgeLocationTree
+                        !nearFeatureEdgeLocation
+                        (
+                            edHit,
+                            existingEdgeLocations
+                        )
                     )
-                )
-                {
-                    // Do not place edge control points too close to a feature
-                    // point or existing edge control points
+                    {
+                        // Do not place edge control points too close to a
+                        // feature point or existing edge control points
 
-                    featureEdgeHits.append(edHit);
-                    featureEdgeFeaturesHit.append(featureHit);
+                        featureEdgeHits.append(edHit);
+                        featureEdgeFeaturesHit.append(featureHit);
 
-                    currentEdgeLocations.append(edHit.hitPoint());
+                        currentEdgeLocations.append(edHit.hitPoint());
+                    }
                 }
             }
         }
-    }
-
-    newEdgeLocations.append(currentEdgeLocations);
 
-    if (keepSurfacePoint)
-    {
-        surfaceHits.append(surfHit);
+        if (keepSurfacePoint)
+        {
+            surfaceHits.append(surfHitI);
 
-        hitSurfaces.append(hitSurface);
+            hitSurfaces.append(hitSurfaceI);
+        }
     }
 }
 
@@ -1819,6 +2290,9 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation()
 
     surfaceConformationVertices_.clear();
 
+    // Use a temporary dynamic list to speed up insertion.
+    DynamicList<Vb> tempSurfaceVertices(number_of_vertices()/10);
+
     for
     (
         Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
@@ -1835,7 +2309,7 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation()
          && vit->index() >= startOfInternalPoints_
         )
         {
-            surfaceConformationVertices_.push_back
+            tempSurfaceVertices.append
             (
                 Vb
                 (
@@ -1847,6 +2321,10 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation()
         }
     }
 
+    tempSurfaceVertices.shrink();
+
+    surfaceConformationVertices_.transfer(tempSurfaceVertices);
+
     Info<< "    Stored "
         << returnReduce
         (
@@ -1868,7 +2346,7 @@ void Foam::conformalVoronoiMesh::reinsertSurfaceConformation()
 
     for
     (
-        std::list<Vb>::iterator vit=surfaceConformationVertices_.begin();
+        List<Vb>::iterator vit=surfaceConformationVertices_.begin();
         vit != surfaceConformationVertices_.end();
         ++vit
     )
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C
index 95040bf865bd13ca748580a50147f96c4cb4c3a3..644d82c96130f880433b385389a4b3f3bfeba823 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C
@@ -24,33 +24,20 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "conformalVoronoiMesh.H"
+#include "vectorTools.H"
+
+using namespace Foam::vectorTools;
 
 // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
 
-bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint
+Foam::List<Foam::extendedFeatureEdgeMesh::edgeStatus>
+Foam::conformalVoronoiMesh::calcPointFeatureEdgesTypes
 (
     const extendedFeatureEdgeMesh& feMesh,
-    label ptI,
-    DynamicList<Foam::point>& pts,
-    DynamicList<label>& indices,
-    DynamicList<label>& types
+    const labelList& pEds,
+    pointFeatureEdgesTypes& pFEdgeTypes
 )
 {
-    const labelList& pEds(feMesh.pointEdges()[ptI]);
-
-    if (pEds.size() != 3)
-    {
-        // Only three edge specialisations available
-
-        return false;
-    }
-
-    label nExternal = 0;
-    label nInternal = 0;
-    label nFlat = 0;
-    label nOpen = 0;
-    label nMultiple = 0;
-
     List<extendedFeatureEdgeMesh::edgeStatus> allEdStat(pEds.size());
 
     forAll(pEds, i)
@@ -65,293 +52,388 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint
         {
             case extendedFeatureEdgeMesh::EXTERNAL:
             {
-                nExternal++;
+                pFEdgeTypes.nExternal++;
                 break;
             }
             case extendedFeatureEdgeMesh::INTERNAL:
             {
-                nInternal++;
+                pFEdgeTypes.nInternal++;
                 break;
             }
             case extendedFeatureEdgeMesh::FLAT:
             {
-                nFlat++;
+                pFEdgeTypes.nFlat++;
                 break;
             }
             case extendedFeatureEdgeMesh::OPEN:
             {
-                nOpen++;
+                pFEdgeTypes.nOpen++;
                 break;
             }
             case extendedFeatureEdgeMesh::MULTIPLE:
             {
-                nMultiple++;
+                pFEdgeTypes.nMultiple++;
                 break;
             }
             case extendedFeatureEdgeMesh::NONE:
             {
+                pFEdgeTypes.nNonFeature++;
                 break;
             }
         }
     }
 
-    if (nExternal == 2 && nInternal == 1)
+    if (debug)
     {
-        // if (!positionOnThisProc(pt))
-        // {
-        //     continue;
-        // }
+        Info<< pFEdgeTypes << endl;
+    }
 
-        // Info<< "nExternal == 2 && nInternal == 1" << endl;
+    return allEdStat;
+}
 
-        // const Foam::point& featPt = feMesh.points()[ptI];
 
-        // scalar ppDist = pointPairDistance(featPt);
+bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const labelList& pEds,
+    const pointFeatureEdgesTypes& pFEdgesTypes,
+    const List<extendedFeatureEdgeMesh::edgeStatus>& allEdStat,
+    const label ptI,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    if
+    (
+        pFEdgesTypes.nExternal == 2
+     && pFEdgesTypes.nInternal == 1
+     && pEds.size() == 3
+    )
+    {
+        Info<< "nExternal == 2 && nInternal == 1" << endl;
 
-        // const vectorField& normals = feMesh.normals();
+        const Foam::point& featPt = feMesh.points()[ptI];
 
-        // const labelListList& edgeNormals = feMesh.edgeNormals();
+        if (!positionOnThisProc(featPt))
+        {
+            return false;
+        }
 
-        // label concaveEdgeI = pEds
-        // [
-        //     findIndex(allEdStat, extendedFeatureEdgeMesh::INTERNAL)
-        // ];
+        const label initialNumOfPoints = pts.size();
 
-        // // // Find which planes are joined to the concave edge
+        const scalar ppDist = pointPairDistance(featPt);
 
-        // // List<label> concaveEdgePlanes(2,label(-1));
+        const vectorField& normals = feMesh.normals();
 
-        // // label concaveEdgeI = concaveEdges[0];
+        const labelListList& edgeNormals = feMesh.edgeNormals();
 
-        // // // Pick up the two faces adjacent to the concave feature edge
-        // // const labelList& eFaces = qSurf_.edgeFaces()[concaveEdgeI];
+        label concaveEdgeI = -1;
+        labelList convexEdgesI(2, -1);
+        label nConvex = 0;
 
-        // // label faceA = eFaces[0];
+        forAll(pEds, i)
+        {
+            const extendedFeatureEdgeMesh::edgeStatus& eS = allEdStat[i];
 
-        // // vector nA = qSurf_.faceNormals()[faceA];
+            if (eS == extendedFeatureEdgeMesh::INTERNAL)
+            {
+                concaveEdgeI = pEds[i];
+            }
+            else if (eS == extendedFeatureEdgeMesh::EXTERNAL)
+            {
+                convexEdgesI[nConvex++] = pEds[i];
+            }
+            else if (eS == extendedFeatureEdgeMesh::FLAT)
+            {
+                WarningIn("Foam::conformalVoronoiMesh::"
+                    "createSpecialisedFeaturePoint")
+                    << "Edge " << eS << " is flat"
+                    << endl;
+            }
+            else
+            {
+                FatalErrorIn("Foam::conformalVoronoiMesh::"
+                    "createSpecialisedFeaturePoint")
+                    << "Edge " << eS << " not concave/convex"
+                    << exit(FatalError);
+            }
+        }
 
-        // // scalar maxNormalDotProduct = -SMALL;
+        const vector& concaveEdgePlaneANormal =
+            normals[edgeNormals[concaveEdgeI][0]];
 
-        // // forAll(uniquePlaneNormals, uPN)
-        // // {
-        // //     scalar normalDotProduct = nA & uniquePlaneNormals[uPN];
+        const vector& concaveEdgePlaneBNormal =
+            normals[edgeNormals[concaveEdgeI][1]];
 
-        // //     if (normalDotProduct > maxNormalDotProduct)
-        // //     {
-        // //         maxNormalDotProduct = normalDotProduct;
+        // Intersect planes parallel to the concave edge planes offset
+        // by ppDist and the plane defined by featPt and the edge vector.
+        plane planeA
+        (
+            featPt + ppDist*concaveEdgePlaneANormal,
+            concaveEdgePlaneANormal
+        );
 
-        // //         concaveEdgePlanes[0] = uPN;
-        // //     }
-        // // }
+        plane planeB
+        (
+            featPt + ppDist*concaveEdgePlaneBNormal,
+            concaveEdgePlaneBNormal
+        );
 
-        // // label faceB = eFaces[1];
-        // // vector nB = qSurf_.faceNormals()[faceB];
+        const vector& concaveEdgeDir = feMesh.edgeDirection
+        (
+            concaveEdgeI,
+            ptI
+        );
 
-        // // maxNormalDotProduct = -SMALL;
+        // Todo,needed later but want to get rid of this.
+        const Foam::point concaveEdgeLocalFeatPt = featPt + ppDist*concaveEdgeDir;
 
-        // // forAll(uniquePlaneNormals, uPN)
-        // // {
-        // //     scalar normalDotProduct = nB & uniquePlaneNormals[uPN];
+        // Finding the nearest point on the intersecting line to the edge
+        // point. Floating point errors often occur using planePlaneIntersect
 
-        // //     if (normalDotProduct > maxNormalDotProduct)
-        // //     {
-        // //         maxNormalDotProduct = normalDotProduct;
+        plane planeF(concaveEdgeLocalFeatPt, concaveEdgeDir);
 
-        // //         concaveEdgePlanes[1] = uPN;
-        // //     }
-        // // }
+        const Foam::point concaveEdgeExternalPt = planeF.planePlaneIntersect
+        (
+            planeA,
+            planeB
+        );
 
-        // // const vector& concaveEdgePlaneANormal =
-        // // uniquePlaneNormals[concaveEdgePlanes[0]];
+        // Redefine planes to be on the feature surfaces to project through
 
-        // // const vector& concaveEdgePlaneBNormal =
-        // // uniquePlaneNormals[concaveEdgePlanes[1]];
+        planeA = plane(featPt, concaveEdgePlaneANormal);
 
-        // // label convexEdgesPlaneI;
+        planeB = plane(featPt, concaveEdgePlaneBNormal);
 
-        // // if (findIndex(concaveEdgePlanes, 0) == -1)
-        // // {
-        // //     convexEdgesPlaneI = 0;
-        // // }
-        // // else if (findIndex(concaveEdgePlanes, 1) == -1)
-        // // {
-        // //     convexEdgesPlaneI = 1;
-        // // }
-        // // else
-        // // {
-        // //     convexEdgesPlaneI = 2;
-        // // }
+        const Foam::point internalPtA =
+            concaveEdgeExternalPt
+          - 2.0*planeA.distance(concaveEdgeExternalPt)
+            *concaveEdgePlaneANormal;
 
-        // // const vector& convexEdgesPlaneNormal =
-        // // uniquePlaneNormals[convexEdgesPlaneI];
+        pts.append(internalPtA);
+        indices.append(0);
+        types.append(4);
 
-        // // const edge& concaveEdge = edges[concaveEdgeI];
+        const Foam::point internalPtB =
+            concaveEdgeExternalPt
+          - 2.0*planeB.distance(concaveEdgeExternalPt)
+            *concaveEdgePlaneBNormal;
 
-        // // // Check direction of edge, if the feature point is at the end()
-        // // // the reverse direction.
+        pts.append(internalPtB);
+        indices.append(0);
+        types.append(3);
 
-        // // scalar edgeDirection = 1.0;
+        // Add the external points
 
-        // // if (ptI == concaveEdge.end())
-        // // {
-        // //     edgeDirection *= -1.0;
-        // // }
+        Foam::point externalPtD;
+        Foam::point externalPtE;
 
+        vector convexEdgePlaneCNormal(0,0,0);
+        vector convexEdgePlaneDNormal(0,0,0);
 
-        // const vector& concaveEdgePlaneANormal =
-        //     normals[edgeNormals[concaveEdgeI][0]];
+        const labelList& concaveEdgeNormals = edgeNormals[concaveEdgeI];
+        const labelList& convexEdgeANormals = edgeNormals[convexEdgesI[0]];
+        const labelList& convexEdgeBNormals = edgeNormals[convexEdgesI[1]];
 
-        // const vector& concaveEdgePlaneBNormal =
-        //     normals[edgeNormals[concaveEdgeI][1]];
+        forAll(concaveEdgeNormals, edgeNormalI)
+        {
+            bool convexEdgeA = false;
+            bool convexEdgeB = false;
 
-        // // Intersect planes parallel to the concave edge planes offset
-        // // by ppDist and the plane defined by featPt and the edge
-        // // vector.
-        // plane planeA
-        // (
-        //     featPt + ppDist*concaveEdgePlaneANormal,
-        //     concaveEdgePlaneANormal
-        // );
+            forAll(convexEdgeANormals, edgeAnormalI)
+            {
+                const vector& concaveNormal
+                    = normals[concaveEdgeNormals[edgeNormalI]];
+                const vector& convexNormal
+                    = normals[convexEdgeANormals[edgeAnormalI]];
+
+                Info<< "Angle between vectors = "
+                    << degAngleBetween(concaveNormal, convexNormal) << endl;
+
+                // Need a looser tolerance, because sometimes adjacent triangles
+                // on the same surface will be slightly out of alignment.
+                if (areParallel(concaveNormal, convexNormal, tolParallel))
+                {
+                    convexEdgeA = true;
+                }
+            }
 
-        // plane planeB
-        // (
-        //     featPt + ppDist*concaveEdgePlaneBNormal,
-        //     concaveEdgePlaneBNormal
-        // );
+            forAll(convexEdgeBNormals, edgeBnormalI)
+            {
+                const vector& concaveNormal
+                    = normals[concaveEdgeNormals[edgeNormalI]];
+                const vector& convexNormal
+                    = normals[convexEdgeBNormals[edgeBnormalI]];
+
+                Info<< "Angle between vectors = "
+                    << degAngleBetween(concaveNormal, convexNormal) << endl;
+
+                // Need a looser tolerance, because sometimes adjacent triangles
+                // on the same surface will be slightly out of alignment.
+                if (areParallel(concaveNormal, convexNormal, tolParallel))
+                {
+                    convexEdgeB = true;
+                }
+            }
 
-        // const vector& concaveEdgeDir = feMesh.edgeDirection
-        // (
-        //     concaveEdgeI,
-        //     ptI
-        // );
+            if ((convexEdgeA && convexEdgeB) || (!convexEdgeA && !convexEdgeB))
+            {
+                WarningIn
+                    (
+                     "Foam::conformalVoronoiMesh"
+                     "::createSpecialisedFeaturePoint"
+                    )
+                    << "Both or neither of the convex edges share the concave "
+                    << "edge's normal."
+                    << " convexEdgeA = " << convexEdgeA
+                    << " convexEdgeB = " << convexEdgeB
+                    << endl;
+
+                // Remove points that have just been added before returning
+                for (label i = 0; i < 2; ++i)
+                {
+                    pts.remove();
+                    indices.remove();
+                    types.remove();
+                }
+
+                return false;
+            }
 
-        // Foam::point concaveEdgeLocalFeatPt = featPt + ppDist*concaveEdgeDir;
+            if (convexEdgeA)
+            {
+                forAll(convexEdgeANormals, edgeAnormalI)
+                {
+                    const vector& concaveNormal
+                        = normals[concaveEdgeNormals[edgeNormalI]];
+                    const vector& convexNormal
+                        = normals[convexEdgeANormals[edgeAnormalI]];
+
+                    if
+                    (
+                        !areParallel(concaveNormal, convexNormal, tolParallel)
+                    )
+                    {
+                        convexEdgePlaneCNormal = convexNormal;
+
+                        plane planeC(featPt, convexEdgePlaneCNormal);
+
+                        externalPtD =
+                            internalPtA
+                          + 2.0*planeC.distance(internalPtA)
+                           *convexEdgePlaneCNormal;
+
+                        pts.append(externalPtD);
+                        indices.append(0);
+                        types.append(-2);
+                    }
+                }
+            }
 
-        // // Finding the nearest point on the intersecting line to the
-        // // edge point.  Floating point errors often encountered using
-        // // planePlaneIntersect
-
-        // plane planeF(concaveEdgeLocalFeatPt, concaveEdgeDir);
-
-        // Foam::point concaveEdgeExternalPt = planeF.planePlaneIntersect
-        // (
-        //     planeA,
-        //     planeB
-        // );
-
-        // label concaveEdgeExternalPtI = number_of_vertices() + 4;
-
-        // // Redefine planes to be on the feature surfaces to project
-        // // through
-
-        // planeA = plane(featPt, concaveEdgePlaneANormal);
-
-        // planeB = plane(featPt, concaveEdgePlaneBNormal);
-
-        // Foam::point internalPtA =
-        //     concaveEdgeExternalPt
-        //   - 2*planeA.distance(concaveEdgeExternalPt)
-        //     *concaveEdgePlaneANormal;
-
-        // label internalPtAI = insertPoint
-        // (
-        //     internalPtA,
-        //     concaveEdgeExternalPtI
-        // );
-
-        // Foam::point internalPtB =
-        //     concaveEdgeExternalPt
-        //   - 2*planeB.distance(concaveEdgeExternalPt)
-        //    *concaveEdgePlaneBNormal;
-
-        // label internalPtBI = insertPoint
-        // (
-        //     internalPtB,
-        //     concaveEdgeExternalPtI
-        // );
-
-        // // TEMPORARY VARIABLE TO TEST
-        // vector convexEdgesPlaneNormal = -concaveEdgeDir;
-
-        // plane planeC(featPt, convexEdgesPlaneNormal);
-        // Foam::point externalPtD =
-        //     internalPtA
-        //   + 2*planeC.distance(internalPtA)*convexEdgesPlaneNormal;
-
-        // insertPoint(externalPtD, internalPtAI);
+            if (convexEdgeB)
+            {
+                forAll(convexEdgeBNormals, edgeBnormalI)
+                {
+                    const vector& concaveNormal
+                        = normals[concaveEdgeNormals[edgeNormalI]];
+                    const vector& convexNormal
+                        = normals[convexEdgeBNormals[edgeBnormalI]];
+
+                    if
+                    (
+                        !areParallel(concaveNormal, convexNormal, tolParallel)
+                    )
+                    {
+                        convexEdgePlaneDNormal = convexNormal;
+
+                        plane planeD(featPt, convexEdgePlaneDNormal);
+
+                        externalPtE =
+                            internalPtB
+                          + 2.0*planeD.distance(internalPtB)
+                           *convexEdgePlaneDNormal;
+
+                        pts.append(externalPtE);
+                        indices.append(0);
+                        types.append(-2);
+                    }
+                }
+            }
+        }
 
-        // Foam::point externalPtE =
-        //     internalPtB
-        //   + 2*planeC.distance(internalPtB)*convexEdgesPlaneNormal;
+        pts.append(concaveEdgeExternalPt);
+        indices.append(0);
+        types.append(-4);
 
-        // insertPoint(externalPtE, internalPtBI);
-
-        // insertPoint(concaveEdgeExternalPt, internalPtAI);
-
-        // Info<< nl << "# featPt " << endl;
-        // meshTools::writeOBJ(Info, featPt);
-        // Info<< "# internalPtA" << endl;
-        // meshTools::writeOBJ(Info, internalPtA);
-        // Info<< "# internalPtB" << endl;
-        // meshTools::writeOBJ(Info, internalPtB);
-        // Info<< "# externalPtD" << endl;
-        // meshTools::writeOBJ(Info, externalPtD);
-        // Info<< "# externalPtE" << endl;
-        // meshTools::writeOBJ(Info, externalPtE);
-
-        // scalar totalAngle = radToDeg
-        // (
-        //     constant::mathematical::pi +
-        //     acos(mag(concaveEdgePlaneANormal & concaveEdgePlaneBNormal))
-        // );
-
-        // if (totalAngle > cvMeshControls().maxQuadAngle())
-        // {
-        //     // Add additional mitering points
-
-        //     scalar angleSign = 1.0;
-
-        //     if
-        //     (
-        //         geometryToConformTo_.outside
-        //         (
-        //             featPt - convexEdgesPlaneNormal*ppDist
-        //         )
-        //     )
-        //     {
-        //         angleSign = -1.0;
-        //     }
-
-        //     scalar phi =
-        //         angleSign*acos(concaveEdgeDir & -convexEdgesPlaneNormal);
+        const scalar totalAngle = radToDeg
+        (
+            constant::mathematical::pi
+          + radAngleBetween(concaveEdgePlaneANormal, concaveEdgePlaneBNormal)
+        );
 
-        //     scalar guard =
-        //     (
-        //         1 + sin(phi)*ppDist/mag
-        //         (
-        //             concaveEdgeLocalFeatPt - concaveEdgeExternalPt
-        //         )
-        //     )/cos(phi) - 1;
-
-        //     Foam::point internalPtF =
-        //         concaveEdgeExternalPt
-        //       + (2 + guard)*(concaveEdgeLocalFeatPt - concaveEdgeExternalPt);
-
-        //     label internalPtFI =
-        //         insertPoint(internalPtF, number_of_vertices() + 1);
-
-        //     Foam::point externalPtG =
-        //         internalPtF
-        //       + 2*planeC.distance(internalPtF) * convexEdgesPlaneNormal;
-
-        //     insertPoint(externalPtG, internalPtFI);
-        // }
-
-        // return true;
+        if (totalAngle > cvMeshControls().maxQuadAngle())
+        {
+            // Add additional mitering points
+            //scalar angleSign = 1.0;
+
+            Info<<convexEdgePlaneCNormal << " " <<convexEdgePlaneDNormal << endl;
+
+            vector convexEdgesPlaneNormal = 0.5*(convexEdgePlaneCNormal + convexEdgePlaneDNormal);
+            plane planeM(featPt, convexEdgesPlaneNormal);
+
+//            if
+//            (
+//                geometryToConformTo_.outside
+//                (
+//                    featPt - convexEdgesPlaneNormal*ppDist
+//                )
+//            )
+//            {
+//                angleSign = -1.0;
+//            }
+
+//            scalar phi =
+//                angleSign*acos(concaveEdgeDir & -convexEdgesPlaneNormal);
+//
+//            scalar guard =
+//            (
+//                1.0 + sin(phi)*ppDist/mag
+//                (
+//                    concaveEdgeLocalFeatPt - concaveEdgeExternalPt
+//                )
+//            )/cos(phi) - 1.0;
+
+            const Foam::point internalPtF =
+                concaveEdgeExternalPt
+            //+ (2.0 + guard)*(concaveEdgeLocalFeatPt - concaveEdgeExternalPt);
+              + 2.0*(concaveEdgeLocalFeatPt - concaveEdgeExternalPt);
+
+            pts.append(internalPtF);
+            indices.append(0);
+            types.append(1);
+
+            const Foam::point externalPtG =
+                internalPtF
+              + 2.0*planeM.distance(internalPtF)*convexEdgesPlaneNormal;
+
+            pts.append(externalPtG);
+            indices.append(0);
+            types.append(-1);
+        }
 
-        return false;
+        if (debug)
+        {
+            for (label ptI = initialNumOfPoints; ptI < pts.size(); ++ptI)
+            {
+                Info<< "Point " << ptI << " : ";
+                meshTools::writeOBJ(Info, pts[ptI]);
+            }
+        }
+
+        return true;
     }
-    else if (nExternal == 1 && nInternal == 2)
+    else if (pFEdgesTypes.nExternal == 1 && pFEdgesTypes.nInternal == 2)
     {
         // Info<< "nExternal == 1 && nInternal == 2" << endl;
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C
new file mode 100644
index 0000000000000000000000000000000000000000..cb2a0c9340c3bd5c88c13c794c28f2c459400ff2
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C
@@ -0,0 +1,923 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "conformalVoronoiMesh.H"
+#include "vectorTools.H"
+
+using namespace Foam::vectorTools;
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+void Foam::conformalVoronoiMesh::insertBoundingPoints()
+{
+    pointField farPts = geometryToConformTo_.globalBounds().points();
+
+    // Shift corners of bounds relative to origin
+    farPts -= geometryToConformTo_.globalBounds().midpoint();
+
+    // Scale the box up
+    farPts *= 10.0;
+
+    // Shift corners of bounds back to be relative to midpoint
+    farPts += geometryToConformTo_.globalBounds().midpoint();
+
+    limitBounds_ = treeBoundBox(farPts);
+
+    forAll(farPts, fPI)
+    {
+        insertPoint(farPts[fPI], Vb::vtFar);
+    }
+}
+
+
+void Foam::conformalVoronoiMesh::createEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    label edgeI = edHit.index();
+
+    extendedFeatureEdgeMesh::edgeStatus edStatus = feMesh.getEdgeStatus(edgeI);
+
+    switch (edStatus)
+    {
+        case extendedFeatureEdgeMesh::EXTERNAL:
+        {
+            createExternalEdgePointGroup(feMesh, edHit, pts, indices, types);
+            break;
+        }
+        case extendedFeatureEdgeMesh::INTERNAL:
+        {
+            createInternalEdgePointGroup(feMesh, edHit, pts, indices, types);
+            break;
+        }
+        case extendedFeatureEdgeMesh::FLAT:
+        {
+            createFlatEdgePointGroup(feMesh, edHit, pts, indices, types);
+            break;
+        }
+        case extendedFeatureEdgeMesh::OPEN:
+        {
+            //createOpenEdgePointGroup(feMesh, edHit, pts, indices, types);
+            break;
+        }
+        case extendedFeatureEdgeMesh::MULTIPLE:
+        {
+            //createMultipleEdgePointGroup(feMesh, edHit, pts, indices, types);
+            break;
+        }
+        case extendedFeatureEdgeMesh::NONE:
+        {
+            break;
+        }
+    }
+}
+
+
+void Foam::conformalVoronoiMesh::createExternalEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    const Foam::point& edgePt = edHit.hitPoint();
+
+    scalar ppDist = pointPairDistance(edgePt);
+
+    const vectorField& feNormals = feMesh.normals();
+    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
+
+    // As this is an external edge, there are two normals by definition
+    const vector& nA = feNormals[edNormalIs[0]];
+    const vector& nB = feNormals[edNormalIs[1]];
+
+    if (areParallel(nA, nB))
+    {
+        // The normals are nearly parallel, so this is too sharp a feature to
+        // conform to.
+        return;
+    }
+
+    // Normalised distance of reference point from edge point
+    vector refVec((nA + nB)/(1 + (nA & nB)));
+
+    if (magSqr(refVec) > sqr(5.0))
+    {
+        // Limit the size of the conformation
+        ppDist *= 5.0/mag(refVec);
+
+        // Pout<< nl << "createExternalEdgePointGroup limit "
+        //     << "edgePt " << edgePt << nl
+        //     << "refVec " << refVec << nl
+        //     << "mag(refVec) " << mag(refVec) << nl
+        //     << "ppDist " << ppDist << nl
+        //     << "nA " << nA << nl
+        //     << "nB " << nB << nl
+        //     << "(nA & nB) " << (nA & nB) << nl
+        //     << endl;
+    }
+
+    // Convex. So refPt will be inside domain and hence a master point
+    Foam::point refPt = edgePt - ppDist*refVec;
+
+    // Result when the points are eventually inserted.
+    // Add number_of_vertices() at insertion of first vertex to all numbers:
+    // pt           index type
+    // refPt        0     1
+    // reflectedA   1     0
+    // reflectedB   2     0
+
+    // Insert the master point pairing the the first slave
+
+    pts.append(refPt);
+    indices.append(0);
+    types.append(1);
+
+    // Insert the slave points by reflecting refPt in both faces.
+    // with each slave refering to the master
+
+    Foam::point reflectedA = refPt + 2*ppDist*nA;
+    pts.append(reflectedA);
+    indices.append(0);
+    types.append(-1);
+
+    Foam::point reflectedB = refPt + 2*ppDist*nB;
+    pts.append(reflectedB);
+    indices.append(0);
+    types.append(-2);
+}
+
+
+void Foam::conformalVoronoiMesh::createInternalEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    const Foam::point& edgePt = edHit.hitPoint();
+
+    scalar ppDist = pointPairDistance(edgePt);
+
+    const vectorField& feNormals = feMesh.normals();
+    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
+
+    // As this is an external edge, there are two normals by definition
+    const vector& nA = feNormals[edNormalIs[0]];
+    const vector& nB = feNormals[edNormalIs[1]];
+
+    if (areParallel(nA, nB))
+    {
+        // The normals are nearly parallel, so this is too sharp a feature to
+        // conform to.
+
+        return;
+    }
+
+    // Normalised distance of reference point from edge point
+    vector refVec((nA + nB)/(1 + (nA & nB)));
+
+    if (magSqr(refVec) > sqr(5.0))
+    {
+        // Limit the size of the conformation
+        ppDist *= 5.0/mag(refVec);
+
+        // Pout<< nl << "createInternalEdgePointGroup limit "
+        //     << "edgePt " << edgePt << nl
+        //     << "refVec " << refVec << nl
+        //     << "mag(refVec) " << mag(refVec) << nl
+        //     << "ppDist " << ppDist << nl
+        //     << "nA " << nA << nl
+        //     << "nB " << nB << nl
+        //     << "(nA & nB) " << (nA & nB) << nl
+        //     << endl;
+    }
+
+    // Concave. master and reflected points inside the domain.
+    Foam::point refPt = edgePt - ppDist*refVec;
+
+    // Generate reflected master to be outside.
+    Foam::point reflMasterPt = refPt + 2*(edgePt - refPt);
+
+    // Reflect reflMasterPt in both faces.
+    Foam::point reflectedA = reflMasterPt - 2*ppDist*nA;
+
+    Foam::point reflectedB = reflMasterPt - 2*ppDist*nB;
+
+    scalar totalAngle =
+        radToDeg(constant::mathematical::pi + radAngleBetween(nA, nB));
+
+    // Number of quadrants the angle should be split into
+    int nQuads = int(totalAngle/cvMeshControls().maxQuadAngle()) + 1;
+
+    // The number of additional master points needed to obtain the
+    // required number of quadrants.
+    int nAddPoints = min(max(nQuads - 2, 0), 2);
+
+    // index of reflMaster
+    label reflectedMaster = 2 + nAddPoints;
+
+    // Add number_of_vertices() at insertion of first vertex to all numbers:
+    // Result for nAddPoints 1 when the points are eventually inserted
+    // pt           index type
+    // reflectedA   0     2
+    // reflectedB   1     2
+    // reflMasterPt 2     0
+
+    // Result for nAddPoints 1 when the points are eventually inserted
+    // pt           index type
+    // reflectedA   0     3
+    // reflectedB   1     3
+    // refPt        2     3
+    // reflMasterPt 3     0
+
+    // Result for nAddPoints 2 when the points are eventually inserted
+    // pt           index type
+    // reflectedA   0     4
+    // reflectedB   1     4
+    // reflectedAa  2     4
+    // reflectedBb  3     4
+    // reflMasterPt 4     0
+
+    // Master A is inside.
+    pts.append(reflectedA);
+    indices.append(0);
+    types.append(reflectedMaster--);
+
+    // Master B is inside.
+    pts.append(reflectedB);
+    indices.append(0);
+    types.append(reflectedMaster--);
+
+    if (nAddPoints == 1)
+    {
+        // One additinal point is the reflection of the slave point,
+        // i.e. the original reference point
+        pts.append(refPt);
+        indices.append(0);
+        types.append(reflectedMaster--);
+    }
+    else if (nAddPoints == 2)
+    {
+        Foam::point reflectedAa = refPt + ppDist*nB;
+        pts.append(reflectedAa);
+        indices.append(0);
+        types.append(reflectedMaster--);
+
+        Foam::point reflectedBb = refPt + ppDist*nA;
+        pts.append(reflectedBb);
+        indices.append(0);
+        types.append(reflectedMaster--);
+    }
+
+    // Slave is outside.
+    pts.append(reflMasterPt);
+    indices.append(0);
+    types.append(-(nAddPoints + 2));
+}
+
+
+void Foam::conformalVoronoiMesh::createFlatEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    const Foam::point& edgePt = edHit.hitPoint();
+
+    const scalar ppDist = pointPairDistance(edgePt);
+
+    const vectorField& feNormals = feMesh.normals();
+    const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()];
+
+    // As this is a flat edge, there are two normals by definition
+    const vector& nA = feNormals[edNormalIs[0]];
+    const vector& nB = feNormals[edNormalIs[1]];
+
+    // Average normal to remove any bias to one side, although as this
+    // is a flat edge, the normals should be essentially the same
+    const vector n = 0.5*(nA + nB);
+
+    // Direction along the surface to the control point, sense of edge
+    // direction not important, as +s and -s can be used because this
+    // is a flat edge
+    vector s = ppDist*(feMesh.edgeDirections()[edHit.index()] ^ n);
+
+    createPointPair(ppDist, edgePt + s, n, pts, indices, types);
+    createPointPair(ppDist, edgePt - s, n, pts, indices, types);
+}
+
+
+void Foam::conformalVoronoiMesh::createOpenEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    Info<< "NOT INSERTING OPEN EDGE POINT GROUP, NOT IMPLEMENTED" << endl;
+}
+
+
+void Foam::conformalVoronoiMesh::createMultipleEdgePointGroup
+(
+    const extendedFeatureEdgeMesh& feMesh,
+    const pointIndexHit& edHit,
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    Info<< "NOT INSERTING MULTIPLE EDGE POINT GROUP, NOT IMPLEMENTED" << endl;
+}
+
+
+void Foam::conformalVoronoiMesh::reinsertBoundingPoints()
+{
+    tmp<pointField> farPts = limitBounds_.points();
+
+    forAll(farPts(), fPI)
+    {
+        insertPoint(farPts()[fPI], Vb::vtFar);
+    }
+}
+
+
+void Foam::conformalVoronoiMesh::reinsertFeaturePoints(bool distribute)
+{
+    Info<< nl << "Reinserting stored feature points" << endl;
+
+    label preReinsertionSize(number_of_vertices());
+
+    if (distribute)
+    {
+        DynamicList<Foam::point> pointsToInsert;
+        DynamicList<label> indices;
+        DynamicList<label> types;
+
+        for
+        (
+            List<Vb>::iterator vit=featureVertices_.begin();
+            vit != featureVertices_.end();
+            ++vit
+        )
+        {
+            pointsToInsert.append(topoint(vit->point()));
+            indices.append(vit->index());
+            types.append(vit->type());
+        }
+
+        // Insert distributed points
+        insertPoints(pointsToInsert, indices, types, true);
+
+        // Save points in new distribution
+        featureVertices_.clear();
+        featureVertices_.setSize(pointsToInsert.size());
+
+        forAll(pointsToInsert, pI)
+        {
+            featureVertices_[pI] =
+                Vb(toPoint(pointsToInsert[pI]), indices[pI], types[pI]);
+        }
+    }
+    else
+    {
+        for
+        (
+            List<Vb>::iterator vit=featureVertices_.begin();
+            vit != featureVertices_.end();
+            ++vit
+        )
+        {
+            // Assuming that all of the reinsertions are pair points, and that
+            // the index and type are relative, i.e. index 0 and type relative
+            // to it.
+            insertPoint
+            (
+                vit->point(),
+                vit->index() + number_of_vertices(),
+                vit->type() + number_of_vertices()
+            );
+        }
+    }
+
+    Info<< "    Reinserted "
+        << returnReduce
+        (
+            label(number_of_vertices()) - preReinsertionSize,
+            sumOp<label>()
+        )
+        << " vertices" << endl;
+}
+
+
+bool Foam::conformalVoronoiMesh::edgesShareNormal
+(
+    const label e1,
+    const label e2
+) const
+{
+    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+    (
+        geometryToConformTo_.features()
+    );
+
+    forAll(feMeshes, i)
+    {
+        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
+
+        const vectorField& e1normals = feMesh.edgeNormals(e1);
+        const vectorField& e2normals = feMesh.edgeNormals(e2);
+
+        forAll(e1normals, nI1)
+        {
+            forAll(e2normals, nI2)
+            {
+                if (degAngleBetween(e1normals[nI1], e2normals[nI2]) < 1)
+                {
+                    return true;
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
+
+void Foam::conformalVoronoiMesh::createConvexFeaturePoints
+(
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+    (
+        geometryToConformTo_.features()
+    );
+
+    forAll(feMeshes, i)
+    {
+        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
+
+        for
+        (
+            label ptI = feMesh.convexStart();
+            ptI < feMesh.concaveStart();
+            ptI++
+        )
+        {
+            const Foam::point& featPt = feMesh.points()[ptI];
+
+            if (!positionOnThisProc(featPt))
+            {
+                continue;
+            }
+
+            const vectorField& featPtNormals = feMesh.featurePointNormals(ptI);
+
+            const scalar ppDist = - pointPairDistance(featPt);
+
+            vector cornerNormal = sum(featPtNormals);
+            cornerNormal /= mag(cornerNormal);
+
+            Foam::point internalPt = featPt + ppDist*cornerNormal;
+
+            // Result when the points are eventually inserted (example n = 4)
+            // Add number_of_vertices() at insertion of first vertex to all
+            // numbers:
+            // pt           index type
+            // internalPt   0     1
+            // externalPt0  1     0
+            // externalPt1  2     0
+            // externalPt2  3     0
+            // externalPt3  4     0
+
+            pts.append(internalPt);
+            indices.append(0);
+            types.append(1);
+
+            label internalPtIndex = -1;
+
+            forAll(featPtNormals, nI)
+            {
+                const vector& n = featPtNormals[nI];
+
+                plane planeN = plane(featPt, n);
+
+                Foam::point externalPt =
+                    internalPt + 2.0 * planeN.distance(internalPt) * n;
+
+                pts.append(externalPt);
+                indices.append(0);
+                types.append(internalPtIndex--);
+            }
+        }
+    }
+}
+
+
+void Foam::conformalVoronoiMesh::createConcaveFeaturePoints
+(
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+    (
+        geometryToConformTo_.features()
+    );
+
+    forAll(feMeshes, i)
+    {
+        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
+
+        for
+        (
+            label ptI = feMesh.concaveStart();
+            ptI < feMesh.mixedStart();
+            ptI++
+        )
+        {
+            const Foam::point& featPt = feMesh.points()[ptI];
+
+            if (!positionOnThisProc(featPt))
+            {
+                continue;
+            }
+
+            const vectorField& featPtNormals = feMesh.featurePointNormals(ptI);
+            const scalar ppDist = pointPairDistance(featPt);
+
+            vector cornerNormal = sum(featPtNormals);
+            cornerNormal /= mag(cornerNormal);
+
+            Foam::point externalPt = featPt + ppDist*cornerNormal;
+
+            label externalPtIndex = featPtNormals.size();
+
+            // Result when the points are eventually inserted (example n = 5)
+            // Add number_of_vertices() at insertion of first vertex to all
+            // numbers:
+            // pt           index type
+            // internalPt0  0     5
+            // internalPt1  1     5
+            // internalPt2  2     5
+            // internalPt3  3     5
+            // internalPt4  4     5
+            // externalPt   5     4
+
+            forAll(featPtNormals, nI)
+            {
+                const vector& n = featPtNormals[nI];
+
+                const plane planeN = plane(featPt, n);
+
+                const Foam::point internalPt =
+                    externalPt - 2.0 * planeN.distance(externalPt) * n;
+
+                pts.append(internalPt);
+                indices.append(0);
+                types.append(externalPtIndex--);
+            }
+
+            pts.append(externalPt);
+            indices.append(0);
+            types.append(-1);
+        }
+    }
+}
+
+
+void Foam::conformalVoronoiMesh::createMixedFeaturePoints
+(
+    DynamicList<Foam::point>& pts,
+    DynamicList<label>& indices,
+    DynamicList<label>& types
+)
+{
+    if (cvMeshControls().mixedFeaturePointPPDistanceCoeff() < 0)
+    {
+        Info<< nl << "Skipping specialised handling for mixed feature points"
+            << endl;
+        return;
+    }
+
+    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+    (
+        geometryToConformTo_.features()
+    );
+
+    forAll(feMeshes, i)
+    {
+        const extendedFeatureEdgeMesh& feMesh = feMeshes[i];
+        const labelListList& pointsEdges = feMesh.pointEdges();
+        const pointField& points = feMesh.points();
+
+        for
+        (
+            label ptI = feMesh.mixedStart();
+            ptI < feMesh.nonFeatureStart();
+            ptI++
+        )
+        {
+            const labelList& pEds = pointsEdges[ptI];
+
+            pointFeatureEdgesTypes pFEdgeTypes(ptI);
+
+            const List<extendedFeatureEdgeMesh::edgeStatus> allEdStat
+                = calcPointFeatureEdgesTypes(feMesh, pEds, pFEdgeTypes);
+
+            bool specialisedSuccess = false;
+
+            if (cvMeshControls().specialiseFeaturePoints())
+            {
+                specialisedSuccess = createSpecialisedFeaturePoint
+                (
+                    feMesh, pEds, pFEdgeTypes, allEdStat, ptI,
+                    pts, indices, types
+                );
+            }
+
+            if (!specialisedSuccess)
+            {
+                // Specialisations available for some mixed feature points.  For
+                // non-specialised feature points, inserting mixed internal and
+                // external edge groups at feature point.
+
+                // Skipping unsupported mixed feature point types
+                bool skipEdge = false;
+
+                forAll(pEds, e)
+                {
+                    const label edgeI = pEds[e];
+
+                    const extendedFeatureEdgeMesh::edgeStatus edStatus
+                        = feMesh.getEdgeStatus(edgeI);
+
+                    if
+                    (
+                        edStatus == extendedFeatureEdgeMesh::OPEN
+                     || edStatus == extendedFeatureEdgeMesh::MULTIPLE
+                    )
+                    {
+                        Info<< "Edge type " << edStatus
+                            << " found for mixed feature point " << ptI
+                            << ". Not supported."
+                            << endl;
+
+                        skipEdge = true;
+                    }
+                }
+
+                if (skipEdge)
+                {
+                    Info<< "Skipping point " << ptI << nl << endl;
+
+                    continue;
+                }
+
+                const Foam::point& pt = points[ptI];
+
+                if (!positionOnThisProc(pt))
+                {
+                    continue;
+                }
+
+                const scalar edgeGroupDistance = mixedFeaturePointDistance(pt);
+
+                forAll(pEds, e)
+                {
+                    const label edgeI = pEds[e];
+
+                    const Foam::point edgePt =
+                        pt + edgeGroupDistance*feMesh.edgeDirection(edgeI, ptI);
+
+                    const pointIndexHit edgeHit(true, edgePt, edgeI);
+
+                    createEdgePointGroup(feMesh, edgeHit, pts, indices, types);
+                }
+            }
+        }
+    }
+}
+
+//
+//void Foam::conformalVoronoiMesh::createFeaturePoints
+//(
+//    DynamicList<Foam::point>& pts,
+//    DynamicList<label>& indices,
+//    DynamicList<label>& types
+//)
+//{
+//    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+//    (
+//        geometryToConformTo_.features()
+//    );
+//
+//    forAll(feMeshes, i)
+//    {
+//        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
+//
+//        for
+//        (
+//            label ptI = feMesh.convexStart();
+//            ptI < feMesh.mixedStart();
+//            ++ptI
+//        )
+//        {
+//            const Foam::point& featPt = feMesh.points()[ptI];
+//
+//            if (!positionOnThisProc(featPt))
+//            {
+//                continue;
+//            }
+//
+//            const scalar searchRadiusSqr = 5.0*targetCellSize(featPt);
+//
+//            labelList indices =
+//                surfacePtLocationTreePtr_().findSphere(featPt, searchRadiusSqr);
+//
+//            pointField nearestSurfacePoints(indices.size());
+//
+//            forAll(indices, pI)
+//            {
+//                nearestSurfacePoints[pI] =
+//                    surfaceConformationVertices_[indices[pI]];
+//            }
+//
+//            forAll()
+//
+//            // Now find the nearest points within the edge cones.
+//
+//            // Calculate preliminary surface point locations
+//
+//
+//        }
+//    }
+//}
+
+
+void Foam::conformalVoronoiMesh::insertFeaturePoints()
+{
+    Info<< nl << "Conforming to feature points" << endl;
+
+    DynamicList<Foam::point> pts;
+    DynamicList<label> indices;
+    DynamicList<label> types;
+
+    const label preFeaturePointSize = number_of_vertices();
+
+    createConvexFeaturePoints(pts, indices, types);
+
+    createConcaveFeaturePoints(pts, indices, types);
+
+//    createFeaturePoints(pts, indices, types);
+
+    createMixedFeaturePoints(pts, indices, types);
+
+    // Insert the created points, distributing to the appropriate processor
+    insertPoints(pts, indices, types, true);
+
+    if (cvMeshControls().objOutput())
+    {
+        writePoints("featureVertices.obj", pts);
+    }
+
+    label nFeatureVertices = number_of_vertices() - preFeaturePointSize;
+
+    if (Pstream::parRun())
+    {
+        reduce(nFeatureVertices, sumOp<label>());
+    }
+
+    if (nFeatureVertices > 0)
+    {
+        Info<< "    Inserted " << nFeatureVertices
+            << " feature vertices" << endl;
+    }
+
+    featureVertices_.clear();
+    featureVertices_.setSize(pts.size());
+
+    forAll(pts, pI)
+    {
+        featureVertices_[pI] = Vb(toPoint(pts[pI]), indices[pI], types[pI]);
+    }
+
+    constructFeaturePointLocations();
+}
+
+
+void Foam::conformalVoronoiMesh::constructFeaturePointLocations()
+{
+    DynamicList<Foam::point> ftPtLocs;
+
+    const PtrList<extendedFeatureEdgeMesh>& feMeshes
+    (
+        geometryToConformTo_.features()
+    );
+
+    forAll(feMeshes, i)
+    {
+        const extendedFeatureEdgeMesh& feMesh(feMeshes[i]);
+
+        if (cvMeshControls().mixedFeaturePointPPDistanceCoeff() < 0)
+        {
+            // Ignoring mixed feature points
+            for
+            (
+                label ptI = feMesh.convexStart();
+                ptI < feMesh.mixedStart();
+                ptI++
+            )
+            {
+                ftPtLocs.append(feMesh.points()[ptI]);
+            }
+        }
+        else
+        {
+            for
+            (
+                label ptI = feMesh.convexStart();
+                ptI < feMesh.nonFeatureStart();
+                ptI++
+            )
+            {
+                ftPtLocs.append(feMesh.points()[ptI]);
+            }
+        }
+    }
+
+    featurePointLocations_.transfer(ftPtLocs);
+}
+
+
+Foam::List<Foam::pointIndexHit>
+Foam::conformalVoronoiMesh::findSurfacePtLocationsNearFeaturePoint
+(
+    const Foam::point& featurePoint
+) const
+{
+    DynamicList<pointIndexHit> dynPointList;
+
+    const scalar searchRadiusSqr = 3*targetCellSize(featurePoint);
+
+    labelList surfacePtList = surfacePtLocationTreePtr_().findSphere
+    (
+       featurePoint,
+       searchRadiusSqr
+    );
+
+    forAll(surfacePtList, elemI)
+    {
+       label index = surfacePtList[elemI];
+
+       const Foam::point& p
+           = surfacePtLocationTreePtr_().shapes().shapePoints()[index];
+
+       pointIndexHit nearHit(true, p, index);
+
+       dynPointList.append(nearHit);
+    }
+
+    return dynPointList.shrink();
+}
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H
index 0cad8731f7f4c1480452ab34d3dbcf1c3e2bc4d0..a18b173ecd3c64890c1d9e24d65da8787ff0d297 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H
@@ -186,6 +186,20 @@ inline Foam::scalar Foam::conformalVoronoiMesh::featureEdgeExclusionDistanceSqr
 }
 
 
+inline Foam::scalar Foam::conformalVoronoiMesh::surfacePtExclusionDistanceSqr
+(
+    const Foam::point& pt
+) const
+{
+    return
+        sqr
+        (
+            targetCellSize(pt)
+           *cvMeshControls().surfacePtExclusionDistanceCoeff()
+        );
+}
+
+
 inline Foam::scalar Foam::conformalVoronoiMesh::surfaceSearchDistanceSqr
 (
     const Foam::point& pt
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
index 6430eab8ce21a2864899b96aba3c99b047cee3fe..bc9d04dfb1e79ca32216f53185c7443267f9996d 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C
@@ -175,6 +175,30 @@ void Foam::conformalVoronoiMesh::writePoints
 }
 
 
+void Foam::conformalVoronoiMesh::writeBoundaryPoints
+(
+    const fileName& fName
+) const
+{
+    OFstream str(runTime_.path()/fName);
+
+    Pout<< nl << "Writing boundary points to " << str.name() << endl;
+
+    for
+    (
+        Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
+        vit != finite_vertices_end();
+        ++vit
+    )
+    {
+        if (!vit->internalPoint())
+        {
+            meshTools::writeOBJ(str, topoint(vit->point()));
+        }
+    }
+}
+
+
 void Foam::conformalVoronoiMesh::writePoints
 (
     const fileName& fName,
@@ -597,29 +621,10 @@ void Foam::conformalVoronoiMesh::writeMesh
             << exit(FatalError);
     }
 
-    // pointIOField cellCs
-    // (
-    //     IOobject
-    //     (
-    //         "cellCentres",
-    //         mesh.pointsInstance(),
-    //         polyMesh::meshSubDir,
-    //         mesh,
-    //         IOobject::NO_READ,
-    //         IOobject::AUTO_WRITE
-    //     ),
-    //     cellCentres
-    // );
-
-    // Info<< nl
-    //     << "Writing " << cellCs.name()
-    //     << " to " << cellCs.instance()
-    //     << endl;
-
-    // cellCs.write();
-
     writeCellSizes(mesh);
 
+    writeCellCentres(mesh);
+
     findRemainingProtrusionSet(mesh);
 }
 
@@ -805,6 +810,34 @@ void Foam::conformalVoronoiMesh::writeCellSizes
 }
 
 
+void Foam::conformalVoronoiMesh::writeCellCentres
+(
+    const fvMesh& mesh
+) const
+{
+    Info<< "Writing components of cellCentre positions to volScalarFields"
+        << " ccx, ccy, ccz in " <<  runTime_.timeName() << endl;
+
+    for (direction i=0; i<vector::nComponents; i++)
+    {
+        volScalarField cci
+        (
+            IOobject
+            (
+                "cc" + word(vector::componentNames[i]),
+                runTime_.timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh.C().component(i)
+        );
+
+        cci.write();
+    }
+}
+
+
 void Foam::conformalVoronoiMesh::findRemainingProtrusionSet
 (
     const fvMesh& mesh
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
index 7e5ea9112e416db3819440ad603034d86cbaf463..7ab4f10853427619285ce87430f1ccf14cd31e42 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H
@@ -33,6 +33,10 @@ Description
     An indexed form of CGAL::Triangulation_cell_base_3<K> used to keep
     track of the Delaunay cells (tets) in the tessellation.
 
+SourceFiles
+    indexedCellI.H
+    indexedCell.C
+
 \*---------------------------------------------------------------------------*/
 
 #ifndef indexedCell_H
@@ -119,248 +123,72 @@ public:
     };
 
 
-    indexedCell()
-    :
-        Cb(),
-        index_(ctFar),
-        filterCount_(0)
-    {}
-
-
-    indexedCell
-    (
-        Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, Vertex_handle v3
-    )
-    :
-        Cb(v0, v1, v2, v3),
-        index_(ctFar),
-        filterCount_(0)
-    {}
-
-
-    indexedCell
-    (
-        Vertex_handle v0,
-        Vertex_handle v1,
-        Vertex_handle v2,
-        Vertex_handle v3,
-        Cell_handle n0,
-        Cell_handle n1,
-        Cell_handle n2,
-        Cell_handle n3
-    )
-    :
-        Cb(v0, v1, v2, v3, n0, n1, n2, n3),
-        index_(ctFar),
-        filterCount_(0)
-    {}
-
-
-    int& cellIndex()
-    {
-        return index_;
-    }
-
-
-    int cellIndex() const
-    {
-        return index_;
-    }
+    // Constructors
 
-    inline bool farCell() const
-    {
-        return index_ == ctFar;
-    }
-
-    inline int& filterCount()
-    {
-        return filterCount_;
-    }
+        inline indexedCell();
 
-
-    inline int filterCount() const
-    {
-        return filterCount_;
-    }
-
-
-    //- Is the Delaunay cell real, i.e. any real vertex
-    inline bool real() const
-    {
-        return
+        inline indexedCell
         (
-            this->vertex(0)->real()
-         || this->vertex(1)->real()
-         || this->vertex(2)->real()
-         || this->vertex(3)->real()
+            Vertex_handle v0,
+            Vertex_handle v1,
+            Vertex_handle v2,
+            Vertex_handle v3
         );
-    }
-
 
-    //- Does the Dual vertex form part of a processor patch
-    inline bool parallelDualVertex() const
-    {
-        return
+        inline indexedCell
         (
-            this->vertex(0)->referred()
-         || this->vertex(1)->referred()
-         || this->vertex(2)->referred()
-         || this->vertex(3)->referred()
+            Vertex_handle v0,
+            Vertex_handle v1,
+            Vertex_handle v2,
+            Vertex_handle v3,
+            Cell_handle n0,
+            Cell_handle n1,
+            Cell_handle n2,
+            Cell_handle n3
         );
-    }
 
-    //- Does the Dual vertex form part of a processor patch
-    inline Foam::label dualVertexMasterProc() const
-    {
-        if (!parallelDualVertex())
-        {
-            return -1;
-        }
 
-        // The master processor is the lowest numbered of the four on this tet.
+    // Member Functions
 
-        int masterProc = Foam::Pstream::nProcs() + 1;
+        inline int& cellIndex();
 
-        for (int i = 0; i < 4; i++)
-        {
-            if (this->vertex(i)->referred())
-            {
-                masterProc = min(masterProc, this->vertex(i)->procIndex());
-            }
-            else
-            {
-                masterProc = min(masterProc, Foam::Pstream::myProcNo());
-            }
-        }
+        inline int cellIndex() const;
 
-        return masterProc;
-    }
+        inline bool farCell() const;
 
+        inline int& filterCount();
 
-    inline Foam::FixedList<Foam::label, 4> processorsAttached() const
-    {
-        if (!parallelDualVertex())
-        {
-            return Foam::FixedList<Foam::label, 4>(Foam::Pstream::myProcNo());
-        }
+        inline int filterCount() const;
 
-        Foam::FixedList<Foam::label, 4> procsAttached
-        (
-            Foam::Pstream::myProcNo()
-        );
-
-        for (int i = 0; i < 4; i++)
-        {
-            if (this->vertex(i)->referred())
-            {
-                procsAttached[i] = this->vertex(i)->procIndex();
-            }
-        }
-
-        return procsAttached;
-    }
-
-
-    // Using the globalIndex object, return a list of four (sorted) global
-    // Delaunay vertex indices that uniquely identify this tet in parallel
-    inline Foam::tetCell vertexGlobalIndices
-    (
-        const Foam::globalIndex& globalDelaunayVertexIndices
-    ) const
-    {
-        // tetVertexGlobalIndices
-        Foam::tetCell tVGI;
-
-        for (int i = 0; i < 4; i++)
-        {
-            Vertex_handle v = this->vertex(i);
-
-            // Finding the global index of each Delaunay vertex
-
-            if (v->referred())
-            {
-                // Referred vertices may have negative indices
-
-                tVGI[i] = globalDelaunayVertexIndices.toGlobal
-                (
-                    v->procIndex(),
-                    Foam::mag(v->index())
-                );
-            }
-            else
-            {
-                tVGI[i] = globalDelaunayVertexIndices.toGlobal
-                (
-                    Foam::Pstream::myProcNo(),
-                    v->index()
-                );
-            }
-        }
+        //- Is the Delaunay cell real, i.e. any real vertex
+        inline bool real() const;
 
-        // bubble sort
-        for (int i = 0; i < tVGI.size(); i++)
-        {
-            for (int j = tVGI.size() - 1 ; j > i; j--)
-            {
-                if (tVGI[j - 1] > tVGI[j])
-                {
-                    Foam::Swap(tVGI[j - 1], tVGI[j]);
-                }
-            }
-        }
+        //- Does the Dual vertex form part of a processor patch
+        inline bool parallelDualVertex() const;
 
-        return tVGI;
-    }
+        //- Does the Dual vertex form part of a processor patch
+        inline Foam::label dualVertexMasterProc() const;
 
+        inline Foam::FixedList<Foam::label, 4> processorsAttached() const;
 
-    // Is the Delaunay cell part of the final dual mesh, i.e. any vertex form
-    // part of the internal or boundary definition
-    inline bool internalOrBoundaryDualVertex() const
-    {
-        return
+        //- Using the globalIndex object, return a list of four (sorted) global
+        //  Delaunay vertex indices that uniquely identify this tet in parallel
+        inline Foam::tetCell vertexGlobalIndices
         (
-            this->vertex(0)->internalOrBoundaryPoint()
-         || this->vertex(1)->internalOrBoundaryPoint()
-         || this->vertex(2)->internalOrBoundaryPoint()
-         || this->vertex(3)->internalOrBoundaryPoint()
-        );
-    }
+            const Foam::globalIndex& globalDelaunayVertexIndices
+        ) const;
 
+        //- Is the Delaunay cell part of the final dual mesh, i.e. any vertex
+        //  form part of the internal or boundary definition
+        inline bool internalOrBoundaryDualVertex() const;
 
-    // Is the Delaunay cell real or referred (or mixed), i.e. all vertices form
-    // part of the real or referred internal or boundary definition
-    inline bool anyInternalOrBoundaryDualVertex() const
-    {
-        return
-        (
-            this->vertex(0)->anyInternalOrBoundaryPoint()
-         || this->vertex(1)->anyInternalOrBoundaryPoint()
-         || this->vertex(2)->anyInternalOrBoundaryPoint()
-         || this->vertex(3)->anyInternalOrBoundaryPoint()
-        );
-    }
-
+        //- Is the Delaunay cell real or referred (or mixed), i.e. all vertices
+        //  form part of the real or referred internal or boundary definition
+        inline bool anyInternalOrBoundaryDualVertex() const;
 
-    // A dual vertex on the boundary will result from a Delaunay cell with
-    // least one Delaunay vertex outside and at least one inside
-    inline bool boundaryDualVertex() const
-    {
-        return
-        (
-            (
-               this->vertex(0)->internalOrBoundaryPoint()
-            || this->vertex(1)->internalOrBoundaryPoint()
-            || this->vertex(2)->internalOrBoundaryPoint()
-            || this->vertex(3)->internalOrBoundaryPoint()
-            )
-         && (
-               !this->vertex(0)->internalOrBoundaryPoint()
-            || !this->vertex(1)->internalOrBoundaryPoint()
-            || !this->vertex(2)->internalOrBoundaryPoint()
-            || !this->vertex(3)->internalOrBoundaryPoint()
-            )
-        );
-    }
+        //- A dual vertex on the boundary will result from a Delaunay cell with
+        //  least one Delaunay vertex outside and at least one inside
+        inline bool boundaryDualVertex() const;
 
 
     // Info
@@ -387,6 +215,8 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#include "indexedCellI.H"
+
 #ifdef NoRepository
 #   include "indexedCell.C"
 #endif
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H
new file mode 100644
index 0000000000000000000000000000000000000000..5fbd378f9d9a220845245127070d9624f2ac9bba
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H
@@ -0,0 +1,288 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+    As a special exception, you have permission to link this program with the
+    CGAL library and distribute executables, as long as you follow the
+    requirements of the GNU GPL in regard to all of the software in the
+    executable aside from CGAL.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Gt, class Cb>
+CGAL::indexedCell<Gt, Cb>::indexedCell()
+:
+    Cb(),
+    index_(ctFar),
+    filterCount_(0)
+{}
+
+
+template<class Gt, class Cb>
+CGAL::indexedCell<Gt, Cb>::indexedCell
+(
+    Vertex_handle v0, Vertex_handle v1, Vertex_handle v2, Vertex_handle v3
+)
+:
+    Cb(v0, v1, v2, v3),
+    index_(ctFar),
+    filterCount_(0)
+{}
+
+
+template<class Gt, class Cb>
+CGAL::indexedCell<Gt, Cb>::indexedCell
+(
+    Vertex_handle v0,
+    Vertex_handle v1,
+    Vertex_handle v2,
+    Vertex_handle v3,
+    Cell_handle n0,
+    Cell_handle n1,
+    Cell_handle n2,
+    Cell_handle n3
+)
+:
+    Cb(v0, v1, v2, v3, n0, n1, n2, n3),
+    index_(ctFar),
+    filterCount_(0)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Gt, class Cb>
+int& CGAL::indexedCell<Gt, Cb>::cellIndex()
+{
+    return index_;
+}
+
+
+template<class Gt, class Cb>
+int CGAL::indexedCell<Gt, Cb>::cellIndex() const
+{
+    return index_;
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::farCell() const
+{
+    return index_ == ctFar;
+}
+
+
+template<class Gt, class Cb>
+inline int& CGAL::indexedCell<Gt, Cb>::filterCount()
+{
+    return filterCount_;
+}
+
+
+template<class Gt, class Cb>
+inline int CGAL::indexedCell<Gt, Cb>::filterCount() const
+{
+    return filterCount_;
+}
+
+
+template<class Gt, class Cb>
+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()
+    );
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::parallelDualVertex() const
+{
+    return
+    (
+        this->vertex(0)->referred()
+     || this->vertex(1)->referred()
+     || this->vertex(2)->referred()
+     || this->vertex(3)->referred()
+    );
+}
+
+
+template<class Gt, class Cb>
+inline Foam::label CGAL::indexedCell<Gt, Cb>::dualVertexMasterProc() const
+{
+    if (!parallelDualVertex())
+    {
+        return -1;
+    }
+
+    // The master processor is the lowest numbered of the four on this tet.
+
+    int masterProc = Foam::Pstream::nProcs() + 1;
+
+    for (int i = 0; i < 4; i++)
+    {
+        if (this->vertex(i)->referred())
+        {
+            masterProc = min(masterProc, this->vertex(i)->procIndex());
+        }
+        else
+        {
+            masterProc = min(masterProc, Foam::Pstream::myProcNo());
+        }
+    }
+
+    return masterProc;
+}
+
+
+template<class Gt, class Cb>
+inline Foam::FixedList<Foam::label, 4>
+CGAL::indexedCell<Gt, Cb>::processorsAttached() const
+{
+    if (!parallelDualVertex())
+    {
+        return Foam::FixedList<Foam::label, 4>(Foam::Pstream::myProcNo());
+    }
+
+    Foam::FixedList<Foam::label, 4> procsAttached
+    (
+        Foam::Pstream::myProcNo()
+    );
+
+    for (int i = 0; i < 4; i++)
+    {
+        if (this->vertex(i)->referred())
+        {
+            procsAttached[i] = this->vertex(i)->procIndex();
+        }
+    }
+
+    return procsAttached;
+}
+
+
+template<class Gt, class Cb>
+inline Foam::tetCell CGAL::indexedCell<Gt, Cb>::vertexGlobalIndices
+(
+    const Foam::globalIndex& globalDelaunayVertexIndices
+) const
+{
+    // tetVertexGlobalIndices
+    Foam::tetCell tVGI;
+
+    for (int i = 0; i < 4; i++)
+    {
+        Vertex_handle v = this->vertex(i);
+
+        // Finding the global index of each Delaunay vertex
+
+        if (v->referred())
+        {
+            // Referred vertices may have negative indices
+
+            tVGI[i] = globalDelaunayVertexIndices.toGlobal
+            (
+                v->procIndex(),
+                Foam::mag(v->index())
+            );
+        }
+        else
+        {
+            tVGI[i] = globalDelaunayVertexIndices.toGlobal
+            (
+                Foam::Pstream::myProcNo(),
+                v->index()
+            );
+        }
+    }
+
+    // bubble sort
+    for (int i = 0; i < tVGI.size(); i++)
+    {
+        for (int j = tVGI.size() - 1 ; j > i; j--)
+        {
+            if (tVGI[j - 1] > tVGI[j])
+            {
+                Foam::Swap(tVGI[j - 1], tVGI[j]);
+            }
+        }
+    }
+
+    return tVGI;
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::internalOrBoundaryDualVertex() const
+{
+    return
+    (
+        this->vertex(0)->internalOrBoundaryPoint()
+     || this->vertex(1)->internalOrBoundaryPoint()
+     || this->vertex(2)->internalOrBoundaryPoint()
+     || this->vertex(3)->internalOrBoundaryPoint()
+    );
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::anyInternalOrBoundaryDualVertex() const
+{
+    return
+    (
+        this->vertex(0)->anyInternalOrBoundaryPoint()
+     || this->vertex(1)->anyInternalOrBoundaryPoint()
+     || this->vertex(2)->anyInternalOrBoundaryPoint()
+     || this->vertex(3)->anyInternalOrBoundaryPoint()
+    );
+}
+
+
+template<class Gt, class Cb>
+inline bool CGAL::indexedCell<Gt, Cb>::boundaryDualVertex() const
+{
+    return
+    (
+        (
+           this->vertex(0)->internalOrBoundaryPoint()
+        || this->vertex(1)->internalOrBoundaryPoint()
+        || this->vertex(2)->internalOrBoundaryPoint()
+        || this->vertex(3)->internalOrBoundaryPoint()
+        )
+     && (
+           !this->vertex(0)->internalOrBoundaryPoint()
+        || !this->vertex(1)->internalOrBoundaryPoint()
+        || !this->vertex(2)->internalOrBoundaryPoint()
+        || !this->vertex(3)->internalOrBoundaryPoint()
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
index 0dae13edb3cad456c640f67406c0533eaed96741..246020fd172bbeb127089dc9bcc085c0aa7908e2 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H
@@ -33,6 +33,10 @@ Description
     An indexed form of CGAL::Triangulation_vertex_base_3<K> used to keep
     track of the Delaunay vertices in the tessellation.
 
+SourceFiles
+    indexedVertexI.H
+    indexedVertex.C
+
 \*---------------------------------------------------------------------------*/
 
 #ifndef indexedVertex_H
@@ -88,12 +92,15 @@ class indexedVertex
         //                         Lowest numbered is inside one (master).
         int type_;
 
-        // Required alignment of the dual cell of this vertex
+        //- Required alignment of the dual cell of this vertex
         Foam::tensor alignment_;
 
-        // Target size of the dual cell of this vertex
+        //- Target size of the dual cell of this vertex
         Foam::scalar targetCellSize_;
 
+        //- Specify whether the vertex is fixed or movable.
+        bool vertexFixed_;
+
 
 public:
 
@@ -104,6 +111,12 @@ public:
         vtFar           = INT_MIN + 2
     };
 
+    enum vertexMotion
+    {
+        fixed   = 0,
+        movable = 1
+    };
+
     typedef typename Vb::Vertex_handle      Vertex_handle;
     typedef typename Vb::Cell_handle        Cell_handle;
     typedef typename Vb::Point              Point;
@@ -116,268 +129,105 @@ public:
     };
 
 
-    indexedVertex()
-    :
-        Vb(),
-        index_(vtInternal),
-        type_(vtInternal),
-        alignment_(),
-        targetCellSize_(0.0)
-    {}
-
-
-    indexedVertex(const Point& p)
-    :
-        Vb(p),
-        index_(vtInternal),
-        type_(vtInternal),
-        alignment_(),
-        targetCellSize_(0.0)
-    {}
-
-
-    indexedVertex(const Point& p, int index, int type)
-    :
-        Vb(p),
-        index_(index),
-        type_(type),
-        alignment_(),
-        targetCellSize_(0.0)
-    {}
-
-
-    indexedVertex(const Point& p, Cell_handle f)
-    :
-        Vb(f, p),
-        index_(vtInternal),
-        type_(vtInternal),
-        alignment_(),
-        targetCellSize_(0.0)
-    {}
-
-
-    indexedVertex(Cell_handle f)
-    :
-        Vb(f),
-        index_(vtInternal),
-        type_(vtInternal),
-        alignment_(),
-        targetCellSize_(0.0)
-    {}
-
-
-    int& index()
-    {
-        return index_;
-    }
+    // Constructors
 
+        inline indexedVertex();
 
-    int index() const
-    {
-        return index_;
-    }
+        inline indexedVertex(const Point& p);
 
+        inline indexedVertex(const Point& p, int index, int type);
 
-    int& type()
-    {
-        return type_;
-    }
+        inline indexedVertex(const Point& p, Cell_handle f);
 
+        inline indexedVertex(Cell_handle f);
 
-    int type() const
-    {
-        return type_;
-    }
 
+    // Member Functions
 
-    inline Foam::tensor& alignment()
-    {
-        return alignment_;
-    }
+        inline int& index();
 
+        inline int index() const;
 
-    inline const Foam::tensor& alignment() const
-    {
-        return alignment_;
-    }
+        inline int& type();
 
+        inline int type() const;
 
-    inline Foam::scalar& targetCellSize()
-    {
-        return targetCellSize_;
-    }
+        inline Foam::tensor& alignment();
 
+        inline const Foam::tensor& alignment() const;
 
-    inline Foam::scalar targetCellSize() const
-    {
-        return targetCellSize_;
-    }
+        inline Foam::scalar& targetCellSize();
 
+        inline Foam::scalar targetCellSize() const;
 
-    inline bool uninitialised() const
-    {
-        return type_ == vtInternal && index_ == vtInternal;
-    }
+        inline bool uninitialised() const;
 
+        //- Is point a far-point
+        inline bool farPoint() const;
 
-    //- Is point a far-point
-    inline bool farPoint() const
-    {
-        return type_ == vtFar;
-    }
+        //- Is point internal, i.e. not on boundary
+        inline bool internalPoint() const;
 
+        //- Is point internal, i.e. not on boundary, external query.
+        inline static bool internalPoint(int type);
 
-    //- Is point internal, i.e. not on boundary
-    inline bool internalPoint() const
-    {
-        return internalPoint(type_);
-    }
+        // is this a referred vertex
+        inline bool referred() const;
 
+        // is this a referred internal or boundary vertex
+        inline bool referredInternalOrBoundaryPoint() const;
 
-    //- Is point internal, i.e. not on boundary, external query.
-    inline static bool internalPoint(int type)
-    {
-        return type <= vtInternal;
-    }
+        // is this a referred external (pair slave) vertex
+        inline bool referredExternal() const;
 
+        // Is this a "real" point on this processor, i.e. is it internal or part
+        // of the boundary description, and not a "far" or "referred" point
+        inline bool real() const;
 
-    // is this a referred vertex
-    inline bool referred() const
-    {
-        return (type_ < 0 && type_ > vtFar);
-    }
-
-
-    // is this a referred internal or boundary vertex
-    inline bool referredInternalOrBoundaryPoint() const
-    {
-        return referred() && index_ >= 0;
-    }
+        // For referred vertices, what is the original processor index
+        inline int procIndex() const;
 
+        inline static int encodeProcIndex(int procI);
 
-    // is this a referred external (pair slave) vertex
-    inline bool referredExternal() const
-    {
-        return referred() && index_ < 0;
-    }
-
+        //- Set the point to be internal
+        inline void setInternal();
 
-    // is this a "real" point on this processor, i.e. is it internal or part of
-    // the boundary description, and not a "far" or "referred" point
-    inline bool real() const
-    {
-        return internalPoint() || pairPoint();
-    }
+        //- Is point internal and near the boundary
+        inline bool nearBoundary() const;
 
+        //- Set the point to be near the boundary
+        inline void setNearBoundary();
 
-    // For referred vertices, what is the original processor index
-    inline int procIndex() const
-    {
-        if (referred())
-        {
-            return -(type_ + 1);
-        }
-        else
-        {
-            return -1;
-        }
-    }
+        //- Either master or slave of pointPair.
+        inline bool pairPoint() const;
 
+        //- Master of a pointPair is the lowest numbered one.
+        inline bool ppMaster() const;
 
-    inline static int encodeProcIndex(int procI)
-    {
-        return -(procI + 1);
-    }
+        //- Master of a pointPair is the lowest numbered one, external query.
+        inline static bool ppMaster(int index, int type);
 
+        //- Slave of a pointPair is the highest numbered one.
+        inline bool ppSlave() const;
 
-    //- Set the point to be internal
-    inline void setInternal()
-    {
-        type_ = vtInternal;
-    }
+        //- Either original internal point or master of pointPair.
+        inline bool internalOrBoundaryPoint() const;
 
+        //- Either original internal point or master of pointPair.
+        //  External query.
+        inline static bool internalOrBoundaryPoint(int index, int type);
 
-    //- Is point internal and near the boundary
-    inline bool nearBoundary() const
-    {
-        return type_ == vtNearBoundary;
-    }
+        //- Is point near the boundary or part of the boundary definition
+        inline bool nearOrOnBoundary() const;
 
+        //- Either a real or referred internal or boundary point
+        inline bool anyInternalOrBoundaryPoint() const;
 
-    //- Set the point to be near the boundary
-    inline void setNearBoundary()
-    {
-        type_ = vtNearBoundary;
-    }
-
-
-    //- Either master or slave of pointPair.
-    inline bool pairPoint() const
-    {
-        return type_ >= 0;
-    }
-
-
-    //- Master of a pointPair is the lowest numbered one.
-    inline bool ppMaster() const
-    {
-        return ppMaster(index_, type_);
-    }
-
-
-    //- Master of a pointPair is the lowest numbered one, external query.
-    inline static bool ppMaster(int index, int type)
-    {
-        if (index >= 0 && type > index)
-        {
-            return true;
-        }
-
-        return false;
-    }
-
-
-    //- Slave of a pointPair is the highest numbered one.
-    inline bool ppSlave() const
-    {
-        if (type_ >= 0 && type_ < index_)
-        {
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-
-
-    //- Either original internal point or master of pointPair.
-    inline bool internalOrBoundaryPoint() const
-    {
-        return internalOrBoundaryPoint(index_, type_);
-    }
-
-
-    //- Either original internal point or master of pointPair, external query.
-    inline static bool internalOrBoundaryPoint(int index, int type)
-    {
-        return internalPoint(type) || ppMaster(index, type);
-    }
-
-
-    //- Is point near the boundary or part of the boundary definition
-    inline bool nearOrOnBoundary() const
-    {
-        return pairPoint() || nearBoundary();
-    }
-
-
-    //- Either a real or referred internal or boundary point
-    inline bool anyInternalOrBoundaryPoint() const
-    {
-        return internalOrBoundaryPoint() || referredInternalOrBoundaryPoint();
-    }
+        //- Is the vertex fixed or movable
+        inline bool isVertexFixed() const;
 
+        //- Fix the vertex so that it can't be moved
+        inline void setVertexFixed() const;
 
     // inline void operator=(const Delaunay::Finite_vertices_iterator vit)
     // {
@@ -414,6 +264,8 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#include "indexedVertexI.H"
+
 #ifdef NoRepository
 #   include "indexedVertex.C"
 #endif
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H
new file mode 100644
index 0000000000000000000000000000000000000000..c02ec4df2009489efa9fe91221a666b9f9ae0050
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H
@@ -0,0 +1,340 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+    As a special exception, you have permission to link this program with the
+    CGAL library and distribute executables, as long as you follow the
+    requirements of the GNU GPL in regard to all of the software in the
+    executable aside from CGAL.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Gt, class Vb>
+inline CGAL::indexedVertex<Gt, Vb>::indexedVertex()
+:
+    Vb(),
+    index_(vtInternal),
+    type_(vtInternal),
+    alignment_(),
+    targetCellSize_(0.0),
+    vertexFixed_(false)
+{}
+
+
+template<class Gt, class Vb>
+inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p)
+:
+    Vb(p),
+    index_(vtInternal),
+    type_(vtInternal),
+    alignment_(),
+    targetCellSize_(0.0),
+    vertexFixed_(false)
+{}
+
+
+template<class Gt, class Vb>
+inline CGAL::indexedVertex<Gt, Vb>::indexedVertex
+(
+    const Point& p,
+    int index,
+    int type
+)
+:
+    Vb(p),
+    index_(index),
+    type_(type),
+    alignment_(),
+    targetCellSize_(0.0),
+    vertexFixed_(false)
+{}
+
+
+template<class Gt, class Vb>
+inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p, Cell_handle f)
+:
+    Vb(f, p),
+    index_(vtInternal),
+    type_(vtInternal),
+    alignment_(),
+    targetCellSize_(0.0),
+    vertexFixed_(false)
+{}
+
+
+template<class Gt, class Vb>
+inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(Cell_handle f)
+:
+    Vb(f),
+    index_(vtInternal),
+    type_(vtInternal),
+    alignment_(),
+    targetCellSize_(0.0),
+    vertexFixed_(false)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Gt, class Vb>
+inline int& CGAL::indexedVertex<Gt, Vb>::index()
+{
+    return index_;
+}
+
+
+template<class Gt, class Vb>
+inline int CGAL::indexedVertex<Gt, Vb>::index() const
+{
+    return index_;
+}
+
+
+template<class Gt, class Vb>
+inline int& CGAL::indexedVertex<Gt, Vb>::type()
+{
+    return type_;
+}
+
+
+template<class Gt, class Vb>
+inline int CGAL::indexedVertex<Gt, Vb>::type() const
+{
+    return type_;
+}
+
+
+template<class Gt, class Vb>
+inline Foam::tensor& CGAL::indexedVertex<Gt, Vb>::alignment()
+{
+    return alignment_;
+}
+
+
+template<class Gt, class Vb>
+inline const Foam::tensor& CGAL::indexedVertex<Gt, Vb>::alignment() const
+{
+    return alignment_;
+}
+
+
+template<class Gt, class Vb>
+inline Foam::scalar& CGAL::indexedVertex<Gt, Vb>::targetCellSize()
+{
+    return targetCellSize_;
+}
+
+
+template<class Gt, class Vb>
+inline Foam::scalar CGAL::indexedVertex<Gt, Vb>::targetCellSize() const
+{
+    return targetCellSize_;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::uninitialised() const
+{
+    return type_ == vtInternal && index_ == vtInternal;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::farPoint() const
+{
+    return type_ == vtFar;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::internalPoint() const
+{
+    return internalPoint(type_);
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::internalPoint(int type)
+{
+    return type <= vtInternal;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::referred() const
+{
+    return (type_ < 0 && type_ > vtFar);
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::referredInternalOrBoundaryPoint() const
+{
+    return referred() && index_ >= 0;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::referredExternal() const
+{
+    return referred() && index_ < 0;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::real() const
+{
+    return internalPoint() || pairPoint();
+}
+
+
+template<class Gt, class Vb>
+inline int CGAL::indexedVertex<Gt, Vb>::procIndex() const
+{
+    if (referred())
+    {
+        return -(type_ + 1);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+
+template<class Gt, class Vb>
+inline int CGAL::indexedVertex<Gt, Vb>::encodeProcIndex(int procI)
+{
+    return -(procI + 1);
+}
+
+
+template<class Gt, class Vb>
+inline void CGAL::indexedVertex<Gt, Vb>::setInternal()
+{
+    type_ = vtInternal;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::nearBoundary() const
+{
+    return type_ == vtNearBoundary;
+}
+
+
+template<class Gt, class Vb>
+inline void CGAL::indexedVertex<Gt, Vb>::setNearBoundary()
+{
+    type_ = vtNearBoundary;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::pairPoint() const
+{
+    return type_ >= 0;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::ppMaster() const
+{
+    return ppMaster(index_, type_);
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::ppMaster(int index, int type)
+{
+    if (index >= 0 && type > index)
+    {
+        return true;
+    }
+
+    return false;
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::ppSlave() const
+{
+    if (type_ >= 0 && type_ < index_)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::internalOrBoundaryPoint() const
+{
+    return internalOrBoundaryPoint(index_, type_);
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::internalOrBoundaryPoint
+(
+    int index,
+    int type
+)
+{
+    return internalPoint(type) || ppMaster(index, type);
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::nearOrOnBoundary() const
+{
+    return pairPoint() || nearBoundary();
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::anyInternalOrBoundaryPoint() const
+{
+    return internalOrBoundaryPoint() || referredInternalOrBoundaryPoint();
+}
+
+
+template<class Gt, class Vb>
+inline bool CGAL::indexedVertex<Gt, Vb>::isVertexFixed() const
+{
+    return vertexFixed_;
+}
+
+
+template<class Gt, class Vb>
+inline void CGAL::indexedVertex<Gt, Vb>::setVertexFixed() const
+{
+    vertexFixed_ = true;
+}
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H
new file mode 100644
index 0000000000000000000000000000000000000000..3009f385b256556a202e55b03ff4cc286ba912a7
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H
@@ -0,0 +1,87 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+    As a special exception, you have permission to link this program with the
+    CGAL library and distribute executables, as long as you follow the
+    requirements of the GNU GPL in regard to all of the software in the
+    executable aside from CGAL.
+
+Class
+    pointFeatureEdgesTypes
+
+Description
+    struct for holding information on the types of feature edges attached to
+    feature points
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef pointFeatureEdgesTypes_H
+#define pointFeatureEdgesTypes_H
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                   Class pointFeatureEdgesTypes Declaration
+\*---------------------------------------------------------------------------*/
+
+//- Hold the types of feature edges attached to the point.
+struct pointFeatureEdgesTypes
+{
+    label ptI;
+    label nExternal, nInternal;
+    label nFlat, nOpen, nMultiple, nNonFeature;
+
+    pointFeatureEdgesTypes(const label pointLabel)
+    {
+        ptI = pointLabel;
+        nExternal = nInternal = 0;
+        nFlat = nOpen = nMultiple = nNonFeature = 0;
+    }
+
+    friend Ostream& operator<<(Ostream& os, const pointFeatureEdgesTypes& p)
+    {
+        os  << "E " << "I " << "F " << "O " << "M " << "N "
+            << "Pt" << nl
+            << p.nExternal << " " << p.nInternal << " "
+            << p.nFlat << " " << p.nOpen << " "
+            << p.nMultiple << " " << p.nNonFeature << " "
+            << p.ptI
+            << endl;
+
+        return os;
+    }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C
index 5e8a8d729746c8bf0c29a6203f56ca15a1e92521..b91d40121d48f23d8a1ff077c9ce679983ed6218 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C
@@ -730,6 +730,49 @@ void Foam::conformationSurfaces::findEdgeNearestByType
 }
 
 
+void Foam::conformationSurfaces::findAllNearestEdges
+(
+    const point& sample,
+    const scalar searchRadiusSqr,
+    List<List<pointIndexHit> >& edgeHitsByFeature,
+    List<label>& featuresHit
+) const
+{
+    // Initialise
+    //featuresHit.setSize(features_.size());
+    //featuresHit = -1;
+    //edgeHitsByFeature.setSize(features_.size());
+
+    // Work arrays
+    List<pointIndexHit> hitInfo(extendedFeatureEdgeMesh::nEdgeTypes);
+
+    forAll(features_, testI)
+    {
+        features_[testI].allNearestFeatureEdges
+        (
+            sample,
+            searchRadiusSqr,
+            hitInfo
+        );
+
+        bool anyHit = false;
+        forAll(hitInfo, hitI)
+        {
+            if (hitInfo[hitI].hit())
+            {
+                anyHit = true;
+            }
+        }
+
+        if (anyHit)
+        {
+            edgeHitsByFeature.append(hitInfo);
+            featuresHit.append(testI);
+        }
+    }
+}
+
+
 void Foam::conformationSurfaces::writeFeatureObj(const fileName& prefix) const
 {
     OFstream ftStr(runTime_.time().path()/prefix + "_allFeatures.obj");
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
index b541bed0032027034eaf4a4d77a73df8af49fdf6..fe883fbaa5cae003313dc9a381ea16a5734a535b 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H
@@ -166,7 +166,7 @@ public:
 
             //- Check if point is closer to the surfaces to conform to than
             //  testDistSqr, in which case return false, otherwise assess in or
-            //  outside and erturn a result depending on the testForInside flag
+            //  outside and return a result depending on the testForInside flag
             Field<bool> wellInOutSide
             (
                 const pointField& samplePts,
@@ -228,7 +228,7 @@ public:
                 label& hitSurface
             ) const;
 
-                //- Find the nearest point to the sample and return it to the
+            //- Find the nearest point to the sample and return it to the
             //  pointIndexHit
             void findSurfaceNearest
             (
@@ -270,7 +270,17 @@ public:
                 const point& sample,
                 scalar nearestDistSqr,
                 List<pointIndexHit>& edgeHit,
-                List<label>& featureHit
+                List<label>& featuresHit
+            ) const;
+
+            //- Find the nearest points on each feature edge that is within
+            //  a given distance from the sample point
+            void findAllNearestEdges
+            (
+                const point& sample,
+                const scalar searchRadiusSqr,
+                List<List<pointIndexHit> >& edgeHitsByFeature,
+                List<label>& featuresHit
             ) const;
 
             //- Find which patch is intersected by the line from one point to
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C
index ce1994e7bd5014a50be06a2a96b3e71d91ed5577..9b59ce9b9b5d0b3a024b0e87445585e46c37ff9c 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C
@@ -30,11 +30,9 @@ License
 
 Foam::cvControls::cvControls
 (
-    const conformalVoronoiMesh& cvMesh,
     const dictionary& cvMeshDict
 )
 :
-    cvMesh_(cvMesh),
     cvMeshDict_(cvMeshDict)
 {
     // Surface conformation controls
@@ -61,6 +59,11 @@ Foam::cvControls::cvControls
         surfDict.lookup("featureEdgeExclusionDistanceCoeff")
     );
 
+    specialiseFeaturePoints_ = Switch
+    (
+        surfDict.lookupOrDefault<Switch>("specialiseFeaturePoints", false)
+    );
+
     surfaceSearchDistanceCoeff_ = readScalar
     (
         surfDict.lookup("surfaceSearchDistanceCoeff")
@@ -96,6 +99,11 @@ Foam::cvControls::cvControls
         coarseDict.subDict("iteration")
     );
 
+    surfacePtExclusionDistanceCoeff_ = readScalar
+    (
+        coarseInitialDict.lookup("surfacePtExclusionDistanceCoeff")
+    );
+
     edgeSearchDistCoeffSqr_coarse_initial_ = sqr
     (
         readScalar
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H
index 8b00b9a163297a944da282cf663e16d40f30e0f6..f6bdb755592a316533cef66e2bcc94710818a0a6 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H
@@ -54,9 +54,6 @@ class cvControls
 {
     // Private data
 
-        //- Reference to the conformalVoronoiMesh holding this cvControls object
-        const conformalVoronoiMesh& cvMesh_;
-
         //- Reference to the cvMeshDict
         const dictionary& cvMeshDict_;
 
@@ -80,6 +77,9 @@ class cvControls
             //  fraction of the local target cell size
             scalar featureEdgeExclusionDistanceCoeff_;
 
+            //- Switch for using specialised feature points
+            Switch specialiseFeaturePoints_;
+
             //- Surface search distance coefficient - fraction of the local
             //  target cell size
             scalar surfaceSearchDistanceCoeff_;
@@ -99,6 +99,11 @@ class cvControls
 
             // Controls for coarse surface conformation
 
+                //- Distance to an existing surface conformation point location
+                //  within which other surface point locations are excluded
+                //  - fraction of the local target cell size
+                scalar surfacePtExclusionDistanceCoeff_;
+
                 //- Distance to search for feature edges near to
                 //  surface protrusions - fraction of the local target
                 //  cell size. Coarse conformation, initial protrusion
@@ -291,7 +296,6 @@ public:
         //- Construct from references to conformalVoronoiMesh and dictionary
         cvControls
         (
-            const conformalVoronoiMesh& cvMesh,
             const dictionary& cvMeshDict
         );
 
@@ -319,6 +323,12 @@ public:
             //- Return the featureEdgeExclusionDistanceCoeff
             inline scalar featureEdgeExclusionDistanceCoeff() const;
 
+            //- Return the surfacePtExclusionDistanceCoeff
+            inline scalar surfacePtExclusionDistanceCoeff() const;
+
+            //- Return whether to use specialised feature points
+            inline Switch specialiseFeaturePoints() const;
+
             //- Return the surfaceSearchDistanceCoeff
             inline scalar surfaceSearchDistanceCoeff() const;
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H
index 5fd33640195e6e8cdccb0731a178387b280b88c3..dc3f391100bd0ee1a28a8007041e8a7812ffa4f5 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H
@@ -54,6 +54,15 @@ inline Foam::scalar Foam::cvControls::featureEdgeExclusionDistanceCoeff() const
     return featureEdgeExclusionDistanceCoeff_;
 }
 
+inline Foam::scalar Foam::cvControls::surfacePtExclusionDistanceCoeff() const
+{
+    return surfacePtExclusionDistanceCoeff_;
+}
+
+inline Foam::Switch Foam::cvControls::specialiseFeaturePoints() const
+{
+    return specialiseFeaturePoints_;
+}
 
 inline Foam::scalar Foam::cvControls::surfaceSearchDistanceCoeff() const
 {
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.C
index ec7a8ed29d8e0c7c30d8684d17dab152e7b5ca61..76d68aa073f753f848bb98628d47ca6cff78d8c7 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.C
@@ -42,12 +42,10 @@ defineRunTimeSelectionTable(faceAreaWeightModel, dictionary);
 faceAreaWeightModel::faceAreaWeightModel
 (
     const word& type,
-    const dictionary& relaxationDict,
-    const conformalVoronoiMesh& cvMesh
+    const dictionary& relaxationDict
 )
 :
     dictionary(relaxationDict),
-    cvMesh_(cvMesh),
     coeffDict_(subDict(type + "Coeffs"))
 {}
 
@@ -56,8 +54,7 @@ faceAreaWeightModel::faceAreaWeightModel
 
 autoPtr<faceAreaWeightModel> faceAreaWeightModel::New
 (
-    const dictionary& relaxationDict,
-    const conformalVoronoiMesh& cvMesh
+    const dictionary& relaxationDict
 )
 {
     word faceAreaWeightModelTypeName
@@ -85,7 +82,7 @@ autoPtr<faceAreaWeightModel> faceAreaWeightModel::New
             << exit(FatalError);
     }
 
-    return autoPtr<faceAreaWeightModel>(cstrIter()(relaxationDict, cvMesh));
+    return autoPtr<faceAreaWeightModel>(cstrIter()(relaxationDict));
 }
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.H
index 0eaf7b14f6650ea66e05c57960d6c2068deac2fa..3e88f5bb74f64768956caf551750a2f0b78712f7 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/faceAreaWeightModel/faceAreaWeightModel.H
@@ -39,7 +39,6 @@ SourceFiles
 #define faceAreaWeightModel_H
 
 #include "point.H"
-#include "conformalVoronoiMesh.H"
 #include "dictionary.H"
 #include "autoPtr.H"
 #include "runTimeSelectionTables.H"
@@ -62,9 +61,6 @@ protected:
 
     // Protected data
 
-        //- Reference to the conformalVoronoiMesh holding this cvControls object
-        const conformalVoronoiMesh& cvMesh_;
-
         //- Method coeffs dictionary
         dictionary coeffDict_;
 
@@ -93,10 +89,9 @@ public:
             faceAreaWeightModel,
             dictionary,
             (
-                const dictionary& faceAreaWeightDict,
-                const conformalVoronoiMesh& cvMesh
+                const dictionary& faceAreaWeightDict
             ),
-            (faceAreaWeightDict, cvMesh)
+            (faceAreaWeightDict)
         );
 
 
@@ -106,8 +101,7 @@ public:
         faceAreaWeightModel
         (
             const word& type,
-            const dictionary& faceAreaWeightDict,
-            const conformalVoronoiMesh& cvMesh
+            const dictionary& faceAreaWeightDict
         );
 
 
@@ -116,8 +110,7 @@ public:
         //- Return a reference to the selected faceAreaWeightModel
         static autoPtr<faceAreaWeightModel> New
         (
-            const dictionary& faceAreaWeightDict,
-            const conformalVoronoiMesh& cvMesh
+            const dictionary& faceAreaWeightDict
         );
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.C
index 2f7df3d3532da09d9bf65cf875a729214071620b..0fa6025c998b6e69a77b03bce8cbd75240a77afe 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.C
@@ -45,11 +45,10 @@ addToRunTimeSelectionTable
 
 piecewiseLinearRamp::piecewiseLinearRamp
 (
-    const dictionary& faceAreaWeightDict,
-    const conformalVoronoiMesh& cvMesh
+    const dictionary& faceAreaWeightDict
 )
 :
-    faceAreaWeightModel(typeName, faceAreaWeightDict, cvMesh),
+    faceAreaWeightModel(typeName, faceAreaWeightDict),
     lAF_(readScalar(coeffDict().lookup("lowerAreaFraction"))),
     uAF_(readScalar(coeffDict().lookup("upperAreaFraction")))
 {}
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.H
index 0c0ba587f32212b6dde84cb8c24a77d9681468e7..14f6a929bb9e9591830084f8c4e6d238f1e48868 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/faceAreaWeightModel/piecewiseLinearRamp/piecewiseLinearRamp.H
@@ -71,8 +71,7 @@ public:
         //- Construct from components
         piecewiseLinearRamp
         (
-            const dictionary& faceAreaWeightDict,
-            const conformalVoronoiMesh& cvMesh
+            const dictionary& faceAreaWeightDict
         );
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C
index bdc314ce64862453aaaf52fbaa1eda7f1dd2e344..84926910dfd50a9a09da5ebf8805711a3dea1749 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C
@@ -177,7 +177,7 @@ bool Foam::autoDensity::combinedWellInside
 
 void Foam::autoDensity::recurseAndFill
 (
-    std::list<Vb::Point>& initialPoints,
+    DynamicList<Vb::Point>& initialPoints,
     const treeBoundBox& bb,
     label levelLimit,
     word recursionName
@@ -272,7 +272,7 @@ void Foam::autoDensity::recurseAndFill
 
 bool Foam::autoDensity::fillBox
 (
-    std::list<Vb::Point>& initialPoints,
+    DynamicList<Vb::Point>& initialPoints,
     const treeBoundBox& bb,
     bool overlapping
 ) const
@@ -677,7 +677,7 @@ bool Foam::autoDensity::fillBox
                             // Pout<< "Final volume probability break accept"
                             //     << endl;
 
-                            initialPoints.push_back
+                            initialPoints.append
                             (
                                 Vb::Point(p.x(), p.y(), p.z())
                             );
@@ -688,7 +688,7 @@ bool Foam::autoDensity::fillBox
                         break;
                     }
 
-                    initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+                    initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
 
                     volumeAdded += localVolume;
                 }
@@ -800,7 +800,7 @@ bool Foam::autoDensity::fillBox
                             // Pout<< "Final volume probability break accept"
                             //     << endl;
 
-                            initialPoints.push_back
+                            initialPoints.append
                             (
                                 Vb::Point(p.x(), p.y(), p.z())
                             );
@@ -811,7 +811,7 @@ bool Foam::autoDensity::fillBox
                         break;
                     }
 
-                    initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+                    initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
 
                     volumeAdded += localVolume;
                 }
@@ -849,10 +849,7 @@ autoDensity::autoDensity
 :
     initialPointsMethod(typeName, initialPointsDict, cvMesh),
     globalTrialPoints_(0),
-    minCellSizeLimit_
-    (
-        detailsDict().lookupOrDefault<scalar>("minCellSizeLimit", 0.0)
-    ),
+    minCellSizeLimit_(readScalar(detailsDict().lookup("minCellSizeLimit"))),
     minLevels_(readLabel(detailsDict().lookup("minLevels"))),
     maxSizeRatio_(readScalar(detailsDict().lookup("maxSizeRatio"))),
     volRes_(readLabel(detailsDict().lookup("sampleResolution"))),
@@ -882,7 +879,7 @@ autoDensity::autoDensity
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-std::list<Vb::Point> autoDensity::initialPoints() const
+List<Vb::Point> autoDensity::initialPoints() const
 {
     treeBoundBox hierBB;
 
@@ -902,7 +899,18 @@ std::list<Vb::Point> autoDensity::initialPoints() const
         );
     }
 
-    std::list<Vb::Point> initialPoints;
+    // Initialise size of points list.
+    const scalar volumeBoundBox = Foam::pow3(hierBB.typDim());
+    const scalar volumeSmallestCell = Foam::pow3(minCellSizeLimit_);
+
+    const int initialPointEstimate
+        = min
+          (
+              static_cast<int>(volumeBoundBox/(volumeSmallestCell + SMALL)/10),
+              1e6
+          );
+
+    DynamicList<Vb::Point> initialPoints(initialPointEstimate);
 
     Info<< nl << "    " << typeName << endl;
 
@@ -919,6 +927,8 @@ std::list<Vb::Point> autoDensity::initialPoints() const
         "recursionBox"
     );
 
+    initialPoints.shrink();
+
     label nInitialPoints = initialPoints.size();
 
     if (Pstream::parRun())
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.H
index 905a3acdf6e87d1e7b25827479c2c6b0cf018c77..4b9063c5cc518aabe479cddc4a46fbc1e3d9d2d6 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.H
@@ -116,7 +116,7 @@ private:
         //- Descend into octants of the supplied bound box
         void recurseAndFill
         (
-            std::list<Vb::Point>& initialPoints,
+            DynamicList<Vb::Point>& initialPoints,
             const treeBoundBox& bb,
             label levelLimit,
             word recursionName
@@ -127,7 +127,7 @@ private:
         //  in favour of further recursion.
         bool fillBox
         (
-            std::list<Vb::Point>& initialPoints,
+            DynamicList<Vb::Point>& initialPoints,
             const treeBoundBox& bb,
             bool overlapping
         ) const;
@@ -156,7 +156,7 @@ public:
     // Member Functions
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const;
+        virtual List<Vb::Point> initialPoints() const;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C
index 0376f1389ac6f8e56b3f6b52f5269423159691a5..f41760311f35c36fad1390f785afab990052522d 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C
@@ -56,7 +56,7 @@ bodyCentredCubic::bodyCentredCubic
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-std::list<Vb::Point> bodyCentredCubic::initialPoints() const
+List<Vb::Point> bodyCentredCubic::initialPoints() const
 {
     boundBox bb;
 
@@ -91,7 +91,7 @@ std::list<Vb::Point> bodyCentredCubic::initialPoints() const
 
     scalar pert = randomPerturbationCoeff_*cmptMin(delta);
 
-    std::list<Vb::Point> initialPoints;
+    DynamicList<Vb::Point> initialPoints(ni*nj*nk/10);
 
     for (label i = 0; i < ni; i++)
     {
@@ -177,13 +177,13 @@ std::list<Vb::Point> bodyCentredCubic::initialPoints() const
                 {
                     const point& p(points[i]);
 
-                    initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+                    initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
                 }
             }
         }
     }
 
-    return initialPoints;
+    return initialPoints.shrink();
 }
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.H
index 434c3280c3c2d5f2d29e1b25455dbdf953f27650..c3d1217d6bd58d942263bfd9cd3baaa4067c89dd 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.H
@@ -89,7 +89,7 @@ public:
     // Member Functions
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const;
+        virtual List<Vb::Point> initialPoints() const;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C
index c9ade503cb13832b3f8dcd49975b8eb4b7e551c9..cafccb55747b6dd52c77a6b4d9c9c9a292e0e9d0 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C
@@ -56,7 +56,7 @@ faceCentredCubic::faceCentredCubic
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-std::list<Vb::Point> faceCentredCubic::initialPoints() const
+List<Vb::Point> faceCentredCubic::initialPoints() const
 {
     boundBox bb;
 
@@ -91,7 +91,7 @@ std::list<Vb::Point> faceCentredCubic::initialPoints() const
 
     scalar pert = randomPerturbationCoeff_*cmptMin(delta);
 
-    std::list<Vb::Point> initialPoints;
+    DynamicList<Vb::Point> initialPoints(ni*nj*nk/10);
 
     for (label i = 0; i < ni; i++)
     {
@@ -238,13 +238,13 @@ std::list<Vb::Point> faceCentredCubic::initialPoints() const
                 {
                     const point& p(points[i]);
 
-                    initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+                    initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
                 }
             }
         }
     }
 
-    return initialPoints;
+    return initialPoints.shrink();
 }
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.H
index c9194b99b65bb1398e0ce68160d94e7e60e02f67..b7660d023bb403b91fd3eb642dbe3d2011a262b6 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.H
@@ -89,7 +89,7 @@ public:
     // Member Functions
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const;
+        virtual List<Vb::Point> initialPoints() const;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/initialPointsMethod/initialPointsMethod.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/initialPointsMethod/initialPointsMethod.H
index 6feb9ac79d93ec2a03fa23674c31313727528dff..d4334ddf98a5a1c227cbe39b37175b5bba45e6c8 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/initialPointsMethod/initialPointsMethod.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/initialPointsMethod/initialPointsMethod.H
@@ -139,7 +139,7 @@ public:
         }
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const = 0;
+        virtual List<Vb::Point> initialPoints() const = 0;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C
index 0c9792710952ede38abb3a1f6757a9cab41abb35..f037435af1d1641e0a8f0335958cfb8e4399decd 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C
@@ -51,7 +51,7 @@ pointFile::pointFile
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-std::list<Vb::Point> pointFile::initialPoints() const
+List<Vb::Point> pointFile::initialPoints() const
 {
     pointIOField points
     (
@@ -69,7 +69,7 @@ std::list<Vb::Point> pointFile::initialPoints() const
 
     if (points.empty())
     {
-        FatalErrorIn("std::list<Vb::Point> pointFile::initialPoints() const")
+        FatalErrorIn("List<Vb::Point> pointFile::initialPoints() const")
             << "Point file contain no points"
             << exit(FatalError) << endl;
     }
@@ -126,8 +126,6 @@ std::list<Vb::Point> pointFile::initialPoints() const
         }
     }
 
-    std::list<Vb::Point> initialPoints;
-
     Field<bool> insidePoints = cvMesh_.geometryToConformTo().wellInside
     (
         points,
@@ -138,16 +136,20 @@ std::list<Vb::Point> pointFile::initialPoints() const
         )
     );
 
+    DynamicList<Vb::Point> initialPoints(insidePoints.size()/10);
+
     forAll(insidePoints, i)
     {
         if (insidePoints[i])
         {
             const point& p(points[i]);
 
-            initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+            initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
         }
     }
 
+    initialPoints.shrink();
+
     label nPointsRejected = points.size() - initialPoints.size();
 
     if (Pstream::parRun())
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.H
index 74c0775d405bd58f13929327b84821be665f1c40..a60e23e67a2ede9db8cd0bd730fdb0e11b6104ff 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.H
@@ -85,7 +85,7 @@ public:
     // Member Functions
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const;
+        virtual List<Vb::Point> initialPoints() const;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C
index 9413b38501f9b0fc08f7ca7cb30aaca482a65320..c440f4cdc95a252ba38942954344b816c3b94374 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C
@@ -56,7 +56,7 @@ uniformGrid::uniformGrid
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-std::list<Vb::Point> uniformGrid::initialPoints() const
+List<Vb::Point> uniformGrid::initialPoints() const
 {
     boundBox bb;
 
@@ -91,7 +91,8 @@ std::list<Vb::Point> uniformGrid::initialPoints() const
 
     scalar pert = randomPerturbationCoeff_*cmptMin(delta);
 
-    std::list<Vb::Point> initialPoints;
+    // Initialise points list
+    DynamicList<Vb::Point> initialPoints(ni*nj*nk/10);
 
     for (label i = 0; i < ni; i++)
     {
@@ -153,13 +154,13 @@ std::list<Vb::Point> uniformGrid::initialPoints() const
                 {
                     const point& p(points[i]);
 
-                    initialPoints.push_back(Vb::Point(p.x(), p.y(), p.z()));
+                    initialPoints.append(Vb::Point(p.x(), p.y(), p.z()));
                 }
             }
         }
     }
 
-    return initialPoints;
+    return initialPoints.shrink();
 }
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.H
index 655efae4702f422525b402501bb2114d01c729a4..158a49b59e9372be1b8e22d30925a4b0b76205ba 100644
--- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.H
+++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.H
@@ -89,7 +89,7 @@ public:
     // Member Functions
 
         //- Return the initial points for the conformalVoronoiMesh
-        virtual std::list<Vb::Point> initialPoints() const;
+        virtual List<Vb::Point> initialPoints() const;
 };
 
 
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMesh.C b/applications/utilities/mesh/generation/cvMesh/cvMesh.C
index fa95c852c11c5ccaa307ab80e7f63c4e2ff0bb19..daf03aa3766ab1bb75e0df22ea441f84579a3dc2 100644
--- a/applications/utilities/mesh/generation/cvMesh/cvMesh.C
+++ b/applications/utilities/mesh/generation/cvMesh/cvMesh.C
@@ -59,6 +59,8 @@ int main(int argc, char *argv[])
         )
     );
 
+    conformalVoronoiMesh::debug = true;
+
     conformalVoronoiMesh mesh(runTime, cvMeshDict);
 
     while (runTime.loop())
@@ -72,7 +74,7 @@ int main(int argc, char *argv[])
             << nl << endl;
     }
 
-    mesh.writeMesh(runTime.constant());
+    mesh.writeMesh(runTime.constant(), true);
 
     Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
         << "  ClockTime = " << runTime.elapsedClockTime() << " s"
diff --git a/applications/utilities/mesh/generation/cvMesh/vectorTools/vectorTools.H b/applications/utilities/mesh/generation/cvMesh/vectorTools/vectorTools.H
new file mode 100644
index 0000000000000000000000000000000000000000..9fb39a159bafbfb8de882cb4b469fbf6e7d14af8
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/vectorTools/vectorTools.H
@@ -0,0 +1,157 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+Class
+    Foam::vectorTools
+
+Description
+    Functions for analysing the relationships between vectors
+
+SourceFiles
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vectorTools_H
+#define vectorTools_H
+
+#include "vector.H"
+#include "unitConversion.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Namespace vectorTools Declaration
+\*---------------------------------------------------------------------------*/
+
+//- Collection of functions for testing relationships between two vectors.
+namespace vectorTools
+{
+    //- Test if a and b are parallel: a.b = 1
+    //  Uses the cross product, so the tolerance is proportional to
+    //  the sine of the angle between a and b in radians
+    template <typename T>
+    bool areParallel
+    (
+        const Vector<T>& a,
+        const Vector<T>& b,
+        const T& tolerance = SMALL
+    )
+    {
+        return (mag(a ^ b) < tolerance) ? true : false;
+//        return ( mag( mag(a & b)/(mag(a)*mag(b)) - 1.0 ) < tolerance )
+//               ? true
+//               : false;
+    }
+
+    //- Test if a and b are orthogonal: a.b = 0
+    //  Uses the dot product, so the tolerance is proportional to
+    //  the cosine of the angle between a and b in radians
+    template <typename T>
+    bool areOrthogonal
+    (
+        const Vector<T>& a,
+        const Vector<T>& b,
+        const T& tolerance = SMALL
+    )
+    {
+        return (mag(a & b) < tolerance) ? true : false;
+    }
+
+    //- Test if angle between a and b is acute: a.b > 0
+    template <typename T>
+    bool areAcute
+    (
+        const Vector<T>& a,
+        const Vector<T>& b
+    )
+    {
+        return ((a & b) > 0) ? true : false;
+    }
+
+    //- Test if angle between a and b is obtuse: a.b < 0
+    template <typename T>
+    bool areObtuse
+    (
+        const Vector<T>& a,
+        const Vector<T>& b
+    )
+    {
+        return ((a & b) < 0) ? true : false;
+    }
+
+    //- Calculate angle between a and b in radians
+    template <typename T>
+    T cosPhi
+    (
+        const Vector<T>& a,
+        const Vector<T>& b,
+        const T& tolerance = SMALL
+    )
+    {
+        scalar cosPhi = (a & b)/(mag(a)*mag(b) + tolerance);
+
+        // Enforce bounding between -1 and 1
+        return min(max(cosPhi, -1), 1);
+    }
+
+    //- Calculate angle between a and b in radians
+    template <typename T>
+    T radAngleBetween
+    (
+        const Vector<T>& a,
+        const Vector<T>& b,
+        const T& tolerance = SMALL
+    )
+    {
+        scalar cosPhi = (a & b)/(mag(a)*mag(b) + tolerance);
+
+        // Enforce bounding between -1 and 1
+        return acos( min(max(cosPhi, -1), 1) );
+    }
+
+    //- Calculate angle between a and b in degrees
+    template <typename T>
+    T degAngleBetween
+    (
+        const Vector<T>& a,
+        const Vector<T>& b,
+        const T& tolerance = SMALL
+    )
+    {
+        return radToDeg(radAngleBetween(a, b, tolerance));
+    }
+
+} // End namespace vectorTools
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/checkMesh/printMeshStats.C b/applications/utilities/mesh/manipulation/checkMesh/printMeshStats.C
index 2179e67b0c0a3085b405abd2e795c193dcd98b25..2951cab590a4c70903d73f1a3a5d719774751dcb 100644
--- a/applications/utilities/mesh/manipulation/checkMesh/printMeshStats.C
+++ b/applications/utilities/mesh/manipulation/checkMesh/printMeshStats.C
@@ -8,6 +8,7 @@
 #include "pyrMatcher.H"
 #include "tetWedgeMatcher.H"
 #include "tetMatcher.H"
+#include "IOmanip.H"
 
 
 void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
@@ -62,22 +63,19 @@ void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
             << nInternalEdges-nInternal1Edges << nl;
     }
 
-    Info<< "    faces:            "
-        << returnReduce(mesh.faces().size(), sumOp<label>()) << nl
-        << "    internal faces:   "
-        << returnReduce(mesh.faceNeighbour().size(), sumOp<label>()) << nl
-        << "    cells:            "
-        << returnReduce(mesh.cells().size(), sumOp<label>()) << nl
-        << "    boundary patches: "
-        << mesh.boundaryMesh().size() << nl
-        << "    point zones:      "
-        << mesh.pointZones().size() << nl
-        << "    face zones:       "
-        << mesh.faceZones().size() << nl
-        << "    cell zones:       "
-        << mesh.cellZones().size() << nl
-        << endl;
+    label nFaces = returnReduce(mesh.faces().size(), sumOp<label>());
+    label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>());
+    label nCells = returnReduce(mesh.cells().size(), sumOp<label>());
 
+    Info<< "    faces:            " << nFaces << nl
+        << "    internal faces:   " << nIntFaces << nl
+        << "    cells:            " << nCells << nl
+        << "    faces per cell:   " << scalar(nFaces + nIntFaces)/nCells << nl
+        << "    boundary patches: " << mesh.boundaryMesh().size() << nl
+        << "    point zones:      " << mesh.pointZones().size() << nl
+        << "    face zones:       " << mesh.faceZones().size() << nl
+        << "    cell zones:       " << mesh.cellZones().size() << nl
+        << endl;
 
     // Construct shape recognizers
     hexMatcher hex;
@@ -96,6 +94,8 @@ void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
     label nTetWedge = 0;
     label nUnknown = 0;
 
+    Map<label> polyhedralFaces;
+
     for (label cellI = 0; cellI < mesh.nCells(); cellI++)
     {
         if (hex.isA(mesh, cellI))
@@ -125,6 +125,7 @@ void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
         else
         {
             nUnknown++;
+            polyhedralFaces(mesh.cells()[cellI].size())++;
         }
     }
 
@@ -144,5 +145,21 @@ void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
         << "    tet wedges:    " << nTetWedge << nl
         << "    tetrahedra:    " << nTet << nl
         << "    polyhedra:     " << nUnknown
-        << nl << endl;
+        << endl;
+
+    if (nUnknown > 0)
+    {
+        Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>());
+
+        Info<< "    Breakdown of polyhedra by number of faces:" << endl;
+        Info<< "        faces" << "   number of cells" << endl;
+
+        forAllConstIter(Map<label>, polyhedralFaces, iter)
+        {
+            Info<< setf(std::ios::right) << setw(13)
+                << iter.key() << "   " << iter() << nl;
+        }
+    }
+
+    Info<< endl;
 }