How CoordTransformer Converts Geographic Latitude and Longitude to Minecraft XZ Coordinates in Arnis

CoordTransformer converts geographic latitude and longitude to Minecraft XZ coordinates by calculating relative positions within a geographic bounding box and scaling them by ground distance factors to produce Minecraft block coordinates.

Arnis is an open-source project that generates Minecraft worlds from real-world OpenStreetMap data. The CoordTransformer module in src/coordinate_system/transformation.rs handles the critical task to convert geographic latitude and longitude to Minecraft XZ coordinates, bridging real-world geographic data with Minecraft's Cartesian plane.

The Three-Stage Conversion Process

The transformation operates in three distinct stages: initializing the transformer with geographic bounds, computing relative positions and scale factors, and transforming individual points to Minecraft XZ coordinates.

Stage 1: Initializing the Transformer with Geographic Bounds

The process begins with CoordTransformer::llbbox_to_xzbbox, which takes an LLBBox (latitude/longitude bounding box) and a user-defined scale factor. This method establishes the transformation parameters by:

  • Using geo_distance to compute the ground distance in meters between the bounding box's opposite corners for both latitude (north-south) and longitude (east-west) axes.
  • Multiplying these distances by the scale factor to create scale_factor_x and scale_factor_z, which represent how many Minecraft blocks correspond to real-world meters.
  • Storing the bounding box dimensions (len_lat, len_lng) and minimum corner coordinates (min_lat, min_lng) for subsequent relative calculations.
// src/coordinate_system/transformation.rs#L23-L50
pub fn llbbox_to_xzbbox(
    llbbox: &LLBBox,
    scale: f64,
) -> Result<(CoordTransformer, XZBBox), String> {
    let (scale_factor_z, scale_factor_x) = geo_distance(llbbox.min(), llbbox.max());
    let scale_factor_z: f64 = scale_factor_z.floor() * scale;
    let scale_factor_x: f64 = scale_factor_x.floor() * scale;
    // ...
    Ok((
        Self {
            len_lat: llbbox.max().lat() - llbbox.min().lat(),
            len_lng: llbbox.max().lng() - llbbox.min().lng(),
            scale_factor_x,
            scale_factor_z,
            min_lat: llbbox.min().lat(),
            min_lng: llbbox.min().lng(),
        },
        xzbbox,
    ))
}

Stage 2: Computing Relative Positions and Scale Factors

Once the transformer is initialized, it retains the geographic bounds and scale factors. The scale_factor_x corresponds to the east-west (longitude) axis, while scale_factor_z corresponds to the north-south (latitude) axis. These factors convert real-world meter distances into Minecraft block counts based on the user-provided scale.

Stage 3: Transforming Individual Points to Minecraft XZ

The CoordTransformer::transform_point method converts individual LLPoint instances to XZPoint coordinates through relative positioning:

  1. Calculate relative position: Compute where the point lies within the bounding box as a percentage (0.0 to 1.0) of the total width and height.
  2. Invert the Z-axis: Subtract the latitude percentage from 1.0 because Minecraft's Z-axis increases southward while latitude increases northward.
  3. Apply scale factors: Multiply the relative positions by scale_factor_x and scale_factor_z to obtain Minecraft block coordinates.
  4. Convert to integers: Cast the results to i32 to produce discrete block positions.
// src/coordinate_system/transformation.rs#L53-L62
pub fn transform_point(&self, llpoint: LLPoint) -> XZPoint {
    let rel_x: f64 = (llpoint.lng() - self.min_lng) / self.len_lng;
    let rel_z: f64 = 1.0 - (llpoint.lat() - self.min_lat) / self.len_lat;
    let x: i32 = (rel_x * self.scale_factor_x) as i32;
    let z: i32 = (rel_z * self.scale_factor_z) as i32;
    XZPoint::new(x, z)
}

Implementation Details and Code Structure

The llbbox_to_xzbbox Method

This constructor method in src/coordinate_system/transformation.rs serves as the entry point for creating a coordinate transformer. It validates the geographic bounding box and computes the scale factors using the Haversine-based geo_distance function to determine real-world distances between coordinates.

The transform_point Method

This method performs the actual coordinate conversion. It handles the axis inversion necessary to reconcile geographic coordinate systems (where latitude increases northward) with Minecraft's coordinate system (where Z decreases northward). The method returns an XZPoint containing i32 values suitable for Minecraft block placement.

Legacy Compatibility Function

The codebase maintains lat_lon_to_minecraft_coords as a standalone function for backward compatibility and verification purposes. The test suite asserts that transform_point produces identical results to this legacy implementation, ensuring functional equivalence while providing a more object-oriented interface.

