считывание точки прицеливания с карты

This commit is contained in:
emelianov
2026-06-23 17:13:30 +03:00
parent 1e8b9f6998
commit d0ec0ef754
2 changed files with 106 additions and 29 deletions
@@ -8,7 +8,9 @@
viewer: null, viewer: null,
mapDataSource: null, mapDataSource: null,
pickHandler: null, pickHandler: null,
resizeObserver: null,
cursorCoordsPanel: null, cursorCoordsPanel: null,
targetOverlay: null,
}; };
function el(id) { function el(id) {
@@ -169,13 +171,15 @@
...naturalEarthLayerOptions(), ...naturalEarthLayerOptions(),
}); });
state.viewer.scene.globe.enableLighting = false; state.viewer.scene.globe.enableLighting = false;
state.viewer.scene.requestRenderMode = true; state.viewer.scene.requestRenderMode = false;
state.mapDataSource = new Cesium.CustomDataSource('angular-motion-map-data'); state.mapDataSource = new Cesium.CustomDataSource('angular-motion-map-data');
state.viewer.dataSources.add(state.mapDataSource); state.viewer.dataSources.add(state.mapDataSource);
initCursorCoordinates(); initCursorCoordinates();
initTargetOverlay();
state.pickHandler = new Cesium.ScreenSpaceEventHandler(state.viewer.scene.canvas); state.pickHandler = new Cesium.ScreenSpaceEventHandler(state.viewer.scene.canvas);
state.pickHandler.setInputAction(function (movement) { state.pickHandler.setInputAction(function (movement) {
if (!state.picking) return; if (!state.picking) return;
resizeMap();
const cartesian = pickGlobePoint(movement.position); const cartesian = pickGlobePoint(movement.position);
if (!cartesian) return; if (!cartesian) return;
const cartographic = Cesium.Cartographic.fromCartesian(cartesian); const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
@@ -183,10 +187,37 @@
el('angular-motion-lon').value = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6); el('angular-motion-lon').value = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
setPicking(false); setPicking(false);
drawMap(); drawMap();
updateTargetOverlay(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
initMapResizeSync();
state.viewer.scene.postRender.addEventListener(() => updateTargetOverlay());
drawMap(); drawMap();
} }
function initMapResizeSync() {
window.addEventListener('resize', scheduleMapResize);
if (typeof ResizeObserver !== 'undefined') {
state.resizeObserver = new ResizeObserver(scheduleMapResize);
state.resizeObserver.observe(el('angular-motion-map'));
}
scheduleMapResize();
}
function scheduleMapResize() {
resizeMap();
requestAnimationFrame(() => {
resizeMap();
requestAnimationFrame(resizeMap);
});
setTimeout(resizeMap, 100);
}
function resizeMap() {
if (!state.viewer) return;
state.viewer.resize();
state.viewer.scene.requestRender();
}
function initCursorCoordinates() { function initCursorCoordinates() {
state.cursorCoordsPanel = document.createElement('div'); state.cursorCoordsPanel = document.createElement('div');
state.cursorCoordsPanel.className = 'angular-motion-cursor-coords-panel'; state.cursorCoordsPanel.className = 'angular-motion-cursor-coords-panel';
@@ -207,6 +238,13 @@
}); });
} }
function initTargetOverlay() {
state.targetOverlay = document.createElement('div');
state.targetOverlay.className = 'angular-motion-target-marker';
state.targetOverlay.innerHTML = '<span class="angular-motion-target-marker__label">ЦЛМ</span><span class="angular-motion-target-marker__dot"></span>';
state.viewer.cesiumWidget.container.appendChild(state.targetOverlay);
}
function naturalEarthLayerOptions() { function naturalEarthLayerOptions() {
const url = '/webjars/cesium/1.107.2/Build/Cesium/Assets/Textures/NaturalEarthII'; const url = '/webjars/cesium/1.107.2/Build/Cesium/Assets/Textures/NaturalEarthII';
if (Cesium.ImageryLayer?.fromProviderAsync && Cesium.TileMapServiceImageryProvider?.fromUrl) { if (Cesium.ImageryLayer?.fromProviderAsync && Cesium.TileMapServiceImageryProvider?.fromUrl) {
@@ -225,9 +263,10 @@
function pickGlobePoint(position) { function pickGlobePoint(position) {
if (!state.viewer || !position) return null; if (!state.viewer || !position) return null;
const scene = state.viewer.scene; const scene = state.viewer.scene;
if (scene.pickPositionSupported) { const ray = state.viewer.camera.getPickRay(position);
const picked = scene.pickPosition(position); if (ray) {
if (Cesium.defined(picked)) return picked; const globePoint = scene.globe.pick(ray, scene);
if (Cesium.defined(globePoint)) return globePoint;
} }
return state.viewer.camera.pickEllipsoid(position, scene.globe.ellipsoid); return state.viewer.camera.pickEllipsoid(position, scene.globe.ellipsoid);
} }
@@ -324,32 +363,27 @@
}); });
} }
function addTarget() { function updateTargetOverlay(screenPosition = null) {
if (!state.mapDataSource) return; if (!state.viewer || !state.targetOverlay) return;
const lat = Number(el('angular-motion-lat').value); const lat = Number(el('angular-motion-lat').value);
const lon = Number(el('angular-motion-lon').value); const lon = Number(el('angular-motion-lon').value);
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return; if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
state.mapDataSource.entities.add({ state.targetOverlay.style.display = 'none';
name: 'Точка съемки', return;
position: Cesium.Cartesian3.fromDegrees(lon, lat, 0), }
point: {
pixelSize: 10, const position = screenPosition || Cesium.SceneTransforms.wgs84ToWindowCoordinates(
color: Cesium.Color.RED, state.viewer.scene,
outlineColor: Cesium.Color.WHITE, Cesium.Cartesian3.fromDegrees(lon, lat, 0)
outlineWidth: 2, );
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, if (!Cesium.defined(position)) {
}, state.targetOverlay.style.display = 'none';
label: { return;
text: 'ЦЛМ', }
font: '12px sans-serif',
fillColor: Cesium.Color.RED, state.targetOverlay.style.display = 'block';
outlineColor: Cesium.Color.WHITE, state.targetOverlay.style.left = `${position.x}px`;
outlineWidth: 2, state.targetOverlay.style.top = `${position.y}px`;
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -18),
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
} }
function flightLineBounds() { function flightLineBounds() {
@@ -400,19 +434,29 @@
function drawMap(centerMode = null) { function drawMap(centerMode = null) {
if (!state.mapDataSource || typeof Cesium === 'undefined') return; if (!state.mapDataSource || typeof Cesium === 'undefined') return;
resizeMap();
state.mapDataSource.entities.removeAll(); state.mapDataSource.entities.removeAll();
const points = Array.isArray(state.flightLine) ? state.flightLine : []; const points = Array.isArray(state.flightLine) ? state.flightLine : [];
addPolyline(points, 'leftLatitudeDeg', 'leftLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Левая граница полосы'); addPolyline(points, 'leftLatitudeDeg', 'leftLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Левая граница полосы');
addPolyline(points, 'rightLatitudeDeg', 'rightLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Правая граница полосы'); addPolyline(points, 'rightLatitudeDeg', 'rightLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Правая граница полосы');
addPolyline(points, 'latitudeDeg', 'longitudeDeg', Cesium.Color.YELLOW, 3, 'Трасса полета'); addPolyline(points, 'latitudeDeg', 'longitudeDeg', Cesium.Color.YELLOW, 3, 'Трасса полета');
addSurveyContour(); addSurveyContour();
addTarget(); updateTargetOverlay();
if (centerMode === 'flight-line') { if (centerMode === 'flight-line') {
fitMapToFlightLine(); fitMapToFlightLine();
} else if (centerMode === 'target') { } else if (centerMode === 'target') {
centerMapOnTarget(); centerMapOnTarget();
} }
requestMapRender();
}
function requestMapRender() {
if (!state.viewer) return;
state.viewer.scene.requestRender(); state.viewer.scene.requestRender();
requestAnimationFrame(() => {
state.viewer?.scene.requestRender();
requestAnimationFrame(() => state.viewer?.scene.requestRender());
});
} }
function setPicking(value) { function setPicking(value) {
@@ -65,6 +65,39 @@
white-space: nowrap; white-space: nowrap;
} }
.angular-motion-target-marker {
position: absolute;
z-index: 1001;
display: none;
pointer-events: none;
transform: translate(-50%, -50%);
}
.angular-motion-target-marker__dot {
display: block;
width: 14px;
height: 14px;
border: 2px solid #fff;
border-radius: 50%;
background: #ff1f2f;
box-shadow: 0 0 0 1px rgba(255, 31, 47, 0.65);
}
.angular-motion-target-marker__label {
position: absolute;
left: 50%;
bottom: 16px;
color: #ff4d5d;
font: 700 12px sans-serif;
text-shadow:
-1px -1px 0 #fff,
1px -1px 0 #fff,
-1px 1px 0 #fff,
1px 1px 0 #fff;
transform: translateX(-50%);
white-space: nowrap;
}
.angular-motion-result-card { .angular-motion-result-card {
min-height: 360px; min-height: 360px;
} }