feat(earth): add cable-landing point relation via city_id

Backend:
- Fix arcgis_landing collector to extract city_id
- Fix arcgis_relation collector to extract city_id
- Fix convert_landing_point_to_geojson to use city_id mapping

Frontend:
- Update landing point cableNames to use array
- Add applyLandingPointVisualState for cable lock highlight
- Dim all landing points when satellite is locked
This commit is contained in:
linkong
2026-03-20 15:45:02 +08:00
parent 3e3090d72a
commit 3fcbae55dc
5 changed files with 139 additions and 26 deletions

View File

@@ -286,7 +286,7 @@ export async function loadLandingPoints(scene, earthObj) {
sphere.userData = {
type: 'landingPoint',
name: properties.name || '未知登陆站',
cableName: properties.cable_system || '未知系统',
cableNames: properties.cable_names || [],
country: properties.country || '未知国家',
status: properties.status || 'Unknown'
};
@@ -362,3 +362,47 @@ export function getCableStateInfo() {
});
return states;
}
export function getLandingPointsByCableName(cableName) {
return landingPoints.filter(lp => lp.userData.cableNames?.includes(cableName));
}
export function getAllLandingPoints() {
return landingPoints;
}
export function applyLandingPointVisualState(lockedCableName, dimAll = false) {
const pulse = (Math.sin(Date.now() * 0.003) + 1) * 0.5;
const brightness = 0.3;
landingPoints.forEach(lp => {
const isRelated = !dimAll && lp.userData.cableNames?.includes(lockedCableName);
if (isRelated) {
lp.material.color.setHex(0xffaa00);
lp.material.emissive.setHex(0x442200);
lp.material.emissiveIntensity = 0.5 + pulse * 0.5;
lp.material.opacity = 0.8 + pulse * 0.2;
lp.scale.setScalar(1.2 + pulse * 0.3);
} else {
const r = 255 * brightness;
const g = 170 * brightness;
const b = 0 * brightness;
lp.material.color.setRGB(r / 255, g / 255, b / 255);
lp.material.emissive.setHex(0x000000);
lp.material.emissiveIntensity = 0;
lp.material.opacity = 0.3;
lp.scale.setScalar(1.0);
}
});
}
export function resetLandingPointVisualState() {
landingPoints.forEach(lp => {
lp.material.color.setHex(0xffaa00);
lp.material.emissive.setHex(0x442200);
lp.material.emissiveIntensity = 0.5;
lp.material.opacity = 1.0;
lp.scale.setScalar(1.0);
});
}

View File

@@ -13,7 +13,7 @@ import {
hideTooltip
} from './ui.js';
import { createEarth, createClouds, createTerrain, createStars, createGridLines, toggleTerrain, getEarth } from './earth.js';
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked, getCableState, setCableState, clearAllCableStates } from './cables.js';
import { loadGeoJSONFromPath, loadLandingPoints, handleCableClick, clearCableSelection, getCableLines, getCablesById, lockedCable as cableLocked, getCableState, setCableState, clearAllCableStates, applyLandingPointVisualState, resetLandingPointVisualState, getAllLandingPoints } from './cables.js';
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, selectSatellite, getSatelliteData, getSatellitePoints, setSatelliteRingState, updateLockedRingPosition, updateHoverRingPosition, getSatellitePositions } from './satellites.js';
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate, resetView } from './controls.js';
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
@@ -475,6 +475,14 @@ function animate() {
applyCableVisualState();
if (lockedObjectType === 'cable' && lockedObject) {
applyLandingPointVisualState(lockedObject.userData.name, false);
} else if (lockedObjectType === 'satellite' && lockedSatellite) {
applyLandingPointVisualState(null, true);
} else {
resetLandingPointVisualState();
}
updateSatellitePositions(16);
const satPositions = getSatellitePositions();