From 8c9d0c46746598a2a708118d25364ec429e3fa16 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 12 Dec 2023 22:39:45 +0100 Subject: [PATCH] Require fewer steps and avoid being lossy when computing `up` --- src/geopos.rs | 26 ++++++++------------------ src/lib.rs | 6 +++--- src/player.rs | 36 ++++++++++++++++++++++++++++++++++++ src/tilemap.rs | 19 +++++++------------ src/tilemap/index.rs | 4 ++-- 5 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/geopos.rs b/src/geopos.rs index 75f6115..c5d7786 100644 --- a/src/geopos.rs +++ b/src/geopos.rs @@ -1,6 +1,5 @@ -use crate::{player::Position, tilemap::TileCoord, GalacticTransformOwned}; +use crate::{player::PlanetaryPosition, tilemap::TileCoord}; use bevy::prelude::*; -use big_space::FloatingOriginSettings; use glam::DVec3; use globe_rs::{CartesianPoint, GeographicPoint}; use std::f32::consts::PI; @@ -56,25 +55,16 @@ impl GeoPos { TileCoord::new(Vec2 { x, y }, zoom) } - /// Prefer using `to_cartesian`, which returns a [`Position`] that has a lot more convenience - /// methods. - pub fn to_cartesian_vec(self) -> DVec3 { + /// Compute the galactic position on the planet's surface. + pub fn to_cartesian(self) -> PlanetaryPosition { let geo = GeographicPoint::new( (self.lon as f64).to_radians(), (self.lat as f64).to_radians(), EARTH_RADIUS as f64, ); let cart = CartesianPoint::from_geographic(&geo); - DVec3::new(-cart.x(), -cart.y(), cart.z()) - } - - /// Compute the galactic position on the planet's surface. - pub fn to_cartesian(self, space: &FloatingOriginSettings) -> Position<'_> { - let pos = self.to_cartesian_vec(); - let (cell, pos) = space.translation_to_grid(pos); - let transform = Transform::from_translation(pos); - let pos = GalacticTransformOwned { transform, cell }; - Position { pos, space } + let pos = DVec3::new(-cart.x(), -cart.y(), cart.z()); + PlanetaryPosition { pos } } pub fn from_cartesian(pos: DVec3) -> Self { @@ -89,9 +79,9 @@ impl GeoPos { /// Tile width and height in meters pub fn tile_size(self, zoom: u8) -> Vec2 { let coord = self.to_tile_coordinates(zoom); - let pos = self.to_cartesian_vec(); - let x = coord.right().to_geo_pos().to_cartesian_vec().distance(pos) as f32; - let y = coord.down().to_geo_pos().to_cartesian_vec().distance(pos) as f32; + let pos = self.to_cartesian(); + let x = coord.right().to_geo_pos().to_cartesian().distance(*pos) as f32; + let y = coord.down().to_geo_pos().to_cartesian().distance(*pos) as f32; Vec2 { x, y } } } diff --git a/src/lib.rs b/src/lib.rs index 5563dbd..9af9775 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,8 +22,8 @@ use big_space::{ FloatingOriginPlugin, FloatingOriginSettings, GridCell, }; use geopos::{GeoPos, EARTH_RADIUS}; -use glam::DVec3; use http_assets::HttpAssetReaderPlugin; +use player::PlanetaryPosition; use tilemap::{TileIndex, TileMap, TILE_ZOOM}; mod flycam; @@ -45,7 +45,7 @@ type GalacticTransformItem<'a> = GridTransformItem<'a, GridPrecision>; #[derive(Resource)] struct Args { - starting_position: DVec3, + starting_position: PlanetaryPosition, height: f32, direction: f32, view: f32, @@ -103,7 +103,7 @@ pub fn main() { let mut app = App::new(); app.insert_resource(Args { - starting_position: pos.to_cartesian_vec(), + starting_position: pos.to_cartesian(), height, direction, view, diff --git a/src/player.rs b/src/player.rs index d8a1a23..b3679a1 100644 --- a/src/player.rs +++ b/src/player.rs @@ -27,6 +27,42 @@ pub struct Player<'w, 's> { pub(crate) space: Res<'w, FloatingOriginSettings>, } +/// A helper for working with positions relative to the planet center. +#[derive(Clone, Copy)] +pub struct PlanetaryPosition { + pub pos: DVec3, +} + +impl Into for PlanetaryPosition { + fn into(self) -> DVec3 { + self.pos + } +} + +impl std::ops::Deref for PlanetaryPosition { + type Target = DVec3; + + fn deref(&self) -> &Self::Target { + &self.pos + } +} + +impl PlanetaryPosition { + pub fn to_galactic_position(self, space: &FloatingOriginSettings) -> Position<'_> { + let (cell, pos) = space.translation_to_grid(self.pos); + let transform = Transform::from_translation(pos); + let pos = GalacticTransformOwned { transform, cell }; + Position { pos, space } + } + + pub fn directions(self) -> Directions { + let up = self.pos.normalize().as_vec3(); + let west = Vec3::Z.cross(up); + let north = up.cross(west); + Directions { up, north, west } + } +} + /// A helper for working with galactic positions. pub struct Position<'a> { pub pos: GalacticTransformOwned, diff --git a/src/tilemap.rs b/src/tilemap.rs index 3d6a063..feab86a 100644 --- a/src/tilemap.rs +++ b/src/tilemap.rs @@ -178,15 +178,10 @@ fn flat_tile( // Four corners of the tile in cartesian coordinates relative to the // planet's center. - let a = coord.to_geo_pos().to_cartesian_vec(); - let b = pos.right().as_coord().to_geo_pos().to_cartesian_vec(); - let c = pos - .down() - .right() - .as_coord() - .to_geo_pos() - .to_cartesian_vec(); - let d = pos.down().as_coord().to_geo_pos().to_cartesian_vec(); + let a = coord.to_geo_pos().to_cartesian(); + let b = pos.right().as_coord().to_geo_pos().to_cartesian(); + let c = pos.down().right().as_coord().to_geo_pos().to_cartesian(); + let d = pos.down().as_coord().to_geo_pos().to_cartesian(); // Normals on a sphere are just the position on the sphere normalized. let normals = vec![ @@ -197,9 +192,9 @@ fn flat_tile( ]; // `a` is our anchor point, all others are relative - let b = b - a; - let c = c - a; - let d = d - a; + let b = *b - *a; + let c = *c - *a; + let d = *d - *a; let (grid, a) = space.translation_to_grid(a); let b = a + b.as_vec3(); diff --git a/src/tilemap/index.rs b/src/tilemap/index.rs index a47f9f7..7051d9f 100644 --- a/src/tilemap/index.rs +++ b/src/tilemap/index.rs @@ -66,9 +66,9 @@ impl TileIndex { pub fn to_cartesian(self, space: &FloatingOriginSettings) -> GalacticTransformOwned { let coord = self.as_coord().center(); - let pos = coord.to_geo_pos().to_cartesian(space); + let pos = coord.to_geo_pos().to_cartesian(); let Directions { up, north, west: _ } = pos.directions(); - let mut pos = pos.pos; + let mut pos = pos.to_galactic_position(space).pos; pos.transform.look_to(north, up); pos }