diff --git a/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C b/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C
index 9d3fd373e0917265a66b1a52685d188db25b7f6b..f5166c6d70909aeb97846d6d0e34a3e8fdc6a5fc 100644
--- a/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C
+++ b/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2020 OpenCFD Ltd.
+    Copyright (C) 2020-2022 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -150,7 +150,7 @@ void Foam::surfaceWriters::abaqusWriter::writeGeometry
         << "** Points" << nl
         << "**" << nl;
 
-    fileFormats::ABAQUSCore::writePoints(os, points, geometryScale_);
+    fileFormats::ABAQUSCore::writePoints(os, points);
 
 
     // Write faces, with on-the-fly decomposition (triangulation)
@@ -237,7 +237,6 @@ void Foam::surfaceWriters::abaqusWriter::writeGeometry
 Foam::surfaceWriters::abaqusWriter::abaqusWriter()
 :
     surfaceWriter(),
-    geometryScale_(1),
     noGeometry_(false),
     outputLayout_(outputLayoutType::BY_FIELD)
 {}
@@ -249,7 +248,6 @@ Foam::surfaceWriters::abaqusWriter::abaqusWriter
 )
 :
     surfaceWriter(options),
-    geometryScale_(options.getOrDefault<scalar>("scale", 1)),
     noGeometry_(options.getOrDefault("noGeometry", false)),
     outputLayout_(outputLayoutType::BY_FIELD)
 {}
@@ -328,7 +326,8 @@ Foam::fileName Foam::surfaceWriters::abaqusWriter::write()
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H b/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H
index 24bdf22eda7008fffba1510ecdd2072df749eb76..cb406661ba66fb87d8e569ef85868659ba32b186 100644
--- a/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H
+++ b/src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H
@@ -31,11 +31,12 @@ Description
 
     The formatOptions for abaqus:
     \table
-        Property   | Description                            | Required | Default
-        scale      | output geometry scaling                | no  | 1
+        Property    | Description                           | Reqd | Default
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
-        noGeometry | Suppress geometry output (beta feature) | no  | false
+        noGeometry  | Suppress geometry output (beta feature) | no  | false
     \endtable
 
     For example,
