Skip to content

Commit

Permalink
Merge pull request #65 from dwuertz/fix-high-zoom
Browse files Browse the repository at this point in the history
Use f64 for screen projection calculations (fixes #63)
  • Loading branch information
podusowski authored Nov 12, 2023
2 parents a1e91e9 + e188e0b commit 851961d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 22 deletions.
24 changes: 13 additions & 11 deletions walkers/src/map.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::collections::{hash_map::Entry, HashMap};

use egui::{Context, Mesh, Painter, Pos2, Rect, Response, Sense, Ui, Vec2, Widget};
use egui::{Context, Mesh, Painter, Rect, Response, Sense, Ui, Vec2, Widget};

use crate::{
mercator::{screen_to_position, PositionExt, TileId},
mercator::{screen_to_position, Pixels, PixelsExt, PositionExt, TileId},
tiles,
zoom::{InvalidZoom, Zoom},
Position, Tiles,
Expand Down Expand Up @@ -83,7 +83,8 @@ impl Projector {
.project(self.memory.zoom.round());

// From the two points above we can calculate the actual point on the screen.
self.clip_rect.center() + projected_position.to_vec2() - map_center_projected_position
self.clip_rect.center().to_vec2()
+ (projected_position - map_center_projected_position).to_vec2()
}
}

Expand Down Expand Up @@ -165,7 +166,7 @@ pub struct AdjustedPosition {
position: Position,

/// Offset in pixels.
offset: Vec2,
offset: Pixels,
}

impl AdjustedPosition {
Expand All @@ -178,7 +179,7 @@ impl AdjustedPosition {
fn zero_offset(self, zoom: u8) -> Self {
Self {
position: screen_to_position(self.position.project(zoom) - self.offset, zoom),
offset: Vec2::ZERO,
offset: Default::default(),
}
}
}
Expand Down Expand Up @@ -210,7 +211,7 @@ impl Center {
let position = match &self {
Center::MyPosition => AdjustedPosition {
position: my_position,
offset: Vec2::ZERO,
offset: Default::default(),
},
Center::Exact(position) | Center::Inertia { position, .. } => position.to_owned(),
};
Expand All @@ -233,7 +234,8 @@ impl Center {
*self = if amount <= &mut 0.0 {
Center::Exact(position.to_owned())
} else {
let offset = position.offset + (*direction * *amount);
let delta = *direction * *amount;
let offset = position.offset + Pixels::new(delta.x as f64, delta.y as f64);

Center::Inertia {
position: AdjustedPosition {
Expand Down Expand Up @@ -314,7 +316,7 @@ impl MapMemory {
pub fn center_at(&mut self, position: Position) {
self.center_mode = Center::Exact(AdjustedPosition {
position,
offset: Vec2::ZERO,
offset: Default::default(),
});
}

Expand All @@ -328,14 +330,14 @@ impl MapMemory {
fn flood_fill_tiles(
painter: &Painter,
tile_id: TileId,
map_center_projected_position: Pos2,
map_center_projected_position: Pixels,
tiles: &mut Tiles,
ui: &mut Ui,
meshes: &mut HashMap<TileId, Option<Mesh>>,
) {
let tile_projected = tile_id.project();
let tile_screen_position = painter.clip_rect().center().to_vec2() + tile_projected.to_vec2()
- map_center_projected_position.to_vec2();
let tile_screen_position = painter.clip_rect().center().to_vec2()
+ (tile_projected - map_center_projected_position).to_vec2();

if painter
.clip_rect()
Expand Down
31 changes: 20 additions & 11 deletions walkers/src/mercator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
pub type Position = geo_types::Point;

/// Location projected on the screen or an abstract bitmap.
pub type Pixels = Pos2;
pub type Pixels = geo_types::Point;

use egui::Pos2;
use std::f64::consts::PI;

pub trait PositionExt {
Expand All @@ -25,6 +24,16 @@ pub trait PositionExt {
fn tile_id(&self, zoom: u8) -> TileId;
}

pub trait PixelsExt {
fn to_vec2(&self) -> egui::Vec2;
}

impl PixelsExt for Pixels {
fn to_vec2(&self) -> egui::Vec2 {
egui::Vec2::new(self.x() as f32, self.y() as f32)
}
}

/// Size of the tiles used by the services like the OSM.
pub(crate) const TILE_SIZE: u32 = 256;

Expand All @@ -49,7 +58,7 @@ impl PositionExt for Position {
let x = x * number_of_pixels as f64;
let y = y * number_of_pixels as f64;

Pixels::new(x as f32, y as f32)
Pixels::new(x, y)
}

fn tile_id(&self, zoom: u8) -> TileId {
Expand Down Expand Up @@ -81,7 +90,7 @@ pub struct TileId {
impl TileId {
/// Tile position (in pixels) on the "World bitmap".
pub fn project(&self) -> Pixels {
Pixels::new((self.x * TILE_SIZE) as f32, (self.y * TILE_SIZE) as f32)
Pixels::new((self.x * TILE_SIZE) as f64, (self.y * TILE_SIZE) as f64)
}

pub fn east(&self) -> Option<TileId> {
Expand Down Expand Up @@ -122,12 +131,12 @@ pub fn screen_to_position(pixels: Pixels, zoom: u8) -> Position {
let number_of_pixels = 2u32.pow(zoom as u32) * TILE_SIZE;
let number_of_pixels: f64 = number_of_pixels.into();

let lon = pixels.x as f64;
let lon = pixels.x();
let lon = lon / number_of_pixels;
let lon = (lon * 2. - 1.) * PI;
let lon = lon.to_degrees();

let lat = pixels.y as f64;
let lat = pixels.y();
let lat = lat / number_of_pixels;
let lat = (-lat * 2. + 1.) * PI;
let lat = lat.sinh().atan().to_degrees();
Expand Down Expand Up @@ -156,16 +165,16 @@ mod tests {

// Projected tile is just its x, y multiplied by the size of tiles.
assert_eq!(
Pos2::new(36590. * 256., 21569. * 256.),
Pixels::new(36590. * 256., 21569. * 256.),
citadel.tile_id(zoom).project()
);

// Projected Citadel position should be somewhere near projected tile, shifted only by the
// position on the tile.
assert_eq!(
Pixels::new(36590. * 256. + 252., 21569. * 256. + 7.5),
citadel.project(zoom)
);
let calculated = citadel.project(zoom);
let citadel_proj = Pixels::new(36590. * 256. + 252., 21569. * 256. + 7.5);
approx::assert_relative_eq!(calculated.x(), citadel_proj.x(), max_relative = 0.5);
approx::assert_relative_eq!(calculated.y(), citadel_proj.y(), max_relative = 0.5);
}

#[test]
Expand Down

0 comments on commit 851961d

Please sign in to comment.