fix(satellites): prevent selecting satellites on far side of earth

- Add isSatelliteFrontFacing() to detect if satellite is on visible side
- Filter satellites in hover and click handlers by front-facing check
- Apply same logic as cables for consistent back-face culling
This commit is contained in:
linkong
2026-03-24 10:44:06 +08:00
parent 543fe35fbb
commit b9fbacade7
2 changed files with 27 additions and 7 deletions

View File

@@ -14,7 +14,7 @@ import {
} 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, applyLandingPointVisualState, resetLandingPointVisualState, getAllLandingPoints, getShowCables } from './cables.js';
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, getSatelliteCount, selectSatellite, getSatelliteData, getSatellitePoints, setSatelliteRingState, updateLockedRingPosition, updateHoverRingPosition, getSatellitePositions, showPredictedOrbit, hidePredictedOrbit, updateBreathingPhase } from './satellites.js';
import { createSatellites, loadSatellites, updateSatellitePositions, toggleSatellites, toggleTrails, getShowSatellites, getSatelliteCount, selectSatellite, getSatelliteData, getSatellitePoints, setSatelliteRingState, updateLockedRingPosition, updateHoverRingPosition, getSatellitePositions, showPredictedOrbit, hidePredictedOrbit, updateBreathingPhase, isSatelliteFrontFacing } from './satellites.js';
import { setupControls, getAutoRotate, getShowTerrain, zoomLevel, setAutoRotate, toggleAutoRotate, resetView } from './controls.js';
import { initInfoCard, showInfoCard, hideInfoCard, getCurrentType, setInfoCardNoBorder } from './info-card.js';
@@ -301,11 +301,14 @@ function onMouseMove(event, camera) {
if (satPoints) {
const satIntersects = raycaster.intersectObject(satPoints);
if (satIntersects.length > 0) {
hoveredSatIndexFromIntersect = satIntersects[0].index;
const satIndex = satIntersects[0].index;
if (isSatelliteFrontFacing(satIndex, camera)) {
hoveredSatIndexFromIntersect = satIndex;
hoveredSat = selectSatellite(hoveredSatIndexFromIntersect);
}
}
}
}
const hasHoveredSatellite = hoveredSat && hoveredSat.properties;
if (hoveredCable) {
@@ -440,14 +443,17 @@ function onClick(event, camera, renderer) {
const clickY = event.clientY;
let selectedIndex;
if (satIntersects.length > 1 &&
const frontFacingSats = satIntersects.filter(s => isSatelliteFrontFacing(s.index, camera));
if (frontFacingSats.length === 0) return;
if (frontFacingSats.length > 1 &&
now - lastSatClickTime < 500 &&
Math.abs(clickX - lastSatClickPos.x) < 30 &&
Math.abs(clickY - lastSatClickPos.y) < 30) {
const currentIdx = satIntersects.findIndex(s => s.index === lastSatClickIndex);
selectedIndex = satIntersects[(currentIdx + 1) % satIntersects.length].index;
const currentIdx = frontFacingSats.findIndex(s => s.index === lastSatClickIndex);
selectedIndex = frontFacingSats[(currentIdx + 1) % frontFacingSats.length].index;
} else {
selectedIndex = satIntersects[0].index;
selectedIndex = frontFacingSats[0].index;
}
lastSatClickTime = now;

View File

@@ -415,6 +415,20 @@ export function getSatellitePositions() {
return satellitePositions;
}
export function isSatelliteFrontFacing(index, camera) {
if (!earthObjRef || !camera) return true;
const positions = satellitePositions;
if (!positions || !positions[index]) return true;
const satPos = positions[index].current;
if (!satPos) return true;
const toCamera = new THREE.Vector3().subVectors(camera.position, earthObjRef.position).normalize();
const toSat = new THREE.Vector3().subVectors(satPos, earthObjRef.position).normalize();
return toCamera.dot(toSat) < 0;
}
let earthObjRef = null;
let sceneRef = null;