diff --git a/src/surfMesh/MeshedSurface/MeshedSurface.C b/src/surfMesh/MeshedSurface/MeshedSurface.C
index 0bc6e4921c4d26da43476bc586f8a9fd1d7b2026..be701e08613e3fc17e705bbb2b79afcd44477beb 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurface.C
+++ b/src/surfMesh/MeshedSurface/MeshedSurface.C
@@ -837,6 +837,61 @@ bool Foam::MeshedSurface<Face>::checkFaces
 }
 
 
+template<class Face>
+Foam::label Foam::MeshedSurface<Face>::nTriangles() const
+{
+    return nTriangles
+    (
+        const_cast<List<label>&>(List<label>::null())
+    );
+}
+
+
+template<class Face>
+Foam::label Foam::MeshedSurface<Face>::nTriangles
+(
+    List<label>& faceMap
+) const
+{
+    label nTri = 0;
+    const List<Face>& faceLst = surfFaces();
+
+    // Count triangles needed
+    forAll(faceLst, facei)
+    {
+        nTri += faceLst[facei].nTriangles();
+    }
+
+    // Nothing to do
+    if (nTri <= faceLst.size())
+    {
+        if (notNull(faceMap))
+        {
+            faceMap.clear();
+        }
+    }
+    else if (notNull(faceMap))
+    {
+        // face map requested
+        faceMap.setSize(nTri);
+
+        nTri = 0;
+        forAll(faceLst, facei)
+        {
+            label n = faceLst[facei].nTriangles();
+            while (n-- > 0)
+            {
+                faceMap[nTri++] = facei;
+            }
+        }
+
+        faceMap.setSize(nTri);
+    }
+
+    return nTri;
+}
+
+
 template<class Face>
 Foam::label Foam::MeshedSurface<Face>::triangulate()
 {
@@ -888,14 +943,11 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
     }
     faceMap.setSize(nTri);
 
-    // remember the number of *additional* faces
-    nTri -= faceLst.size();
-
     if (this->points().empty())
     {
         // triangulate without points
         // simple face triangulation around f[0]
-        label newFacei = 0;
+        nTri = 0;
         forAll(faceLst, facei)
         {
             const Face& f = faceLst[facei];
@@ -904,9 +956,9 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
             {
                 label fp1 = f.fcIndex(fp);
 
-                newFaces[newFacei] = triFace(f[0], f[fp], f[fp1]);
-                faceMap[newFacei] = facei;
-                newFacei++;
+                newFaces[nTri] = triFace(f[0], f[fp], f[fp1]);
+                faceMap[nTri] = facei;
+                nTri++;
             }
         }
     }
@@ -915,7 +967,7 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
         // triangulate with points
         List<face> tmpTri(maxTri);
 
-        label newFacei = 0;
+        nTri = 0;
         forAll(faceLst, facei)
         {
             // 'face' not '<Face>'
@@ -925,16 +977,19 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
             f.triangles(this->points(), nTmp, tmpTri);
             for (label triI = 0; triI < nTmp; triI++)
             {
-                newFaces[newFacei] = Face
+                newFaces[nTri] = Face
                 (
                     static_cast<labelUList&>(tmpTri[triI])
                 );
-                faceMap[newFacei] = facei;
-                newFacei++;
+                faceMap[nTri] = facei;
+                nTri++;
             }
         }
     }
 
+    // The number of *additional* faces
+    nTri -= faceLst.size();
+
     faceLst.transfer(newFaces);
     remapFaces(faceMap);
 
@@ -947,6 +1002,7 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
 
     // Topology can change because of renumbering
     ParentType::clearOut();
+
     return nTri;
 }
 
diff --git a/src/surfMesh/MeshedSurface/MeshedSurface.H b/src/surfMesh/MeshedSurface/MeshedSurface.H
index c30686f6b484d026f68e8bf1e6ac9d503cda3c00..3922edf29e6955fc7603786941b7b0512e2bb94a 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurface.H
+++ b/src/surfMesh/MeshedSurface/MeshedSurface.H
@@ -51,7 +51,7 @@ SourceFiles
 #include "PatchTools.H"
 #include "pointField.H"
 #include "face.H"
