use super::*;
impl MapState {
pub(super) fn refresh_streamed_vector_layer_features(&mut self) -> HashMap<String, bool> {
let streamed_layers: Vec<StreamedVectorLayerRefreshSpec> = self
.layers
.iter()
.filter_map(|layer| {
let vector_layer = layer
.as_any()
.downcast_ref::<crate::layers::VectorLayer>()?;
let source_id = vector_layer.query_source_id.as_ref()?;
let runtime = self.streamed_vector_sources.get(source_id)?;
let layer_key = vector_layer
.query_layer_id
.as_deref()
.unwrap_or(vector_layer.name())
.to_owned();
Some(StreamedVectorLayerRefreshSpec {
runtime_id: layer.id(),
layer_key,
source_id: source_id.clone(),
source_layer: vector_layer.query_source_layer.clone(),
visible_tiles: runtime.visible_tiles().tiles.clone(),
})
})
.collect();
let resolved = resolve_streamed_vector_layer_refresh(streamed_layers);
let mut changed = HashMap::new();
let active_keys: HashSet<String> = resolved
.iter()
.map(|entry| entry.layer_key.clone())
.collect();
self.streamed_vector_layer_fingerprints
.retain(|key, _| active_keys.contains(key));
self.streamed_vector_query_payloads
.retain(|key, _| active_keys.contains(key));
for resolved_layer in resolved {
let was_changed = self
.streamed_vector_layer_fingerprints
.get(&resolved_layer.layer_key)
.copied()
!= Some(resolved_layer.fingerprint);
self.streamed_vector_layer_fingerprints
.insert(resolved_layer.layer_key.clone(), resolved_layer.fingerprint);
let (features, provenance) = resolved_layer.rebuild_feature_inputs();
self.streamed_vector_query_payloads.insert(
resolved_layer.layer_key.clone(),
resolved_layer.tile_payloads,
);
if let Some(layer) = self
.layers
.iter_mut()
.find(|layer| layer.id() == resolved_layer.runtime_id)
{
if let Some(vector_layer) = layer
.as_any_mut()
.downcast_mut::<crate::layers::VectorLayer>()
{
vector_layer.set_features_with_provenance(features, provenance);
}
}
changed.insert(resolved_layer.layer_key, was_changed);
}
changed
}
pub(super) fn rebuild_symbol_query_payloads(&mut self) {
let view = VisiblePlacedSymbolView::new(&self.placed_symbols);
self.streamed_symbol_query_payloads = view.rebuild_query_payloads();
self.streamed_symbol_dependency_payloads = view.rebuild_dependency_payloads();
}
pub(super) fn streamed_payload_view_for(&self, layer_id: &str) -> StreamedPayloadView<'_> {
StreamedPayloadView::from_optional(
self.streamed_vector_query_payloads
.get(layer_id)
.map(Vec::as_slice),
)
}
pub(super) fn streamed_symbol_query_payloads_for(
&self,
layer_id: &str,
) -> &[SymbolQueryPayload] {
symbol_query_payloads_from_optional(
self.streamed_symbol_query_payloads
.get(layer_id)
.map(Vec::as_slice),
)
}
pub(super) fn invalidate_symbol_dependency_tiles(
&mut self,
matches: impl Fn(&crate::symbols::SymbolAssetDependencies) -> bool,
) -> usize {
let affected: HashSet<StreamedSymbolPayloadKey> =
collect_affected_symbol_payloads(&self.streamed_symbol_dependency_payloads, matches);
if affected.is_empty() {
return 0;
}
for (layer_id, tile) in &affected {
if let Some(tile) = tile {
self.dirty_streamed_symbol_tiles
.entry(layer_id.clone())
.or_default()
.insert(*tile);
} else {
self.dirty_streamed_symbol_layers.insert(layer_id.clone());
}
}
self.data_update_elapsed = self.data_update_interval;
self.placed_symbols = Arc::new(prune_affected_symbol_payloads(
&affected,
&self.placed_symbols,
&mut self.streamed_symbol_query_payloads,
&mut self.streamed_symbol_dependency_payloads,
));
self.symbol_assets
.rebuild_from_symbols(&self.placed_symbols);
affected.len()
}
pub(super) fn update_heavy_layers(&mut self, dt_seconds: f64) {
use crate::layer::LayerKind;
use crate::layers::{VectorLayer, VectorRenderMode};
if let Some(terrain_tiles) = self.desired_terrain_tiles() {
self.update_terrain_with_tiles(&terrain_tiles);
} else {
self.update_terrain();
}
let camera_projection = self.camera.projection();
let mut all_vectors: Vec<VectorMeshData> = Vec::new();
let mut symbol_candidates = Vec::new();
let mut had_symbol_layer = false;
let mut active_keys: HashSet<SyncVectorCacheKey> = HashSet::new();
self.refresh_streamed_vector_layer_features();
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());
let is_streamed_layer = vector_layer
.query_source_id
.as_ref()
.is_some_and(|source_id| self.streamed_vector_sources.contains_key(source_id));
had_symbol_layer =
had_symbol_layer || vector_layer.style.render_mode == VectorRenderMode::Symbol;
let cache_key = SyncVectorCacheKey {
layer_id: vector_layer.id(),
style_fingerprint: vector_layer.style.tessellation_fingerprint(),
data_generation: vector_layer.data_generation(),
projection: camera_projection,
};
active_keys.insert(cache_key);
if let Some(entry) = self.sync_vector_cache.get(&cache_key) {
if !entry.mesh.is_empty() {
all_vectors.push(entry.mesh.clone());
}
} else {
let mesh = vector_layer.tessellate(camera_projection);
if !mesh.is_empty() {
all_vectors.push(mesh.clone());
}
self.sync_vector_cache
.insert(cache_key, SyncVectorCacheEntry { mesh });
}
if is_streamed_layer {
let streamed_payloads = self.streamed_payload_view_for(layer_id);
let (features, provenance) = streamed_payloads.rebuild_feature_inputs();
symbol_candidates.extend(
vector_layer.symbol_candidates_for_features(&features, &provenance),
);
} else {
symbol_candidates.extend(vector_layer.symbol_candidates());
}
}
}
self.sync_vector_cache
.retain(|key, _| active_keys.contains(key));
self.vector_meshes = Arc::new(all_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();
}
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);
self.collect_visualization_overlays();
self.collect_image_overlays();
self.dirty_streamed_symbol_layers.clear();
self.dirty_streamed_symbol_tiles.clear();
}
pub(super) fn apply_pending_frame_overrides(&mut self) {
if let Some(meshes) = self.pending_terrain_meshes.take() {
self.terrain_meshes = meshes;
}
if let Some(meshes) = self.pending_vector_meshes.take() {
self.vector_meshes = meshes;
}
if let Some(instances) = self.pending_model_instances.take() {
self.model_instances = instances;
}
}
pub(super) fn collect_visualization_overlays(&mut self) {
use crate::visualization::{
GridExtrusionLayer, GridScalarLayer, InstancedColumnLayer, PointCloudLayer,
VisualizationOverlay,
};
let mut overlays = Vec::new();
for layer in self.layers.iter() {
if !layer.visible() {
continue;
}
if layer.kind() != crate::layer::LayerKind::Visualization {
continue;
}
if let Some(grid_layer) = layer.as_any().downcast_ref::<GridScalarLayer>() {
overlays.push(VisualizationOverlay::GridScalar {
layer_id: grid_layer.id(),
grid: grid_layer.grid.clone(),
field: grid_layer.field.clone(),
ramp: grid_layer.ramp.clone(),
});
} else if let Some(grid_layer) = layer.as_any().downcast_ref::<GridExtrusionLayer>() {
overlays.push(VisualizationOverlay::GridExtrusion {
layer_id: grid_layer.id(),
grid: grid_layer.grid.clone(),
field: grid_layer.field.clone(),
ramp: grid_layer.ramp.clone(),
params: grid_layer.params.clone(),
});
} else if let Some(col_layer) = layer.as_any().downcast_ref::<InstancedColumnLayer>() {
overlays.push(VisualizationOverlay::Columns {
layer_id: col_layer.id(),
columns: col_layer.columns.clone(),
ramp: col_layer.ramp.clone(),
});
} else if let Some(point_layer) = layer.as_any().downcast_ref::<PointCloudLayer>() {
overlays.push(VisualizationOverlay::Points {
layer_id: point_layer.id(),
points: point_layer.points.clone(),
ramp: point_layer.ramp.clone(),
});
}
}
self.visualization_overlays = Arc::new(overlays);
}
pub(super) fn collect_image_overlays(&mut self) {
use crate::layers::DynamicImageOverlayLayer;
use crate::layers::ImageOverlayLayer;
let projection = self.camera.projection();
let mut overlays = Vec::new();
for layer in self.layers.iter_mut() {
if !layer.visible() {
continue;
}
if let Some(img_layer) = layer.as_any().downcast_ref::<ImageOverlayLayer>() {
overlays.push(img_layer.to_overlay_data(projection));
} else if let Some(dyn_layer) = layer
.as_any_mut()
.downcast_mut::<DynamicImageOverlayLayer>()
{
dyn_layer.poll_frame();
if let Some(data) = dyn_layer.to_overlay_data(projection) {
overlays.push(data);
}
}
}
self.image_overlays = Arc::new(overlays);
}
pub(super) fn apply_style_document(
&mut self,
document: &StyleDocument,
) -> Result<(), StyleError> {
let layers = document.to_runtime_layers()?;
self.layers = LayerStack::new();
for layer in layers {
self.layers.push(layer);
}
self.streamed_vector_sources = build_streamed_vector_sources(document);
self.streamed_vector_layer_fingerprints.clear();
self.streamed_vector_query_payloads.clear();
self.streamed_symbol_query_payloads.clear();
self.streamed_symbol_dependency_payloads.clear();
self.dirty_streamed_symbol_layers.clear();
self.dirty_streamed_symbol_tiles.clear();
Ok(())
}
}
impl MapState {
pub fn style_source_is_used(&self, source_id: &str) -> bool {
match self.style_document() {
Some(document) => document.source_is_used(source_id),
None => false,
}
}
pub fn style_layer_ids_using_source(&self, source_id: &str) -> Vec<&str> {
match self.style_document() {
Some(document) => document.layer_ids_using_source(source_id),
None => Vec::new(),
}
}
pub fn reload_style_source(
&mut self,
source_id: impl Into<String>,
source: crate::style::StyleSource,
) -> Result<bool, StyleError> {
let Some(mut style): Option<MapStyle> = self.style.take() else {
return Ok(false);
};
style.document_mut().set_source(source_id.into(), source);
self.apply_style_document(style.document())?;
self.style = Some(style);
Ok(true)
}
pub fn clear_style_source(
&mut self,
source_id: &str,
) -> Result<Option<crate::style::StyleSource>, StyleError> {
let Some(mut style): Option<MapStyle> = self.style.take() else {
return Ok(None);
};
let removed = style.document_mut().remove_source(source_id);
self.apply_style_document(style.document())?;
self.style = Some(style);
Ok(removed)
}
}
fn build_streamed_vector_sources(
document: &StyleDocument,
) -> HashMap<String, crate::layers::TileLayer> {
document
.sources()
.filter_map(|(source_id, source)| match source {
crate::style::StyleSource::VectorTile(vector_source) => {
vector_source.make_tile_source().map(|tile_source| {
(
source_id.to_owned(),
crate::layers::TileLayer::new_with_selection_config(
format!("__vector_source::{source_id}"),
tile_source,
vector_source.cache_capacity,
vector_source.selection.clone(),
),
)
})
}
_ => None,
})
.collect()
}
pub(super) fn wrapped_world_delta(delta: f64) -> f64 {
let half_world = WGS84_CIRCUMFERENCE * 0.5;
if delta > half_world {
delta - WGS84_CIRCUMFERENCE
} else if delta < -half_world {
delta + WGS84_CIRCUMFERENCE
} else {
delta
}
}
pub(super) fn translated_world_bounds(bounds: &WorldBounds, delta: glam::DVec2) -> WorldBounds {
WorldBounds::new(
WorldCoord::new(
bounds.min.position.x + delta.x,
bounds.min.position.y + delta.y,
bounds.min.position.z,
),
WorldCoord::new(
bounds.max.position.x + delta.x,
bounds.max.position.y + delta.y,
bounds.max.position.z,
),
)
}