Get the center of position between both positions, 2 `Vector3`

s so that’s easy:

```
local center = (position1 + position2) / 2
```

Pretty simple, then you would need to push this point on X/Z axis depending on the movement of the train, say you have the direction in which the train is turning as a vector3, we can do this:

```
local offset = turnDirection.Unit * curvature
```

And the final position of the center point is just

```
center + offset
```

For the side that’s closer to the center of rotation you will use `-offset`

as it needs to go inwards and not outwards. I came up with the math right now so it may or may not work lol, it theoretically should though… After u have this “center” point you should be able to move the mesh, you said you had bones so afaik it’s easy to do it with that, I’ve never worked with bones though.

I didn’t tell you how to calculate curvature so I’ll guess you don’t know and tell you, in case you already knew u can ignore this part.

We first need start and end of the curve, Y-axis is ignored as we don’t need that, the train won’t drive upwards or downwards, will it?

```
local curveStart = Vector3.new(x1, 0, z1)
local curveEnd = Vector3.new(x2, 0, z2)
```

We need to calculate the slop, `m`

, now, it’s the same as 2D graphs, our 2D plain is X and Z (X and Y in normal 2D) so it’s pretty easy, instead of doing `(y2 - y1) / (x2 - x1)`

we will do `(z2 - z1) / (x2 - x1)`

```
local m = (curveEnd.Z - curveStart.Z) / (curveEnd.X - curveStart.Y)
```

We now need to calculate the perpendicular bisector, it’s pretty easy. Perpendicular bisector is the line that intersects the original line at a right angle and passes through the midpoint of the line segment between the two points.

```
local midpoint = (curveStart + curveEnd) / 2
local perpendicularSlope = -1 / m
local perpendicularBisector = midpoint.Z - perpendicularSlope * midpoint.X
```

Now we calculate the center of curvature on each of our axes.

```
local centerOfCurvatureX = (midpoint.Z - perpendicularBisector) / (2 * perpendicularSlope)
local centerOfCurvatureZ = perpendicularSlope * centerOfCurvatureX + perpendicularBisector
```

And now the the radius of curvature (distance from the curveStart to the center of curvature).

```
local radiusOfCurvature = math.sqrt((curveStart.X - centerOfCurvatureX) ^ 2 + (curveStart.Z - centerOfCurvatureZ) ^ 2)
```

And last but not least we calculate the actual curvature

```
local curvature = 1 / radiusOfCurvature
```

Full code:

```
local curveStart = Vector3.new(x1, 0, z1)
local curveEnd = Vector3.new(x2, 0, z2)
local m = (curveEnd.Z - curveStart.Z) / (curveEnd.X - curveStart.X)
local midpoint = (curveStart + curveEnd) / 2
local perpendicularSlope = -1 / m
local perpendicularIntercept = midpoint.Z - perpendicularSlope * midpoint.X
local centerOfCurvatureX = (midpoint.Z - perpendicularIntercept) / (2 * perpendicularSlope)
local centerOfCurvatureZ = perpendicularSlope * centerOfCurvatureX + perpendicularIntercept
local radiusOfCurvature = math.sqrt((curveStart.X - centerOfCurvatureX) ^ 2 + (curveStart.Z - centerOfCurvatureZ) ^ 2)
local curvature = 1 / radiusOfCurvature
```

Too long? I’m just as surprised as you are! Lmao