// src/coordinate_system/transformation.rs#L99-L120
pub fn lat_lon_to_minecraft_coords(
    lat: f64,
    lon: f64,
    bbox: LLBBox,
    scale_factor_z: f64,
    scale_factor_x: f64,
) -> (i32, i32) {
    // Legacy implementation for comparison
}

Practical Usage Example

The following example demonstrates how to initialize a CoordTransformer and convert geographic coordinates to Minecraft XZ coordinates:

use arnis::coordinate_system::{
    geographic::{LLBBox, LLPoint},
    transformation::CoordTransformer,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Define the geographic area to map (e.g., Munich city centre)
    let llbbox = LLBBox::new(
        LLPoint::new(48.1351, 11.5760)?, // min lat, min lng
        LLPoint::new(48.1551, 11.5960)?, // max lat, max lng
    )?;

    // Build a transformer with a desired scale (1 Minecraft block ≈ 1 metre)
    let scale = 1.0;
    let (transformer, _xz_bbox) = CoordTransformer::llbbox_to_xzbbox(&llbbox, scale)?;

    // Convert a latitude/longitude inside the bbox to Minecraft X‑Z
    let point = LLPoint::new(48.1450, 11.5860)?;
    let xz = transformer.transform_point(point);

    println!("Minecraft coordinates: X = {}, Z = {}", xz.x, xz.z);
    Ok(())
}

You can also verify the results using the legacy helper function:

let (scale_factor_z, scale_factor_x) = arnis::coordinate_system::transformation::geo_distance(
    llbbox.min(),
    llbbox.max(),
);
let (x, z) = arnis::coordinate_system::transformation::lat_lon_to_minecraft_coords(
    point.lat(),
    point.lng(),
    llbbox,
    scale_factor_z.floor() * scale,
    scale_factor_x.floor() * scale,
);
assert_eq!((xz.x, xz.z), (x, z));

Key Source Files

File Role
src/coordinate_system/transformation.rs Contains CoordTransformer, llbbox_to_xzbbox, transform_point, distance helpers, and the legacy conversion function.
src/coordinate_system/geographic/llpoint.rs Represents a single latitude/longitude point (LLPoint).
src/coordinate_system/geographic/llbbox.rs Bounding-box wrapper (LLBBox) used to define the geographic extents.
src/coordinate_system/cartesian/xzpoint.rs Simple struct for Minecraft X‑Z coordinates (XZPoint).
src/coordinate_system/cartesian/xzbbox/mod.rs Defines the Minecraft‑world bounding box (XZBBox).

These components together enable Arnis to map real-world map data onto Minecraft worlds with precise, reproducible coordinate transformations.

Summary

  • CoordTransformer serves as the core engine to convert geographic latitude and longitude to Minecraft XZ coordinates in the Arnis project.
  • The three-stage process involves initializing the transformer with a geographic bounding box, computing ground distance scale factors using geo_distance, and applying relative positioning calculations via transform_point.
  • Axis inversion is handled automatically: latitude increases northward in geographic coordinates, but the Z-axis increases southward in Minecraft, requiring the 1.0 - relative_lat calculation.
  • transform_point returns i32 block coordinates directly suitable for Minecraft world generation.
  • Legacy compatibility is maintained through lat_lon_to_minecraft_coords, which validates the modern implementation against historical behavior.

Frequently Asked Questions

How does CoordTransformer handle the scale factor between real-world meters and Minecraft blocks?

The scale factor is applied during the initialization phase in llbbox_to_xzbbox. The method calculates the ground distance in meters between the geographic bounding box corners using geo_distance, then multiplies these distances by the user-provided scale parameter to produce scale_factor_x and scale_factor_z. A scale of 1.0 means one Minecraft block equals approximately one real-world meter.

Why does the Z coordinate calculation subtract the relative latitude from 1.0?

Minecraft's coordinate system defines the Z-axis as positive toward the south, while geographic latitude increases toward the north. To reconcile these opposing directions, transform_point calculates the relative position as (lat - min_lat) / len_lat, then inverts it with 1.0 - relative_lat. This ensures that northern geographic coordinates map to lower Z values in Minecraft, maintaining correct directional orientation.

Can I use the legacy conversion function instead of CoordTransformer?

Yes, the legacy function lat_lon_to_minecraft_coords remains available in src/coordinate_system/transformation.rs for backward compatibility. However, the modern CoordTransformer approach is recommended because it encapsulates the bounding box and scale factors within a reusable struct, eliminating the need to pass these parameters repeatedly for each point conversion. The test suite verifies that both methods produce identical results.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →