Q:

Modify endcap .round style, to be more apparently round, unlike the example image shown here

I've just learned that the standard Apple .round endcap
let l = CAShapeLayer()
l.path = .. just a straight line, say 50 long
l.lineWidth =  say "3.1" in the example shown here
l.lineCap = .round

is not very apparently round in some cases, see images.
If I want apparently "exact semi-circle" endcaps, what to do?
I appreciate that I could build my own line line and fill it.
But is there a way to perhaps subclass "endcap" in some way?
It would be magic if you could say = .myHappyEndcapMode

How do we fix this?

You can see how far off it is here:

Further info:
The non-round visual look appears to arise in the case of:

Thin lines
Possibly when the width is non-integer
In the situation at hand I had gradients on gradients and fades everywhere, it may not help

A:

There is no way to “subclass” the cap shape. You will have to manually construct the outline of the shape if you want a different cap shape.
The round cap is already exactly as circular as a circle created with CGPath(ellipseIn:).
Here's a round-capped line drawn on top of a circle of slightly larger radius, zoomed 8x:

The curvature of the line cap starts exactly at the horizontal center of the circle.
Here's the code:
import UIKit
import PlaygroundSupport

let lineWidth: CGFloat = 20
let circleRadius = lineWidth / 2 + 1

let lineLayer = CAShapeLayer()
lineLayer.position = .init(x: 30, y: 30)
let path = CGMutablePath()
path.move(to: .zero)
path.addLine(to: .init(x: 30, y: 0))
lineLayer.path = path
lineLayer.lineWidth = lineWidth
lineLayer.lineCap = .round
lineLayer.strokeColor = UIColor.gray.cgColor
lineLayer.fillColor = nil

let circleLayer = CAShapeLayer()
circleLayer.position = lineLayer.position
circleLayer.path = CGPath(ellipseIn: CGRect.zero.insetBy(dx: -circleRadius, dy: -circleRadius), transform: nil)
circleLayer.fillColor = UIColor.blue.cgColor

let view = UIView(frame: .init(x: 0, y: 0, width: 100, height: 80))
view.layer.backgroundColor = UIColor.white.cgColor
view.layer.addSublayer(circleLayer)
view.layer.addSublayer(lineLayer)
PlaygroundPage.current.liveView = view