@@ -112,9 +113,6 @@ class abaqusWriter
 {
     // Private Data
 
-        //- Output geometry scaling
-        const scalar geometryScale_;
-
         //- BETA feature
         bool noGeometry_;
 
diff --git a/src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C b/src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C
index 1ca932b147e7fcc0972567388b85eb35fbf60780..df06f13694628863222ca49e064a0248ec1cbf88 100644
--- a/src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C
+++ b/src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C
@@ -126,7 +126,8 @@ Foam::fileName Foam::surfaceWriters::abaqusWriter::writeTemplate
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.C b/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.C
index fde30e2ebcc6a15e96ffa84279b74949d0d9d4a7..982d34e22b1a5d1a621512008d6eb06eee18d819 100644
--- a/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.C
+++ b/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.C
@@ -169,7 +169,8 @@ Foam::fileName Foam::surfaceWriters::boundaryDataWriter::write()
     // Dummy Time to use as objectRegistry
     autoPtr<Time> dummyTimePtr(Time::New(argList::envGlobalPath()));
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -230,7 +231,8 @@ Foam::fileName Foam::surfaceWriters::boundaryDataWriter::writeTemplate
     // Dummy Time to use as objectRegistry
     autoPtr<Time> dummyTimePtr(Time::New(argList::envGlobalPath()));
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.H b/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.H
index e20392402b95612d9a428f8f7dc80ee5e1ec6395..0f51032337b5de47649b2285cdf2ab05aef2bab9 100644
--- a/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.H
+++ b/src/surfMesh/writers/boundary/boundaryDataSurfaceWriter.H
@@ -49,6 +49,8 @@ Description
         header      | Generate files with FoamFile header   | no  | true
         format      | ascii/binary                          | no  | ascii
         compression | Use file compression                  | no  | false
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
diff --git a/src/surfMesh/writers/common/surfaceWriter.C b/src/surfMesh/writers/common/surfaceWriter.C
index 382e9d0fd9b50158359fbad521ee2c9f55d04082..402a70ad0835aba09c41507b39f91cd7dac07ac3 100644
--- a/src/surfMesh/writers/common/surfaceWriter.C
+++ b/src/surfMesh/writers/common/surfaceWriter.C
@@ -31,6 +31,8 @@ License
 
 #include "Time.H"
 #include "globalIndex.H"
+#include "coordinateRotation.H"
+#include "transformField.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -44,8 +46,6 @@ namespace Foam
 
 Foam::scalar Foam::surfaceWriter::defaultMergeDim = 1e-8;
 
-const Foam::meshedSurf::emptySurface Foam::surfaceWriter::emptySurface_;
-
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
@@ -139,9 +139,12 @@ Foam::surfaceWriter::New
 
 Foam::surfaceWriter::surfaceWriter()
 :
-    surf_(std::cref<meshedSurf>(emptySurface_)),
-    surfComp_(),
-    useComponents_(false),
+    surf_(),
+    mergedSurf_(),
+    adjustedSurf_(),
+    mergeDim_(defaultMergeDim),
+    geometryScale_(1),
+    geometryTransform_(),
     upToDate_(false),
     wroteGeom_(false),
     parallel_(true),
@@ -149,8 +152,6 @@ Foam::surfaceWriter::surfaceWriter()
     isPointData_(false),
     verbose_(false),
     nFields_(0),
-    mergeDim_(defaultMergeDim),
-    merged_(),
     currTime_(),
     outputPath_(),
     fieldLevel_(),
@@ -165,6 +166,20 @@ Foam::surfaceWriter::surfaceWriter(const dictionary& options)
     surfaceWriter()
 {
     options.readIfPresent("verbose", verbose_);
+
+    geometryScale_ = 1;
+    geometryTransform_.clear();
+
+    options.readIfPresent("scale", geometryScale_);
+
+    const dictionary* dictptr;
+
+    // Optional cartesian coordinate system transform
+    if ((dictptr = options.findDict("transform", keyType::LITERAL))!= nullptr)
+    {
+        geometryTransform_ = coordSystem::cartesian(*dictptr);
+    }
+
     fieldLevel_ = options.subOrEmptyDict("fieldLevel");
     fieldScale_ = options.subOrEmptyDict("fieldScale");
 }
@@ -294,9 +309,7 @@ void Foam::surfaceWriter::clear()
 {
     close();
     expire();
-    useComponents_ = false;
-    surf_ = std::cref<meshedSurf>(emptySurface_);
-    surfComp_.clear();
+    surf_.clear();
 }
 
 
@@ -307,9 +320,7 @@ void Foam::surfaceWriter::setSurface
 )
 {
     expire();
-    useComponents_ = false;
-    surf_ = std::cref<meshedSurf>(surf);
-    surfComp_.clear();
+    surf_.reset(surf);
     parallel_ = (parallel && Pstream::parRun());
 }
 
@@ -322,9 +333,7 @@ void Foam::surfaceWriter::setSurface
 )
 {
     expire();
-    useComponents_ = true;
-    surf_ = std::cref<meshedSurf>(emptySurface_);
-    surfComp_.reset(points, faces);
+    surf_.reset(points, faces);
     parallel_ = (parallel && Pstream::parRun());
 }
 
@@ -366,7 +375,8 @@ bool Foam::surfaceWriter::expire()
 
     upToDate_ = false;
     wroteGeom_ = false;
-    merged_.clear();
+    adjustedSurf_.clear();
+    mergedSurf_.clear();
 
     // Field count (nFields_) is a different type of accounting
     // and is unaffected by geometry changes
@@ -377,18 +387,13 @@ bool Foam::surfaceWriter::expire()
 
 bool Foam::surfaceWriter::hasSurface() const
 {
-    return (useComponents_ || (&emptySurface_ != &(surf_.get())));
+    return surf_.valid();
 }
 
 
 bool Foam::surfaceWriter::empty() const
 {
-    const bool value =
-    (
-        useComponents_
-      ? surfComp_.faces().empty()
-      : surf_.get().faces().empty()
-    );
+    const bool value = surf_.faces().empty();
 
     return (parallel_ ? returnReduce(value, andOp<bool>()) : value);
 }
@@ -396,12 +401,7 @@ bool Foam::surfaceWriter::empty() const
 
 Foam::label Foam::surfaceWriter::size() const
 {
-    const label value =
-    (
-        useComponents_
-      ? surfComp_.faces().size()
-      : surf_.get().faces().size()
-    );
+    const label value = surf_.faces().size();
 
     return (parallel_ ? returnReduce(value, sumOp<label>()) : value);
 }