-#include "triFace.H"
+#include "labelledTri.H"
 
 #include "surfZoneList.H"
 #include "surfaceFormatsCore.H"
@@ -134,7 +134,10 @@ protected:
 
     // Protected Member functions
 
-        //- Transfer points/zones and transcribe face -> triFace
+        //- Transfer points/zones from 'face' to other other shapes.
+        //  Eg, transcribe face to triFace, or face -> labelledTri, including
+        //  any addZonesToFaces adjustment.
+        //  No general form, only specializations.
         void transcribe(MeshedSurface<face>&);
 
         //- Basic sanity check on zones
@@ -386,6 +389,12 @@ public:
                 const bool cullEmpty=false
             );
 
+            //- Propagate zone information on face regions.
+            //  Normally a no-op, only used by the labelledTri specialization.
+            //  Specializations return true, others return false.
+            bool addZonesToFaces();
+
+
             //- Remove surface zones
             virtual void removeZones();
 
@@ -428,7 +437,14 @@ public:
                 const bool verbose=false
             );
 
-            //- Triangulate in-place, returning the number of triangles added
+            //- Count number of triangles.
+            virtual label nTriangles() const;
+
+            //- Count number of triangles, returning a face map of original ids.
+            //  The faceMap is zero-sized when no triangulation would be needed.
+            virtual label nTriangles(List<label>& faceMap) const;
+
+            //- Triangulate in-place, returning the number of triangles added.
             virtual label triangulate();
 
             //- Triangulate in-place, returning the number of triangles added
@@ -436,7 +452,6 @@ public:
             //  The faceMap is zero-sized when no triangulation was done.
             virtual label triangulate(List<label>& faceMap);
 
-
             //- Return new surface.
             //  Returns return pointMap, faceMap from subsetMeshMap
             MeshedSurface subsetMesh
@@ -521,33 +536,10 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-//- Specialization for holding triangulated information
-template<>
-inline bool MeshedSurface<triFace>::isTri()
-{
-    return true;
-}
-
-
-//- Specialization for holding triangulated information
-template<>
-inline label MeshedSurface<triFace>::triangulate()
-{
-    return 0;
-}
-
-
-//- Specialization for holding triangulated information
+//- Specialization for labelledTri.
 template<>
-inline label MeshedSurface<triFace>::triangulate(List<label>& faceMap)
-{
-    if (notNull(faceMap))
-    {
-        faceMap.clear();
-    }
+bool MeshedSurface<labelledTri>::addZonesToFaces();
 
-    return 0;
-}
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -556,6 +548,8 @@ inline label MeshedSurface<triFace>::triangulate(List<label>& faceMap)
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#include "MeshedSurfaceI.H"
+
 #ifdef NoRepository
     #include "MeshedSurface.C"
 #endif
diff --git a/src/surfMesh/MeshedSurface/MeshedSurfaceCore.C b/src/surfMesh/MeshedSurface/MeshedSurfaceCore.C
index 08851de6278ae63055a3014f9b35de6791969910..8640b6e5aeb0aa571943318c1bc20f016a7b2321 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurfaceCore.C
+++ b/src/surfMesh/MeshedSurface/MeshedSurfaceCore.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,18 +30,34 @@ License
 namespace Foam
 {
 
-    // specialization: from face -> triFace
+    // Transcribe 'face' to 'face' (ie, just transfer)
     template<>
-    void Foam::MeshedSurface<triFace>::transcribe(MeshedSurface<face>& surf)
+    void Foam::MeshedSurface<Foam::face>::transcribe
+    (
+        MeshedSurface<face>& surf
+    )
     {
-        // first triangulate
+        this->transfer(surf);
+        this->addZonesToFaces(); // currently a no-op
+    }
+
+    // Transcribe 'face' to 'triFace'
+    // Transfer points/zones and triangulate faces
+    template<>
+    void Foam::MeshedSurface<Foam::triFace>::transcribe
+    (
+        MeshedSurface<face>& surf
+    )
+    {
+        // First triangulate
+        // - slightly wasteful for space, but manages adjusts the zones too!
         surf.triangulate();
         this->storedPoints().transfer(surf.storedPoints());
         this->storedZones().transfer(surf.storedZones());
 
         // transcribe from face -> triFace
-        List<face>&    origFaces = surf.storedFaces();
-        List<triFace>  newFaces(origFaces.size());
+        const List<face>& origFaces = surf.surfFaces();
+        List<triFace> newFaces(origFaces.size());
         forAll(origFaces, facei)
         {
             newFaces[facei] = triFace
@@ -52,18 +68,65 @@ namespace Foam
         surf.clear();
 
         this->storedFaces().transfer(newFaces);
+        this->addZonesToFaces(); // currently a no-op
     }
 
 
-    // specialization: from face -> face
+    // Transcribe 'face' to 'labelledTri'
+    // Transfer points/zones and triangulate faces
     template<>
-    void Foam::MeshedSurface<face>::transcribe(MeshedSurface<face>& surf)
+    void Foam::MeshedSurface<Foam::labelledTri>::transcribe
+    (
+        MeshedSurface<face>& surf
+    )
     {
-        this->transfer(surf);
+        // First triangulate
+        // - slightly wasteful for space, but manages adjusts the zones too!
+        surf.triangulate();
+        this->storedPoints().transfer(surf.storedPoints());
+        this->storedZones().transfer(surf.storedZones());
+
+        // transcribe from face -> triFace
+        const List<face>& origFaces = surf.surfFaces();
+        List<labelledTri> newFaces(origFaces.size());
+        forAll(origFaces, facei)
+        {
+            newFaces[facei] = triFace
+            (
+                static_cast<const labelUList&>(origFaces[facei])
+            );
+        }
+        surf.clear();
+
+        this->storedFaces().transfer(newFaces);
+        this->addZonesToFaces(); // for labelledTri
+    }
+
+
+    // Propagate zone information on face regions for labelledTri.
+    template<>
+    bool Foam::MeshedSurface<Foam::labelledTri>::addZonesToFaces()
+    {
+        List<labelledTri>& faceLst = this->storedFaces();
+        const surfZoneList& zones = this->surfZones();
+
+        forAll(zones, zoneI)
+        {
+            const surfZone& zone = zones[zoneI];
+
+            label faceI = zone.start();
+            forAll(zone, i)
+            {
+                faceLst[faceI++].region() = zoneI;
+            }
+        }
+
+        return true;
     }
 
 
 }  // end of namespace Foam
 
 
+
 // ************************************************************************* //
diff --git a/src/surfMesh/MeshedSurface/MeshedSurfaceI.H b/src/surfMesh/MeshedSurface/MeshedSurfaceI.H
new file mode 100644
index 0000000000000000000000000000000000000000..a7415f7b4b69e8ef8a15731bdfc2e4598090c20b
--- /dev/null
+++ b/src/surfMesh/MeshedSurface/MeshedSurfaceI.H
@@ -0,0 +1,103 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// A triFace surface only handles triangulated faces
+template<>
+inline bool MeshedSurface<triFace>::isTri()
+{
+    return true;
+}
+
+
+// A labelledTri surface only handles triangulated faces
+template<>
+inline bool MeshedSurface<labelledTri>::isTri()
+{
+    return true;
+}
+
+
+// Number of triangles for a triFace surface
+template<>
+inline label MeshedSurface<triFace>::nTriangles() const
+{
+    return ParentType::size();
+}
+
+// Number of triangles for a labelledTri surface
+template<>
+inline label MeshedSurface<labelledTri>::nTriangles() const
+{
+    return ParentType::size();
+}
+
+
+// Inplace triangulation of triFace surface = no-op
+template<>
+inline label MeshedSurface<triFace>::triangulate()
+{
+    return 0;
+}
+
+// Inplace triangulation of labelledTri surface = no-op
+template<>
+inline label MeshedSurface<labelledTri>::triangulate()
+{
+    return 0;
+}
+
+// Inplace triangulation of triFace surface (with face map) = no-op
+template<>
+inline label MeshedSurface<triFace>::triangulate(List<label>& faceMap)
+{
+    if (notNull(faceMap))
+    {
+        faceMap.clear();
+    }
+    return 0;
+}
+
+// Inplace triangulation of labelledTri surface (with face map) = no-op
+template<>
+inline label MeshedSurface<labelledTri>::triangulate(List<label>& faceMap)
+{
+    if (notNull(faceMap))
+    {
+        faceMap.clear();
+    }
+    return 0;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/surfMesh/MeshedSurface/MeshedSurfaceZones.C b/src/surfMesh/MeshedSurface/MeshedSurfaceZones.C
index 767d1e5b9c62d8d72590ad26d53a23f9c721b841..512746741833dfdcc1e65a5edbe6731bd9d2f650 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurfaceZones.C
+++ b/src/surfMesh/MeshedSurface/MeshedSurfaceZones.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -131,7 +131,7 @@ void Foam::MeshedSurface<Face>::addZones
     const bool cullEmpty
 )
 {
-    label start   = 0;
+    label start = 0;
     label nZone = 0;
 
     surfZoneList& zones = this->storedZones();
@@ -162,7 +162,7 @@ void Foam::MeshedSurface<Face>::addZones
     const bool cullEmpty
 )
 {
-    label start   = 0;
+    label start = 0;
     label nZone = 0;
 
     surfZoneList& zones = this->storedZones();
@@ -186,6 +186,14 @@ void Foam::MeshedSurface<Face>::addZones
 }
 
 
+template<class Face>
+bool Foam::MeshedSurface<Face>::addZonesToFaces()
+{
+    // Normally a no-op, only the specializations are used.
+    return false;
+}
+
+
 template<class Face>
 void Foam::MeshedSurface<Face>::removeZones()
 {
diff --git a/src/surfMesh/MeshedSurface/MeshedSurfaces.C b/src/surfMesh/MeshedSurface/MeshedSurfaces.C
index 999c755c7e5faaceeddbf6a2236b9d4dcf57333b..8795a37e2525bc16f7dfeaa21a678e9e7261f8f1 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurfaces.C
+++ b/src/surfMesh/MeshedSurface/MeshedSurfaces.C
@@ -46,6 +46,7 @@ namespace Foam
 
 makeSurface(MeshedSurface, face)
 makeSurface(MeshedSurface, triFace)
+makeSurface(MeshedSurface, labelledTri)
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.C b/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.C
index 1b1ad73ccf73a98099ec7527d4a9e21edef022ce..d7c92fa620ff84ce14d8b1fd4b5eacf56f8c81c3 100644
--- a/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.C
+++ b/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.C
@@ -235,4 +235,41 @@ Foam::MeshedSurfaceProxy<Face>::~MeshedSurfaceProxy()
 {}
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+namespace Foam
+{
+
+// Number of triangles for a triFace surface
+template<>
+inline label MeshedSurfaceProxy<triFace>::nTriangles() const
+{
+    return this->size();
+}
+
+// Number of triangles for a labelledTri surface
+template<>
+inline label MeshedSurfaceProxy<labelledTri>::nTriangles() const
+{
+    return this->size();
+}
+
+}
+
+
+template<class Face>
+inline Foam::label Foam::MeshedSurfaceProxy<Face>::nTriangles() const
+{
+    label nTri = 0;
+    const List<Face>& faceLst = this->surfFaces();
+    forAll(faceLst, facei)
+    {
+        nTri += faceLst[facei].nTriangles();
+    }
+
+    return nTri;
+}
+
+
 // ************************************************************************* //
diff --git a/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.H b/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.H
index 870949e09d92bee98de61c96014205432cc6e682..3bedc3f0767f90fea6c792158c60676764be8469 100644
--- a/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.H
+++ b/src/surfMesh/MeshedSurfaceProxy/MeshedSurfaceProxy.H
@@ -38,8 +38,7 @@ SourceFiles
 #define MeshedSurfaceProxy_H
 
 #include "pointField.H"
-#include "face.H"
-#include "triFace.H"
+#include "labelledTri.H"
 
 #include "surfZoneList.H"
 #include "surfaceFormatsCore.H"
@@ -139,6 +138,12 @@ public:
 
         // Access
 
+            //- The surface size is the number of faces
+            inline label size() const
+            {
+                return faces_.size();
+            }
+
             //- Return const access to the points
             inline const pointField& points() const
             {
@@ -171,6 +176,10 @@ public:
                 return faceMap_.size() == faces_.size();
             }
 
+            //- Count number of triangles.
+            inline label nTriangles() const;
+
+
         // Write
 
             //- Generic write routine. Chooses writer based on extension.
diff --git a/src/surfMesh/UnsortedMeshedSurface/UnsortedMeshedSurfaces.C b/src/surfMesh/UnsortedMeshedSurface/UnsortedMeshedSurfaces.C
index 400cafb1487272d1ed0f67c8d66ba74aa083c1cb..69c499174881f939d18e7e2d58f4f0f6ec3459db 100644
--- a/src/surfMesh/UnsortedMeshedSurface/UnsortedMeshedSurfaces.C
+++ b/src/surfMesh/UnsortedMeshedSurface/UnsortedMeshedSurfaces.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,6 +46,7 @@ namespace Foam
 
 makeSurface(UnsortedMeshedSurface, face)
 makeSurface(UnsortedMeshedSurface, triFace)
+makeSurface(UnsortedMeshedSurface, labelledTri)
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C b/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
index c88b4ed5b0523f9dd298aec30dbb9a4c6e4968a4..9bc86e0cf38e3f4dbe1f46aaf58ece6eb388925f 100644
--- a/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
@@ -49,7 +49,6 @@ bool Foam::fileFormats::AC3DsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     IFstream is(filename);
@@ -199,7 +198,7 @@ bool Foam::fileFormats::AC3DsurfaceFormat<Face>::read
 
                     labelUList& f = static_cast<labelUList&>(verts);
 
-                    if (mustTriangulate && f.size() > 3)
+                    if (MeshedSurface<Face>::isTri() && f.size() > 3)
                     {
                         // simple face triangulation about f[0]
                         // points may be incomplete
@@ -248,7 +247,9 @@ bool Foam::fileFormats::AC3DsurfaceFormat<Face>::read
 
     // add zones, culling empty ones
     this->addZones(sizes, names, true);
+    this->addZonesToFaces(); // for labelledTri
     this->stitchFaces(SMALL);
+
     return true;
 }
 
diff --git a/src/surfMesh/surfaceFormats/gts/GTSsurfaceFormat.C b/src/surfMesh/surfaceFormats/gts/GTSsurfaceFormat.C
index 069c0b9db2009f107f259f19ef5bffbaa9df355b..731b2e1b96aa397c06aeeecfb80073ea37721161 100644
--- a/src/surfMesh/surfaceFormats/gts/GTSsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/gts/GTSsurfaceFormat.C
@@ -203,6 +203,7 @@ bool Foam::fileFormats::GTSsurfaceFormat<Face>::read
     }
 
     this->storedZoneToc().transfer(newZones);
+    this->addZonesToFaces(); // for labelledTri
 
     return true;
 }
