Meander is a procedural system for generating historical maps of rivers that never existed.
In 1944. Harold Fisk, working with the US Army Corp. of Engineers, designed a map-based data visualization that mapped the length of the Mississippi River. What sets his visualization apart from others is that he maps the river through time, and manages to do so in a way that is both beautiful and surprisingly effective.
We want to pay homage to his series of maps by creating our own system for procedurally generating maps of meandering rivers.
This map generator system was created with Houdini. All the system requires is an input guide line. The line becomes the river and the river moves and evolves over time and leaves behind a visual history of its growth.
The map is of a place, albeit a fictional place, so there needs to be terrain on which the river flows. I generate a plausible randomized terrain and use the guide line to cut away a valley.
The valley controls the flow of the river: slow rivers on flat plains meander, fast rivers on steep terrain do not.
As a river moves through the landscape, it is constantly eroding material from the river bed and depositing it downstream. This process continually reshapes the flow of the river causing it to create snaking bends. Browsing through satellite images of the Earth, it is easy to find examples of river meandering. Below are a few examples that will inform our attempts to recreate the geological process with custom code.
The underlying dynamics of this system are easy enough to understand: rivers pick up material and deposit it downstream, rivers erode the outer bank of a curve where the water speed is higher and deposit on the inner bank where the water speed is slower, and rivers can cut off meanders in favor of a straighter path which forms isolated sections called oxbow lakes.
To simulate this process with code, we can ignore erosion and deposition and just think of a curved line on a plane. Each point on the curve has a coordinate frame which is represented by three vectors: normal, tangent, and bitangent.
Since we are dealing with a planar phenominon (ignoring changes in elevation for now), we can disregard the normal vector (in our case, the normal just points straight up) and just make use of the tangent and bitangent vectors. The tangent points in the direction of the line and the bitangent is at a right angle to the tangent.
One thing to note, the bitangent vector isn't enough to make our curve meander. A derived bitangent generally points to the same side of the line, whereas we need our bitangent to be aware of which way the line is curved. It should always point to the outside of the curve and its length should be proportional to the curvature of the line at that point.
Using the tangent and modified bitangent, we create a new vector that is a blend of the two. This new vector is added to the position of each point on the curve. With this basic logic, the bends in the river form organically.
The style of the bends can be influenced by adjusting the overall influence of these two vectors individually, and the intensity of the bends can be adjusted by increasing the scale of the final blended vector.
When a river bends back into itself, the meander bend gets cut off in favor of a shorter path. This process creates oxbow lakes which are generally crescent shaped bodies of water to the sides of the main river flow.
To find potential oxbows in our river, we do distance checks to see if the river is in danger of overlapping itself. If a near collision is found, the part of the curve between the two collision points is isolated and turned into its own curve segment.
The only behavior that these newly generated lakes exhibit is that they get smaller over time until they are deleted from the system. (The current system doesn't allow for the river to reintersect the oxbow lakes, so an extra step is added to ensure that the lake deletes parts of itself that are at risk of being overlapped by the river.)
The background grid-based plots were created by scattering some points on the main river spline and some additional points on the background plane.
Voronoi Fracture is used to turn the background plane into smaller polygons with irregular edges. Each polygon is then broken up into a non-uniform grid. Each of those new polygons is broken up further with an iterated subdivision loop which creates plots of pseudo-random sizes.
Finally, an organic shape created from the river geometry is used to create boundary plots along the shore. The center point of the final set of polygons is calculated which becomes the location of the plot id number text layer.
The network of roads didn't begin as a network of roads. The initial algorithm was an attempt to create an organic growth pattern.
The system begins with some randomly placed points. Each point is given a directional growth vector. The point moves along this growth vector and draws a line as it goes. If the point encounters another line, it stops.
As the point moves, the directional vector rotates slowly. I found that if I mix curving vectors with non-curving vectors, the result ended up resembling intersecting roads. I emphasized this result by making the thickness of the lines be directly proportional its length.
The first map images we prototyped lacked a sense of place. There were no names for any of the places which seemed like a missed opportunity to do something compelling. We considered randomly generated nonsense strings, or manually naming places, but neither of these options seemed like a good scalable solution.
We found a USGS database (GNIS data) of geographic place names. We wrote a python script to parse the content and crop off the suffix (things like "Lake" or "Summit") to produce a list of proper names to use for features. We didn't want to name features after places that already exist so cropping off the suffix helps to reduce the likelihood of recreating something called "Hudson River". Instead, new suffixes were randomly added to produce feature names like "Hudson Summit" or "Hudson Swamp". Additionally, we pulled out duplicate entries as well as excessively long names ( Little West Fork West Branch Feather River showed up in one of the generated maps).
The features that were isolated for naming include the main river, lakes, islands, peaks, basins, and marshland. The river, lakes, and islands were easy enough since those features are present from the creation of the river system itself. The peaks and basins were isolated by analyzing the slope of the terrain. Flat sections were found and if those flats were near the water level, it was considered a basin. If the flat was at a high elevation, it was designated as a peak. The marshland was slightly more challenging. Areas with low slope were isolated and turned into axis-aligned bounding boxes whose center became the location for the label. Future iterations of this project will find ways to lay the text out in a more map-like manner with text flowing along features like ridges and thin lakes.
After completing three limited print runs and a successful ArtBlocks release, we are thrilled about the potential of MEANDER's future. Our team recognizes the value of the extensive research and development invested in this project and we're eager to explore opportunities to showcase it in alternative formats.
2 East Broadway, 5th Floor
New York, NY 10038
contact@rarevolume.com
+1 917 410 2690
11801 Domain Blvd, 3rd Floor
Austin, TX 78758