# How Arnis Generates Highways and Maintains Connectivity Information in Minecraft Worlds

> Learn how Arnis generates Minecraft highways by building a connectivity map first. See how it maintains information for slopes, bridges, and elevated decks.

- Repository: [Louis Erbkamm/arnis](https://github.com/louis-e/arnis)
- Tags: internals
- Published: 2026-03-20

---

**Arnis builds a highway connectivity map before generating any roads, then references that map during generation to determine when slopes, bridges, and elevated decks are needed at intersections.**

Arnis transforms OpenStreetMap (OSM) data into detailed Minecraft worlds, and the highway generation process depends heavily on accurate connectivity information. This article explains how the `louis-e/arnis` repository constructs a connectivity map in [`src/element_processing/highways.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/highways.rs) and uses it to render realistic multi-level road networks with proper elevation handling.

## Building the Highway Connectivity Map

The generation process begins with `build_highway_connectivity_map`, which iterates through every `ProcessedElement::Way` containing a `highway` tag. This function constructs a `HashMap<(i32, i32), Vec<i32>>` that maps ground coordinates to the set of highway layers present at that location.

```rust
// src/element_processing/highways.rs
pub fn build_highway_connectivity_map(elements: &[ProcessedElement])
    -> HighwayConnectivityMap {
    let mut connectivity_map = HashMap::new();

    for element in elements {
        if let ProcessedElement::Way(way) = element {
            if way.tags.contains_key("highway") {
                // Parse the OSM "layer" tag – defaults to 0, negative layers become 0.
                let layer_value = way.tags.get("layer")
                    .and_then(|l| l.parse::<i32>().ok())
                    .unwrap_or(0)
                    .max(0);

                // Record the layer for the way's start and end nodes.
                if !way.nodes.is_empty() {
                    let start = (way.nodes[0].x, way.nodes[0].z);
                    let end   = (way.nodes.last().unwrap().x, way.nodes.last().unwrap().z);
                    connectivity_map.entry(start).or_default().push(layer_value);
                    connectivity_map.entry(end).or_default().push(layer_value);
                }
            }
        }
    }
    connectivity_map
}

```

The function normalizes OSM `layer` tags by converting negative values to 0, ensuring that underground layers do not complicate the surface generation logic. Each highway way contributes its layer value to the start and end node coordinates, creating a comprehensive intersection registry.

## Storing and Passing Connectivity Data

In [`src/data_processing.rs`](https://github.com/louis-e/arnis/blob/main/src/data_processing.rs), the world generation pipeline constructs the connectivity map once before processing any elements. This single construction avoids redundant calculations and ensures consistent reference data throughout the generation phase.

```rust
// src/data_processing.rs (excerpt)
let highway_connectivity = highways::build_highway_connectivity_map(&elements);
// …later, for each element…
if way.tags.contains_key("highway") {
    highways::generate_highways(
        &mut editor,
        &element,
        args,
        &highway_connectivity,
        &flood_fill_cache,
    );
}

```

The `highway_connectivity` map is passed by reference to `generate_highways` for every highway element, allowing the generation logic to query intersection complexity without reprocessing the entire OSM dataset.

## Generating Highways with Elevation Logic

The `generate_highways` function in [`src/element_processing/highways.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/highways.rs) delegates to `generate_highways_internal`, which orchestrates the 3D road construction. This function uses the connectivity map to determine slope requirements, calculate elevations, and render physical road structures.

### Parsing Layer and Bridge Tags

The internal generator first extracts the `layer` tag, clamping values to a minimum of 0, and checks for `bridge` and `indoor` modifiers. The base elevation is computed as `layer * 6` blocks, establishing the vertical offset for the highway deck.

### Calculating Elevations and Slopes

For each highway endpoint, the generator calls `should_add_slope_at_node` to query the connectivity map. This helper returns `true` when the current way is the only highway at its layer for that coordinate, indicating that a ramp is required to connect to other layers or ground level.

```rust
// src/element_processing/highways.rs – slope helper
fn should_add_slope_at_node(
    node: &crate::osm_parser::ProcessedNode,
    current_layer: i32,
    highway_connectivity: &HashMap<(i32, i32), Vec<i32>>,
) -> bool {
    let coord = (node.x, node.z);

    // No connectivity data → add a slope whenever we're not on ground level.
    if highway_connectivity.is_empty() {
        return current_layer != 0;
    }

    // Look up other ways that meet this node.
    if let Some(layers) = highway_connectivity.get(&coord) {
        // Count how many ways share the same layer as this one.
        let same_layer = layers.iter().filter(|&&l| l == current_layer).count();
        // If we're the only way at this layer, we need a ramp.
        return same_layer <= 1 && current_layer != 0;
    }

    // No other ways → ramp needed if we're elevated.
    current_layer != 0
}

```

The `calculate_point_elevation` function interpolates height across the way length, applying slope transitions at start and end points when required. Slope length defaults to 35% of the total way length, clamped between 15 and 50 blocks to prevent excessive gradients.

### Rendering Road Surfaces and Support Structures

The generator uses Bresenham line algorithms to rasterize the road surface, adding lane stripes, outlines, and zebra crossings where appropriate. For elevated sections, it detects *valley bridges* by sampling terrain between endpoints; if the terrain dips more than `VALLEY_BRIDGE_THRESHOLD` (7 blocks), the generator uses a flat bridge deck rather than following terrain contours.

Support pillars are placed periodically under elevated sections using `add_highway_support_pillar` or `add_highway_support_pillar_absolute`, ensuring physical plausibility for multi-level road networks. For area highways marked with `area=yes`, the generator fills the entire polygon using the pre-computed `FloodFillCache`.

## Helper Functions for Connectivity Queries

The highway module provides several utilities that leverage the connectivity map:

- **`should_add_slope_at_node`** – Determines ramp necessity by checking if the current way is isolated at its layer for a given coordinate.
- **`calculate_way_length`** – Computes Euclidean distance between consecutive nodes, informing slope length calculations and bridge valley heuristics.
- **`calculate_point_elevation`** – Interpolates elevation across way points, applying slope transitions at endpoints when connectivity analysis indicates they are needed.

These helpers ensure that every highway segment integrates correctly with the surrounding road network, maintaining vertical consistency at intersections.

## Summary

- **Arnis pre-computes a connectivity map** using `build_highway_connectivity_map` in [`src/element_processing/highways.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/highways.rs), recording which highway layers exist at each (x, z) coordinate.
- **The map is built once** in [`src/data_processing.rs`](https://github.com/louis-e/arnis/blob/main/src/data_processing.rs) and passed by reference to all highway generation calls, ensuring consistent intersection handling.
- **Slope and elevation decisions** depend on `should_add_slope_at_node`, which queries the connectivity map to determine if a way is the only one at its layer for a given node.
- **Elevation calculation** uses `layer * 6` as a base, with slopes covering 35% of way length (clamped 15–50 blocks), and valley bridges triggered when terrain dips exceed 7 blocks.
- **Rendering** includes Bresenham line rasterization, support pillars for elevated sections, and flood-fill for area highways using the cached connectivity data.

## Frequently Asked Questions

### How does Arnis determine where to place highway slopes?

Arnis checks the connectivity map using `should_add_slope_at_node` to see if the current highway way is the only one at its specific layer for a given coordinate. If the way is isolated at an elevated layer (not ground level), the function returns `true` and the generator creates a slope at that endpoint to connect with other layers or the ground.

### What is the purpose of the highway connectivity map in Arnis?

The connectivity map serves as a lookup table that records which highway layers exist at every (x, z) coordinate where highways intersect or terminate. Built once before generation begins in [`src/data_processing.rs`](https://github.com/louis-e/arnis/blob/main/src/data_processing.rs), this `HashMap<(i32, i32), Vec<i32>>` allows the renderer to make informed decisions about elevation changes, slope placement, and bridge construction without re-parsing the entire OSM dataset for each highway segment.

### How does Arnis handle elevation calculations for multi-level highways?

Arnis calculates base elevation as `layer * 6` blocks, where the layer value is extracted from OSM tags and clamped to a minimum of 0. For slope transitions, the system uses `calculate_point_elevation` to interpolate heights across the way length, applying gradients at start and end points when the connectivity map indicates they are needed. Slope lengths default to 35% of the total way length but are clamped between 15 and 50 blocks to maintain realistic gradients.

### What triggers the creation of valley bridges versus standard elevated highways?

During generation, Arnis samples the terrain between highway endpoints to detect significant elevation drops. If the terrain dips more than `VALLEY_BRIDGE_THRESHOLD` (defined as 7 blocks) below the highway deck level, the generator switches from terrain-following mode to a flat bridge deck construction. This creates realistic valley bridges that span deep terrain cuts without following the valley floor, while support pillars are placed periodically underneath to maintain physical plausibility.