mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
parent
0b9404a518
commit
1934555013
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run demo (debug+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -p maplibre-demo --features trace" />
|
||||
<configuration default="false" name="Run headed demo (debug+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -p maplibre-demo --features trace -- headed" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run demo (release+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -p maplibre-demo --release --features trace" />
|
||||
<configuration default="false" name="Run headed demo (release+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -p maplibre-demo --release --features trace -- headed" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
@ -23,3 +23,5 @@ tracing = "0.1.35"
|
||||
tracing-subscriber = { version = "0.3.14", optional = true }
|
||||
tracing-tracy = { version = "0.8", optional = true }
|
||||
tracy-client = { version = "0.12.7", optional = true }
|
||||
|
||||
clap = { version = "3.2.12", features = ["derive"] }
|
||||
|
||||
16
maplibre-demo/src/headed.rs
Normal file
16
maplibre-demo/src/headed.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use maplibre::{
|
||||
platform::{http_client::ReqwestHttpClient, schedule_method::TokioScheduleMethod},
|
||||
MapBuilder,
|
||||
};
|
||||
use maplibre_winit::winit::WinitMapWindowConfig;
|
||||
|
||||
pub async fn run_headed() {
|
||||
MapBuilder::new()
|
||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||
.with_http_client(ReqwestHttpClient::new(None))
|
||||
.with_schedule_method(TokioScheduleMethod::new())
|
||||
.build()
|
||||
.initialize()
|
||||
.await
|
||||
.run()
|
||||
}
|
||||
55
maplibre-demo/src/headless.rs
Normal file
55
maplibre-demo/src/headless.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use maplibre::{
|
||||
coords::{LatLon, WorldTileCoords},
|
||||
error::Error,
|
||||
headless::HeadlessMapWindowConfig,
|
||||
platform::{http_client::ReqwestHttpClient, schedule_method::TokioScheduleMethod},
|
||||
render::settings::{RendererSettings, TextureFormat},
|
||||
util::grid::google_mercator,
|
||||
window::WindowSize,
|
||||
MapBuilder,
|
||||
};
|
||||
use tile_grid::{extent_wgs84_to_merc, Extent, GridIterator};
|
||||
|
||||
pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
|
||||
let mut map = MapBuilder::new()
|
||||
.with_map_window_config(HeadlessMapWindowConfig {
|
||||
size: WindowSize::new(tile_size, tile_size).unwrap(),
|
||||
})
|
||||
.with_http_client(ReqwestHttpClient::new(None))
|
||||
.with_schedule_method(TokioScheduleMethod::new())
|
||||
.with_renderer_settings(RendererSettings {
|
||||
texture_format: TextureFormat::Rgba8UnormSrgb,
|
||||
..RendererSettings::default()
|
||||
})
|
||||
.build()
|
||||
.initialize_headless()
|
||||
.await;
|
||||
|
||||
let tile_limits = google_mercator().tile_limits(
|
||||
extent_wgs84_to_merc(&Extent {
|
||||
minx: min.longitude,
|
||||
miny: min.latitude,
|
||||
maxx: max.longitude,
|
||||
maxy: max.latitude,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
for (z, x, y) in GridIterator::new(10, 10, tile_limits) {
|
||||
let coords = WorldTileCoords::from((x as i32, y as i32, z.into()));
|
||||
println!("Rendering {}", &coords);
|
||||
map.map_schedule
|
||||
.fetch_process(&coords)
|
||||
.await
|
||||
.expect("Failed to fetch and process!");
|
||||
|
||||
match map.map_schedule_mut().update_and_redraw() {
|
||||
Ok(_) => {}
|
||||
Err(Error::Render(e)) => {
|
||||
eprintln!("{}", e);
|
||||
if e.should_exit() {}
|
||||
}
|
||||
e => eprintln!("{:?}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,31 +1,12 @@
|
||||
use std::collections::HashSet;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
use maplibre::{
|
||||
benchmarking::tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||
coords::{TileCoords, ViewRegion, WorldTileCoords, ZoomLevel},
|
||||
error::Error,
|
||||
headless::{utils::HeadlessPipelineProcessor, HeadlessMapWindowConfig},
|
||||
io::{
|
||||
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
||||
source_client::{HttpClient, HttpSourceClient},
|
||||
tile_pipelines::build_vector_tile_pipeline,
|
||||
tile_repository::StoredLayer,
|
||||
RawLayer, TileRequest,
|
||||
},
|
||||
platform::{
|
||||
http_client::ReqwestHttpClient, run_multithreaded, schedule_method::TokioScheduleMethod,
|
||||
},
|
||||
render::{
|
||||
settings::{RendererSettings, TextureFormat},
|
||||
ShaderVertex,
|
||||
},
|
||||
style::source::TileAddressingScheme,
|
||||
util::{grid::google_mercator, math::Aabb2},
|
||||
window::{EventLoop, WindowSize},
|
||||
MapBuilder,
|
||||
};
|
||||
use maplibre_winit::winit::WinitMapWindowConfig;
|
||||
use tile_grid::{extent_wgs84_to_merc, Extent, GridIterator};
|
||||
use clap::{builder::ValueParser, Parser, Subcommand};
|
||||
use maplibre::{coords::LatLon, platform::run_multithreaded};
|
||||
|
||||
use crate::{headed::run_headed, headless::run_headless};
|
||||
|
||||
mod headed;
|
||||
mod headless;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
fn enable_tracing() {
|
||||
@ -36,63 +17,46 @@ fn enable_tracing() {
|
||||
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
||||
}
|
||||
|
||||
fn run_in_window() {
|
||||
run_multithreaded(async {
|
||||
MapBuilder::new()
|
||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||
.with_http_client(ReqwestHttpClient::new(None))
|
||||
.with_schedule_method(TokioScheduleMethod::new())
|
||||
.build()
|
||||
.initialize()
|
||||
.await
|
||||
.run()
|
||||
})
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[clap(propagate_version = true)]
|
||||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
fn run_headless() {
|
||||
run_multithreaded(async {
|
||||
let mut map = MapBuilder::new()
|
||||
.with_map_window_config(HeadlessMapWindowConfig {
|
||||
size: WindowSize::new(1000, 1000).unwrap(),
|
||||
})
|
||||
.with_http_client(ReqwestHttpClient::new(None))
|
||||
.with_schedule_method(TokioScheduleMethod::new())
|
||||
.with_renderer_settings(RendererSettings {
|
||||
texture_format: TextureFormat::Rgba8UnormSrgb,
|
||||
..RendererSettings::default()
|
||||
})
|
||||
.build()
|
||||
.initialize_headless()
|
||||
.await;
|
||||
fn parse_lat_long(env: &str) -> Result<LatLon, std::io::Error> {
|
||||
let split = env.split(',').collect::<Vec<_>>();
|
||||
if let (Some(latitude), Some(longitude)) = (split.get(0), split.get(1)) {
|
||||
Ok(LatLon::new(
|
||||
latitude.parse::<f64>().unwrap(),
|
||||
longitude.parse::<f64>().unwrap(),
|
||||
))
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"Failed to parse latitude and longitude.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
let tile_limits = google_mercator().tile_limits(
|
||||
extent_wgs84_to_merc(&Extent {
|
||||
minx: 11.3475219363,
|
||||
miny: 48.0345697188,
|
||||
maxx: 11.7917815798,
|
||||
maxy: 48.255861,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
for (z, x, y) in GridIterator::new(10, 10, tile_limits) {
|
||||
let coords = WorldTileCoords::from((x as i32, y as i32, z.into()));
|
||||
println!("Rendering {}", &coords);
|
||||
map.map_schedule
|
||||
.fetch_process(&coords)
|
||||
.await
|
||||
.expect("Failed to fetch and process!");
|
||||
|
||||
match map.map_schedule_mut().update_and_redraw() {
|
||||
Ok(_) => {}
|
||||
Err(Error::Render(e)) => {
|
||||
eprintln!("{}", e);
|
||||
if e.should_exit() {}
|
||||
}
|
||||
e => eprintln!("{:?}", e),
|
||||
};
|
||||
}
|
||||
})
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Headed {},
|
||||
Headless {
|
||||
#[clap(default_value_t = 400)]
|
||||
tile_size: u32,
|
||||
#[clap(
|
||||
value_parser = ValueParser::new(parse_lat_long),
|
||||
default_value_t = LatLon::new(48.0345697188, 11.3475219363)
|
||||
)]
|
||||
min: LatLon,
|
||||
#[clap(
|
||||
value_parser = ValueParser::new(parse_lat_long),
|
||||
default_value_t = LatLon::new(48.255861, 11.7917815798)
|
||||
)]
|
||||
max: LatLon,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -101,6 +65,20 @@ fn main() {
|
||||
#[cfg(feature = "trace")]
|
||||
enable_tracing();
|
||||
|
||||
//run_headless();
|
||||
run_in_window();
|
||||
let cli = Cli::parse();
|
||||
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level cmd
|
||||
match &cli.command {
|
||||
Commands::Headed {} => {
|
||||
run_multithreaded(async { run_headed().await });
|
||||
}
|
||||
Commands::Headless {
|
||||
tile_size,
|
||||
min,
|
||||
max,
|
||||
} => {
|
||||
run_multithreaded(async { run_headless(*tile_size, *min, *max).await });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,15 +20,14 @@ pub struct ViewState {
|
||||
impl ViewState {
|
||||
pub fn new<P: Into<cgmath::Rad<f64>>>(
|
||||
window_size: &WindowSize,
|
||||
position: WorldCoords,
|
||||
zoom: Zoom,
|
||||
center: LatLon,
|
||||
pitch: f64,
|
||||
fovy: P,
|
||||
) -> Self {
|
||||
let tile_center = TILE_SIZE / 2.0;
|
||||
let fovy = fovy.into();
|
||||
let height = tile_center / (fovy / 2.0).tan();
|
||||
let position = WorldCoords::from_lat_lon(center, zoom);
|
||||
|
||||
let camera = Camera::new(
|
||||
(position.x, position.y, height),
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
//! Provides utilities related to coordinates.
|
||||
|
||||
use std::{f64::consts::PI, fmt};
|
||||
use std::{
|
||||
f64::consts::PI,
|
||||
fmt,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
|
||||
use cgmath::{num_traits::Pow, AbsDiffEq, Matrix4, Point3, Vector3};
|
||||
|
||||
@ -112,17 +116,32 @@ impl Into<u8> for ZoomLevel {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct LatLon(f64, f64);
|
||||
pub struct LatLon {
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
}
|
||||
|
||||
impl LatLon {
|
||||
pub fn new(latitude: f64, longitude: f64) -> Self {
|
||||
LatLon(latitude, longitude)
|
||||
LatLon {
|
||||
latitude,
|
||||
longitude,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LatLon {
|
||||
fn default() -> Self {
|
||||
LatLon(0.0, 0.0)
|
||||
LatLon {
|
||||
latitude: 0.0,
|
||||
longitude: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LatLon {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{},{}", self.latitude, self.longitude)
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,10 +496,10 @@ impl WorldCoords {
|
||||
pub fn from_lat_lon(lat_lon: LatLon, zoom: Zoom) -> WorldCoords {
|
||||
let tile_size = TILE_SIZE * 2.0_f64.powf(zoom.0);
|
||||
// Get x value
|
||||
let x = (lat_lon.1 + 180.0) * (tile_size / 360.0);
|
||||
let x = (lat_lon.longitude + 180.0) * (tile_size / 360.0);
|
||||
|
||||
// Convert from degrees to radians
|
||||
let lat_rad = (lat_lon.0 * PI) / 180.0;
|
||||
let lat_rad = (lat_lon.latitude * PI) / 180.0;
|
||||
|
||||
// get y value
|
||||
let merc_n = f64::ln(f64::tan((PI / 4.0) + (lat_rad / 2.0)));
|
||||
|
||||
@ -13,7 +13,7 @@ use wgpu::{BufferAsyncError, BufferSlice};
|
||||
|
||||
use crate::{
|
||||
context::{MapContext, ViewState},
|
||||
coords::{LatLon, ViewRegion, WorldTileCoords, Zoom},
|
||||
coords::{LatLon, ViewRegion, WorldCoords, WorldTileCoords, Zoom, TILE_SIZE},
|
||||
error::Error,
|
||||
headless::utils::HeadlessPipelineProcessor,
|
||||
io::{
|
||||
@ -114,12 +114,9 @@ where
|
||||
) -> Self {
|
||||
let view_state = ViewState::new(
|
||||
&window_size,
|
||||
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
|
||||
style
|
||||
.center
|
||||
.map(|center| LatLon::new(center[0], center[1]))
|
||||
.unwrap_or_default(),
|
||||
style.pitch.unwrap_or_default(),
|
||||
WorldCoords::from((TILE_SIZE / 2., TILE_SIZE / 2.)),
|
||||
Zoom::default(),
|
||||
0.0,
|
||||
cgmath::Deg(110.0),
|
||||
);
|
||||
let tile_repository = TileRepository::new();
|
||||
@ -210,6 +207,8 @@ where
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
self.map_context.tile_repository.clear();
|
||||
|
||||
while let Some(layer) = processor.layers.pop() {
|
||||
self.map_context
|
||||
.tile_repository
|
||||
|
||||
@ -67,6 +67,10 @@ impl TileRepository {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.tree.clear();
|
||||
}
|
||||
|
||||
/// Inserts a tessellated layer into the quad tree at its world tile coords.
|
||||
/// If the space is vacant, the tessellated layer is inserted into a new
|
||||
/// [crate::io::tile_repository::CachedTile].
|
||||
|
||||
@ -2,7 +2,7 @@ use std::{marker::PhantomData, mem};
|
||||
|
||||
use crate::{
|
||||
context::{MapContext, ViewState},
|
||||
coords::{LatLon, Zoom},
|
||||
coords::{LatLon, WorldCoords, Zoom, TILE_SIZE},
|
||||
error::Error,
|
||||
io::{
|
||||
scheduler::Scheduler,
|
||||
@ -52,16 +52,14 @@ where
|
||||
wgpu_settings: WgpuSettings,
|
||||
renderer_settings: RendererSettings,
|
||||
) -> Self {
|
||||
let view_state = ViewState::new(
|
||||
&window_size,
|
||||
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
|
||||
style
|
||||
.center
|
||||
.map(|center| LatLon::new(center[0], center[1]))
|
||||
.unwrap_or_default(),
|
||||
style.pitch.unwrap_or_default(),
|
||||
cgmath::Deg(110.0),
|
||||
);
|
||||
let zoom = style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default();
|
||||
let position = style
|
||||
.center
|
||||
.map(|center| WorldCoords::from_lat_lon(LatLon::new(center[0], center[1]), zoom))
|
||||
.unwrap_or_default();
|
||||
let pitch = style.pitch.unwrap_or_default();
|
||||
let view_state = ViewState::new(&window_size, position, zoom, pitch, cgmath::Deg(110.0));
|
||||
|
||||
let tile_repository = TileRepository::new();
|
||||
let mut schedule = Schedule::default();
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ pub struct Style {
|
||||
pub metadata: HashMap<String, String>,
|
||||
pub sources: HashMap<String, Source>,
|
||||
pub layers: Vec<StyleLayer>,
|
||||
pub center: Option<[f64; 2]>,
|
||||
pub center: Option<[f64; 2]>, // TODO: Use LatLon type here
|
||||
pub zoom: Option<f64>,
|
||||
pub pitch: Option<f64>,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user