From 1d08ed9be2551bdfbeedeb0edb3980501c9b7af8 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Mon, 5 Oct 2020 12:36:19 +0200
Subject: [PATCH] ENH: support arc edge specification with origin point

- 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,

      arc 0 1 origin (0 0 0);

  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 specify a \em flatness factor as a multiplier
  of the radius. For example,

      arc 0 1 origin 1.1 (0 0 0);

ENH: minor code cleanup for block edges

ENH: expose point appending as polyList::concat
---
 .../blockEdges/BSplineEdge/BSpline.C          |   2 +-
 .../blockEdges/BSplineEdge/BSpline.H          |  21 +-
 .../blockEdges/BSplineEdge/BSplineEdge.C      |  22 +-
 .../blockEdges/BSplineEdge/BSplineEdge.H      |  19 +-
 .../blockMesh/blockEdges/arcEdge/arcEdge.C    | 229 ++++++++++++++----
 .../blockMesh/blockEdges/arcEdge/arcEdge.H    |  95 ++++++--
 src/mesh/blockMesh/blockEdges/bezier/bezier.C |   8 +-
 src/mesh/blockMesh/blockEdges/bezier/bezier.H |  17 +-
 .../blockEdges/blockEdge/blockEdge.C          |  25 +-
 .../blockEdges/blockEdge/blockEdge.H          |  58 +++--
 .../blockEdges/blockEdge/blockEdgeI.H         |   6 +-
 .../blockEdges/lineDivide/lineDivide.H        |  12 +-
 .../blockMesh/blockEdges/lineEdge/lineEdge.C  |  20 +-
 .../blockMesh/blockEdges/lineEdge/lineEdge.H  |  19 +-
 .../blockEdges/polyLineEdge/polyLine.C        |  82 +++++--
 .../blockEdges/polyLineEdge/polyLine.H        |  49 ++--
 .../blockEdges/polyLineEdge/polyLineEdge.C    |   8 +-
 .../blockEdges/polyLineEdge/polyLineEdge.H    |  18 +-
 .../projectCurveEdge/projectCurveEdge.C       |  28 ++-
 .../projectCurveEdge/projectCurveEdge.H       |  27 +--
 .../blockEdges/projectEdge/projectEdge.C      |  23 +-
 .../blockEdges/projectEdge/projectEdge.H      |  20 +-
 .../blockEdges/splineEdge/CatmullRomSpline.C  |   2 +-
 .../blockEdges/splineEdge/CatmullRomSpline.H  |  19 +-
 .../blockEdges/splineEdge/splineEdge.C        |  22 +-
 .../blockEdges/splineEdge/splineEdge.H        |  21 +-
 26 files changed, 574 insertions(+), 298 deletions(-)

diff --git a/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C b/src/mesh/blockMesh/blockEdges/BSplineEdge/BSpline.C
index 39d3b99b8cb..29957a0ceb9 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 e9da49bcdc5..00f77df5b0b 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 81c3ab24ee0..af5e4d89ed8 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 e04434c593a..68eefdab87e 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 7c614b88291..698fec2a8db 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 8db6fcaa975..459b6a70f0d 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 b1b884d32a1..cac55d1ba3b 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 b1f14dab279..5feaeb41392 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 01621e08c8a..a49880b1212 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 30d09f00f1b..dd48cba8343 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 a781be5f968..6aab3064f06 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 acd035602d0..1c58386a0ff 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 713d9bec153..203f16220a8 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 b44b3ab14ad..1bbc9d67ce5 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 0703696698e..42f6a74db69 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 e7208122013..b7bf40e8afc 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 c350a823222..9a1b014fee0 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 9eb66901431..bcce9c738e2 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 08fa1186a5d..f6f182207a2 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 1e6ca665eee..7f939b9d58b 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 8259bc77ed6..16b99b1bbf3 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 1c3d180d7fc..44c9d143d85 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 a8ee8c1d712..bfa0aaf27b0 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 c78803d9d35..27093f9cbd4 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 048d19878bf..5494d4ed884 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 a5519ec883d..3ac595cbac7 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;
 };
 
-- 
GitLab