diff --git a/src/Data_Source/Data_Source.tsx b/src/Data_Source/Data_Source.tsx index dd35a50..03b4878 100644 --- a/src/Data_Source/Data_Source.tsx +++ b/src/Data_Source/Data_Source.tsx @@ -35,6 +35,10 @@ export type Data_Source_Map_Display_Config = { map2d: Data_Source_Map_Display_Data map3d: Data_Source_Map_Display_Data } +type Aircraft_Track_Request_Item = { + icao: string + last_size: number +} export function default_map_display_data(): Data_Source_Map_Display_Data { return { base_station_show: true, @@ -187,6 +191,13 @@ export class Data_Source extends enhance.Base { } async set_monitor_all_aircraft_mode(enabled: boolean) { this.monitor_all_aircraft_mode = enabled; + if (!enabled) { + for (const aircraft of this.aircraftMap.values()) { + if (!this.manual_track_icao_set.has(aircraft.icao)) { + aircraft.hide_path(); + } + } + } await this.refresh_manual_tracked_aircraft(); this.refresh_manual_tracking_views(); } @@ -210,19 +221,35 @@ export class Data_Source extends enhance.Base { this.manual_track_icao_set.clear(); this.refresh_manual_tracking_views(); } - async refresh_manual_tracked_aircraft() { - const tasks: Promise[] = []; - const tracked_icaos = new Set(this.monitor_all_aircraft_mode ? Array.from(this.aircraftMap.keys()) : []); - for (const icao of this.manual_track_icao_set) { - tracked_icaos.add(icao); - } - for (const icao of tracked_icaos) { + tracked_aircraft_track_request_items(): Aircraft_Track_Request_Item[] { + const tracked_icaos = this.monitor_all_aircraft_mode ? Array.from(this.aircraftMap.keys()) : this.manual_track_icao_list(); + const ret: Aircraft_Track_Request_Item[] = []; + tracked_icaos.forEach((icao) => { const aircraft = this.aircraftMap.get(icao); if (aircraft) { - tasks.push(aircraft.refresh_monitored_path()); + ret.push({icao, last_size: aircraft.last_size}); } + }); + return ret; + } + async refresh_manual_tracked_aircraft() { + const items = this.tracked_aircraft_track_request_items(); + if (items.length === 0) { + return; } - await Promise.all(tasks); + const res = await axios.post(`${baseURL}/get_aircraft_track_list_batch`, { + data_source_key: this.key, + items + }); + const list = Array.isArray(res.data?.list) ? res.data.list : []; + list.forEach((item: any) => { + const aircraft = this.aircraftMap.get(item.icao); + if (!aircraft) { + return; + } + aircraft.is_show_path = true; + aircraft.append_path_response(item); + }); } refresh_manual_tracking_views() { app.cesium_map?.sync_data_sources(); diff --git a/src/Map/Aircraft.tsx b/src/Map/Aircraft.tsx index 79d0142..dd3661b 100644 --- a/src/Map/Aircraft.tsx +++ b/src/Map/Aircraft.tsx @@ -481,19 +481,23 @@ export class Aircraft { icao: this.icao, last_size: this.last_size }) - if (!res.data) { + return this.apply_track_data(res.data) + } + + apply_track_data(data: any) { + if (!data) { return [] } - let list = res.data.list; - let end_seq = res.data.end_seq; - let sta_seq = res.data.sta_seq; + let list = Array.isArray(data.list) ? data.list : []; + let end_seq = Number(data.end_seq ?? this.last_size); + let sta_seq = Number(data.sta_seq ?? this.last_size); let old_seq = this.last_size; if (sta_seq != old_seq) { return [] } this.last_size = end_seq; - if (res.data.track_orientation) { - this.data_model.trackOrientation = orientation_from_item(res.data, this.data_model.trackOrientation); + if (data.track_orientation) { + this.data_model.trackOrientation = orientation_from_item(data, this.data_model.trackOrientation); this.data_model.heading = this.data_model.trackOrientation.heading; this.data_model.pitch = this.data_model.trackOrientation.pitch; this.data_model.roll = this.data_model.trackOrientation.roll; @@ -504,28 +508,37 @@ export class Aircraft { } append_path() { + return this.load_track_data().then(list => this.append_loaded_path(list)) + } + + append_loaded_path(list: any[]) { let map = app.leaflet_map?.map; - return this.load_track_data().then(list => { - list.forEach((data) => { - let point = new Aircraft_Track_Point(data); - const style = this.data_source.map2d_style(); - point.setColor(style.track_point_color || lightenColor(style.color)); - if (map) { - point.addTo(map); - } - this.track_point_list.push(point) - this.track_path.addLatLng(point.getLatLng()); - }); - this.track_point_list.forEach((data, i) => { - if (map) { + list.forEach((data) => { + let point = new Aircraft_Track_Point(data); + const style = this.data_source.map2d_style(); + point.setColor(style.track_point_color || lightenColor(style.color)); + if (map) { + point.addTo(map); + } + this.track_point_list.push(point) + this.track_path.addLatLng(point.getLatLng()); + }); + this.track_point_list.forEach((data) => { + if (map) { + if (!map.hasLayer(data)) { data.addTo(map) } - }); - if (map) { + } + }); + if (map) { + if (!map.hasLayer(this.track_path)) { this.track_path.addTo(map) } - this.refresh_pos_by_track(); - }) + } + this.refresh_pos_by_track(); + } + append_path_response(data: any) { + this.append_loaded_path(this.apply_track_data(data)); } refresh_monitored_path() { this.is_show_path = true; diff --git a/src/Map/Cesium_Map.tsx b/src/Map/Cesium_Map.tsx index 27ade1c..4111c52 100644 --- a/src/Map/Cesium_Map.tsx +++ b/src/Map/Cesium_Map.tsx @@ -46,11 +46,21 @@ import {mark_cesium_webgl_unavailable, webgl_unavailable_message} from "./WebGL_ type Aircraft_Entity_Record = { aircraft: Cesium.Entity track: Cesium.Entity - point_entities: Cesium.Entity[] + point_collection: Cesium.PointPrimitiveCollection + point_records: Cesium_Track_Point_Record[] point_start_index: number track_positions: Cesium.Cartesian3[] track_positions_key: string } +type Cesium_Track_Point_Record = { + primitive?: Cesium.PointPrimitive + entity?: Cesium.Entity +} +type Track_Point_Pick_Record = { + ecap_track_point: Aircraft_Track_Point_Model + ecap_track_key: string + ecap_track_description: string +} type Base_Station_Entity_Record = { model: Cesium.Entity height_line: Cesium.Entity @@ -114,6 +124,7 @@ export class Cesium_Map extends enhance.Base { performance_observer: PerformanceObserver | null = null; performance_info: Performance_Info = {fps: 0, frame_ms: 0, cpu_pressure: 0, js_heap_mb: null, gpu_renderer: "", tile_state: ""}; context_menu: Cesium_Context_Menu | null = null; + track_point_selection_entity: Cesium.Entity | null = null; prevent_context_menu_listener: ((event: Event) => void) | null = null; max_track_points_per_aircraft = 1000; constructor(scene_mode: Scene_Mode_Key = "3d") { @@ -527,11 +538,7 @@ export class Cesium_Map extends enhance.Base { } for (const [key, record] of this.entity_map) { if (alive.has(key)) continue; - this.viewer.entities.remove(record.aircraft); - this.viewer.entities.remove(record.track); - for (const point of record.point_entities) { - this.viewer.entities.remove(point); - } + this.remove_aircraft_record(record); this.entity_map.delete(key); if (this.selected_aircraft && key === this.entity_key(this.selected_aircraft.data_source.key, this.selected_aircraft.icao)) { this.clear_selected_aircraft(); @@ -924,7 +931,15 @@ export class Cesium_Map extends enhance.Base { } }); (aircraft_entity as any).ecap_aircraft = aircraft; - return {aircraft: aircraft_entity, track: track_entity, point_entities: [], point_start_index: 0, track_positions, track_positions_key: ""}; + const point_collection = this.viewer!.scene.primitives.add(new Cesium.PointPrimitiveCollection()) as Cesium.PointPrimitiveCollection; + point_collection.show = false; + return {aircraft: aircraft_entity, track: track_entity, point_collection, point_records: [], point_start_index: 0, track_positions, track_positions_key: ""}; + } + remove_aircraft_record(record: Aircraft_Entity_Record) { + this.viewer!.entities.remove(record.aircraft); + this.viewer!.entities.remove(record.track); + this.clear_track_point_records(record); + this.viewer!.scene.primitives.remove(record.point_collection); } aircraft_model_item(aircraft: Aircraft): Map_Model_Item_Config { const key = aircraft.data_model.vortexTypeKey; @@ -996,6 +1011,16 @@ export class Cesium_Map extends enhance.Base { if (record.track.polyline) { record.track.polyline.material = new Cesium.ColorMaterialProperty(color.withAlpha(0.8)); } + this.apply_track_point_style(record, aircraft); + } + apply_track_point_style(record: Aircraft_Entity_Record, aircraft: Aircraft) { + const style = aircraft.data_source.map3d_style(); + const color = Cesium.Color.fromCssColorString(style.track_point_color || style.color).withAlpha(0.9); + for (const point of record.point_records) { + if (point.primitive) { + point.primitive.color = color; + } + } } aircraft_label_enabled(aircraft: Aircraft): boolean { const source = aircraft.data_source.map3d_style(); @@ -1015,24 +1040,21 @@ export class Cesium_Map extends enhance.Base { } sync_track_points(key: string, aircraft: Aircraft, record: Aircraft_Entity_Record) { const points = aircraft.data_model.track_points; - if (points.length < record.point_start_index + record.point_entities.length) { - for (const entity of record.point_entities) { - this.viewer!.entities.remove(entity); - } - record.point_entities = []; + if (points.length < record.point_start_index + record.point_records.length) { + this.clear_track_point_records(record); record.point_start_index = 0; } const next_start = Math.max(0, points.length - this.max_track_points_per_aircraft); if (next_start > record.point_start_index) { - const remove_count = Math.min(next_start - record.point_start_index, record.point_entities.length); - for (const entity of record.point_entities.splice(0, remove_count)) { - this.viewer!.entities.remove(entity); + const remove_count = Math.min(next_start - record.point_start_index, record.point_records.length); + for (const item of record.point_records.splice(0, remove_count)) { + this.remove_track_point_record(record, item); } record.point_start_index += remove_count; } - const next_index = record.point_start_index + record.point_entities.length; + const next_index = record.point_start_index + record.point_records.length; for (let i = next_index; i < points.length; i++) { - record.point_entities.push(this.create_track_point_entity(key, aircraft, points[i], i)); + record.point_records.push(this.create_track_point_record(record, key, aircraft, points[i], i)); } const displayed_points = points.slice(record.point_start_index); const aircraft_position = this.aircraft_position(aircraft); @@ -1050,9 +1072,43 @@ export class Cesium_Map extends enhance.Base { } this.show_track(record); } + clear_track_point_records(record: Aircraft_Entity_Record) { + for (const point of record.point_records) { + this.remove_track_point_record(record, point); + } + record.point_records = []; + } + remove_track_point_record(record: Aircraft_Entity_Record, point: Cesium_Track_Point_Record) { + if (point.primitive) { + record.point_collection.remove(point.primitive); + } + if (point.entity) { + this.viewer!.entities.remove(point.entity); + } + } same_position(left: Aircraft_Position, right: Aircraft_Position): boolean { return left.lon === right.lon && left.lat === right.lat && left.alt === right.alt; } + create_track_point_record(record: Aircraft_Entity_Record, key: string, aircraft: Aircraft, point: Aircraft_Track_Point_Model, index: number): Cesium_Track_Point_Record { + if (this.is_special_track_point(point)) { + return {entity: this.create_track_point_entity(key, aircraft, point, index)}; + } + const style = aircraft.data_source.map3d_style(); + const id: Track_Point_Pick_Record = { + ecap_track_point: point, + ecap_track_key: key, + ecap_track_description: this.track_point_description(point) + }; + const primitive = record.point_collection.add({ + position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat, point.alt), + pixelSize: 7, + color: Cesium.Color.fromCssColorString(style.track_point_color || style.color).withAlpha(0.9), + outlineColor: Cesium.Color.BLACK, + outlineWidth: 1, + id + }); + return {primitive}; + } create_track_point_entity(key: string, aircraft: Aircraft, point: Aircraft_Track_Point_Model, index: number): Cesium.Entity { const base = { id: `${key}:point:${index}`, @@ -1060,21 +1116,12 @@ export class Cesium_Map extends enhance.Base { position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat, point.alt), description: this.track_point_description(point) }; - const entity = this.viewer!.entities.add(this.is_special_track_point(point) ? { + const entity = this.viewer!.entities.add({ ...base, model: { uri: track_point_model_uri, scale: 16 } - } : { - ...base, - point: { - pixelSize: 7, - color: Cesium.Color.fromCssColorString(aircraft.data_source.map3d_style().track_point_color || aircraft.data_source.map3d_style().color).withAlpha(0.9), - outlineColor: Cesium.Color.BLACK, - outlineWidth: 1, - heightReference: Cesium.HeightReference.NONE - } }); (entity as any).ecap_track_point = point; (entity as any).ecap_track_key = key; @@ -1086,8 +1133,11 @@ export class Cesium_Map extends enhance.Base { } hide_track(record: Aircraft_Entity_Record) { record.track.show = false; - for (const entity of record.point_entities) { - entity.show = false; + record.point_collection.show = false; + for (const point of record.point_records) { + if (point.entity) { + point.entity.show = false; + } } } hide_all_tracks() { @@ -1099,8 +1149,11 @@ export class Cesium_Map extends enhance.Base { } show_track(record: Aircraft_Entity_Record) { record.track.show = true; - for (const entity of record.point_entities) { - entity.show = true; + record.point_collection.show = true; + for (const point of record.point_records) { + if (point.entity) { + point.entity.show = true; + } } } record_is_track_monitored(record: Aircraft_Entity_Record): boolean { @@ -1111,23 +1164,25 @@ export class Cesium_Map extends enhance.Base { const properties = point.properties || {}; return Boolean(properties.alarm || properties.alert || properties.warning || properties.is_alarm || properties.event_type); } - pick_interactive_entity(position: Cesium.Cartesian2): Cesium.Entity | null { + pick_interactive_target(position: Cesium.Cartesian2): Cesium.Entity | Track_Point_Pick_Record | null { if (!this.viewer) return null; const picked_list = this.viewer.scene.drillPick(position, 16); for (const picked of picked_list) { - const entity = picked.id as Cesium.Entity | undefined; - if (!entity || (entity as any).ecap_ignore_pick) { + const target = picked.id as Cesium.Entity | Track_Point_Pick_Record | undefined; + if (!target || (target as any).ecap_ignore_pick) { continue; } - return entity; + if ((target as any).ecap_aircraft || (target as any).ecap_base_station || (target as any).ecap_track_point) { + return target; + } } return null; } handle_right_click(position: Cesium.Cartesian2) { if (!this.viewer) return; - const entity = this.pick_interactive_entity(position); - const aircraft = entity ? (entity as any).ecap_aircraft as Aircraft | undefined : undefined; - const base_station = entity ? (entity as any).ecap_base_station as Data_Source | undefined : undefined; + const target = this.pick_interactive_target(position); + const aircraft = target ? (target as any).ecap_aircraft as Aircraft | undefined : undefined; + const base_station = target ? (target as any).ecap_base_station as Data_Source | undefined : undefined; if (aircraft) { this.context_menu = {x: position.x, y: position.y, aircraft}; this.flush(); @@ -1144,24 +1199,24 @@ export class Cesium_Map extends enhance.Base { handle_click(position: Cesium.Cartesian2) { if (!this.viewer) return; this.context_menu = null; - const entity = this.pick_interactive_entity(position); - if (!entity) { + const target = this.pick_interactive_target(position); + if (!target) { this.clear_selected_aircraft(); return; } - const aircraft = (entity as any).ecap_aircraft as Aircraft | undefined; + const aircraft = (target as any).ecap_aircraft as Aircraft | undefined; if (aircraft) { this.select_aircraft(aircraft); return; } - const track_point = (entity as any).ecap_track_point as Aircraft_Track_Point_Model | undefined; + const track_point = (target as any).ecap_track_point as Aircraft_Track_Point_Model | undefined; if (track_point) { - this.select_track_point(entity); + this.select_track_point(target); return; } - const base_station = (entity as any).ecap_base_station as Data_Source | undefined; + const base_station = (target as any).ecap_base_station as Data_Source | undefined; if (base_station) { - this.select_base_station(entity); + this.select_base_station(target as Cesium.Entity); return; } this.clear_selected_aircraft(); @@ -1173,9 +1228,20 @@ export class Cesium_Map extends enhance.Base { this.viewer.selectedEntity = entity; this.viewer.scene.requestRender(); } - select_track_point(entity: Cesium.Entity) { + select_track_point(target: Cesium.Entity | Track_Point_Pick_Record) { if (!this.viewer) return; - this.viewer.selectedEntity = entity; + const primitive_track_point = target as Track_Point_Pick_Record; + if (primitive_track_point.ecap_track_description) { + if (!this.track_point_selection_entity) { + this.track_point_selection_entity = this.viewer.entities.add({id: "ecap:selected-track-point", show: false}); + } + this.track_point_selection_entity.name = "轨迹点"; + this.track_point_selection_entity.position = new Cesium.ConstantPositionProperty(Cesium.Cartesian3.fromDegrees(primitive_track_point.ecap_track_point.lon, primitive_track_point.ecap_track_point.lat, primitive_track_point.ecap_track_point.alt)); + this.track_point_selection_entity.description = new Cesium.ConstantProperty(primitive_track_point.ecap_track_description); + this.viewer.selectedEntity = this.track_point_selection_entity; + } else { + this.viewer.selectedEntity = target as Cesium.Entity; + } this.viewer.scene.requestRender(); } select_aircraft(aircraft: Aircraft) {