项目更新
This commit is contained in:
@@ -78,7 +78,6 @@ class Data_Source_Aircraft_Stream {
|
||||
source.apply_aircraft_delta(Array.isArray(source_update.change_list) ? source_update.change_list : [], Array.isArray(source_update.removed_icaos) ? source_update.removed_icaos : []);
|
||||
source.apply_track_stream_list(Array.isArray(source_update.tracks) ? source_update.tracks : []);
|
||||
}
|
||||
app.cesium_map?.request_sync_data_sources();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ export class Data_Source_Map_Runtime {
|
||||
aircraft.refresh_from_change_list(item);
|
||||
this.aircraft_map.set(item.icao, aircraft);
|
||||
this.aircraft_change_versions.set(item.icao, String(item.change_version || ""));
|
||||
app.cesium_map?.update_aircraft(aircraft);
|
||||
}
|
||||
this.refresh_aircraft_range();
|
||||
}
|
||||
@@ -173,6 +174,7 @@ export class Data_Source_Map_Runtime {
|
||||
if (!aircraft) return;
|
||||
aircraft.hide_track();
|
||||
aircraft.pos_marker.remove();
|
||||
app.cesium_map?.remove_aircraft(app.cesium_map.entity_key(this.source.key, icao));
|
||||
this.aircraft_map.delete(icao);
|
||||
this.aircraft_change_versions.delete(icao);
|
||||
if (this.active_aircraft === aircraft) this.active_aircraft = null;
|
||||
@@ -216,6 +218,7 @@ export class Data_Source_Map_Runtime {
|
||||
if (!aircraft) continue;
|
||||
aircraft.is_show_path = true;
|
||||
aircraft.append_path_response(item);
|
||||
app.cesium_map?.update_aircraft(aircraft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-38
@@ -4,7 +4,7 @@ import {app} from "../App.tsx"
|
||||
import {baseURL, lightenColor, StateHolder} from "../Global.ts";
|
||||
import axios from "axios";
|
||||
import {Data_Source} from "../Data_Source/Data_Source.tsx";
|
||||
import {Aircraft_Model, Aircraft_Status, get_aircraft_angle, orientation_from_item} from "./Aircraft_Model.tsx";
|
||||
import {Aircraft_Model, Aircraft_Status} from "./Aircraft_Model.tsx";
|
||||
|
||||
class Aircraft_Marker extends Marker {
|
||||
constructor(latlng: LatLngExpression, options?: MarkerOptions) {
|
||||
@@ -74,7 +74,6 @@ export class Aircraft {
|
||||
|
||||
mlat: boolean
|
||||
track_point_list: Aircraft_Track_Point[] = []
|
||||
data_list: any[] = [];
|
||||
data_model: Aircraft_Model;
|
||||
status = new StateHolder<Aircraft_Status>(Aircraft_Status.Need_Init);
|
||||
angle = new StateHolder<number>(0);
|
||||
@@ -113,17 +112,16 @@ export class Aircraft {
|
||||
const svg = this.generateSVG(color, size, rotationDegree);
|
||||
const selected = this.data_source.active_aircraft === this;
|
||||
const outline = selected ? "filter: drop-shadow(1px 0 0 #111) drop-shadow(-1px 0 0 #111) drop-shadow(0 1px 0 #111) drop-shadow(0 -1px 0 #111) drop-shadow(0 0 4px #fff);" : "";
|
||||
|
||||
|
||||
const positionStyle = this.get_label_position(size);
|
||||
|
||||
|
||||
const lines: string[] = [];
|
||||
if (style.show_icao) lines.push(this.icao);
|
||||
if (style.show_call_sign) lines.push(this.call_sign);
|
||||
if (style.show_fly_status) lines.push(this.fly_status);
|
||||
if (style.show_heading) {
|
||||
lines.push(`航向 H ${this.data_model.heading.toFixed(1)}°`);
|
||||
lines.push(`vortex_type ${this.data_model.vortexType ?? "未知"}`);
|
||||
}
|
||||
let label=`</>`
|
||||
|
||||
if (lines.length != 0) {
|
||||
label = `
|
||||
<div style="position: absolute; ${positionStyle} font-size: 12px; transform: rotate(0deg); background-color: rgba(255, 255, 255); padding: 0; margin: 0; border-radius: 5px;">
|
||||
@@ -131,8 +129,6 @@ export class Aircraft {
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div style="position: relative; width: ${size}px; height: ${size}px;">
|
||||
@@ -193,27 +189,13 @@ export class Aircraft {
|
||||
});
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
refresh_pos_by_track() {
|
||||
let list = this.data_list;
|
||||
if (list.length >= 1) {
|
||||
let last_data = list[list.length - 1];
|
||||
let last_pos = L.latLng(last_data.lat, last_data.lon);
|
||||
if (list.length >= 2) {
|
||||
let second_last_data = list[list.length - 2];
|
||||
let second_last_pos = L.latLng(second_last_data.lat, second_last_data.lon, second_last_data.alt);
|
||||
let angle = get_aircraft_angle(second_last_pos, last_pos);
|
||||
this.angle.set(angle);
|
||||
// @ts-ignore
|
||||
this.pos_marker.setRotationAngle(this.angle);
|
||||
const points = this.data_model.track_points;
|
||||
if (points.length === 0) return;
|
||||
const last = points[points.length - 1];
|
||||
this.set_angle(this.data_model.heading)
|
||||
this.pos_marker.setLatLng(L.latLng(last.lat, last.lon, last.alt))
|
||||
}
|
||||
this.pos_marker.setLatLng(last_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
refresh_from_change_list(item) {
|
||||
const previous_alt = this.data_model.status === Aircraft_Status.Need_Init ? undefined : this.data_model.alt
|
||||
this.data_model.update_from_change(item, previous_alt)
|
||||
@@ -228,13 +210,8 @@ export class Aircraft {
|
||||
set_pos(lat: number, lon: number, alt : number) {
|
||||
let pos = L.latLng(lat, lon, alt);
|
||||
this.pos = pos;
|
||||
let old_pos = this.pos_marker.getLatLng();
|
||||
if (pos.lat != old_pos.lat || pos.lng != old_pos.lng) {
|
||||
let angle = get_aircraft_angle(old_pos, pos);
|
||||
this.set_angle(angle)
|
||||
this.pos_marker.setLatLng(pos);
|
||||
}
|
||||
}
|
||||
|
||||
apply_track_data(data: any) {
|
||||
if (!data) {
|
||||
@@ -249,13 +226,9 @@ export class Aircraft {
|
||||
}
|
||||
this.last_size = end_seq;
|
||||
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;
|
||||
this.data_model.update_orientation(data)
|
||||
}
|
||||
this.data_model.append_track_points(list)
|
||||
this.data_list.push(...list);
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,7 @@ export class Aircraft_Model {
|
||||
this.lat = Number(item.latitude)
|
||||
this.lon = Number(item.longitude)
|
||||
this.alt = Number(item.altitude || 0)
|
||||
this.trackOrientation = orientation_from_item(item, this.trackOrientation)
|
||||
this.heading = this.trackOrientation.heading
|
||||
this.pitch = this.trackOrientation.pitch
|
||||
this.roll = this.trackOrientation.roll
|
||||
this.update_orientation(item)
|
||||
this.timestamp = item.utc ?? item.timestamp ?? item.last_seen ?? this.timestamp
|
||||
this.call_sign = item.call_sign ?? this.call_sign
|
||||
this.vortexType = typeof item.vortex_type === "number" ? item.vortex_type : this.vortexType
|
||||
@@ -75,6 +72,24 @@ export class Aircraft_Model {
|
||||
properties: rest
|
||||
})
|
||||
}
|
||||
this.resolve_orientation()
|
||||
}
|
||||
update_orientation(item: any) {
|
||||
this.trackOrientation = orientation_from_item(item, this.trackOrientation)
|
||||
this.resolve_orientation()
|
||||
}
|
||||
private resolve_orientation() {
|
||||
if (this.track_points.length < 2) {
|
||||
this.heading = this.trackOrientation.heading
|
||||
this.pitch = this.trackOrientation.pitch
|
||||
this.roll = this.trackOrientation.roll
|
||||
return
|
||||
}
|
||||
const last = this.track_points.length - 1
|
||||
const orientation = orientation_from_points(this.track_points[last - 1], this.track_points[last])
|
||||
this.heading = orientation.heading
|
||||
this.pitch = orientation.pitch
|
||||
this.roll = orientation.roll
|
||||
}
|
||||
}
|
||||
export function orientation_from_item(item: any, fallback: Aircraft_Orientation_Model): Aircraft_Orientation_Model {
|
||||
@@ -110,6 +125,17 @@ function aircraft_status_text(status: Aircraft_Status): string {
|
||||
[Aircraft_Status.Need_Init]: "未初始化",
|
||||
}[status]
|
||||
}
|
||||
export function get_aircraft_angle(p1: { lat: number, lng: number }, p2: { lat: number, lng: number }) {
|
||||
return Math.atan2(p2.lng - p1.lng, p2.lat - p1.lat) * 180 / Math.PI
|
||||
function orientation_from_points(first: Aircraft_Track_Point_Model, second: Aircraft_Track_Point_Model): Aircraft_Orientation_Model {
|
||||
const radians = Math.PI / 180
|
||||
const lat1 = first.lat * radians
|
||||
const lat2 = second.lat * radians
|
||||
const delta_lat = (second.lat - first.lat) * radians
|
||||
const delta_lon = (second.lon - first.lon) * radians
|
||||
const y = Math.sin(delta_lon) * Math.cos(lat2)
|
||||
const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(delta_lon)
|
||||
const heading = (Math.atan2(y, x) / radians + 360) % 360
|
||||
const haversine = Math.sin(delta_lat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(delta_lon / 2) ** 2
|
||||
const distance = 6371000 * 2 * Math.atan2(Math.sqrt(haversine), Math.sqrt(1 - haversine))
|
||||
const pitch = Math.atan2(second.alt - first.alt, distance) / radians
|
||||
return {heading, pitch, roll: 0}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,14 @@
|
||||
import type {Aircraft} from "./Aircraft.tsx";
|
||||
import type {Cesium_Map} from "./Cesium_Map.tsx";
|
||||
|
||||
type Aircraft_Sync_Task = {
|
||||
key: string
|
||||
aircraft: Aircraft
|
||||
}
|
||||
|
||||
export class Cesium_Data_Source_Sync {
|
||||
private request_timer: number | null = null;
|
||||
private queue_timer: number | null = null;
|
||||
private generation = 0;
|
||||
private aircraft_tasks: Aircraft_Sync_Task[] = [];
|
||||
private refreshing = false;
|
||||
|
||||
constructor(private readonly map: Cesium_Map) {}
|
||||
|
||||
destroy() {
|
||||
if (this.request_timer) window.clearTimeout(this.request_timer);
|
||||
if (this.queue_timer) window.clearTimeout(this.queue_timer);
|
||||
this.request_timer = null;
|
||||
this.queue_timer = null;
|
||||
this.aircraft_tasks = [];
|
||||
this.generation++;
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
@@ -47,14 +34,8 @@ export class Cesium_Data_Source_Sync {
|
||||
|
||||
sync() {
|
||||
if (!this.map.viewer) return;
|
||||
if (this.queue_timer) {
|
||||
window.clearTimeout(this.queue_timer);
|
||||
this.queue_timer = null;
|
||||
}
|
||||
const generation = ++this.generation;
|
||||
const alive = new Set<string>();
|
||||
const alive_base_stations = new Set<string>();
|
||||
const tasks: Aircraft_Sync_Task[] = [];
|
||||
for (const source of this.map.list()) {
|
||||
if (!source.enable) continue;
|
||||
this.map.sync_base_station(source, alive_base_stations);
|
||||
@@ -62,10 +43,9 @@ export class Cesium_Data_Source_Sync {
|
||||
for (const [icao, aircraft] of source.aircraftMap) {
|
||||
const key = this.map.entity_key(source.key, icao);
|
||||
alive.add(key);
|
||||
tasks.push({key, aircraft});
|
||||
this.map.sync_aircraft(key, aircraft);
|
||||
}
|
||||
}
|
||||
this.aircraft_tasks = tasks;
|
||||
for (const [key, record] of this.map.entity_map) {
|
||||
if (alive.has(key)) continue;
|
||||
this.map.remove_aircraft_record(record);
|
||||
@@ -79,25 +59,6 @@ export class Cesium_Data_Source_Sync {
|
||||
this.map.remove_base_station_record(record);
|
||||
this.map.base_station_entity_map.delete(key);
|
||||
}
|
||||
this.process_queue(generation);
|
||||
}
|
||||
|
||||
private process_queue(generation: number) {
|
||||
if (!this.map.viewer || generation !== this.generation) return;
|
||||
const start = performance.now();
|
||||
let count = 0;
|
||||
while (this.aircraft_tasks.length > 0 && count < 10 && (count === 0 || performance.now() - start < 8)) {
|
||||
const task = this.aircraft_tasks.shift()!;
|
||||
this.map.sync_aircraft(task.key, task.aircraft);
|
||||
count++;
|
||||
}
|
||||
if (this.aircraft_tasks.length > 0) {
|
||||
this.queue_timer = window.setTimeout(() => {
|
||||
this.queue_timer = null;
|
||||
this.process_queue(generation);
|
||||
}, 180);
|
||||
return;
|
||||
}
|
||||
this.map.viewer.scene.requestRender();
|
||||
}
|
||||
}
|
||||
|
||||
+33
-8
@@ -1148,6 +1148,22 @@ export class Cesium_Map extends enhance.Base {
|
||||
sync_aircraft(key: string, aircraft: Aircraft) {
|
||||
this.aircraft_layer.sync(key, aircraft);
|
||||
}
|
||||
update_aircraft(aircraft: Aircraft) {
|
||||
const key = this.entity_key(aircraft.data_source.key, aircraft.icao);
|
||||
if (aircraft.data_source.enable && aircraft.data_source.map3d_style().aircraft_show) {
|
||||
this.sync_aircraft(key, aircraft);
|
||||
} else {
|
||||
this.remove_aircraft(key);
|
||||
}
|
||||
this.viewer?.scene.requestRender();
|
||||
}
|
||||
remove_aircraft(key: string) {
|
||||
const record = this.entity_map.get(key);
|
||||
if (!record) return;
|
||||
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();
|
||||
}
|
||||
ensure_aircraft_track_entities(key: string, aircraft: Aircraft, record: Aircraft_Entity_Record) {
|
||||
this.aircraft_layer.ensure_track_entities(key, aircraft, record);
|
||||
}
|
||||
@@ -1238,7 +1254,6 @@ export class Cesium_Map extends enhance.Base {
|
||||
record.occlusion_marker.description = new Cesium.ConstantProperty(this.aircraft_occlusion_description(aircraft, result));
|
||||
}
|
||||
if (record.aircraft.model) {
|
||||
const selected = this.is_selected_aircraft(this.entity_key(aircraft.data_source.key, aircraft.icao));
|
||||
record.aircraft.model.silhouetteColor = new Cesium.ConstantProperty(color);
|
||||
record.aircraft.model.silhouetteSize = new Cesium.ConstantProperty(result ? result.obstructed ? 2 : 0 : 1);
|
||||
}
|
||||
@@ -1309,13 +1324,13 @@ export class Cesium_Map extends enhance.Base {
|
||||
return {lon: model.lon, lat: model.lat, alt: model.alt};
|
||||
}
|
||||
aircraft_heading(aircraft: Aircraft): number {
|
||||
return aircraft.data_model.trackOrientation.heading;
|
||||
return aircraft.data_model.heading;
|
||||
}
|
||||
aircraft_pitch(aircraft: Aircraft): number {
|
||||
return aircraft.data_model.trackOrientation.pitch || 0;
|
||||
return aircraft.data_model.pitch;
|
||||
}
|
||||
aircraft_roll(aircraft: Aircraft): number {
|
||||
return aircraft.data_model.trackOrientation.roll || 0;
|
||||
return aircraft.data_model.roll;
|
||||
}
|
||||
aircraft_orientation(aircraft: Aircraft, position: Cesium.Cartesian3): Cesium.Quaternion {
|
||||
const model = this.aircraft_model_item(aircraft);
|
||||
@@ -1392,7 +1407,7 @@ export class Cesium_Map extends enhance.Base {
|
||||
}
|
||||
aircraft_label_enabled(aircraft: Aircraft): boolean {
|
||||
const source = aircraft.data_source.map3d_style();
|
||||
return source.show_icao || source.show_call_sign || source.show_fly_status;
|
||||
return source.show_icao || source.show_call_sign || source.show_fly_status || source.show_heading;
|
||||
}
|
||||
should_show_aircraft_track(key: string, aircraft: Aircraft): boolean {
|
||||
return this.is_selected_aircraft(key) || aircraft.data_source.is_aircraft_track_monitored(aircraft.icao);
|
||||
@@ -1403,9 +1418,19 @@ export class Cesium_Map extends enhance.Base {
|
||||
const model = aircraft.data_model;
|
||||
if (source.show_icao) lines.push(model.icao);
|
||||
if (source.show_call_sign && model.call_sign) lines.push(model.call_sign);
|
||||
if (source.show_fly_status && model.fly_status) lines.push(`${model.fly_status} ${model.heading.toFixed(0)}°`);
|
||||
if (source.show_fly_status && model.fly_status) lines.push(model.fly_status);
|
||||
if (source.show_heading) {
|
||||
const config = this.aircraft_model_item(aircraft);
|
||||
lines.push(`vortex_type ${model.vortexType ?? "未知"}`);
|
||||
lines.push(`当前 H ${model.heading.toFixed(1)}° P ${model.pitch.toFixed(1)}° R ${model.roll.toFixed(1)}°`);
|
||||
lines.push(`偏移 H ${config.heading_offset_degrees.toFixed(1)}° P ${config.pitch_offset_degrees.toFixed(1)}° R ${config.roll_offset_degrees.toFixed(1)}°`);
|
||||
lines.push(`模型 H ${this.normalize_degrees(model.heading + config.heading_offset_degrees).toFixed(1)}° P ${(model.pitch + config.pitch_offset_degrees).toFixed(1)}° R ${(model.roll + config.roll_offset_degrees).toFixed(1)}°`);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
normalize_degrees(value: number): number {
|
||||
return (value % 360 + 360) % 360;
|
||||
}
|
||||
sync_track_points(key: string, aircraft: Aircraft, record: Aircraft_Entity_Record) {
|
||||
this.ensure_aircraft_track_entities(key, aircraft, record);
|
||||
const points = aircraft.data_model.track_points;
|
||||
@@ -1596,8 +1621,8 @@ export class Cesium_Map extends enhance.Base {
|
||||
`高度: ${model.alt}`,
|
||||
`航向: ${model.heading.toFixed(1)}°`,
|
||||
`涡流/目标类型: ${model.vortexTypeLabel || model.vortexTypeKey || ""}`,
|
||||
`航迹俯仰: ${model.trackOrientation.pitch.toFixed(1)}°`,
|
||||
`航迹横滚: ${model.trackOrientation.roll.toFixed(1)}°`
|
||||
`航迹俯仰: ${model.pitch.toFixed(1)}°`,
|
||||
`航迹横滚: ${model.roll.toFixed(1)}°`
|
||||
].join("<br>");
|
||||
}
|
||||
track_point_description(point: Aircraft_Track_Point_Model) {
|
||||
|
||||
Reference in New Issue
Block a user