1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
// ---------------------------------------------------------------------------
//! # Bevy ECS marker components for map entities
//!
//! Every visual entity managed by the rustial Bevy plugin carries one
//! of the marker components defined here. The plugin's sync systems
//! use these components to query, reposition, and despawn entities as
//! the map state changes each frame.
//!
//! ## Component to system mapping
//!
//! ```text
//! Component Spawned / consumed by Schedule
//! ---------------------------------------------------------------
//! MapCamera setup_from_config Startup
//! TileEntity sync_tiles Update
//! TerrainEntity sync_terrain Update
//! VectorEntity sync_vectors Update
//! ModelEntity sync_models Update
//! MapEntity + sync_geo_entities Update
//! GeoTransform (user-spawned, system repositions)
//! ```
//!
//! ## Camera-relative positioning
//!
//! All map entities are rendered relative to the camera's world-space
//! origin ([`Camera::target_world`](rustial_engine::Camera::target_world))
//! so that large Web Mercator coordinates are reduced to small f32
//! values before reaching the GPU (avoids floating-point jitter).
//!
//! Two patterns are used depending on how the entity's mesh data is
//! produced:
//!
//! ### Pattern A -- `spawn_origin` offset (terrain, vectors)
//!
//! Vertex positions are baked into the mesh at spawn time as
//! `world_pos - camera_origin`. The entity stores that camera
//! origin in a `spawn_origin` field. Each frame the sync system
//! sets `Transform.translation = spawn_origin - current_camera_origin`,
//! so the net vertex position is always `world_pos - current_camera_origin`
//! without ever re-uploading mesh data.
//!
//! ### Pattern B -- per-frame world query (tiles, models)
//!
//! Tile quad meshes use small half-extent vertices centred on the
//! mesh origin; the tile's world centre is recomputed from
//! [`tile_bounds_world`](rustial_engine::tile_bounds_world) each frame.
//! Model entities reproject their `GeoCoord` each frame. These
// entities do not need a `spawn_origin` because the world position is
// cheap to recompute and the mesh data is position-independent.
//
// ### Pattern C -- user entities (MapEntity + GeoTransform)
//
// User-spawned entities are repositioned each frame by
// `sync_geo_entities`, which projects the `GeoTransform` coordinate and
// writes `Transform.translation` directly.
// ---------------------------------------------------------------------------
use *;
use DVec3;
use ;
// ---------------------------------------------------------------------------
// Camera
// ---------------------------------------------------------------------------
/// Marker component for the Bevy camera controlled by the map plugin.
;
// ---------------------------------------------------------------------------
// Deferred asset cleanup
// ---------------------------------------------------------------------------
/// Resource that holds mesh and material handles for one extra frame
/// after their entities are despawned.
///
/// When an entity is despawned, its `Handle<Mesh>` and
/// `Handle<TileFogMaterial>` may be the last strong references. If
/// dropped immediately, Bevy frees the underlying GPU buffers -- but
/// the render world may have already extracted them for the current
/// frame's render pass. Accessing a freed buffer triggers a wgpu
/// validation panic ("Buffer is invalid").
///
/// This resource acts as a one-frame keep-alive: handles are pushed
/// here on the frame of despawn and drained on the *next* frame,
/// giving the render pipeline time to finish using them.
// ---------------------------------------------------------------------------
// Tile entities
// ---------------------------------------------------------------------------
/// Marker component for tile quad entities.
///
/// Each tile stores the camera origin and map projection used when its
/// projection-specialized quad was baked, allowing the mesh to be
/// repositioned cheaply as the camera moves and rebuilt when the active
/// planar projection changes.
///
/// The [`upload_textures`](crate::systems::texture_upload::upload_textures)
/// system later assigns raster imagery as `base_color_texture` on
/// the tile's [`StandardMaterial`].
// ---------------------------------------------------------------------------
// Terrain entities
// ---------------------------------------------------------------------------
/// Marker component for terrain mesh entities.
///
/// Tracks both the tile identity and the camera origin at which the
/// mesh vertex positions were baked. The
/// [`sync_terrain`](crate::systems::terrain_sync::sync_terrain)
/// system uses `spawn_origin` to compute a `Transform` offset each
/// frame so that vertices remain correctly camera-relative as the
/// user pans, without needing to rebuild the mesh.
///
/// ## Repositioning formula
///
/// ```text
/// Transform.translation = spawn_origin - current_camera_origin
///
/// vertex_world = vertex_mesh + translation
/// = (world_pos - spawn_origin) + (spawn_origin - camera_origin)
/// = world_pos - camera_origin
/// ```
/// Marker component for dedicated hillshade overlay entities.
// ---------------------------------------------------------------------------
// Vector entities
// ---------------------------------------------------------------------------
/// Marker component for vector geometry entities.
///
/// Tracks the layer name and the camera origin at which the mesh
/// vertex positions were baked. The
/// [`sync_vectors`](crate::systems::vector_sync::sync_vectors)
/// system uses `spawn_origin` to compute a `Transform` offset each
/// frame -- the same repositioning formula as [`TerrainEntity`].
///
/// ## Rebuild strategy
///
/// Vector entities use a **rebuild-on-change** lifecycle: when the
/// engine's `vector_meshes` count changes all entities are despawned
/// and respawned. When the count is stable, only the `Transform`
/// translation is updated (cheap reposition path).
/// Marker component for image overlay entities.
///
/// Each image overlay is a textured quad spanning four geographic
/// corners. The sync system spawns one entity per
/// [`ImageOverlayData`](rustial_engine::layers::ImageOverlayData)
/// and uses `spawn_origin` for camera-relative repositioning.
/// Marker component for grid scalar overlay entities.
/// Marker component for extruded grid overlay entities.
/// Marker component for instanced column overlay entities.
/// Marker component for point-cloud overlay entities.
// ---------------------------------------------------------------------------
// Model entities
// ---------------------------------------------------------------------------
/// Marker component for 3D model entities.
///
/// Used by [`sync_models`](crate::systems::model_sync::sync_models)
/// to track which engine model instance each Bevy entity represents.
///
/// ## Rebuild strategy
///
/// Model entities use a **rebuild-on-change** lifecycle similar to
/// vectors. When the instance count matches, only the `Transform` is
/// updated each frame (the model's `GeoCoord` is reprojected and the
/// camera origin subtracted -- no `spawn_origin` needed because the
/// transform is fully recomputed from the instance data).
///
/// When the instance count changes, all model entities are despawned
/// and respawned from scratch.
// ---------------------------------------------------------------------------
// User geographic entities
// ---------------------------------------------------------------------------
/// Tag component for user-placed entities that should be automatically
/// repositioned each frame relative to the map camera origin.
///
/// Attach this to any Bevy entity along with a [`GeoTransform`] to
/// have the plugin keep its `Transform.translation` in sync with the
/// map view. User-supplied rotation and scale are preserved -- only
/// the translation is overwritten.
///
/// ## Required companion components
///
/// | Component | Purpose |
/// |-----------|---------|
/// | [`GeoTransform`] | Geographic position + altitude mode |
/// | [`Transform`] | Written by [`sync_geo_entities`](crate::systems::geo_entity_sync::sync_geo_entities) |
/// | [`Visibility`] | Standard Bevy visibility |
///
/// ## Example
///
/// ```rust,no_run
/// use bevy::prelude::*;
/// use rustial_renderer_bevy::components::{MapEntity, GeoTransform};
///
/// fn spawn_pin(mut commands: Commands) {
/// commands.spawn((
/// MapEntity,
/// GeoTransform::from_lat_lon(48.8566, 2.3522), // Paris
/// Transform::default(),
/// Visibility::default(),
/// // ... add your own mesh, sprite, etc.
/// ));
/// }
/// ```
;
/// Geographic position and altitude mode for a user entity on the map.
///
/// Pair with [`MapEntity`] on a Bevy entity. Each frame the
/// [`sync_geo_entities`](crate::systems::geo_entity_sync::sync_geo_entities)
/// system projects this coordinate to camera-relative Bevy
/// `Transform.translation`, keeping the entity aligned with the tile
/// layer regardless of panning, zooming, or rotation.
///
/// # Construction
///
/// | Method | Altitude | Mode |
/// |--------|----------|------|
/// | [`from_lat_lon`](Self::from_lat_lon) | 0 | `ClampToGround` |
/// | [`new`](Self::new) | from `GeoCoord.alt` | explicit |
///
/// # Example
///
/// ```rust,no_run
/// use bevy::prelude::*;
/// use rustial_renderer_bevy::components::{MapEntity, GeoTransform};
///
/// fn spawn_pin(mut commands: Commands) {
/// commands.spawn((
/// MapEntity,
/// GeoTransform::from_lat_lon(48.8566, 2.3522),
/// Transform::default(),
/// Visibility::default(),
/// ));
/// }
/// ```
/// How a [`GeoTransform`] entity's altitude is resolved.
///
/// Used by [`sync_geo_entities`](crate::systems::geo_entity_sync::sync_geo_entities)
/// to compute the Z component of `Transform.translation`.
///
/// When terrain is disabled or the elevation tile for the entity's
/// coordinate has not loaded yet, ground elevation is treated as 0 m.
// ---------------------------------------------------------------------------
// Placeholder entities
// ---------------------------------------------------------------------------
/// Marker component for loading-placeholder entities.
///
/// Placeholder entities are flat coloured quads displayed at tile
/// world bounds while tile data is still loading. They are managed
/// by [`sync_placeholders`](crate::systems::placeholder_sync::sync_placeholders)
/// which despawns and respawns them every frame based on the engine's
/// [`LoadingPlaceholder`](rustial_engine::LoadingPlaceholder) list.