diff --git a/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C b/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
index 9bc86e0cf38e3f4dbe1f46aaf58ece6eb388925f..0c60b22ede22db7b1b71739a0b67cc76bcbd21fc 100644
--- a/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/ac3d/AC3DsurfaceFormat.C
@@ -24,10 +24,8 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "AC3DsurfaceFormat.H"
-#include "clock.H"
 #include "IStringStream.H"
-#include "tensor.H"
-#include "primitivePatch.H"
+#include "PrimitivePatch.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -254,6 +252,57 @@ bool Foam::fileFormats::AC3DsurfaceFormat<Face>::read
 }
 
 
+namespace Foam
+{
+// file-scope writing of a patch of faces
+template
+<
+    class Face,
+    template<class> class FaceList,
+    class PointField,
+    class PointType
+>
+static void writeZone
+(
+    Ostream& os,
+    const PrimitivePatch<Face, FaceList, PointField, PointType>& patch,
+    const word& name,
+    const label zoneI
+)
+{
+    // An isolated surface region (patch).
+    os  << "OBJECT poly" << nl
+        << "name \"" << name << "\"" << nl;
+
+    os << "numvert " << patch.nPoints() << nl;
+
+    forAll(patch.localPoints(), pti)
+    {
+        const point& pt = patch.localPoints()[pti];
+
+        os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
+    }
+
+    os << "numsurf " << patch.size() << nl;
+
+    forAll(patch.localFaces(), facei)
+    {
+        const Face& f = patch.localFaces()[facei];
+
+        os  << "SURF 0x20" << nl          // polygon
+            << "mat " << zoneI << nl
+            << "refs " << f.size() << nl;
+
+        forAll(f, fp)
+        {
+            os << f[fp] << " 0 0" << nl;
+        }
+    }
+
+    os << "kids 0" << endl;
+}
+}
+
 template<class Face>
 void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
 (
@@ -273,14 +322,6 @@ void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
 
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
-    if (useFaceMap)
-    {
-        FatalErrorInFunction
-            << "output with faceMap is not supported " << filename
-            << exit(FatalError);
-    }
-
-
     OFstream os(filename);
     if (!os.good())
     {
@@ -291,52 +332,42 @@ void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
 
     writeHeader(os, zones);
 
-    forAll(zones, zoneI)
+    if (zones.size() == 1)
     {
-        const surfZone& zone = zones[zoneI];
-
-        os  << "OBJECT poly" << nl
-            << "name \"" << zone.name() << "\"\n";
-
-        // Temporary PrimitivePatch to calculate compact points & faces
-        // use 'UList' to avoid allocations!
         PrimitivePatch<Face, UList, const pointField&> patch
         (
-            SubList<Face>
-            (
-                faceLst,
-                zone.size(),
-                zone.start()
-            ),
-            pointLst
+            faceLst, pointLst
         );
 
-        os << "numvert " << patch.nPoints() << endl;
+        writeZone(os, patch, zones[0].name(), 0);
+        return;
+    }
+
+    forAll(zones, zoneI)
+    {
+        const surfZone& zone = zones[zoneI];
 
-        forAll(patch.localPoints(), ptI)
+        if (useFaceMap)
         {
-            const point& pt = patch.localPoints()[ptI];
+            SubList<label> zoneMap(surf.faceMap(), zone.size(), zone.start());
+            PrimitivePatch<Face, UIndirectList, const pointField&> patch
+            (
+                UIndirectList<Face>(faceLst, zoneMap),
+                pointLst
+            );
 
-            os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
+            writeZone(os, patch, zone.name(), zoneI);
         }
-
-        os << "numsurf " << patch.localFaces().size() << endl;
-
-        forAll(patch.localFaces(), localFacei)
+        else
         {
-            const Face& f = patch.localFaces()[localFacei];
-
-            os  << "SURF 0x20" << nl          // polygon
-                << "mat " << zoneI << nl
-                << "refs " << f.size() << nl;
+            PrimitivePatch<Face, UList, const pointField&> patch
+            (
+                SubList<Face>(faceLst, zone.size(), zone.start()),
+                pointLst
+            );
 
-            forAll(f, fp)
-            {
-                os << f[fp] << " 0 0" << nl;
-            }
+            writeZone(os, patch, zone.name(), zoneI);
         }
-
-        os << "kids 0" << endl;
     }
 }
 
@@ -348,81 +379,44 @@ void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
     const UnsortedMeshedSurface<Face>& surf
 )
 {
+    OFstream os(filename);
+    if (!os.good())
+    {
+        FatalErrorInFunction
+            << "Cannot open file for writing " << filename
+            << exit(FatalError);
+    }
+
     labelList faceMap;
     List<surfZone> zoneLst = surf.sortedZones(faceMap);
 
     if (zoneLst.size() <= 1)
     {
-        write
+        const List<surfZone>& zones =
         (
-            filename,
-            MeshedSurfaceProxy<Face>
-            (
-                surf.points(),
-                surf.surfFaces(),
-                zoneLst
-            )
+            zoneLst.size()
+          ? zoneLst
+          : surfaceFormatsCore::oneZone(surf.surfFaces())
         );
-    }
-    else
-    {
-        OFstream os(filename);
-        if (!os.good())
-        {
-            FatalErrorInFunction
-                << "Cannot open file for writing " << filename
-                << exit(FatalError);
-        }
-
-        writeHeader(os, zoneLst);
-
-        label faceIndex = 0;
-        forAll(zoneLst, zoneI)
-        {
-            const surfZone& zone = zoneLst[zoneI];
-
-            os  << "OBJECT poly" << nl
-                << "name \"" << zone.name() << "\"\n";
 
-            // Create zone with only zone faces included for ease of addressing
-            labelHashSet include(surf.size());
-
-            forAll(zone, localFacei)
-            {
-                const label facei = faceMap[faceIndex++];
-                include.insert(facei);
-            }
-
-            UnsortedMeshedSurface<Face> subm = surf.subsetMesh(include);
-
-            // Now we have isolated surface for this patch alone. Write it.
-            os << "numvert " << subm.nPoints() << endl;
-
-            forAll(subm.localPoints(), ptI)
-            {
-                const point& pt = subm.localPoints()[ptI];
-
-                os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
-            }
-
-            os << "numsurf " << subm.localFaces().size() << endl;
-
-            forAll(subm.localFaces(), localFacei)
-            {
-                const Face& f = subm.localFaces()[localFacei];
+        writeHeader(os, zones);
+        writeZone(os, surf, zones[0].name(), 0);
+        return;
+    }
 
-                os  << "SURF 0x20" << nl          // polygon
-                    << "mat " << zoneI << nl
-                    << "refs " << f.size() << nl;
+    writeHeader(os, zoneLst);
+    forAll(zoneLst, zoneI)
+    {
+        const surfZone& zone = zoneLst[zoneI];
 
-                forAll(f, fp)
-                {
-                    os << f[fp] << " 0 0" << nl;
-                }
-            }
+        SubList<label> zoneMap(faceMap, zone.size(), zone.start());
+        PrimitivePatch<Face, UIndirectList, const pointField&> patch
+        (
+            UIndirectList<Face>(surf.surfFaces(), zoneMap),
+            surf.points()
+        );
 
-            os << "kids 0" << endl;
-        }
+        writeZone(os, patch, zone.name(), zoneI);
     }
 }