diff --git a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
index 2a7ea0ebc7953d8980f645a9fc731eadc45f35cd..d7b932ec485de4fba41ca5b3efbb1ae4996bc325 100644
--- a/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/nas/NASsurfaceFormat.C
@@ -47,7 +47,6 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     IFstream is(filename);
@@ -253,7 +252,7 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
             }
 
 
-            if (mustTriangulate)
+            if (MeshedSurface<Face>::isTri())
             {
                 dynFaces.append(triFace(f[0], f[1], f[2]));
                 dynFaces.append(triFace(f[0], f[2], f[3]));
@@ -374,9 +373,8 @@ bool Foam::fileFormats::NASsurfaceFormat<Face>::read
     }
 
     this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
-
-    // add zones, culling empty ones
-    this->addZones(dynSizes, names, true);
+    this->addZones(dynSizes, names, true); // add zones, cull empty ones
+    this->addZonesToFaces(); // for labelledTri
 
     return true;
 }
diff --git a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
index 2107d02a5f61688648ea87dbd02433696f335cb3..04274c775a65bdf23581c7434914d0a3ebeb60f6 100644
--- a/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/obj/OBJsurfaceFormat.C
@@ -51,7 +51,6 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     IFstream is(filename);
@@ -173,7 +172,7 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
 
             labelUList& f = static_cast<labelUList&>(dynVertices);
 
