use super::*;
impl MapState {
#[allow(clippy::type_complexity)]
pub(super) fn dispatch_data_requests(&mut self) {
use crate::layer::LayerKind;
use crate::layers::{TileLayer, VectorLayer};
if self.async_pipeline.is_none() {
return;
}
self.request_coordinator.begin_frame();
let zoom_level = self.zoom_level;
let camera_world = self.mercator_camera_world();
let flat_view = self.camera.flat_tile_view();
let camera_distance = self.camera.distance();
let viewport_bounds = self.viewport_bounds;
let use_covering = self.terrain.enabled()
&& self.camera.pitch() > 0.3
&& self.camera.mode() == crate::camera::CameraMode::Perspective;
let covering_params = if use_covering {
let fzoom = self.fractional_zoom();
self.camera.covering_camera(fzoom).map(|cam| {
let opts = rustial_math::CoveringTilesOptions {
min_zoom: 0,
max_zoom: rustial_math::MAX_ZOOM,
round_zoom: false,
tile_size: 256,
max_tiles: 512,
allow_variable_zoom: true,
render_world_copies: true,
};
(cam, opts)
})
} else {
None
};
for layer in self.layers.iter_mut() {
if !layer.visible() {
continue;
}
if layer.kind() == LayerKind::Tile {
if let Some(tile_layer) = layer.as_any_mut().downcast_mut::<TileLayer>() {
if let (Some(frustum), Some((ref cam, ref opts))) =
(self.frustum.as_ref(), covering_params.as_ref())
{
tile_layer.update_with_covering(frustum, cam, opts, camera_world);
} else {
tile_layer.update_with_view(
&viewport_bounds,
zoom_level,
camera_world,
camera_distance,
flat_view.as_ref(),
);
}
self.visible_tiles = Arc::new(tile_layer.visible_tiles().tiles.clone());
}
}
}
{
use crate::tile_source::TileData;
let pipeline = self.async_pipeline.as_mut().expect("checked above");
for visible_tile in self.visible_tiles.iter() {
if let Some(TileData::RawVector(ref raw)) = visible_tile.data {
let freshness = crate::tile_source::TileFreshness::default();
pipeline.dispatch_decode(visible_tile.actual, raw, freshness);
}
}
}
self.update_streamed_vector_source_layers(
zoom_level,
camera_world,
camera_distance,
&viewport_bounds,
flat_view.as_ref(),
covering_params.as_ref(),
);
if self.terrain.enabled() {
let terrain_tiles = self.desired_terrain_tiles();
let tile_data = if let Some(ref terrain_tiles) = terrain_tiles {
self.terrain
.update_sources_with_tiles(terrain_tiles, self.zoom_level)
} else {
let cam_world = self.mercator_camera_world();
self.terrain.update_sources(
&self.viewport_bounds,
self.zoom_level,
cam_world,
self.camera.distance(),
self.camera.pitch(),
)
};
let resolution = self.terrain.mesh_resolution();
let exaggeration = self.terrain.vertical_exaggeration();
let pipeline = self.async_pipeline.as_mut().expect("checked above");
let mut visible_tile_ids: Vec<rustial_math::TileId> =
Vec::with_capacity(tile_data.len());
for (tile, elevation, generation) in tile_data {
visible_tile_ids.push(tile);
let elevation_source_tile = self.terrain.elevation_source_tile_for(tile);
let elevation_region = self.terrain.elevation_region_for(tile);
pipeline.dispatch_terrain(TerrainTaskInput {
tile,
elevation_source_tile,
elevation_region,
elevation,
resolution,
vertical_exaggeration: exaggeration,
generation,
});
}
pipeline.prune_terrain(&visible_tile_ids);
}
let camera_projection = self.camera.projection();
let mut active_layer_ids = Vec::new();
let streamed_changes = self.refresh_streamed_vector_layer_features();
let mut vector_inputs: Vec<(
String,
crate::geometry::FeatureCollection,
crate::layers::VectorStyle,
Option<String>,
Option<String>,
Vec<Option<FeatureProvenance>>,
Vec<(GeoCoord, f64)>,
bool,
)> = Vec::new();
let mut streamed_bucket_inputs: Vec<(
String,
crate::layers::VectorStyle,
Option<String>,
Option<String>,
HashMap<TileId, FeatureCollection>,
HashMap<TileId, Vec<Option<FeatureProvenance>>>,
Vec<TileId>,
Vec<TileId>,
Vec<(GeoCoord, f64)>,
bool,
)> = Vec::new();
for layer in self.layers.iter() {
if !layer.visible() || layer.kind() != LayerKind::Vector {
continue;
}
if let Some(vector_layer) = layer.as_any().downcast_ref::<VectorLayer>() {
let layer_id = vector_layer
.query_layer_id
.as_deref()
.unwrap_or(vector_layer.name())
.to_owned();
active_layer_ids.push(layer_id.clone());
let mut terrain_samples = Vec::new();
if self.terrain.enabled() {
for feature in &vector_layer.features.features {
super::picking::collect_terrain_samples_from_geometry(
&feature.geometry,
&self.terrain,
&mut terrain_samples,
);
}
}
let features_changed = streamed_changes
.get(
vector_layer
.query_layer_id
.as_deref()
.unwrap_or(vector_layer.name()),
)
.copied()
.unwrap_or(false)
|| self.dirty_streamed_symbol_layers.contains(
vector_layer
.query_layer_id
.as_deref()
.unwrap_or(vector_layer.name()),
);
let is_streamed_layer = vector_layer
.query_source_id
.as_ref()
.is_some_and(|source_id| self.streamed_vector_sources.contains_key(source_id));
if is_streamed_layer {
let streamed_payloads = self.streamed_payload_view_for(&layer_id);
let (tile_features, tile_provenance) = streamed_payloads.rebuild_tile_buckets();
let mut visible_tiles: Vec<TileId> = self
.streamed_vector_query_payloads
.get(&layer_id)
.into_iter()
.flat_map(|payloads| payloads.iter().map(|payload| payload.tile))
.collect();
if visible_tiles.is_empty() {
visible_tiles.extend(tile_features.keys().copied());
}
let dirty_tiles: Vec<TileId> = self
.dirty_streamed_symbol_tiles
.get(&layer_id)
.into_iter()
.flat_map(|tiles| tiles.iter().copied())
.collect();
for tile in &dirty_tiles {
if !visible_tiles.contains(tile) {
visible_tiles.push(*tile);
}
}
streamed_bucket_inputs.push((
layer_id,
vector_layer.style.clone(),
vector_layer.query_source_id.clone(),
vector_layer.query_source_layer.clone(),
tile_features,
tile_provenance,
visible_tiles,
dirty_tiles,
terrain_samples,
features_changed,
));
continue;
}
vector_inputs.push((
layer_id,
vector_layer.features.clone(),
vector_layer.style.clone(),
vector_layer.query_source_id.clone(),
vector_layer.query_source_layer.clone(),
vector_layer.feature_provenance.clone(),
terrain_samples,
features_changed,
));
}
}
let mut models = Vec::new();
for layer in self.layers.iter() {
if !layer.visible() || layer.kind() != LayerKind::Model {
continue;
}
if let Some(model_layer) = layer.as_any().downcast_ref::<crate::layers::ModelLayer>() {
models.extend(model_layer.instances.iter().cloned());
}
}
self.model_instances = Arc::new(models);
let pipeline = self.async_pipeline.as_mut().expect("checked above");
for (
layer_id,
features,
style,
query_source_id,
query_source_layer,
feature_provenance,
terrain_samples,
features_changed,
) in vector_inputs
{
let data_gen = pipeline.layer_generation(&layer_id, features_changed);
let key = VectorCacheKey {
layer_id: layer_id.clone(),
data_generation: data_gen,
projection: camera_projection,
};
pipeline.dispatch_vector(VectorTaskInput {
cache_key: key,
features,
style,
query_layer_id: Some(layer_id.clone()),
query_source_id,
query_source_layer,
feature_provenance,
projection: camera_projection,
terrain_samples,
});
if features_changed {
self.dirty_streamed_symbol_layers.remove(&layer_id);
}
}
for (
layer_id,
style,
query_source_id,
query_source_layer,
tile_features,
tile_provenance,
_visible_tiles,
dirty_tiles,
terrain_samples,
features_changed,
) in streamed_bucket_inputs
{
let data_gen = pipeline.layer_generation(&layer_id, features_changed);
if features_changed {
pipeline.dispatch_vector_buckets(
&layer_id,
data_gen,
camera_projection,
&style,
&tile_features,
query_source_id.as_deref(),
query_source_layer.as_deref(),
&tile_provenance,
&terrain_samples,
);
self.dirty_streamed_symbol_layers.remove(&layer_id);
self.dirty_streamed_symbol_tiles.remove(&layer_id);
continue;
}
if dirty_tiles.is_empty() {
continue;
}
let data_gen = pipeline.layer_generation(&layer_id, true);
pipeline.evict_vector_buckets(&layer_id, &dirty_tiles);
let dirty_tile_set: HashSet<TileId> = dirty_tiles.iter().copied().collect();
let dirty_tile_features: HashMap<TileId, FeatureCollection> = tile_features
.into_iter()
.filter(|(tile, _)| dirty_tile_set.contains(tile))
.collect();
let dirty_tile_provenance: HashMap<TileId, Vec<Option<FeatureProvenance>>> =
tile_provenance
.into_iter()
.filter(|(tile, _)| dirty_tile_set.contains(tile))
.collect();
pipeline.dispatch_vector_buckets(
&layer_id,
data_gen,
camera_projection,
&style,
&dirty_tile_features,
query_source_id.as_deref(),
query_source_layer.as_deref(),
&dirty_tile_provenance,
&terrain_samples,
);
self.dirty_streamed_symbol_tiles.remove(&layer_id);
}
pipeline.prune_vectors(&active_layer_ids);
pipeline.prune_vector_buckets(&active_layer_ids);
self.request_coordinator.finish_frame();
}
pub(super) fn poll_completed_results(&mut self, dt_seconds: f64) {
use crate::layers::VectorRenderMode;
if self.async_pipeline.is_none() {
return;
}
{
let pipeline = self.async_pipeline.as_mut().expect("checked above");
pipeline.poll_terrain();
pipeline.poll_vector();
pipeline.poll_vector_buckets();
pipeline.poll_decodes();
}
{
let decoded = self
.async_pipeline
.as_mut()
.expect("checked above")
.take_decoded_tiles();
if !decoded.is_empty() {
use crate::layer::LayerKind;
use crate::layers::TileLayer;
for layer in self.layers.iter_mut() {
if layer.kind() == LayerKind::Tile {
if let Some(tile_layer) = layer.as_any_mut().downcast_mut::<TileLayer>() {
tile_layer.promote_decoded(decoded.clone());
}
}
}
}
}
{
let pipeline = self.async_pipeline.as_ref().expect("checked above");
let (terrain_meshes, hillshade_rasters) = pipeline.collect_all_terrain();
self.terrain_meshes = Arc::new(terrain_meshes);
self.hillshade_rasters = Arc::new(hillshade_rasters);
}
let camera_projection = self.camera.projection();
let mut vector_cache_keys = Vec::new();
let mut streamed_bucket_collect_specs: Vec<(String, u64, Vec<TileId>)> = Vec::new();
let mut had_symbol_layer = false;
let mut layer_ids: Vec<String> = Vec::new();
for layer in self.layers.iter() {
if !layer.visible() {
continue;
}
if let Some(vector_layer) = layer.as_any().downcast_ref::<crate::layers::VectorLayer>()
{
let layer_id = vector_layer
.query_layer_id
.as_deref()
.unwrap_or(vector_layer.name())
.to_owned();
let is_streamed_layer = vector_layer
.query_source_id
.as_ref()
.is_some_and(|source_id| self.streamed_vector_sources.contains_key(source_id));
if is_streamed_layer {
let visible_tiles: Vec<TileId> = self
.streamed_vector_query_payloads
.get(&layer_id)
.into_iter()
.flat_map(|payloads| payloads.iter().map(|payload| payload.tile))
.collect();
streamed_bucket_collect_specs.push((layer_id.clone(), 0, visible_tiles));
} else {
layer_ids.push(layer_id);
}
had_symbol_layer =
had_symbol_layer || vector_layer.style.render_mode == VectorRenderMode::Symbol;
}
}
{
let pipeline = self.async_pipeline.as_mut().expect("checked above");
for layer_id in &layer_ids {
let data_gen = pipeline.layer_generation(layer_id, false);
vector_cache_keys.push(VectorCacheKey {
layer_id: layer_id.clone(),
data_generation: data_gen,
projection: camera_projection,
});
}
for (layer_id, data_gen, _) in &mut streamed_bucket_collect_specs {
*data_gen = pipeline.layer_generation(layer_id, false);
}
}
let (vectors, symbol_candidates) = {
let pipeline = self.async_pipeline.as_ref().expect("checked above");
let mut out = pipeline.collect_vectors(&vector_cache_keys);
for (layer_id, data_gen, visible_tiles) in &streamed_bucket_collect_specs {
let (meshes, candidates) = pipeline.collect_vector_buckets(
layer_id,
*data_gen,
camera_projection,
visible_tiles,
);
out.0.extend(meshes);
out.1.extend(candidates);
}
out
};
self.vector_meshes = Arc::new(vectors);
if had_symbol_layer && !symbol_candidates.is_empty() {
let meters_per_pixel = self.camera.meters_per_pixel();
let placed = self.symbol_placement.place_candidates(
&symbol_candidates,
camera_projection,
meters_per_pixel,
dt_seconds,
Some(&self.scene_viewport_bounds),
);
self.symbol_assets.rebuild_from_symbols(&placed);
self.placed_symbols = Arc::new(placed);
self.rebuild_symbol_query_payloads();
} else if !had_symbol_layer {
self.placed_symbols = Arc::new(Vec::new());
self.streamed_symbol_query_payloads.clear();
self.streamed_symbol_dependency_payloads.clear();
self.dirty_streamed_symbol_tiles.clear();
}
}
}