NIMBY Rails devblog 2021-12

End of v1.3 development, end of year, start of v1.4

v.1.3.15 is the final release in the v1.3 series, and it implements the new multiplayer simulation sync system exposed in the last post. v1.3 was shorter and more focused than v1.2, which is to be expected given the very large scope of v1.2. My hope for v1.4 and future versions is to keep this shorter development cycle.

After v1.3.15 was done I slowed down for the holiday period, and to triage and prioritize my internal roadmap for v1.4. The major feature for v1.4, “station review”, is not fully defined, on purpose, to leave the door open to ideas I might have discarded in the past, and also because there’s some peripheral work I need to do before I commit to a new station design. These tasks are all related to stations in some ways, but are self-contained and have their own impact in the game design. I started v1.4 development with some of these tasks for the remainder of December, and this post is about them.

Mercator distances correction

The game using Mercator coordinates directly for distance calculation was one of these prototype phase decisions which weren’t reviewed or prioritized enough back in the day, and it stuck for release. Fixing it thus became one of the top player requests, to near meme status. But fixing it has real impact on existing saves. Player built objects are anchored to particular geo coordinates, and this must be respected. This means that everything will become shorter when Mercator coordinates are corrected. But at the same time some things must be left “uncorrected” on purpose, like the parallel track offsets, and kept at the specified distance. I anticipate that stations will be the most likely object to need some editing in for v1.3 imported in v1.4, but since they are being redesigned anyway, it will be desirable to do so, not just because of the Mercator fix.

Here’s an example of a v1.3 station in Iceland:

And here it is in v1.4 (station drawing is mostly disabled, only a footprint is displayed at this point):

Notice the shorter platform length. The train both screenshots is exactly 200m.

The technical explanation for the Mercator issue and fix is that Mercator coordinates are a way to unwrap a sphere into a cylinder which is then unwrapped into a plane (GIS pros: I’m just simplifying things, you know it). There are many ways to do that and the Mercator way has the nice property of respecting the original angles on the surface of the sphere, but in turn it does not respect the arc distances. So it’s an ideal projection for maps, and the default one for all OSM tools and web GIS tools in general due to Google Maps tradition (actually Web Mercator which has its own share of idiosyncrasies compared to plain Mercator.)

So the game, to be corrected, needs to calculate distances based on arcs on a sphere instead of plain Euclidean distance on Mercator coordinates, which is completely wrong, even if completely consistent in its own way. It’s actually a bit more complicated than just replacing a distance formula by another one, since a very common operation is “distance projection”. The double track offset I mentioned earlier is an example of this. Five meters in the equator is a different Mercator length in Anchorage, AK, US. This is where attempting to use sphere arcs gets specially hairy. So instead of sphere arcs I’m doing something cheaper and easier: given a latitude, it is possible to calculate how “wrong” a Mercator length is compared to a real length, by just taking the cosine of it, and multiplying or dividing as a factor, depending on the operation. So now the game has a quick and easy way to correct distances over Mercator coordinates, and to transform metric translation into Mercator coordinates. Given the Earth being an spheroid and not a sphere, and some of the idiosyncrasies I hinted earlier about Web Mercator, this idea actually has an error of about 0.6% in the worst case. But compared to the previous state I believe it’s good enough.

Horizontal offset for tangent track constraints

In v1.2 I was forced to make a decision to salvage v1.1 saves. By allowing construction inside station platforms I gained the space I needed to add signals and scissor junctions to tracks, to enable the new double track system in v1.1 saves. But it came at a huge cost, and an entire host of features became more complex to implement and some of them are indefinitely on hold, like proper train stops on platforms or natural train direction reversal. Platforms should have stayed free of construction, and I intend to do so in v1.4.

But construction inside platforms has some good UX aspects, like platforms “owning” these rail features and seamlessly moving and scaling with them. I want to reproduce this, while keeping said infrastructure outside of the platform proper. The way to do so in v1.4 will be tangent constrained tracks (already present since v1.2), but with horizontal offsets:

The two tracks immediately attached to the platform in the gif are constrained to always have their control nodes in the same tangent as the platform, and always at 50m of distance. When combined with the usual double track station set of signals and branches this design will offer the same UX as the current double track stations, while keeping the platforms themselves empty and fully dedicated to train maneuvers (imported v1.3 saves will allow construction on platforms, but only on existing platforms; these existing platforms won’t support new train maneuvers and will fall back to accordion and warping).

Layered drawing for trains

Another often requested feature is layering of trains in tracks, rather than always drawing them on top. v1.4 will have a more complex draw system for stations, specially for the non-track parts, and these must play nice with the track layering. So I reviewed all the track, train and object drawing in general, and implemented a layer system which supports all the drawing operations in the game, including the map itself. The first feature is trains being layered correctly on their track layer:

I also intend to add selective drawing of track layers, with controls in the map panel, so for example you restrict display to only a couple subway layers in a city.

Speaking of subways, I also enabled another layering mode which interacted with the map, so tunnel tracks are drawn under streets and map areas:

But in the end I had to disable it. It turns out OSM water areas are designed assuming an opaque fill, since they sometimes overlap in glitchy-looking ways. Which makes sense since that’s the way virtually every map in the map world is displayed. Fixing this on my side would require monkeying around with the stencil buffer and/or rebuilding water geometry with some very expensive union operations. Both of these efforts are very out of scope, so for now all the tracks will remain displayed above ground.