The simplest way to think about this is to transform the coordinate system, rotating by the angle between the two points, scaling by the distance between them and translating by the first point (assuming the sine starts at 0,0).
The OP has specified that he doesn't just want to draw the curve (in which case all one needs to do is apply the transform to the graphics context), but rather to use the curve in a SpriteKit SKAction.followPath call, so the transform has to be applied to the coordinates in the path, not to the context.
Here's a solution using CGPath rather than UIBezierPath, but they are equivalent, and you can get the UI version simply by let uip = UIBezierPath(cgPath: path). (I prefer CoreGraphics as they are cross-platform).
Playground code...
class MyView: UIView {
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.setFillColor(UIColor.red.cgColor)
context.fill(self.bounds)
// Calculate the transform
let p1 = CGPoint(x: 100, y: 100)
let p2 = CGPoint(x: 400, y: 400)
let dx = p2.x - p1.x
let dy = p2.y - p1.y
let d = sqrt(dx * dx + dy * dy)
let a = atan2(dy, dx)
let cosa = cos(a) // Calculate only once...
let sina = sin(a) // Ditto
// Initialise our path
let path = CGMutablePath()
path.move(to: p1)
// Plot a parametric function with 100 points
let nPoints = 100
for t in 0 ... nPoints {
// Calculate the un-transformed x,y
let tx = CGFloat(t) / CGFloat(nPoints) // 0 ... 1
let ty = 0.1 * sin(tx * 2 * CGFloat.pi ) // 0 ... 2ฯ, arbitrary amplitude
// Apply the transform
let x = p1.x + d * (tx * cosa - ty * sina)
let y = p1.y + d * (tx * sina + ty * cosa)
// Add the transformed point to the path
path.addLine(to: CGPoint(x: x, y: y))
}
// Draw the path
context.setStrokeColor(UIColor.blue.cgColor)
context.addPath(path)
context.strokePath()
}
}
let v = MyView(frame: CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 500, height: 500)))
