mirror of
https://github.com/louis-e/arnis.git
synced 2026-01-04 12:18:03 -05:00
Merge pull request #79 from scd31/world_scale
allow custom world scales
This commit is contained in:
@@ -29,6 +29,10 @@ pub struct Args {
|
||||
#[arg(long, default_value = "requests")]
|
||||
pub downloader: String,
|
||||
|
||||
/// World scale to use, in blocks per meter
|
||||
#[arg(long, default_value = "1.0")]
|
||||
pub scale: f64,
|
||||
|
||||
/// Enable debug mode (optional)
|
||||
#[arg(long, default_value_t = false, action = clap::ArgAction::SetTrue)]
|
||||
pub debug: bool,
|
||||
|
||||
@@ -116,36 +116,20 @@ fn lat_lon_to_minecraft_coords(
|
||||
lat: f64,
|
||||
lon: f64,
|
||||
bbox: (f64, f64, f64, f64), // (min_lon, min_lat, max_lon, max_lat)
|
||||
scale_factor_x: f64,
|
||||
scale_factor_z: f64,
|
||||
scale_factor_x: f64,
|
||||
) -> (i32, i32) {
|
||||
let (min_lon, min_lat, max_lon, max_lat) = bbox;
|
||||
|
||||
// Calculate the relative position within the bounding box
|
||||
let rel_x: f64 = 1.0 - (lat - min_lat) / (max_lat - min_lat);
|
||||
let rel_z: f64 = (lon - min_lon) / (max_lon - min_lon);
|
||||
let rel_x: f64 = (lon - min_lon) / (max_lon - min_lon);
|
||||
let rel_z: f64 = 1.0 - (lat - min_lat) / (max_lat - min_lat);
|
||||
|
||||
// Apply scaling factors for each dimension and convert to Minecraft coordinates
|
||||
let x: i32 = (rel_x * scale_factor_x) as i32;
|
||||
let z: i32 = (rel_z * scale_factor_z) as i32;
|
||||
|
||||
(z, x) // Swap x and z coords to avoid a mirrored projection on the Minecraft map
|
||||
}
|
||||
|
||||
/// Function to determine the number of decimal places in a float as a string
|
||||
fn count_decimal_places(value: f64) -> usize {
|
||||
let s: String = value.to_string();
|
||||
if let Some(pos) = s.find('.') {
|
||||
s.len() - pos - 1 // Number of digits after the decimal point
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Function to convert f64 to an integer based on the number of decimal places
|
||||
fn convert_to_scaled_int(value: f64, max_decimal_places: usize) -> i64 {
|
||||
let multiplier: i64 = 10_i64.pow(max_decimal_places as u32); // Compute multiplier
|
||||
(value * multiplier as f64).round() as i64 // Scale and convert to integer
|
||||
(x, z)
|
||||
}
|
||||
|
||||
pub fn parse_osm_data(
|
||||
@@ -159,40 +143,10 @@ pub fn parse_osm_data(
|
||||
let data: OsmData =
|
||||
serde_json::from_value(json_data.clone()).expect("Failed to parse OSM data");
|
||||
|
||||
// Calculate the maximum number of decimal places in bbox elements
|
||||
let max_decimal_places: usize = [
|
||||
count_decimal_places(bbox.0),
|
||||
count_decimal_places(bbox.1),
|
||||
count_decimal_places(bbox.2),
|
||||
count_decimal_places(bbox.3),
|
||||
]
|
||||
.into_iter()
|
||||
.max()
|
||||
.unwrap();
|
||||
|
||||
// Convert each element to a scaled integer
|
||||
let bbox_scaled: (i64, i64, i64, i64) = (
|
||||
convert_to_scaled_int(bbox.0, max_decimal_places),
|
||||
convert_to_scaled_int(bbox.1, max_decimal_places),
|
||||
convert_to_scaled_int(bbox.2, max_decimal_places),
|
||||
convert_to_scaled_int(bbox.3, max_decimal_places),
|
||||
);
|
||||
|
||||
// Determine which dimension is larger and assign scale factors accordingly
|
||||
let (scale_factor_x, scale_factor_z) =
|
||||
if (bbox_scaled.2 - bbox_scaled.0) > (bbox_scaled.3 - bbox_scaled.1) {
|
||||
// Longitude difference is greater than latitude difference
|
||||
(
|
||||
((bbox_scaled.3 - bbox_scaled.1) * 14 / 100) as f64, // Scale for width (x) is based on latitude difference
|
||||
((bbox_scaled.2 - bbox_scaled.0) * 10 / 100) as f64, // Scale for length (z) is based on longitude difference
|
||||
)
|
||||
} else {
|
||||
// Latitude difference is greater than or equal to longitude difference
|
||||
(
|
||||
((bbox_scaled.2 - bbox_scaled.0) * 14 / 100) as f64, // Scale for width (x) is based on longitude difference
|
||||
((bbox_scaled.3 - bbox_scaled.1) * 10 / 100) as f64, // Scale for length (z) is based on latitude difference
|
||||
)
|
||||
};
|
||||
let (scale_factor_z, scale_factor_x) = geo_distance(bbox.1, bbox.3, bbox.0, bbox.2);
|
||||
let scale_factor_z = scale_factor_z.floor() * args.scale;
|
||||
let scale_factor_x = scale_factor_x.floor() * args.scale;
|
||||
|
||||
if args.debug {
|
||||
println!("Scale factor X: {}", scale_factor_x);
|
||||
@@ -209,7 +163,7 @@ pub fn parse_osm_data(
|
||||
if element.r#type == "node" {
|
||||
if let (Some(lat), Some(lon)) = (element.lat, element.lon) {
|
||||
let (x, z) =
|
||||
lat_lon_to_minecraft_coords(lat, lon, bbox, scale_factor_x, scale_factor_z);
|
||||
lat_lon_to_minecraft_coords(lat, lon, bbox, scale_factor_z, scale_factor_x);
|
||||
|
||||
let processed = ProcessedNode {
|
||||
id: element.id,
|
||||
@@ -309,7 +263,7 @@ pub fn parse_osm_data(
|
||||
}));
|
||||
}
|
||||
|
||||
(processed_elements, scale_factor_z, scale_factor_x)
|
||||
(processed_elements, scale_factor_x, scale_factor_z)
|
||||
}
|
||||
|
||||
const PRIORITY_ORDER: [&str; 6] = [
|
||||
@@ -327,3 +281,36 @@ pub fn get_priority(element: &ProcessedElement) -> usize {
|
||||
// Return a default priority if none of the tags match
|
||||
PRIORITY_ORDER.len()
|
||||
}
|
||||
|
||||
// (lat meters, lon meters)
|
||||
fn geo_distance(lat1: f64, lat2: f64, lon1: f64, lon2: f64) -> (f64, f64) {
|
||||
let z = lat_distance(lat1, lat2);
|
||||
|
||||
// distance between two lons depends on their latitude. In this case we'll just average them
|
||||
let x = lon_distance((lat1 + lat2) / 2.0, lon1, lon2);
|
||||
|
||||
(z, x)
|
||||
}
|
||||
|
||||
// Haversine but optimized for a latitude delta of 0
|
||||
// returns meters
|
||||
fn lon_distance(lat: f64, lon1: f64, lon2: f64) -> f64 {
|
||||
const R: f64 = 6371_000.0;
|
||||
let d_lon = (lon2 - lon1).to_radians();
|
||||
let a =
|
||||
lat.to_radians().cos() * lat.to_radians().cos() * (d_lon / 2.0).sin() * (d_lon / 2.0).sin();
|
||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
|
||||
R * c
|
||||
}
|
||||
|
||||
// Haversine but optimized for a longitude delta of 0
|
||||
// returns meters
|
||||
fn lat_distance(lat1: f64, lat2: f64) -> f64 {
|
||||
const R: f64 = 6371_000.0;
|
||||
let d_lat = (lat2 - lat1).to_radians();
|
||||
let a = (d_lat / 2.0).sin() * (d_lat / 2.0).sin();
|
||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
|
||||
R * c
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user