-            if (mustTriangulate && f.size() > 3)
+            if (MeshedSurface<Face>::isTri() && f.size() > 3)
             {
                 // simple face triangulation about f[0]
                 // points may be incomplete
@@ -200,9 +199,9 @@ bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
     this->storedPoints().transfer(dynPoints);
 
     this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
+    this->addZones(dynSizes, dynNames, true); // add zones, cull empty ones
+    this->addZonesToFaces(); // for labelledTri
 
-    // add zones, culling empty ones
-    this->addZones(dynSizes, dynNames, true);
     return true;
 }
 
diff --git a/src/surfMesh/surfaceFormats/off/OFFsurfaceFormat.C b/src/surfMesh/surfaceFormats/off/OFFsurfaceFormat.C
index b4cb06a81fc88ba2f8a2f6f36978dcbf8e7a914a..fd869a0c5086db67467529aa42bac8d9f282f080 100644
--- a/src/surfMesh/surfaceFormats/off/OFFsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/off/OFFsurfaceFormat.C
@@ -50,7 +50,6 @@ bool Foam::fileFormats::OFFsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     IFstream is(filename);
@@ -116,7 +115,7 @@ bool Foam::fileFormats::OFFsurfaceFormat<Face>::read
 
             labelUList& f = static_cast<labelUList&>(verts);
 
