diff --git a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C
index 39d3b99b8cb83cdfc120107bea409af2f0c89791..29957a0ceb94440ddb176f45f958e2058ae309cb 100644
--- a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C
+++ b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C
@@ -134,7 +134,7 @@ Foam::point Foam::BSpline::position
 Foam::scalar Foam::BSpline::length() const
 {
     NotImplemented;
-    return 1.0;
+    return 1;
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.H b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.H
index e9da49bcdc57b3c924c241de835186f097b187ab..00f77df5b0bdab360cfb5acaa15f5ef1a676d1a3 100644
--- a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.H
+++ b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -77,21 +78,12 @@ class BSpline
 :
     public polyLine
 {
-    // Private Member Functions
-
-        //- No copy construct
-        BSpline(const BSpline&) = delete;
-
-        //- No copy assignment
-        void operator=(const BSpline&) = delete;
-
-
 public:
 
     // Constructors
 
         //- Construct from components
-        BSpline
+        explicit BSpline
         (
             const pointField& knots,
             const bool notImplementedClosed = false
@@ -100,15 +92,16 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the global curve parameter
         //  0 <= lambda <= 1
         point position(const scalar lambda) const;
 
-        //- Return the point position corresponding to the local parameter
-        //  0 <= lambda <= 1 on the given segment
+        //- The point position corresponding to the local lambda (0-1)
+        //- on the given segment
         point position(const label segment, const scalar lambda) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
+        //  \note NotImplemented
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.C b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.C
index 81c3ab24ee0ee7e6b8bfaa6083992985f775c7d1..af5e4d89ed8f763dc6b31a3c70ace092f2889019 100644
--- a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.C
+++ b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2014-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,9 +27,9 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "BSplineEdge.H"
+#include "polyLine.H"
 #include "addToRunTimeSelectionTable.H"
 
-
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
@@ -59,7 +59,10 @@ Foam::blockEdges::BSplineEdge::BSplineEdge
 )
 :
     blockEdge(points, start, end),
-    BSpline(appendEndPoints(points, start, end, internalPoints))
+    BSpline
+    (
+        polyLine::concat(points[start_], internalPoints, points[end_])
+    )
 {}
 
 
@@ -73,13 +76,16 @@ Foam::blockEdges::BSplineEdge::BSplineEdge
 )
 :
     blockEdge(dict, index, points, is),
-    BSpline(appendEndPoints(points, start_, end_, pointField(is)))
+    BSpline
+    (
+        polyLine::concat(points[start_], pointField(is), points[end_])
+    )
 {
-    token t(is);
-    is.putBack(t);
+    token tok(is);
+    is.putBack(tok);
 
-    // discard unused start/end tangents
-    if (t == token::BEGIN_LIST)
+    // Discard unused start/end tangents
+    if (tok == token::BEGIN_LIST)
     {
         vector tangent0Ignored(is);
         vector tangent1Ignored(is);
diff --git a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.H b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.H
index e04434c593a14cc9b5cbc51228632bf04abfab07..68eefdab87ec36b9c9cc18b7eea950a536c8edb0 100644
--- a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.H
+++ b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSplineEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2014-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -77,20 +77,20 @@ public:
         //- Construct from components
         BSplineEdge
         (
-            const pointField&,
-            const label start,
-            const label end,
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
             const pointField& internalPoints
         );
 
-        //- Construct from Istream, setting pointsList
+        //- Construct from Istream and point field.
         BSplineEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
-            Istream&
+            const pointField& points,   //!< Referenced point field
+            Istream& is
         );
 
 
@@ -100,11 +100,12 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         virtual point position(const scalar) const;
 
-        //- Return the length of the spline curve (not implemented)
+        //- The length of the spline curve
+        //  \note NotImplemented
         virtual scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
index 7c614b8829179c37ae90a868feb69267dd2581ea..698fec2a8db45418ebc3f7a8878b1e862728a21d 100644
--- a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
+++ b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -43,10 +44,15 @@ namespace blockEdges
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::coordSystem::cylindrical Foam::blockEdges::arcEdge::calcAngle()
+void Foam::blockEdges::arcEdge::calcFromMidPoint
+(
+    const point& p1,
+    const point& p3,
+    const point& p2
+)
 {
-    const vector a = p2_ - p1_;
-    const vector b = p3_ - p1_;
+    const vector a = p2 - p1;
+    const vector b = p3 - p1;
 
     // Find centre of arcEdge
     const scalar asqr = a & a;
@@ -55,7 +61,7 @@ Foam::coordSystem::cylindrical Foam::blockEdges::arcEdge::calcAngle()
 
     const scalar denom = asqr*bsqr - adotb*adotb;
 
-    if (mag(denom) < VSMALL)
+    if (mag(denom) < ROOTVSMALL)
     {
         FatalErrorInFunction
             << denom
@@ -64,63 +70,157 @@ Foam::coordSystem::cylindrical Foam::blockEdges::arcEdge::calcAngle()
 
     const scalar fact = 0.5*(bsqr - adotb)/denom;
 
-    point centre = 0.5*a + fact*((a ^ b) ^ a);
+    const point centre = p1 + 0.5*a + fact*((a ^ b) ^ a);
+
+    // Position vectors from centre
+    const vector r1(p1 - centre);
+    const vector r2(p2 - centre);
+    const vector r3(p3 - centre);
 
-    centre += p1_;
+    const scalar mag1(mag(r1));
+    const scalar mag3(mag(r3));
 
-    // Find position vectors w.r.t. the arcEdge centre
-    const vector r1(p1_ - centre);
-    const vector r2(p2_ - centre);
-    const vector r3(p3_ - centre);
+    vector arcAxis(r1 ^ r3);
+
+    // The radius from r1 and from r3 will be identical
+    radius_ = mag(r3);
 
-    // Find angle (in degrees)
-    angle_ = radToDeg(acos((r3 & r1)/(mag(r3) * mag(r1))));
+
+    // Determine the angle
+    angle_ = acos((r1 & r3)/(mag1*mag3));
 
     // Check if the vectors define an exterior or an interior arcEdge
     if (((r1 ^ r2) & (r1 ^ r3)) < 0.0)
     {
-        angle_ = 360.0 - angle_;
+        angle_ = constant::mathematical::twoPi - angle_;
     }
 
-    vector arcAxis;
-
-    if (angle_ <= 180.0)
+    if (angle_ <= constant::mathematical::pi)
     {
-        arcAxis = r1 ^ r3;
-
-        if (mag(arcAxis)/(mag(r1)*mag(r3)) < 0.001)
+        if (mag(arcAxis)/(mag1*mag3) < 0.001)
         {
             arcAxis = r1 ^ r2;
         }
     }
     else
     {
-        arcAxis = r3 ^ r1;
+        arcAxis = -arcAxis;
     }
 
-    radius_ = mag(r3);
+    // Corresponding local cylindrical coordinate system
+    cs_ = coordSystem::cylindrical(centre, arcAxis, r1);
+}
+
+
+void Foam::blockEdges::arcEdge::calcFromCentre
+(
+    const point& p1,
+    const point& p3,
+    const point& centre,
+    bool adjustCentre,
+    scalar rMultiplier
+)
+{
+    // Position vectors from centre
+    const vector r1(p1 - centre);
+    const vector r3(p3 - centre);
+
+    const scalar mag1(mag(r1));
+    const scalar mag3(mag(r3));
+
+    const vector chord(p3 - p1);
 
-    // The corresponding local cylindrical coordinate system (radians)
-    return coordSystem::cylindrical("arc", centre, arcAxis, r1);
+    const vector arcAxis(r1 ^ r3);
+
+    // The average radius
+    radius_ = 0.5*(mag1 + mag3);
+
+    // The included angle
+    angle_ = acos((r1 & r3)/(mag1*mag3));
+
+    // TODO? check for 180 degrees (co-linear points)?
+
+    bool needsAdjust = false;
+
+    if (adjustCentre)
+    {
+        needsAdjust = !equal(mag1, mag3);
+
+        if (!equal(rMultiplier, 1))
+        {
+            // The min radius is constrained by the chord,
+            // otherwise bad things will happen.
+
+            needsAdjust = true;
+            radius_ *= rMultiplier;
+            radius_ = max(radius_, (1.001*0.5*mag(chord)));
+        }
+    }
+
+    if (needsAdjust)
+    {
+        // The centre is not equidistant to p1 and p3.
+        // Use the chord and the arcAxis to determine the vector to
+        // the midpoint of the chord and adjust the centre along this
+        // line.
+
+        const point newCentre =
+        (
+            (0.5 * (p3 + p1))                   // mid-chord point
+          + sqrt(sqr(radius_) - 0.25 * magSqr(chord))
+          * normalised(arcAxis ^ chord)         // mid-chord -> centre
+        );
+
+        //// Info<< nl << "Adjust centre. r1=" << mag1 << " r3=" << mag3
+        ////     << " radius=" << radius_ << nl
+        ////     << "angle=" << radToDeg(angle_) << ' '
+        ////     << coordSystem::cylindrical(centre, arcAxis, r1) << nl;
+
+        // Recalculate - do attempt to readjust
+        calcFromCentre(p1, p3, newCentre, false);
+    }
+    else
+    {
+        // Corresponding local cylindrical coordinate system
+        cs_ = coordSystem::cylindrical(centre, arcAxis, r1);
+    }
 }
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
+Foam::blockEdges::arcEdge::arcEdge
+(
+    const pointField& points,
+    const point& origin,
+    const label start,
+    const label end
+)
+:
+    blockEdge(points, start, end),
+    radius_(0),
+    angle_(0),
+    cs_()
+{
+    calcFromCentre(points[start_], points[end_], origin);
+}
+
+
 Foam::blockEdges::arcEdge::arcEdge
 (
     const pointField& points,
     const label start,
     const label end,
-    const point& pMid
+    const point& midPoint
 )
 :
     blockEdge(points, start, end),
-    p1_(points_[start_]),
-    p2_(pMid),
-    p3_(points_[end_]),
-    cs_(calcAngle())
-{}
+    radius_(0),
+    angle_(0),
+    cs_()
+{
+    calcFromMidPoint(points[start_], points[end_], midPoint);
+}
 
 
 Foam::blockEdges::arcEdge::arcEdge
@@ -133,41 +233,82 @@ Foam::blockEdges::arcEdge::arcEdge
 )
 :
     blockEdge(dict, index, points, is),
-    p1_(points_[start_]),
-    p2_(is),
-    p3_(points_[end_]),
-    cs_(calcAngle())
-{}
+    radius_(0),
+    angle_(0),
+    cs_()
+{
+    point p;
+
+    token tok(is);
+    if (tok.isWord())
+    {
+        // Can be
+        //   - origin (0 0 0)
+        //   - origin 1.2 (0 0 0)
+
+        scalar rMultiplier = 1;
+
+        is >> tok;
+        if (tok.isNumber())
+        {
+            rMultiplier = tok.number();
+        }
+        else
+        {
+            is.putBack(tok);
+        }
+
+        is >> p;  // The origin (centre)
+
+        calcFromCentre(points_[start_], points_[end_], p, true, rMultiplier);
+    }
+    else
+    {
+        is.putBack(tok);
+
+        is >> p;  // A mid-point
+
+        calcFromMidPoint(points_[start_], points_[end_], p);
+    }
+
+    // Debug information
+    #if 0
+    Info<< "arc " << start_ << ' ' << end_
+        << ' ' << position(0.5) << ' ' << cs_
+        // << " radius=" << radius_ << " angle=" << radToDeg(angle_)
+        << nl;
+    #endif
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::point Foam::blockEdges::arcEdge::position(const scalar lambda) const
 {
+    #ifdef FULLDEBUG
     if (lambda < -SMALL || lambda > 1 + SMALL)
     {
-        FatalErrorInFunction
-            << "Parameter out of range, lambda = " << lambda
-            << abort(FatalError);
+        WarningInFunction
+            << "Parameter out of range, lambda = " << lambda << nl;
     }
+    #endif
 
     if (lambda < SMALL)
     {
-        return p1_;
+        return points_[start_];
     }
-    else if (lambda > 1 - SMALL)
+    else if (lambda >= 1 - SMALL)
     {
-        return p3_;
+        return points_[end_];
     }
 
-    // The angle is degrees, the coordinate system in radians
-    return cs_.globalPosition(vector(radius_, degToRad(lambda*angle_), 0));
+    return cs_.globalPosition(vector(radius_, (lambda*angle_), 0));
 }
 
 
-Foam::scalar Foam::blockEdges::arcEdge::length() const
+Foam::scalar Foam::blockEdges::arcEdge::length() const noexcept
 {
-    return degToRad(radius_*angle_);
+    return (radius_*angle_);
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
index 8db6fcaa97525a54d5faeb24c26bf7479f71e075..459b6a70f0d3f525c42ac06e8ec3d7b14b4f1d96 100644
--- a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
+++ b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017 OpenCFD Ltd.
+    Copyright (C) 2017-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,7 +28,32 @@ Class
     Foam::blockEdges::arcEdge
 
 Description
-    Defines the arcEdge of a circle in terms of 3 points on its circumference
+    A blockEdge defined as an arc of a circle.
+
+    The arc is normally defined by its endpoints and a point on
+    its circumference, typically a midpoint. For example,
+    \verbatim
+    points ((1 0 0) (0 1 0));
+
+    arc 0 1 (0.707107 0.707107 0);
+    \endverbatim
+    The arc can enclose an angle greater than 0 and less than 360 degrees.
+
+    The arc will frequently enclose an angle less than 180 degrees.
+    For the case, it is possible to define the arc by its endpoints and its
+    centre (origin) point. For example,
+    \verbatim
+    arc 0 1 origin (0 0 0);
+    \endverbatim
+    When defined in the way, any discrepancy in the arc radius for the
+    endpoints is resolved by adjusting the origin to ensure that the average
+    radius is satisfied.
+
+    It is also possible to define a \em flatness factor as a multiplier of
+    the calculated radius. For example,
+    \verbatim
+    arc 0 1 origin 1.1 (0 0 0);
+    \endverbatim
 
 SourceFiles
     arcEdge.C
@@ -56,26 +81,41 @@ class arcEdge
 :
     public blockEdge
 {
-    // Private data
-
-        // Begin, mid, end points
-        point p1_, p2_, p3_;
-
-        //- The arc angle (in degrees)
-        scalar angle_;
+    // Private Data
 
         //- The arc radius
         scalar radius_;
 
+        //- The arc angle (radians)
+        scalar angle_;
+
         //- The local cylindrical coordinate system
         coordSystem::cylindrical cs_;
 
 
     // Private Member Functions
 
-        //- Calculate the angle, radius and axis
-        //  \return the cylindrical coordinate system
-        coordSystem::cylindrical calcAngle();
+        //- Calculate angle, radius, cylindrical coordinate system
+        //- from end points and the given point on the circumference
+        void calcFromMidPoint
+        (
+            const point& p1,        //!< Start point
+            const point& p3,        //!< End point
+            const point& p2         //!< Point on circumference
+        );
+
+        //- Calculate angle, radius, cylindrical coordinate system
+        //- from end points and the given origin.
+        //  Optionally adjust centre to accommodate deviations in the
+        //  effective radius to the end-points
+        void calcFromCentre
+        (
+            const point& p1,        //!< Start point
+            const point& p3,        //!< End point
+            const point& centre,    //!< Centre
+            bool adjustCentre = false,  //!< Adjust centre
+            scalar rMultiplier = 1      //!< Adjust radius by this factor
+        );
 
         //- No copy construct
         arcEdge(const arcEdge&) = delete;
@@ -92,23 +132,34 @@ public:
 
     // Constructors
 
-        //- Construct from components
+        //- Construct from components, given the origin of the circle
+        arcEdge
+        (
+            const pointField& points,   //!< Referenced point field
+            const point& origin,    //!< The origin of the circle
+            const label start,      //!< Start point in referenced point field
+            const label end         //!< End point in referenced point field
+        );
+
+        //- Construct from components, using a point on the circumference
         arcEdge
         (
-            const pointField& points,
-            const label start,
-            const label end,
-            const point& pMid
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
+            const point& midPoint   //!< A point on the circumference
         );
 
-        //- Construct from Istream setting pointsList
+        //- Construct from Istream and point field.
+        //  The Istream can specify either a point on the circumference,
+        //  or with a tag to specify the origin.
         arcEdge
         (
             const dictionary& dict,
             const label index,
-            const searchableSurfaces& geometry,
-            const pointField& points,
-            Istream&
+            const searchableSurfaces& geometry, // unsed
+            const pointField& points,   //!< Referenced point field
+            Istream& is
         );
 
 
@@ -122,7 +173,7 @@ public:
         point position(const scalar lambda) const;
 
         //- The length of the curve
-        scalar length() const;
+        scalar length() const noexcept;
 };
 
 
diff --git a/src/mesh/blockMesh/blockEdges/bezier/bezier.C b/src/mesh/blockMesh/blockEdges/bezier/bezier.C
index b1b884d32a16118ae3f5b53e1c524edd1bcdd5e3..cac55d1ba3bfd3e246ae8b87dbc8238ebaa3a8e0 100644
--- a/src/mesh/blockMesh/blockEdges/bezier/bezier.C
+++ b/src/mesh/blockMesh/blockEdges/bezier/bezier.C
@@ -26,6 +26,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "bezier.H"
+#include "polyLine.H"
 #include "SubList.H"
 #include "addToRunTimeSelectionTable.H"
 
@@ -66,7 +67,10 @@ Foam::blockEdges::bezier::bezier
 )
 :
     blockEdge(dict, index, points, is),
-    control_(appendEndPoints(points, start_, end_, pointField(is)))
+    control_
+    (
+        polyLine::concat(points[start_], pointField(is), points[end_])
+    )
 {}
 
 
@@ -94,7 +98,7 @@ Foam::point Foam::blockEdges::bezier::position(const scalar lambda) const
 Foam::scalar Foam::blockEdges::bezier::length() const
 {
     NotImplemented;
-    return 1.0;
+    return 1;
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/bezier/bezier.H b/src/mesh/blockMesh/blockEdges/bezier/bezier.H
index b1f14dab2792783cb38f4525ffd91a778adb8d3a..5feaeb4139205511df37f97fe69f8db89a726bea 100644
--- a/src/mesh/blockMesh/blockEdges/bezier/bezier.H
+++ b/src/mesh/blockMesh/blockEdges/bezier/bezier.H
@@ -63,7 +63,7 @@ class bezier
 :
     public blockEdge
 {
-private:
+    // Private Data
 
         //- Control points
         pointField control_;
@@ -89,20 +89,20 @@ public:
         //- Construct from components
         bezier
         (
-            const pointField& points,
-            const label start,
-            const label end,
-            const pointField& control
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
+            const pointField& control   //!< The control points
         );
 
-        //- Construct from Istream
+        //- Construct from Istream and point field.
         bezier
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
-            Istream&
+            const pointField& points,   //!< Referenced point field
+            Istream& is
         );
 
 
@@ -117,6 +117,7 @@ public:
         point position(const scalar lambda) const;
 
         //- Return the length of the curve
+        //  \not NotImplemented
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.C b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.C
index 01621e08c8a4de5c612f9d0223b790a76d59b995..a49880b12123ee67531c0e05cf97890ef368e52c 100644
--- a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.C
+++ b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,6 +28,7 @@ License
 
 #include "blockEdge.H"
 #include "blockVertex.H"
+#include "polyLine.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -104,32 +105,22 @@ Foam::autoPtr<Foam::blockEdge> Foam::blockEdge::New
 }
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
 Foam::pointField Foam::blockEdge::appendEndPoints
 (
-    const pointField& points,
+    const pointField& pts,
     const label start,
     const label end,
-    const pointField& otherKnots
+    const pointField& intermediate
 )
 {
-    pointField allKnots(otherKnots.size() + 2);
-
-    // Start/end knots
-    allKnots[0] = points[start];
-    allKnots[otherKnots.size() + 1] = points[end];
-
-    // Intermediate knots
-    forAll(otherKnots, knotI)
-    {
-        allKnots[knotI+1] = otherKnots[knotI];
-    }
-
-    return allKnots;
+    return pointField(polyLine::concat(pts[start], intermediate, pts[end]));
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 Foam::tmp<Foam::pointField>
 Foam::blockEdge::position(const scalarList& lambdas) const
 {
diff --git a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.H b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.H
index 30d09f00f1b68efd7e4a3c17e17d84576031a97c..dd48cba834356d67b06031a48c65ce1c94f11f70 100644
--- a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.H
+++ b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,6 +24,12 @@ License
     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::blockEdges
+
+Description
+    A namespace for various blockEdge types.
+
 Class
     Foam::blockEdge
 
@@ -46,13 +52,10 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of friend functions and operators
-
+// Forward Declarations
 class blockEdge;
-
 Ostream& operator<<(Ostream&, const blockEdge&);
 
-
 /*---------------------------------------------------------------------------*\
                          Class blockEdge Declaration
 \*---------------------------------------------------------------------------*/
@@ -61,24 +64,29 @@ class blockEdge
 {
 protected:
 
-    // Protected data
+    // Protected Data
 
+        //- The referenced point field
         const pointField& points_;
 
+        //- Index of the start point
         const label start_;
+
+        //- Index of the end point
         const label end_;
 
 
     // Protected Member Functions
 
         //- Return a complete point field by appending the start/end points
-        //  to the given list
+        //- to the given list
+        //  \deprecated(2020-10) use polyLine::concat
         static pointField appendEndPoints
         (
-            const pointField&,
-            const label start,
-            const label end,
-            const pointField& otherKnots
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
+            const pointField& intermediate  //!< Intermediate points (knots)
         );
 
 
@@ -110,18 +118,18 @@ public:
         //- Construct from components
         blockEdge
         (
-            const pointField& points,
-            const label start,
-            const label end
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end         //!< End point in referenced point field
         );
 
-        //- Construct from Istream setting pointsList
+        //- Construct from Istream and point field.
         blockEdge
         (
             const dictionary& dict,
             const label index,
-            const pointField&,
-            Istream&
+            const pointField& points,   //!< Referenced point field
+            Istream& is
         );
 
         //- Clone function
@@ -133,8 +141,8 @@ public:
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
-            Istream&
+            const pointField& points,
+            Istream& is
         );
 
         //- Class used for the read-construction of
@@ -174,10 +182,10 @@ public:
 
     // Member Functions
 
-        //- Return label of start point
+        //- Index of start point
         inline label start() const;
 
-        //- Return label of end point
+        //- Index of end point
         inline label end() const;
 
         //- Compare the given start and end points with this curve
@@ -201,22 +209,22 @@ public:
         //  - -1: same edge, but different orientation
         inline int compare(const label start, const label end) const;
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         virtual point position(const scalar) const = 0;
 
-        //- Return the point positions corresponding to the curve parameters
+        //- The point positions corresponding to the curve parameters
         //  0 <= lambda <= 1
         virtual tmp<pointField> position(const scalarList&) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
         virtual scalar length() const = 0;
 
         //- Write edge with variable backsubstitution
         void write(Ostream&, const dictionary&) const;
 
 
-    // Ostream operator
+    // Ostream Operator
 
         friend Ostream& operator<<(Ostream&, const blockEdge&);
 };
diff --git a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdgeI.H b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdgeI.H
index a781be5f968f991a2dfc4274384be52ff4b65ed1..6aab3064f06d052b2d49d07a294b6afbc9546c2a 100644
--- a/src/mesh/blockMesh/blockEdges/blockEdge/blockEdgeI.H
+++ b/src/mesh/blockMesh/blockEdges/blockEdge/blockEdgeI.H
@@ -49,10 +49,8 @@ inline int Foam::blockEdge::compare(const label start, const label end) const
     {
         return -1;
     }
-    else
-    {
-        return 0;
-    }
+
+    return 0;
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/lineDivide/lineDivide.H b/src/mesh/blockMesh/blockEdges/lineDivide/lineDivide.H
index acd035602d001210d540e973b85d6cc65e660f90..1c58386a0ffc62093d3bd3144071a81e020f0caf 100644
--- a/src/mesh/blockMesh/blockEdges/lineDivide/lineDivide.H
+++ b/src/mesh/blockMesh/blockEdges/lineDivide/lineDivide.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,6 +47,7 @@ SourceFiles
 namespace Foam
 {
 
+// Forward Declarations
 class blockEdge;
 
 /*---------------------------------------------------------------------------*\
@@ -54,7 +56,7 @@ class blockEdge;
 
 class lineDivide
 {
-    // Private data
+    // Private Data
 
         pointField points_;
 
@@ -67,18 +69,18 @@ public:
         //- Construct from components
         lineDivide
         (
-            const blockEdge&,
-            const label ndiv,
+            const blockEdge& cedge,
+            const label nDiv,
             const gradingDescriptors& gd = gradingDescriptors()
         );
 
 
     // Member Functions
 
-        //- Return the points
+        //- The points
         const pointField& points() const;
 
-        //- Return the list of lambda values
+        //- The list of lambda values
         const scalarList& lambdaDivisions() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.C b/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.C
index 713d9bec153bc5aae3865c4d0a50fd8e75b061c8..203f16220a8ac0b5c589f289e51a81ff2d73df84 100644
--- a/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.C
+++ b/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -71,11 +71,21 @@ Foam::blockEdges::lineEdge::lineEdge
 
 Foam::point Foam::blockEdges::lineEdge::position(const scalar lambda) const
 {
-    if (lambda < -SMALL || lambda > 1+SMALL)
+    #ifdef FULLDEBUG
+    if (lambda < -SMALL || lambda > 1 + SMALL)
     {
-        FatalErrorInFunction
-            << "Parameter out of range, lambda = " << lambda
-            << abort(FatalError);
+        WarningInFunction
+            << "Parameter out of range, lambda = " << lambda << nl;
+    }
+    #endif
+
+    if (lambda < SMALL)
+    {
+        return points_[start_];
+    }
+    else if (lambda >= 1 - SMALL)
+    {
+        return points_[end_];
     }
 
     return points_[start_] + lambda * (points_[end_] - points_[start_]);
diff --git a/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.H b/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.H
index b44b3ab14adfffcf01a79599a5d0fa2558a5c500..1bbc9d67ce5b3d6f24bcba2aa4f27488830b3a33 100644
--- a/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.H
+++ b/src/mesh/blockMesh/blockEdges/lineEdge/lineEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -51,12 +51,10 @@ namespace blockEdges
                           Class lineEdge Declaration
 \*---------------------------------------------------------------------------*/
 
-
 class lineEdge
 :
     public blockEdge
 {
-
 public:
 
     //- Runtime type information
@@ -66,15 +64,20 @@ public:
     // Constructors
 
         //- Construct from components
-        lineEdge(const pointField&, const label start, const label end);
+        lineEdge
+        (
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end         //!< End point in referenced point field
+        );
 
-        //- Construct from Istream with a pointField
+        //- Construct from Istream and point field.
         lineEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
+            const pointField& points,   //!< Referenced point field
             Istream& is
         );
 
@@ -85,11 +88,11 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         point position(const scalar) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.C b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.C
index 0703696698e47bb74db3ab5c5f6a647e5a292d88..42f6a74db691bebd9fac04b3fda427d3f7853c9c 100644
--- a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.C
+++ b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,16 +27,41 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "polyLine.H"
+#include "SubList.H"
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+Foam::tmp<Foam::pointField> Foam::polyLine::concat
+(
+    const point& p0,
+    const pointField& intermediate,
+    const point& p1
+)
+{
+    auto tresult = tmp<pointField>::New(intermediate.size() + 2);
+    auto& result = tresult.ref();
+
+    // Intermediate points (knots)
+    SubList<point>(result, intermediate.size(), 1) = intermediate;
+
+    // Start/end points (knots)
+    result.first() = p0;
+    result.last() = p1;
+
+    return tresult;
+}
+
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
 void Foam::polyLine::calcParam()
 {
-    param_.setSize(points_.size());
+    lineLength_ = 0;
+    param_.resize(points_.size());
 
     if (param_.size())
     {
-        param_[0] = 0.0;
+        param_[0] = 0;
 
         for (label i=1; i < param_.size(); i++)
         {
@@ -48,23 +74,34 @@ void Foam::polyLine::calcParam()
         {
             param_[i] /= lineLength_;
         }
-        param_.last() = 1.0;
-    }
-    else
-    {
-        lineLength_ = 0.0;
+        param_.last() = 1;
     }
 }
 
 
-
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::polyLine::polyLine(const pointField& ps, const bool)
 :
     points_(ps),
-    lineLength_(0.0),
-    param_(0)
+    lineLength_(0),
+    param_()
+{
+    calcParam();
+}
+
+
+Foam::polyLine::polyLine
+(
+    const point& start,
+    const pointField& intermediate,
+    const point& end,
+    const bool
+)
+:
+    points_(polyLine::concat(start, intermediate, end)),
+    lineLength_(0),
+    param_()
 {
     calcParam();
 }
@@ -101,19 +138,20 @@ Foam::label Foam::polyLine::localParameter(scalar& lambda) const
     // Search table of cumulative distances to find which line-segment
     // we are on.
     // Check the upper bound.
+    // Too small to bother with a binary search...
 
-    label segmentI = 1;
-    while (param_[segmentI] < lambda)
+    label segment = 1;
+    while (param_[segment] < lambda)
     {
-        segmentI++;
+        ++segment;
     }
-    segmentI--;   // We want the corresponding lower bound
+    --segment;   // We want the corresponding lower bound
 
     // The local parameter [0-1] on this line segment
     lambda =
-        (lambda - param_[segmentI])/(param_[segmentI+1] - param_[segmentI]);
+        (lambda - param_[segment])/(param_[segment+1] - param_[segment]);
 
-    return segmentI;
+    return segment;
 }
 
 
@@ -151,8 +189,8 @@ Foam::point Foam::polyLine::position
         return points_.last();
     }
 
-    const point& p0 = points()[segment];
-    const point& p1 = points()[segment+1];
+    const point& p0 = points_[segment];
+    const point& p1 = points_[segment+1];
 
     // Special cases - no calculation needed
     if (mu <= 0.0)
@@ -163,11 +201,9 @@ Foam::point Foam::polyLine::position
     {
         return p1;
     }
-    else
-    {
-        // Linear interpolation
-        return points_[segment] + mu*(p1 - p0);
-    }
+
+    // Linear interpolation
+    return points_[segment] + mu*(p1 - p0);
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.H b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.H
index e7208122013972bd9b683e342df1215957262e0e..b7bf40e8afc424b538418ee179d9649b35ba6c08 100644
--- a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.H
+++ b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLine.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -52,26 +53,16 @@ namespace Foam
                           Class polyLine Declaration
 \*---------------------------------------------------------------------------*/
 
-
 class polyLine
 {
-    // Private Member Functions
-
-        //- No copy construct
-        polyLine(const polyLine&) = delete;
-
-        //- No copy assignment
-        void operator=(const polyLine&) = delete;
-
-
 protected:
 
-    // Protected data
+    // Protected Data
 
         //- The control points or ends of each segments
         pointField points_;
 
-        //- The real line length
+        //- The real (total) line length
         scalar lineLength_;
 
         //- The rational (0-1) cumulative parameter value for each point
@@ -81,11 +72,11 @@ protected:
     // Protected Member Functions
 
         //- Precalculate the rational cumulative parameter value
-        //  and the line-length
+        //- and the line-length
         void calcParam();
 
         //- Return the line segment and the local parameter [0..1]
-        //  corresponding to the global lambda [0..1]
+        //- corresponding to the global lambda [0..1]
         label localParameter(scalar& lambda) const;
 
 
@@ -94,30 +85,50 @@ public:
     // Constructors
 
         //- Construct from components
+        explicit polyLine
+        (
+            const pointField& points,   //!< The poly-line points
+            const bool notImplementedClosed = false
+        );
+
+        //- Construct from begin, intermediate, end points
         polyLine
         (
-            const pointField&,
+            const point& start,             //!< The start point
+            const pointField& intermediate, //!< The intermediate points
+            const point& end,               //!< The end point
             const bool notImplementedClosed = false
         );
 
 
+    // Static Member Functions
+
+        //- Concatenate begin, intermediate and end points
+        static tmp<pointField> concat
+        (
+            const point& start,             //!< The start point
+            const pointField& intermediate, //!< The intermediate points
+            const point& end                //!< The end point
+        );
+
+
     // Member Functions
 
         //- Return const-access to the control-points
         const pointField& points() const;
 
-        //- Return the number of line segments
+        //- The number of line segments
         label nSegments() const;
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         point position(const scalar) const;
 
-        //- Return the point position corresponding to the local parameter
+        //- The point position corresponding to the local parameter
         //  0 <= lambda <= 1 on the given segment
         point position(const label segment, const scalar) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.C b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.C
index c350a8232224bde825c15e75c13695eef464bbd3..9a1b014fee0fe3517953d7648bd613515c10ea8d 100644
--- a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.C
+++ b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -48,11 +48,11 @@ Foam::blockEdges::polyLineEdge::polyLineEdge
     const pointField& ps,
     const label start,
     const label end,
-    const pointField& otherPoints
+    const pointField& intermediate
 )
 :
     blockEdge(ps, start, end),
-    polyLine(appendEndPoints(ps, start_, end_, otherPoints))
+    polyLine(ps[start_], intermediate, ps[end_])
 {}
 
 
@@ -66,7 +66,7 @@ Foam::blockEdges::polyLineEdge::polyLineEdge
 )
 :
     blockEdge(dict, index, ps, is),
-    polyLine(appendEndPoints(ps, start_, end_, pointField(is)))
+    polyLine(ps[start_], pointField(is), ps[end_])
 {}
 
 
diff --git a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.H b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.H
index 9eb66901431446db27450388042305fd9edecc53..bcce9c738e2599aaafc3655caa3e49b1f79a4dbf 100644
--- a/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.H
+++ b/src/mesh/blockMesh/blockEdges/polyLineEdge/polyLineEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -77,19 +77,19 @@ public:
         //- Construct from components
         polyLineEdge
         (
-            const pointField&,
-            const label start,
-            const label end,
-            const pointField& otherPoints
+            const pointField& points,       //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
+            const pointField& intermediate  //!< The intermediate points
         );
 
-        //- Construct from Istream
+        //- Construct from Istream and point field.
         polyLineEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
+            const pointField& points,       //!< Referenced point field
             Istream& is
         );
 
@@ -100,11 +100,11 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         point position(const scalar lambda) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.C b/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.C
index 08fa1186a5db81aa32cf8a516ce65af6756c93f4..f6f182207a288aff214ab2e4e22ac8fcd91e4c9f 100644
--- a/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.C
+++ b/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.C
@@ -59,7 +59,7 @@ Foam::projectCurveEdge::projectCurveEdge
     geometry_(geometry)
 {
     wordList names(is);
-    surfaces_.setSize(names.size());
+    surfaces_.resize(names.size());
     forAll(names, i)
     {
         surfaces_[i] = geometry_.findSurfaceID(names[i]);
@@ -83,6 +83,14 @@ Foam::projectCurveEdge::projectCurveEdge
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+Foam::point
+Foam::projectCurveEdge::position(const scalar) const
+{
+    NotImplemented;
+    return point::max;
+}
+
+
 Foam::tmp<Foam::pointField>
 Foam::projectCurveEdge::position(const scalarList& lambdas) const
 {
@@ -101,8 +109,8 @@ Foam::projectCurveEdge::position(const scalarList& lambdas) const
     }
 
 
-    tmp<pointField> tpoints(new pointField(lambdas.size()));
-    pointField& points = tpoints.ref();
+    auto tpoints = tmp<pointField>::New(lambdas.size());
+    auto& points = tpoints.ref();
 
     const point& startPt = points_[start_];
     const point& endPt = points_[end_];
@@ -149,10 +157,11 @@ Foam::projectCurveEdge::position(const scalarList& lambdas) const
 
 
     // Upper limit for number of iterations
-    const label maxIter = 10;
+    constexpr label maxIter = 10;
+
     // Residual tolerance
-    const scalar relTol = 0.1;
-    const scalar absTol = 1e-4;
+    constexpr scalar relTol = 0.1;
+    constexpr scalar absTol = 1e-4;
 
     scalar initialResidual = 0.0;
 
@@ -258,4 +267,11 @@ Foam::projectCurveEdge::position(const scalarList& lambdas) const
 }
 
 
+Foam::scalar Foam::projectCurveEdge::length() const
+{
+    NotImplemented;
+    return 1;
+}
+
+
 // ************************************************************************* //
diff --git a/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.H b/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.H
index 1e6ca665eeef4ed8d29937908fe7a53f5a176316..7f939b9d58bc3114882a766a8a6d1b5969002e2a 100644
--- a/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.H
+++ b/src/mesh/blockMesh/blockEdges/projectCurveEdge/projectCurveEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,6 +46,7 @@ SourceFiles
 namespace Foam
 {
 
+// Forward Declarations
 class pointConstraint;
 
 /*---------------------------------------------------------------------------*\
@@ -81,13 +82,13 @@ public:
 
     // Constructors
 
-        //- Construct from Istream setting pointsList
+        //- Construct from Istream and point field.
         projectCurveEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField& points,
+            const pointField& points,   //!< Referenced point field
             Istream& is
         );
 
@@ -98,24 +99,18 @@ public:
 
     // Member Functions
 
-        //- Return the point positions corresponding to the curve parameters
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
-        virtual point position(const scalar) const
-        {
-            NotImplemented;
-            return point::max;
-        }
+        //  \note NotImplemented
+        virtual point position(const scalar) const;
 
-        //- Return the point positions corresponding to the curve parameters
+        //- The point positions corresponding to the curve parameters
         //  0 <= lambda <= 1
         virtual tmp<pointField> position(const scalarList&) const;
 
-        //- Return the length of the curve
-        virtual scalar length() const
-        {
-            NotImplemented;
-            return 1;
-        }
+        //- The length of the curve
+        //  \note NotImplemented
+        virtual scalar length() const;
 };
 
 
diff --git a/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.C b/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.C
index 8259bc77ed6caff66a95af540171985caf4e08ef..16b99b1bbf36f403b89c821357193c10de08f9c9 100644
--- a/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.C
+++ b/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.C
@@ -26,13 +26,12 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "searchableSurfacesQueries.H"
 #include "projectEdge.H"
-#include "unitConversion.H"
-#include "addToRunTimeSelectionTable.H"
 #include "pointConstraint.H"
+#include "searchableSurfacesQueries.H"
 #include "OBJstream.H"
 #include "linearInterpolationWeights.H"
+#include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -146,8 +145,8 @@ Foam::projectEdge::position(const scalarList& lambdas) const
     }
 
 
-    tmp<pointField> tpoints(new pointField(lambdas.size()));
-    pointField& points = tpoints.ref();
+    auto tpoints = tmp<pointField>::New(lambdas.size());
+    auto& points = tpoints.ref();
 
     const point& startPt = points_[start_];
     const point& endPt = points_[end_];
@@ -161,10 +160,11 @@ Foam::projectEdge::position(const scalarList& lambdas) const
 
 
     // Upper limit for number of iterations
-    const label maxIter = 10;
+    constexpr label maxIter = 10;
+
     // Residual tolerance
-    const scalar relTol = 0.1;
-    const scalar absTol = 1e-4;
+    constexpr scalar relTol = 0.1;
+    constexpr scalar absTol = 1e-4;
 
     scalar initialResidual = 0.0;
 
@@ -270,4 +270,11 @@ Foam::projectEdge::position(const scalarList& lambdas) const
 }
 
 
+Foam::scalar Foam::projectEdge::length() const
+{
+    NotImplemented;
+    return 1;
+}
+
+
 // ************************************************************************* //
diff --git a/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.H b/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.H
index 1c3d180d7fc1a11a7756c0fac35e62a144d2ee26..44c9d143d8581f1996a86a158042f45cd9f54382 100644
--- a/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.H
+++ b/src/mesh/blockMesh/blockEdges/projectEdge/projectEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,6 +46,7 @@ SourceFiles
 namespace Foam
 {
 
+// Forward Declarations
 class pointConstraint;
 
 /*---------------------------------------------------------------------------*\
@@ -84,13 +85,13 @@ public:
 
     // Constructors
 
-        //- Construct from Istream setting pointsList
+        //- Construct from Istream and point field.
         projectEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField& points,
+            const pointField& points,   //!< Referenced point field
             Istream& is
         );
 
@@ -101,20 +102,17 @@ public:
 
     // Member Functions
 
-        //- Return the point positions corresponding to the curve parameters
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         virtual point position(const scalar) const;
 
-        //- Return the point positions corresponding to the curve parameters
+        //- The point positions corresponding to the curve parameters
         //  0 <= lambda <= 1
         virtual tmp<pointField> position(const scalarList&) const;
 
-        //- Return the length of the curve
-        virtual scalar length() const
-        {
-            NotImplemented;
-            return 1;
-        }
+        //- The length of the edge
+        //  \note NotImplemented
+        virtual scalar length() const;
 };
 
 
diff --git a/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.C b/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.C
index a8ee8c1d712d5ce9b273dccba27705a8bc21a70c..bfa0aaf27b01a809028cc051959a959bc7009c06 100644
--- a/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.C
+++ b/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.C
@@ -134,7 +134,7 @@ Foam::point Foam::CatmullRomSpline::position
 Foam::scalar Foam::CatmullRomSpline::length() const
 {
     NotImplemented;
-    return 1.0;
+    return 1;
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.H b/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.H
index c78803d9d35129d0af972b60be1abc67b21e3fcc..27093f9cbd439b383804b0d163677abe9f7a54ef 100644
--- a/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.H
+++ b/src/mesh/blockMesh/blockEdges/splineEdge/CatmullRomSpline.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -79,21 +80,12 @@ class CatmullRomSpline
 :
     public polyLine
 {
-    // Private Member Functions
-
-        //- No copy construct
-        CatmullRomSpline(const CatmullRomSpline&) = delete;
-
-        //- No copy assignment
-        void operator=(const CatmullRomSpline&) = delete;
-
-
 public:
 
     // Constructors
 
         //- Construct from components
-        CatmullRomSpline
+        explicit CatmullRomSpline
         (
             const pointField& knots,
             const bool notImplementedClosed = false
@@ -102,15 +94,16 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         point position(const scalar lambda) const;
 
-        //- Return the point position corresponding to the local parameter
+        //- The point position corresponding to the local parameter
         //  0 <= lambda <= 1 on the given segment
         point position(const label segment, const scalar lambda) const;
 
-        //- Return the length of the curve
+        //- The length of the curve
+        //  \note NotImplemented
         scalar length() const;
 };
 
diff --git a/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.C b/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.C
index 048d19878bfe76083ee067bf69854c6dee0d7555..5494d4ed884fe19464b05c0dd10a11bdc2f8a380 100644
--- a/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.C
+++ b/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,9 +27,9 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "splineEdge.H"
+#include "polyLine.H"
 #include "addToRunTimeSelectionTable.H"
 
-
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
@@ -59,7 +59,10 @@ Foam::blockEdges::splineEdge::splineEdge
 )
 :
     blockEdge(points, start, end),
-    CatmullRomSpline(appendEndPoints(points, start, end, internalPoints))
+    CatmullRomSpline
+    (
+        polyLine::concat(points[start_], internalPoints, points[end_])
+    )
 {}
 
 
@@ -73,13 +76,16 @@ Foam::blockEdges::splineEdge::splineEdge
 )
 :
     blockEdge(dict, index, points, is),
-    CatmullRomSpline(appendEndPoints(points, start_, end_, pointField(is)))
+    CatmullRomSpline
+    (
+        polyLine::concat(points[start_], pointField(is), points[end_])
+    )
 {
-    token t(is);
-    is.putBack(t);
+    token tok(is);
+    is.putBack(tok);
 
-    // discard unused start/end tangents
-    if (t == token::BEGIN_LIST)
+    // Discard unused start/end tangents
+    if (tok == token::BEGIN_LIST)
     {
         vector tangent0Ignored(is);
         vector tangent1Ignored(is);
diff --git a/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.H b/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.H
index a5519ec883d1a150883292cb01fb55b30eed7c7c..3ac595cbac7fc0b87e91ad72cbb475f743a62ba9 100644
--- a/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.H
+++ b/src/mesh/blockMesh/blockEdges/splineEdge/splineEdge.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,6 +30,10 @@ Class
 Description
     A blockEdge interface for Catmull-Rom splines.
 
+See also
+    BSpline
+    CatmullRomSpline
+
 SourceFiles
     splineEdge.C
 
@@ -77,19 +81,19 @@ public:
         //- Construct from components
         splineEdge
         (
-            const pointField&,
-            const label start,
-            const label end,
+            const pointField& points,   //!< Referenced point field
+            const label start,      //!< Start point in referenced point field
+            const label end,        //!< End point in referenced point field
             const pointField& internalPoints
         );
 
-        //- Construct from Istream, setting pointsList
+        //- Construct from Istream and point field.
         splineEdge
         (
             const dictionary& dict,
             const label index,
             const searchableSurfaces& geometry,
-            const pointField&,
+            const pointField& points,   //!< Referenced point field
             Istream&
         );
 
@@ -100,11 +104,12 @@ public:
 
     // Member Functions
 
-        //- Return the point position corresponding to the curve parameter
+        //- The point position corresponding to the curve parameter
         //  0 <= lambda <= 1
         virtual point position(const scalar) const;
 
-        //- Return the length of the spline curve (not implemented)
+        //- The length of the spline curve
+        //  \note NotImplemented
         virtual scalar length() const;
 };