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">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run demo (debug+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<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" />
|
<option name="command" value="run -p maplibre-demo --features trace -- headed" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="requiredFeatures" value="true" />
|
<option name="requiredFeatures" value="true" />
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run demo (release+enable-tracing)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
<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" />
|
<option name="command" value="run -p maplibre-demo --release --features trace -- headed" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<option name="channel" value="DEFAULT" />
|
<option name="channel" value="DEFAULT" />
|
||||||
<option name="requiredFeatures" value="true" />
|
<option name="requiredFeatures" value="true" />
|
||||||
@ -23,3 +23,5 @@ tracing = "0.1.35"
|
|||||||
tracing-subscriber = { version = "0.3.14", optional = true }
|
tracing-subscriber = { version = "0.3.14", optional = true }
|
||||||
tracing-tracy = { version = "0.8", optional = true }
|
tracing-tracy = { version = "0.8", optional = true }
|
||||||
tracy-client = { version = "0.12.7", 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::{
|
use clap::{builder::ValueParser, Parser, Subcommand};
|
||||||
benchmarking::tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
use maplibre::{coords::LatLon, platform::run_multithreaded};
|
||||||
coords::{TileCoords, ViewRegion, WorldTileCoords, ZoomLevel},
|
|
||||||
error::Error,
|
use crate::{headed::run_headed, headless::run_headless};
|
||||||
headless::{utils::HeadlessPipelineProcessor, HeadlessMapWindowConfig},
|
|
||||||
io::{
|
mod headed;
|
||||||
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
mod headless;
|
||||||
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};
|
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
fn enable_tracing() {
|
fn enable_tracing() {
|
||||||
@ -36,63 +17,46 @@ fn enable_tracing() {
|
|||||||
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_in_window() {
|
#[derive(Parser)]
|
||||||
run_multithreaded(async {
|
#[clap(author, version, about, long_about = None)]
|
||||||
MapBuilder::new()
|
#[clap(propagate_version = true)]
|
||||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
struct Cli {
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
#[clap(subcommand)]
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
command: Commands,
|
||||||
.build()
|
|
||||||
.initialize()
|
|
||||||
.await
|
|
||||||
.run()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_headless() {
|
fn parse_lat_long(env: &str) -> Result<LatLon, std::io::Error> {
|
||||||
run_multithreaded(async {
|
let split = env.split(',').collect::<Vec<_>>();
|
||||||
let mut map = MapBuilder::new()
|
if let (Some(latitude), Some(longitude)) = (split.get(0), split.get(1)) {
|
||||||
.with_map_window_config(HeadlessMapWindowConfig {
|
Ok(LatLon::new(
|
||||||
size: WindowSize::new(1000, 1000).unwrap(),
|
latitude.parse::<f64>().unwrap(),
|
||||||
})
|
longitude.parse::<f64>().unwrap(),
|
||||||
.with_http_client(ReqwestHttpClient::new(None))
|
))
|
||||||
.with_schedule_method(TokioScheduleMethod::new())
|
} else {
|
||||||
.with_renderer_settings(RendererSettings {
|
Err(std::io::Error::new(
|
||||||
texture_format: TextureFormat::Rgba8UnormSrgb,
|
ErrorKind::InvalidData,
|
||||||
..RendererSettings::default()
|
"Failed to parse latitude and longitude.",
|
||||||
})
|
))
|
||||||
.build()
|
}
|
||||||
.initialize_headless()
|
}
|
||||||
.await;
|
|
||||||
|
|
||||||
let tile_limits = google_mercator().tile_limits(
|
#[derive(Subcommand)]
|
||||||
extent_wgs84_to_merc(&Extent {
|
enum Commands {
|
||||||
minx: 11.3475219363,
|
Headed {},
|
||||||
miny: 48.0345697188,
|
Headless {
|
||||||
maxx: 11.7917815798,
|
#[clap(default_value_t = 400)]
|
||||||
maxy: 48.255861,
|
tile_size: u32,
|
||||||
}),
|
#[clap(
|
||||||
0,
|
value_parser = ValueParser::new(parse_lat_long),
|
||||||
);
|
default_value_t = LatLon::new(48.0345697188, 11.3475219363)
|
||||||
|
)]
|
||||||
for (z, x, y) in GridIterator::new(10, 10, tile_limits) {
|
min: LatLon,
|
||||||
let coords = WorldTileCoords::from((x as i32, y as i32, z.into()));
|
#[clap(
|
||||||
println!("Rendering {}", &coords);
|
value_parser = ValueParser::new(parse_lat_long),
|
||||||
map.map_schedule
|
default_value_t = LatLon::new(48.255861, 11.7917815798)
|
||||||
.fetch_process(&coords)
|
)]
|
||||||
.await
|
max: LatLon,
|
||||||
.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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -101,6 +65,20 @@ fn main() {
|
|||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
enable_tracing();
|
enable_tracing();
|
||||||
|
|
||||||
//run_headless();
|
let cli = Cli::parse();
|
||||||
run_in_window();
|
|
||||||
|
// 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 {
|
impl ViewState {
|
||||||
pub fn new<P: Into<cgmath::Rad<f64>>>(
|
pub fn new<P: Into<cgmath::Rad<f64>>>(
|
||||||
window_size: &WindowSize,
|
window_size: &WindowSize,
|
||||||
|
position: WorldCoords,
|
||||||
zoom: Zoom,
|
zoom: Zoom,
|
||||||
center: LatLon,
|
|
||||||
pitch: f64,
|
pitch: f64,
|
||||||
fovy: P,
|
fovy: P,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let tile_center = TILE_SIZE / 2.0;
|
let tile_center = TILE_SIZE / 2.0;
|
||||||
let fovy = fovy.into();
|
let fovy = fovy.into();
|
||||||
let height = tile_center / (fovy / 2.0).tan();
|
let height = tile_center / (fovy / 2.0).tan();
|
||||||
let position = WorldCoords::from_lat_lon(center, zoom);
|
|
||||||
|
|
||||||
let camera = Camera::new(
|
let camera = Camera::new(
|
||||||
(position.x, position.y, height),
|
(position.x, position.y, height),
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
//! Provides utilities related to coordinates.
|
//! 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};
|
use cgmath::{num_traits::Pow, AbsDiffEq, Matrix4, Point3, Vector3};
|
||||||
|
|
||||||
@ -112,17 +116,32 @@ impl Into<u8> for ZoomLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct LatLon(f64, f64);
|
pub struct LatLon {
|
||||||
|
pub latitude: f64,
|
||||||
|
pub longitude: f64,
|
||||||
|
}
|
||||||
|
|
||||||
impl LatLon {
|
impl LatLon {
|
||||||
pub fn new(latitude: f64, longitude: f64) -> Self {
|
pub fn new(latitude: f64, longitude: f64) -> Self {
|
||||||
LatLon(latitude, longitude)
|
LatLon {
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LatLon {
|
impl Default for LatLon {
|
||||||
fn default() -> Self {
|
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 {
|
pub fn from_lat_lon(lat_lon: LatLon, zoom: Zoom) -> WorldCoords {
|
||||||
let tile_size = TILE_SIZE * 2.0_f64.powf(zoom.0);
|
let tile_size = TILE_SIZE * 2.0_f64.powf(zoom.0);
|
||||||
// Get x value
|
// 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
|
// 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
|
// get y value
|
||||||
let merc_n = f64::ln(f64::tan((PI / 4.0) + (lat_rad / 2.0)));
|
let merc_n = f64::ln(f64::tan((PI / 4.0) + (lat_rad / 2.0)));
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use wgpu::{BufferAsyncError, BufferSlice};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{MapContext, ViewState},
|
context::{MapContext, ViewState},
|
||||||
coords::{LatLon, ViewRegion, WorldTileCoords, Zoom},
|
coords::{LatLon, ViewRegion, WorldCoords, WorldTileCoords, Zoom, TILE_SIZE},
|
||||||
error::Error,
|
error::Error,
|
||||||
headless::utils::HeadlessPipelineProcessor,
|
headless::utils::HeadlessPipelineProcessor,
|
||||||
io::{
|
io::{
|
||||||
@ -114,12 +114,9 @@ where
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let view_state = ViewState::new(
|
let view_state = ViewState::new(
|
||||||
&window_size,
|
&window_size,
|
||||||
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
|
WorldCoords::from((TILE_SIZE / 2., TILE_SIZE / 2.)),
|
||||||
style
|
Zoom::default(),
|
||||||
.center
|
0.0,
|
||||||
.map(|center| LatLon::new(center[0], center[1]))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
style.pitch.unwrap_or_default(),
|
|
||||||
cgmath::Deg(110.0),
|
cgmath::Deg(110.0),
|
||||||
);
|
);
|
||||||
let tile_repository = TileRepository::new();
|
let tile_repository = TileRepository::new();
|
||||||
@ -210,6 +207,8 @@ where
|
|||||||
pool.clear();
|
pool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.map_context.tile_repository.clear();
|
||||||
|
|
||||||
while let Some(layer) = processor.layers.pop() {
|
while let Some(layer) = processor.layers.pop() {
|
||||||
self.map_context
|
self.map_context
|
||||||
.tile_repository
|
.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.
|
/// 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
|
/// If the space is vacant, the tessellated layer is inserted into a new
|
||||||
/// [crate::io::tile_repository::CachedTile].
|
/// [crate::io::tile_repository::CachedTile].
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::{marker::PhantomData, mem};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{MapContext, ViewState},
|
context::{MapContext, ViewState},
|
||||||
coords::{LatLon, Zoom},
|
coords::{LatLon, WorldCoords, Zoom, TILE_SIZE},
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{
|
io::{
|
||||||
scheduler::Scheduler,
|
scheduler::Scheduler,
|
||||||
@ -52,16 +52,14 @@ where
|
|||||||
wgpu_settings: WgpuSettings,
|
wgpu_settings: WgpuSettings,
|
||||||
renderer_settings: RendererSettings,
|
renderer_settings: RendererSettings,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let view_state = ViewState::new(
|
let zoom = style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default();
|
||||||
&window_size,
|
let position = style
|
||||||
style.zoom.map(|zoom| Zoom::new(zoom)).unwrap_or_default(),
|
.center
|
||||||
style
|
.map(|center| WorldCoords::from_lat_lon(LatLon::new(center[0], center[1]), zoom))
|
||||||
.center
|
.unwrap_or_default();
|
||||||
.map(|center| LatLon::new(center[0], center[1]))
|
let pitch = style.pitch.unwrap_or_default();
|
||||||
.unwrap_or_default(),
|
let view_state = ViewState::new(&window_size, position, zoom, pitch, cgmath::Deg(110.0));
|
||||||
style.pitch.unwrap_or_default(),
|
|
||||||
cgmath::Deg(110.0),
|
|
||||||
);
|
|
||||||
let tile_repository = TileRepository::new();
|
let tile_repository = TileRepository::new();
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ pub struct Style {
|
|||||||
pub metadata: HashMap<String, String>,
|
pub metadata: HashMap<String, String>,
|
||||||
pub sources: HashMap<String, Source>,
|
pub sources: HashMap<String, Source>,
|
||||||
pub layers: Vec<StyleLayer>,
|
pub layers: Vec<StyleLayer>,
|
||||||
pub center: Option<[f64; 2]>,
|
pub center: Option<[f64; 2]>, // TODO: Use LatLon type here
|
||||||
pub zoom: Option<f64>,
|
pub zoom: Option<f64>,
|
||||||
pub pitch: Option<f64>,
|
pub pitch: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user