However, there's one thing that cannot be done without calling an external function, and that is to limit curvature angles for roads to avoid generating roads like this:
As you can see, the exit angle from the red bridge is at an unacceptable angle which would make the road extremely dangerous and thus unrealistic. (The screenshot above is from the intermediate stage where paths have been generated and some terraforming has been done, but before final road geometry has been generated.)
There is one parameter that can be used to assign a cost to path curvature:
This applies the value of the Angular Cost attribute multiplied by the angle turned in degrees at each point. Using this will take us a little further, but not all the way. It won't help in the situation in the first screenshot, as the value for the bridge in all cases must be much higher than that of the curvature (or we would get bridges all over the terrain).
One possible approach might be to assign a uniform value to the angular_cost attribute to cater for all normal road points and a considerably higher value for bridges and tunnels. This would take us some way further, but again not all the way as it still would allow for extremely sharp angles if there is no alternative path.
The only solution to this problem I see is to handle this like all other costs: to create a cost function that will return INF (1e1000) for paths that never should be possible. The Find Shortest Path node is designed to handle this type of cost, as it won't consider paths or nodes with INF costs.
To do this, the Custom Edge Cost parameter would be used to call an external function that would accept three path points: the previous, the current, and the next under consideration. It would calculate the XZ angle between these points and return 1e1000 for impossible paths. This is straightforward to implement.
As the terrain is very large, typically 10x10 km with a pathfinding grid resolution of 5 meters, and this computation would be done many, many times, it's obvious that speed is of the essence. Thus I have two questions:
1. What would be faster here, an HScript custom function or Python?
2. Is there a faster way to achieve the same thing without calling an external function? Preliminary experiments indicate a slowdown of several magnitudes, and that's indeed painful as it would require cooking overnight.
This problem definitely has been solved before. It's part of creating the road networks in the Ghost Recon series and many other AAA games I know use Houdini for terrain generation. I'd be surprised if they didn't use this Houdini node for A*/Dijkstra terrain path searches.
Grateful for any ideas.