-            if (mustTriangulate && f.size() > 3)
+            if (MeshedSurface<Face>::isTri() && f.size() > 3)
             {
                 // simple face triangulation about f[0]
                 // cannot use face::triangulation (points may be incomplete)
diff --git a/src/surfMesh/surfaceFormats/smesh/SMESHsurfaceFormat.C b/src/surfMesh/surfaceFormats/smesh/SMESHsurfaceFormat.C
index e8e7ed21cc5a5636db3242951fc4e78b7724480d..01640aa5ec87665adb28c1b2dcfedada0ab91b1e 100644
--- a/src/surfMesh/surfaceFormats/smesh/SMESHsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/smesh/SMESHsurfaceFormat.C
@@ -25,9 +25,7 @@ License
 
 #include "SMESHsurfaceFormat.H"
 #include "clock.H"
-#include "IFstream.H"
 #include "OFstream.H"
-#include "Ostream.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -58,7 +56,6 @@ void Foam::fileFormats::SMESHsurfaceFormat<Face>::write
 
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
-
     OFstream os(filename);
     if (!os.good())
     {
diff --git a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
index 219448967cfb40b8c481d016e8ecf62452ff4318..7240ee78245a01aad1371e18d01ccdf1b7233dfe 100644
--- a/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/starcd/STARCDsurfaceFormat.C
@@ -79,7 +79,6 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     fileName baseName = filename.lessExt();
@@ -194,24 +193,19 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
             }
 
             SubList<label> vertices(vertexLabels, vertexLabels.size());
-            if (mustTriangulate && nLabels > 3)
+            if (MeshedSurface<Face>::isTri() && nLabels > 3)
             {
+                // face needs triangulation
                 face f(vertices);
 
-                faceList triFaces(f.nTriangles());
+                faceList trias(f.nTriangles());
                 label nTri = 0;
-                f.triangles(this->points(), nTri, triFaces);
+                f.triangles(this->points(), nTri, trias);
 
-                forAll(triFaces, facei)
+                forAll(trias, facei)
                 {
-                    // a triangular face, but not yet a triFace
-                    dynFaces.append
-                    (
-                        triFace
-                        (
-                            static_cast<labelUList&>(triFaces[facei])
-                        )
-                    );
+                    // a triangular 'face', convert to 'triFace' etc
+                    dynFaces.append(Face(trias[facei]));
                     dynZones.append(zoneI);
                     dynSizes[zoneI]++;
                 }
@@ -228,8 +222,9 @@ bool Foam::fileFormats::STARCDsurfaceFormat<Face>::read
 
     this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
 
-    // add zones, culling empty ones
-    this->addZones(dynSizes, dynNames, true);
+    this->addZones(dynSizes, dynNames, true); // add zones, cull empty ones
+    this->addZonesToFaces(); // for labelledTri
+
     return true;
 }
 
diff --git a/src/surfMesh/surfaceFormats/stl/STLsurfaceFormat.C b/src/surfMesh/surfaceFormats/stl/STLsurfaceFormat.C
index 17dcb781f4d77c40127766a03ae304b49284a167..ce53aed44bcaf8e9da312d24cb87c8101a8f06e0 100644
--- a/src/surfMesh/surfaceFormats/stl/STLsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/stl/STLsurfaceFormat.C
@@ -24,7 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "STLsurfaceFormat.H"
-#include "ListOps.H"
+#include "labelledTri.H"
 #include "triPointRef.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
@@ -180,13 +180,13 @@ bool Foam::fileFormats::STLsurfaceFormat<Face>::read
     {
         this->addZones(sizes);
     }
-
+    this->addZonesToFaces(); // for labelledTri
     this->stitchFaces(SMALL);
+
     return true;
 }
 
 