@@ -422,17 +422,20 @@ bool Foam::surfaceWriter::merge() const
 {
     bool changed = false;
 
-    if (parallel_ && Pstream::parRun() && !upToDate_)
+    if (!upToDate_)
     {
-        if (useComponents_)
+        adjustedSurf_.clear();
+
+        if (parallel_ && Pstream::parRun())
         {
-            changed = merged_.merge(surfComp_, mergeDim_);
+            changed = mergedSurf_.merge(surf_, mergeDim_);
         }
         else
         {
-            changed = merged_.merge(surf_.get(), mergeDim_);
+            mergedSurf_.clear();
         }
     }
+
     upToDate_ = true;
 
     if (changed)
@@ -450,17 +453,45 @@ const Foam::meshedSurf& Foam::surfaceWriter::surface() const
 
     if (parallel_ && Pstream::parRun())
     {
-        return merged_;
+        return mergedSurf_;
     }
 
-    if (useComponents_)
+    return surf_;
+}
+
+
+const Foam::meshedSurfRef& Foam::surfaceWriter::adjustSurface() const
+{
+    if (!upToDate_)
     {
-        return surfComp_;
+        adjustedSurf_.clear();
     }
-    else
+
+    if (!adjustedSurf_.valid())
     {
-        return surf_.get();
+        adjustedSurf_.reset(surface());
+
+        if
+        (
+            geometryTransform_.valid()
+         &&
+            (
+                (magSqr(geometryTransform_.origin()) > ROOTVSMALL)
+             || !geometryTransform_.R().is_identity()
+            )
+        )
+        {
+            // Forward transform
+            adjustedSurf_.movePoints
+            (
+                geometryTransform_.globalPosition(adjustedSurf_.points0())
+            );
+        }
+
+        adjustedSurf_.scalePoints(geometryScale_);
     }
+
+    return adjustedSurf_;
 }
 
 
@@ -488,11 +519,11 @@ Foam::tmp<Foam::Field<Type>> Foam::surfaceWriter::mergeFieldTemplate
         (
             Pstream::master()
          && this->isPointData()
-         && merged_.pointsMap().size()
+         && mergedSurf_.pointsMap().size()
         )
         {
-            inplaceReorder(merged_.pointsMap(), allFld);
-            allFld.resize(merged_.points().size());
+            inplaceReorder(mergedSurf_.pointsMap(), allFld);
+            allFld.resize(mergedSurf_.points().size());
         }
 
         return tfield;
@@ -577,6 +608,28 @@ Foam::tmp<Foam::Field<Type>> Foam::surfaceWriter::adjustFieldTemplate
             // Apply scaling
             tadjusted.ref() *= value;
         }
+
+        // Rotate fields (vector and non-spherical tensors)
+        if
+        (
+            (pTraits<Type>::rank != 0 && pTraits<Type>::nComponents > 1)
+         && geometryTransform_.valid()
+         && !geometryTransform_.R().is_identity()
+        )
+        {
+            if (!tadjusted)
+            {
+                // Steal or clone
+                tadjusted.reset(tfield.ptr());
+            }
+
+            Foam::transform
+            (
+                tadjusted.ref(),
+                geometryTransform_.R(),
+                tadjusted()
+            );
+        }
     }
 
     return (tadjusted ? tadjusted : tfield);
diff --git a/src/surfMesh/writers/common/surfaceWriter.H b/src/surfMesh/writers/common/surfaceWriter.H
index bb9817e2d2db378c456efbbb14121a8aa94b881c..f867b34a8929e4e15781e453e320886378e685ea 100644
--- a/src/surfMesh/writers/common/surfaceWriter.H
+++ b/src/surfMesh/writers/common/surfaceWriter.H
@@ -57,16 +57,28 @@ Description
             {
                 "p.*"   0.01;   // [Pa] -> [mbar]
             }
+
+            scale   1000;  // [m] -> [mm]
+            transform
+            {
+                origin  (0 0 0);
+                rotation axisAngle;
+                axis    (1 0 0);
+                angle   45;
+            }
+
         }
     }
     \endverbatim
 
   Format options:
     \table
-        Property | Description                              | Required | Default
-        verbose  | Additional output verbosity              | no  | no
-        fieldLevel | Subtract field level before scaling    | no  | empty dict
-        fieldScale | Output field scaling                   | no  | empty dict
+        Property    | Description                           | Reqd | Default
+        verbose     | Additional output verbosity           | no  | no
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
+        fieldLevel  | Subtract field level before scaling   | no  | empty dict
+        fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
 
 Note
@@ -83,10 +95,10 @@ SourceFiles
 #ifndef Foam_surfaceWriter_H
 #define Foam_surfaceWriter_H
 
-#include <functional>
 #include "typeInfo.H"
 #include "autoPtr.H"
 #include "tmp.H"
+#include "cartesianCS.H"
 #include "Field.H"
 #include "fileName.H"
 #include "instant.H"
@@ -118,22 +130,30 @@ class surfaceWriter
 {
 protected:
 
-   // Static Data Members
+    // Private Data
 
-        //- Placeholder
-        static const meshedSurf::emptySurface emptySurface_;
+        //- Reference to surface or surface components
+        meshedSurfRef surf_;
 
+        //- Surface after merging (parallel)
+        mutable mergedSurf mergedSurf_;
 
-    // Protected Data
+        //- The surface after point coordinate transforms and scaling
+        mutable meshedSurfRef adjustedSurf_;
+
+        //- Dimension for merging
+        scalar mergeDim_;
+
+        //- Output geometry scaling after rotate/translate
+        scalar geometryScale_;
+
+        //- Local coordinate system transformation
+        coordSystem::cartesian geometryTransform_;
 
-        //- Reference to a surface
-        std::reference_wrapper<const meshedSurf> surf_;
 
-        //- Reference to raw surface components
-        meshedSurfRef surfComp_;
+protected:
 
-        //- Use raw surface components instead of surface reference
-        bool useComponents_;
+    // Protected Data
 
         //- The topology/surface is up-to-date?
         mutable bool upToDate_;
@@ -156,12 +176,6 @@ protected:
         //- The number of fields
         label nFields_;
 
-        //- Dimension for merging
-        scalar mergeDim_;
-
-        //- Merging information and the resulting merged surface (parallel)
-        mutable mergedSurf merged_;
-
         //- The current time value/name
         instant currTime_;
 
@@ -184,10 +198,14 @@ protected:
         //- or simply mark the surface as being up-to-date
         virtual bool merge() const;
 
-        //- Merge surfaces (if not upToDate) and return merged or
-        //- the regular surface
+        //- Merge surfaces (if not upToDate) and return merged (parallel)
+        //- or regular surface (non-parallel)
         const meshedSurf& surface() const;
 
+        //- Merge surfaces (if not upToDate) and return merged (parallel)
+        //- or regular surface (non-parallel)
+        //- and apply any coordinate system changes and/or output scaling.
+        const meshedSurfRef& adjustSurface() const;
 
         //- Gather (merge) fields with renumbering and shrinking for point data
         template<class Type>
@@ -433,6 +451,16 @@ public:
         //  \return old value
         inline scalar mergeDim(const scalar dist) noexcept;
 
+        //- The current value of the geometry scaling
+        inline scalar scale() const noexcept;
+
+        //- Change the geometry scaling
+        //  \return old value
+        inline scalar scale(const scalar factor) noexcept;
+
+        //- The current (cartesian) coordinate system transformation
+        inline const coordSystem::cartesian& transform() const noexcept;
+
 
     // Time
 
diff --git a/src/surfMesh/writers/common/surfaceWriterI.H b/src/surfMesh/writers/common/surfaceWriterI.H
index bded94061f03db7c245042d8bc71de1b2f577d34..b6d2ca3f9671d75eb343f7c801ba84e4c00f49ab 100644
--- a/src/surfMesh/writers/common/surfaceWriterI.H
+++ b/src/surfMesh/writers/common/surfaceWriterI.H
@@ -103,6 +103,28 @@ inline Foam::scalar Foam::surfaceWriter::mergeDim(const scalar dist) noexcept
 }
 
 
+inline Foam::scalar Foam::surfaceWriter::scale() const noexcept
+{
+    return geometryScale_;
+}
+
+
+inline Foam::scalar Foam::surfaceWriter::scale(const scalar factor) noexcept
+{
+    // This is probably not yet needed -> adjustedSurf_.clear();
+    scalar old(geometryScale_);
+    geometryScale_ = factor;
+    return old;
+}
+
+
+inline const Foam::coordSystem::cartesian&
+Foam::surfaceWriter::transform() const noexcept
+{
+    return geometryTransform_;
+}
+
+
 inline bool Foam::surfaceWriter::hasTime() const
 {
     return currTime_.name().size();
diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriter.H b/src/surfMesh/writers/ensight/ensightSurfaceWriter.H
index c4cb698133f5c4a951d2a9ad5655ccac14c35138..e7f3a3b8f7bc9e16349202cbf16d2b7e39a025a0 100644
--- a/src/surfMesh/writers/ensight/ensightSurfaceWriter.H
+++ b/src/surfMesh/writers/ensight/ensightSurfaceWriter.H
@@ -45,7 +45,9 @@ Description
     \table
         Property | Description                              | Required | Default
         format   | ascii/binary                             | no  | ascii
-        collateTimes | use common geometry for times        | no  | true
+        collateTimes | Use common geometry for times        | no  | true
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C b/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C
index 179cfbdb8e09171468ae6000a69c83cd6ac97dc2..511df9159a8106f7ef124139fa4bd5a4c6b6ddef 100644
--- a/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C
+++ b/src/surfMesh/writers/ensight/ensightSurfaceWriterCollated.C
@@ -94,7 +94,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
         Info<< endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C b/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C
index 6519f49205c69b9127bdf8d3646de15ddc562f0e..fde360edc0c1ccc465464547c6d62df689cedac4 100644
--- a/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C
+++ b/src/surfMesh/writers/ensight/ensightSurfaceWriterUncollated.C
@@ -59,7 +59,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated()
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -159,7 +160,8 @@ Foam::fileName Foam::surfaceWriters::ensightWriter::writeUncollated
         Info<< endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/foam/foamSurfaceWriter.C b/src/surfMesh/writers/foam/foamSurfaceWriter.C
index 0006c67eb85643c960ef22b726c59a755c2fe161..4dcf5dadc5d8fa80dc2e7b8eb7e23f0b2d3f175c 100644
--- a/src/surfMesh/writers/foam/foamSurfaceWriter.C
+++ b/src/surfMesh/writers/foam/foamSurfaceWriter.C
@@ -119,7 +119,8 @@ Foam::fileName Foam::surfaceWriters::foamWriter::write()
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/foam/foamSurfaceWriter.H b/src/surfMesh/writers/foam/foamSurfaceWriter.H
index 8b18757eff98e56e4029657a8c272528ab38efd1..67b01f906054042cc404e0961706d6089b5c3ae2 100644
--- a/src/surfMesh/writers/foam/foamSurfaceWriter.H
+++ b/src/surfMesh/writers/foam/foamSurfaceWriter.H
@@ -53,7 +53,9 @@ Description
     \table
         Property | Description                              | Required | Default
         format   | ascii/binary                             | no  | ascii
-        compression | output file compression               | no  | false
+        compression | Use file compression                  | no  | false
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
index dac8cfb2a7f5118d4af2c7960e77eef0b03ab20d..b1b2c7be5744598dfac6e2ce1c6acb2609f25080 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.C
@@ -196,7 +196,7 @@ void Foam::surfaceWriters::nastranWriter::writeGeometry
 
     forAll(points, pointi)
     {
-        writeCoord(os, points[pointi]*geometryScale_, pointi);
+        writeCoord(os, points[pointi], pointi);
     }
 
     // Write faces, with on-the-fly decomposition (triangulation)
@@ -310,7 +310,6 @@ Foam::surfaceWriters::nastranWriter::nastranWriter()
     writeFormat_(fieldFormat::SHORT),
     fieldMap_(),
     commonGeometry_(false),
-    geometryScale_(1),
     separator_()
 {
     // if (writeFormat_ == fieldFormat::FREE)
@@ -337,7 +336,6 @@ Foam::surfaceWriters::nastranWriter::nastranWriter
     ),
     fieldMap_(),
     commonGeometry_(options.getOrDefault("commonGeometry", false)),
-    geometryScale_(options.getOrDefault<scalar>("scale", 1)),
     separator_()
 {
     if (writeFormat_ == fieldFormat::FREE)
@@ -411,7 +409,8 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::write()
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
index d6661ad5e06124bb911eff76c26644680736163c..15d51da629f12758d0ecc7712ad7d237aae780a2 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriter.H
@@ -32,13 +32,14 @@ Description
 
     The formatOptions for nastran:
     \table
-        Property | Description                              | Required | Default
-        fields   | field pairs for PLOAD2/PLOAD4            | yes   |
-        format   | short / long / free                      | no    | long
-        scale    | output geometry scaling                  | no    | 1
+        Property    | Description                           | Reqd | Default
+        fields      | Field pairs for PLOAD2/PLOAD4         | yes |
+        format      | Nastran format (short/long/free)      | no  | long
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
-        commonGeometry | use separate geometry files        | no    | false
+        commonGeometry | use separate geometry files        | no  | false
     \endtable
 
     For example,
@@ -144,9 +145,6 @@ private:
         //- Use common geometry file
         bool commonGeometry_;
 
-        //- Output geometry scaling
-        const scalar geometryScale_;
-
         //- Separator (used for free format)
         word separator_;
 
diff --git a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
index 1653bdbcfd310b218fa711d424213deea897fd41..54c0c09e7e09b41656da97341c073a6aa9944bf6 100644
--- a/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
+++ b/src/surfMesh/writers/nastran/nastranSurfaceWriterImpl.C
@@ -232,7 +232,8 @@ Foam::fileName Foam::surfaceWriters::nastranWriter::writeTemplate
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/proxy/proxySurfaceWriter.C b/src/surfMesh/writers/proxy/proxySurfaceWriter.C
index fab764096544ff30dc9e2d89dd42b567cf97cc94..5d47ca9a3bfd093eeb7332fbf716f9080cf002a8 100644
--- a/src/surfMesh/writers/proxy/proxySurfaceWriter.C
+++ b/src/surfMesh/writers/proxy/proxySurfaceWriter.C
@@ -125,7 +125,8 @@ Foam::fileName Foam::surfaceWriters::proxyWriter::write()
         Info<< "Writing geometry to " << outputFile << endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/proxy/proxySurfaceWriter.H b/src/surfMesh/writers/proxy/proxySurfaceWriter.H
index 830365667e0778c4139d4f2178b385309a0d9e2b..5e395ef15937d91beac88ab5902422e864d6acb2 100644
--- a/src/surfMesh/writers/proxy/proxySurfaceWriter.H
+++ b/src/surfMesh/writers/proxy/proxySurfaceWriter.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2015-2020 OpenCFD Ltd.
+    Copyright (C) 2015-2022 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -51,7 +51,9 @@ Note
     \table
         Property | Description                              | Required | Default
         format   | ascii/binary                             | no  | ascii
-        compression | File compression                      | no  | false
+        compression | Use file compression                  | no  | false
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
     \endtable
 
 SourceFiles
diff --git a/src/surfMesh/writers/raw/rawSurfaceWriter.C b/src/surfMesh/writers/raw/rawSurfaceWriter.C
index 1d2233001694a192c450679c604eca6f1253b556..192376c20851bd661dffc07e4ac6f775c7e0d1ab 100644
--- a/src/surfMesh/writers/raw/rawSurfaceWriter.C
+++ b/src/surfMesh/writers/raw/rawSurfaceWriter.C
@@ -61,8 +61,7 @@ Foam::surfaceWriters::rawWriter::rawWriter()
     surfaceWriter(),
     streamOpt_(),
     precision_(IOstream::defaultPrecision()),
-    writeNormal_(false),
-    geometryScale_(1)
+    writeNormal_(false)
 {}
 
 
@@ -81,8 +80,7 @@ Foam::surfaceWriters::rawWriter::rawWriter
     (
         options.getOrDefault("precision", IOstream::defaultPrecision())
     ),
-    writeNormal_(options.getOrDefault("normal", false)),
-    geometryScale_(options.getOrDefault<scalar>("scale", 1))
+    writeNormal_(options.getOrDefault("normal", false))
 {}
 
 
@@ -137,7 +135,8 @@ Foam::fileName Foam::surfaceWriters::rawWriter::write()
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -167,11 +166,11 @@ Foam::fileName Foam::surfaceWriters::rawWriter::write()
         // Write faces centres (optionally faceArea normals)
         for (const face& f : faces)
         {
-            writePoint(os, f.centre(points)*geometryScale_);
+            writePoint(os, f.centre(points));
             if (withFaceNormal)
             {
                 os << ' ';
-                writePoint(os, f.areaNormal(points)*geometryScale_);
+                writePoint(os, f.areaNormal(points));
             }
             os << nl;
         }
diff --git a/src/surfMesh/writers/raw/rawSurfaceWriter.H b/src/surfMesh/writers/raw/rawSurfaceWriter.H
index 60855dba70b697291ca82ef744ff0c2ef5b6e8b2..2601a8fcd2615f43e6b748af6976a78fddf4028d 100644
--- a/src/surfMesh/writers/raw/rawSurfaceWriter.H
+++ b/src/surfMesh/writers/raw/rawSurfaceWriter.H
@@ -34,8 +34,9 @@ Description
     \table
         Property    | Description                           | Required | Default
         compression | Use file compression                  | no  | false
-        precision   | Write precision in ascii              | no  | same as IOstream
+        precision   | Write precision in ascii          | no  | same as IOstream
         scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
         normal      | Write face area normal in output      | no  | false
@@ -116,9 +117,6 @@ class rawWriter
         //- Output face area normal
         const bool writeNormal_;
 
-        //- Output geometry scaling
-        const scalar geometryScale_;
-
 
     // Private Member Functions
 
diff --git a/src/surfMesh/writers/raw/rawSurfaceWriterImpl.C b/src/surfMesh/writers/raw/rawSurfaceWriterImpl.C
index fec67c262f5845537cbf8439538cc465c3974681..5109b8f9ea7b88bafedbc4bdbb1cd8dd1ab55539 100644
--- a/src/surfMesh/writers/raw/rawSurfaceWriterImpl.C
+++ b/src/surfMesh/writers/raw/rawSurfaceWriterImpl.C
@@ -114,7 +114,8 @@ Foam::fileName Foam::surfaceWriters::rawWriter::writeTemplate
         Info<< " to " << outputFile << endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -159,7 +160,7 @@ Foam::fileName Foam::surfaceWriters::rawWriter::writeTemplate
             // Node values
             forAll(values, elemi)
             {
-                writePoint(os, points[elemi]*geometryScale_);
+                writePoint(os, points[elemi]);
                 writeData(os, values[elemi]);
                 os << nl;
             }
@@ -171,12 +172,12 @@ Foam::fileName Foam::surfaceWriters::rawWriter::writeTemplate
             {
                 const face& f = faces[elemi];
 
-                writePoint(os, f.centre(points)*geometryScale_);
+                writePoint(os, f.centre(points));
                 writeData(os,  values[elemi]);
                 if (withFaceNormal)
                 {
                     os << ' ';
-                    writePoint(os, f.areaNormal(points)*geometryScale_);
+                    writePoint(os, f.areaNormal(points));
                 }
                 os << nl;
             }
diff --git a/src/surfMesh/writers/starcd/starcdSurfaceWriter.C b/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
index 4817d1f4f1d69d0d6b4667b990c7746033b66c4d..1cdeb8ac09f31ad4b09a08657d6e9a8924fa2004 100644
--- a/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
+++ b/src/surfMesh/writers/starcd/starcdSurfaceWriter.C
@@ -137,7 +137,8 @@ Foam::fileName Foam::surfaceWriters::starcdWriter::write()
         Info<< "Writing geometry to " << outputFile << endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -215,7 +216,8 @@ Foam::fileName Foam::surfaceWriters::starcdWriter::writeTemplate
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/starcd/starcdSurfaceWriter.H b/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
index 9ef62cfb8d729e2106419e485ae6d82470be71eb..c1740129258cb835f5cba36b5c8fff6fdaea31a7 100644
--- a/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
+++ b/src/surfMesh/writers/starcd/starcdSurfaceWriter.H
@@ -34,6 +34,8 @@ Description
     \table
         Property    | Description                           | Required | Default
         compression | Use file compression                  | no  | false
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
diff --git a/src/surfMesh/writers/vtk/vtkSurfaceWriter.C b/src/surfMesh/writers/vtk/vtkSurfaceWriter.C
index 862a616967bae1bf4ae9b69856d0769e8983c44d..7b6448e3b1c5f6cd6e1c04f30a7c284ada2e22c7 100644
--- a/src/surfMesh/writers/vtk/vtkSurfaceWriter.C
+++ b/src/surfMesh/writers/vtk/vtkSurfaceWriter.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019-2021 OpenCFD Ltd.
+    Copyright (C) 2019-2022 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -212,7 +212,8 @@ Foam::fileName Foam::surfaceWriters::vtkWriter::write()
         Info<< "Writing geometry to " << outputFile << endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (!writer_ && (Pstream::master() || !parallel_))
     {
diff --git a/src/surfMesh/writers/vtk/vtkSurfaceWriter.H b/src/surfMesh/writers/vtk/vtkSurfaceWriter.H
index 6635b945c3323037f9f23f428467a265df07f6ef..ef17661fceb9fe929c97e5449b93b31a146c2257 100644
--- a/src/surfMesh/writers/vtk/vtkSurfaceWriter.H
+++ b/src/surfMesh/writers/vtk/vtkSurfaceWriter.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2015-2021 OpenCFD Ltd.
+    Copyright (C) 2015-2022 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,6 +36,8 @@ Description
         format      | ascii or binary format                | no  | binary
         legacy      | Legacy VTK output                     | no  | false
         precision   | Write precision in ascii         | no | same as IOstream
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
         normal      | Write face area-normal in output      | no  | false
diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
index 25b657f8a0e848fb4bb04453d9fe7e76cad3d850..85aaf31321b08754987a5649ca7df7fd7875b860 100644
--- a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
+++ b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
@@ -214,7 +214,8 @@ Foam::fileName Foam::surfaceWriters::x3dWriter::write()
         Info<< "Writing geometry to " << outputFile << endl;
     }
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
@@ -278,7 +279,8 @@ Foam::fileName Foam::surfaceWriters::x3dWriter::writeTemplate
     }
 
 
-    const meshedSurf& surf = surface();
+    // const meshedSurf& surf = surface();
+    const meshedSurfRef& surf = adjustSurface();
 
     if (Pstream::master() || !parallel_)
     {
diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.H b/src/surfMesh/writers/x3d/x3dSurfaceWriter.H
index 619471e3353d5cb2abadc7022966d2a3e4b42182..1295194adb644bbe16167b6f3ceb2fbd926da06e 100644
--- a/src/surfMesh/writers/x3d/x3dSurfaceWriter.H
+++ b/src/surfMesh/writers/x3d/x3dSurfaceWriter.H
@@ -32,9 +32,11 @@ Description
     The formatOptions for x3d:
     \table
         Property    | Description                           | Required | Default
-        compression | Use file compression                  | no  | false
         range       | The min/max range for colour table    | no  | automatic
         colourMap   | The colour map for rendering          | no  | coolToWarm
+        compression | Use file compression                  | no  | false
+        scale       | Output geometry scaling               | no  | 1
+        transform   | Output coordinate transform           | no  |
         fieldLevel  | Subtract field level before scaling   | no  | empty dict
         fieldScale  | Output field scaling                  | no  | empty dict
     \endtable
diff --git a/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/implicit/system/sampling b/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/implicit/system/sampling
index bc310e247628f69e6f1de31a44a32680f656e634..f269fc05144196e842c2fbc342bd7f42f8e2d44b 100644
--- a/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/implicit/system/sampling
+++ b/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/implicit/system/sampling
@@ -92,9 +92,9 @@ plane
     libs    (sampling);
 
     writeControl    writeTime;
+    fields          ( cellZoneID U );
 
     surfaceFormat   vtk;
-    fields          ( cellZoneID U );
 
     surfaces
     {
@@ -104,6 +104,25 @@ plane
             point       (0 0 0);
             normal      (0 0 1);
             interpolate false;
+
+            surfaceFormat   ensight;
+
+            formatOptions
+            {
+                ensight
+                {
+                    scale 2;  // Some arbitrary scaling
+
+                    // Align with global x-axis, translate by arbitrary amount
+                    transform
+                    {
+                        origin  (0.05 -0.05 0);
+                        rotation axisAngle;
+                        axis    (0 0 1);
+                        angle   -45;
+                    }
+                }
+            }
         }
 
         slices
@@ -122,6 +141,23 @@ plane
                 axis    (0 0 1);
                 angle   45;
             }
+
+            formatOptions
+            {
+                vtk
+                {
+                    scale 2;  // Some arbitrary scaling
+
+                    // Align with global x-axis, translate by arbitrary amount
+                    transform
+                    {
+                        origin  (0.05 0 0);
+                        rotation axisAngle;
+                        axis    (0 0 1);
+                        angle   -45;
+                    }
+                }
+            }
         }
     }
 }