Skip to content

Commit

Permalink
Merge pull request #259 from podusowski/position-mod
Browse files Browse the repository at this point in the history
position module
  • Loading branch information
podusowski authored Feb 22, 2025
2 parents 1ad2980 + 9067f73 commit dc7ed3e
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 79 deletions.
5 changes: 4 additions & 1 deletion walkers/src/center.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use egui::{Response, Vec2};

use crate::{map::AdjustedPosition, mercator::Pixels, Position};
use crate::{
position::{AdjustedPosition, Pixels},
Position,
};

/// Position at the map's center. Initially, the map follows `my_position` argument which typically
/// is meant to be fed by a GPS sensor or other geo-localization method. If user drags the map,
Expand Down
4 changes: 3 additions & 1 deletion walkers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ pub mod extras;
mod io;
mod map;
mod mercator;
mod position;
pub mod sources;
mod tiles;
mod zoom;

pub use download::{HeaderValue, HttpOptions};
pub use map::{Map, MapMemory, Plugin, Projector};
pub use mercator::{lat_lon, lon_lat, screen_to_position, Position, TileId};
pub use mercator::{screen_to_position, TileId};
pub use position::{lat_lon, lon_lat, Position};
pub use tiles::{HttpTiles, Texture, TextureWithUv, Tiles};
pub use zoom::InvalidZoom;
49 changes: 2 additions & 47 deletions walkers/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use egui::{Mesh, PointerButton, Rect, Response, Sense, Ui, UiBuilder, Vec2, Widg

use crate::{
center::Center,
mercator::{project, screen_to_position, tile_id, Pixels, PixelsExt, TileId},
mercator::{project, tile_id, TileId},
position::{AdjustedPosition, Pixels, PixelsExt},
tiles,
zoom::{InvalidZoom, Zoom},
Position, Tiles,
Expand Down Expand Up @@ -336,52 +337,6 @@ impl Widget for Map<'_, '_, '_> {
}
}

/// [`Position`] alone is not able to represent detached (e.g. after map gets dragged) position
/// due to insufficient accuracy.
#[derive(Debug, Clone, PartialEq)]
pub struct AdjustedPosition {
/// Base geographical position.
pub position: Position,

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

impl AdjustedPosition {
pub(crate) fn new(position: Position, offset: Pixels) -> Self {
Self { position, offset }
}

/// Calculate the real position, i.e. including the offset.
pub(crate) fn position(&self, zoom: f64) -> Position {
screen_to_position(project(self.position, zoom) - self.offset, zoom)
}

/// Recalculate `position` so that `offset` is zero.
pub(crate) fn zero_offset(self, zoom: f64) -> Self {
Self {
position: screen_to_position(project(self.position, zoom) - self.offset, zoom),
offset: Default::default(),
}
}

pub(crate) fn shift(self, offset: Vec2) -> Self {
Self {
position: self.position,
offset: self.offset + Pixels::new(offset.x as f64, offset.y as f64),
}
}
}

impl From<Position> for AdjustedPosition {
fn from(position: Position) -> Self {
Self {
position,
offset: Default::default(),
}
}
}

/// State of the map widget which must persist between frames.
#[derive(Debug, Default, Clone)]
pub struct MapMemory {
Expand Down
37 changes: 7 additions & 30 deletions walkers/src/mercator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,17 @@
//! <https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames>
//! <https://www.netzwolf.info/osm/tilebrowser.html?lat=51.157800&lon=6.865500&zoom=14>
use crate::{
lon_lat,
position::{Pixels, Position},
};
use std::f64::consts::PI;

// zoom level tile coverage number of tiles tile size(*) in degrees
// 0 1 tile 1 tile 360° x 170.1022°
// 1 2 × 2 tiles 4 tiles 180° x 85.0511°
// 2 4 × 4 tiles 16 tiles 90° x [variable]

/// Geographical position with latitude and longitude.
pub type Position = geo_types::Point;

/// Construct `Position` from latitude and longitude.
pub fn lat_lon(lat: f64, lon: f64) -> Position {
Position::new(lon, lat)
}

/// Construct `Position` from longitude and latitude. Note that it is common standard to write
/// coordinates starting with the latitude instead (e.g. `51.104465719934176, 17.075169894118684` is
/// the [Wrocław's zoo](https://zoo.wroclaw.pl/en/)).
pub fn lon_lat(lon: f64, lat: f64) -> Position {
Position::new(lon, lat)
}

/// Zoom specifies how many pixels are in the whole map. For example, zoom 0 means that the whole
/// map is just one 256x256 tile, zoom 1 means that it is 2x2 tiles, and so on.
pub(crate) fn total_pixels(zoom: f64) -> f64 {
Expand All @@ -36,21 +27,6 @@ pub fn total_tiles(zoom: u8) -> u32 {
/// Size of a single tile in pixels. Walkers uses 256px tiles as most of the tile sources do.
const TILE_SIZE: u32 = 256;

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

use std::f64::consts::PI;

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)
}
}

/// Project the position into the Mercator projection and normalize it to 0-1 range.
fn mercator_normalized(position: Position) -> (f64, f64) {
// Project into Mercator (cylindrical map projection).
Expand Down Expand Up @@ -160,6 +136,7 @@ pub fn screen_to_position(pixels: Pixels, zoom: f64) -> Position {
#[cfg(test)]
mod tests {
use super::*;
use crate::lat_lon;

#[test]
fn projecting_position_and_tile() {
Expand Down
78 changes: 78 additions & 0 deletions walkers/src/position.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//! Types and functions for working with positions.
use crate::{mercator::project, screen_to_position};
use egui::Vec2;

/// Geographical position with latitude and longitude.
pub type Position = geo_types::Point;

/// Construct `Position` from latitude and longitude.
pub fn lat_lon(lat: f64, lon: f64) -> Position {
Position::new(lon, lat)
}

/// Construct `Position` from longitude and latitude. Note that it is common standard to write
/// coordinates starting with the latitude instead (e.g. `51.104465719934176, 17.075169894118684` is
/// the [Wrocław's zoo](https://zoo.wroclaw.pl/en/)).
pub fn lon_lat(lon: f64, lat: f64) -> Position {
Position::new(lon, lat)
}

/// [`Position`] alone is not able to represent detached (e.g. after map gets dragged) position
/// due to insufficient accuracy.
#[derive(Debug, Clone, PartialEq)]
pub struct AdjustedPosition {
/// Base geographical position.
pub position: Position,

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

impl AdjustedPosition {
pub(crate) fn new(position: Position, offset: Pixels) -> Self {
Self { position, offset }
}

/// Calculate the real position, i.e. including the offset.
pub(crate) fn position(&self, zoom: f64) -> Position {
screen_to_position(project(self.position, zoom) - self.offset, zoom)
}

/// Recalculate `position` so that `offset` is zero.
pub(crate) fn zero_offset(self, zoom: f64) -> Self {
Self {
position: screen_to_position(project(self.position, zoom) - self.offset, zoom),
offset: Default::default(),
}
}

pub(crate) fn shift(self, offset: Vec2) -> Self {
Self {
position: self.position,
offset: self.offset + Pixels::new(offset.x as f64, offset.y as f64),
}
}
}

impl From<Position> for AdjustedPosition {
fn from(position: Position) -> Self {
Self {
position,
offset: Default::default(),
}
}
}

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

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)
}
}

0 comments on commit dc7ed3e

Please sign in to comment.