-
 template<class Face>
 void Foam::fileFormats::STLsurfaceFormat<Face>::writeAscii
 (
@@ -271,22 +271,8 @@ void Foam::fileFormats::STLsurfaceFormat<Face>::writeBinary
 
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
-
-    unsigned int nTris = 0;
-    if (MeshedSurface<Face>::isTri())
-    {
-        nTris = faceLst.size();
-    }
-    else
-    {
-        // count triangles for on-the-fly triangulation
-        forAll(faceLst, facei)
-        {
-            nTris += faceLst[facei].size() - 2;
-        }
-    }
-
     // Write the STL header
+    unsigned int nTris = surf.nTriangles();
     STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
 
     label faceIndex = 0;
@@ -345,7 +331,7 @@ void Foam::fileFormats::STLsurfaceFormat<Face>::writeAscii
     // a single zone - we can skip sorting
     if (surf.zoneToc().size() == 1)
     {
-        os << "solid " << surf.zoneToc()[0].name() << endl;
+        os << "solid " << surf.zoneToc()[0].name() << nl;
         forAll(faceLst, facei)
         {
             writeShell(os, pointLst, faceLst[facei]);
@@ -391,21 +377,8 @@ void Foam::fileFormats::STLsurfaceFormat<Face>::writeBinary
     const List<Face>&  faceLst  = surf.surfFaces();
     const List<label>& zoneIds  = surf.zoneIds();
 
-    unsigned int nTris = 0;
-    if (MeshedSurface<Face>::isTri())
-    {
-        nTris = faceLst.size();
-    }
-    else
-    {
-        // count triangles for on-the-fly triangulation
-        forAll(faceLst, facei)
-        {
-            nTris += faceLst[facei].size() - 2;
-        }
-    }
-
     // Write the STL header
+    unsigned int nTris = surf.nTriangles();
     STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
 
     // always write unsorted
diff --git a/src/surfMesh/surfaceFormats/tri/TRIsurfaceFormat.C b/src/surfMesh/surfaceFormats/tri/TRIsurfaceFormat.C
index 4261afacf154e59705920a59f90246fff8eb4f4d..5b0aba1f8808a1a6885bd5925f2fe08ef9e42c7d 100644
--- a/src/surfMesh/surfaceFormats/tri/TRIsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/tri/TRIsurfaceFormat.C
@@ -24,7 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "TRIsurfaceFormat.H"
-#include "ListOps.H"
+#include "OFstream.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -51,7 +51,7 @@ inline void Foam::fileFormats::TRIsurfaceFormat<Face>::writeShell
             << p1.x() << ' ' << p1.y() << ' ' << p1.z() << ' '
             << p2.x() << ' ' << p2.y() << ' ' << p2.z() << ' '
             // zone as colour
-            << "0x" << hex << zoneI << dec << endl;
+            << "0x" << hex << zoneI << dec << nl;
     }
 }
 
@@ -120,6 +120,7 @@ bool Foam::fileFormats::TRIsurfaceFormat<Face>::read
     this->storedFaces().transfer(faceLst);
 
     this->addZones(sizes);
+    this->addZonesToFaces(); // for labelledTri
     this->stitchFaces(SMALL);
     return true;
 }
diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
index a738dc53df998d524999a06b657738dd4007e10a..aedd18d6c853b42e048bfd75f514f62b4d8e85aa 100644
--- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
@@ -26,6 +26,7 @@ License
 #include "VTKsurfaceFormat.H"
 #include "vtkUnstructuredReader.H"
 #include "scalarIOField.H"
+#include "OFstream.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -69,7 +70,6 @@ bool Foam::fileFormats::VTKsurfaceFormat<Face>::read
     const fileName& filename
 )
 {
-    const bool mustTriangulate = this->isTri();
     this->clear();
 
     IFstream is(filename);
@@ -148,18 +148,21 @@ bool Foam::fileFormats::VTKsurfaceFormat<Face>::read
     }
 
 
-    // See if needs triangulation
+    // Check if it needs triangulation
     label nTri = 0;
-    if (mustTriangulate)
+    if (MeshedSurface<Face>::isTri())
     {
         forAll(faces, facei)
         {
-            nTri += faces[facei].size()-2;
+            nTri += faces[facei].nTriangles();
         }
     }
 
-    if (nTri > 0)
+    if (nTri > faces.size())
     {
+        // We are here if the target surface needs triangles and
+        // the source surface has non-triangles
+
         DynamicList<Face> dynFaces(nTri);
         DynamicList<label> dynZones(nTri);
         forAll(faces, facei)
@@ -207,6 +210,7 @@ bool Foam::fileFormats::VTKsurfaceFormat<Face>::read
         // add zones, culling empty ones
         this->addZones(zoneSizes, zoneNames, true);
     }
+    this->addZonesToFaces(); // for labelledTri
 
     // transfer to normal lists
     this->storedPoints().transfer(reader.points());
diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
index 89f051eae8eb6d5172ec507cd20053ad09377b2d..a9c63ccf4114f26f2019e1c27e6c2469a28765a1 100644
--- a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
@@ -24,12 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "X3DsurfaceFormat.H"
-#include "clock.H"
-#include "IFstream.H"
-#include "IStringStream.H"
-#include "Ostream.H"
 #include "OFstream.H"
-#include "ListOps.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -55,7 +50,7 @@ void Foam::fileFormats::X3DsurfaceFormat<Face>::write
     const List<surfZone>& zones =
     (
         surf.surfZones().empty()
-      ? surfaceFormatsCore::oneZone(faceLst, "")
+      ? surfaceFormatsCore::oneZone(faceLst, word::null)
       : surf.surfZones()
     );