Stabilize Earth module and fix satellite TLE handling
This commit is contained in:
@@ -1,329 +1,398 @@
|
||||
// cables.js - Cable loading and rendering module
|
||||
|
||||
import * as THREE from 'three';
|
||||
import * as THREE from "three";
|
||||
|
||||
import { CONFIG, CABLE_COLORS, PATHS, CABLE_STATE } from './constants.js';
|
||||
import { latLonToVector3 } from './utils.js';
|
||||
import { updateEarthStats, showStatusMessage } from './ui.js';
|
||||
import { showInfoCard } from './info-card.js';
|
||||
import { CONFIG, CABLE_COLORS, PATHS, CABLE_STATE } from "./constants.js";
|
||||
import { latLonToVector3 } from "./utils.js";
|
||||
import { updateEarthStats, showStatusMessage } from "./ui.js";
|
||||
import { showInfoCard } from "./info-card.js";
|
||||
|
||||
export let cableLines = [];
|
||||
export let landingPoints = [];
|
||||
export let lockedCable = null;
|
||||
let cableIdMap = new Map();
|
||||
let cableStates = new Map();
|
||||
let cablesVisible = true;
|
||||
|
||||
function disposeMaterial(material) {
|
||||
if (!material) return;
|
||||
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(disposeMaterial);
|
||||
return;
|
||||
}
|
||||
|
||||
if (material.map) {
|
||||
material.map.dispose();
|
||||
}
|
||||
material.dispose();
|
||||
}
|
||||
|
||||
function disposeObject(object, parent) {
|
||||
if (!object) return;
|
||||
const owner = parent || object.parent;
|
||||
if (owner) {
|
||||
owner.remove(object);
|
||||
}
|
||||
if (object.geometry) {
|
||||
object.geometry.dispose();
|
||||
}
|
||||
if (object.material) {
|
||||
disposeMaterial(object.material);
|
||||
}
|
||||
}
|
||||
|
||||
function getCableColor(properties) {
|
||||
if (properties.color) {
|
||||
if (typeof properties.color === 'string' && properties.color.startsWith('#')) {
|
||||
if (
|
||||
typeof properties.color === "string" &&
|
||||
properties.color.startsWith("#")
|
||||
) {
|
||||
return parseInt(properties.color.substring(1), 16);
|
||||
} else if (typeof properties.color === 'number') {
|
||||
}
|
||||
if (typeof properties.color === "number") {
|
||||
return properties.color;
|
||||
}
|
||||
}
|
||||
|
||||
const cableName = properties.Name || properties.cableName || properties.shortname || '';
|
||||
if (cableName.includes('Americas II')) {
|
||||
return CABLE_COLORS['Americas II'];
|
||||
} else if (cableName.includes('AU Aleutian A')) {
|
||||
return CABLE_COLORS['AU Aleutian A'];
|
||||
} else if (cableName.includes('AU Aleutian B')) {
|
||||
return CABLE_COLORS['AU Aleutian B'];
|
||||
|
||||
const cableName =
|
||||
properties.Name || properties.cableName || properties.shortname || "";
|
||||
if (cableName.includes("Americas II")) {
|
||||
return CABLE_COLORS["Americas II"];
|
||||
}
|
||||
|
||||
if (cableName.includes("AU Aleutian A")) {
|
||||
return CABLE_COLORS["AU Aleutian A"];
|
||||
}
|
||||
if (cableName.includes("AU Aleutian B")) {
|
||||
return CABLE_COLORS["AU Aleutian B"];
|
||||
}
|
||||
|
||||
return CABLE_COLORS.default;
|
||||
}
|
||||
|
||||
function createCableLine(points, color, properties, earthObj) {
|
||||
function createCableLine(points, color, properties) {
|
||||
if (points.length < 2) return null;
|
||||
|
||||
|
||||
const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
|
||||
const lineMaterial = new THREE.LineBasicMaterial({
|
||||
color: color,
|
||||
lineGeometry.computeBoundingSphere();
|
||||
|
||||
const lineMaterial = new THREE.LineBasicMaterial({
|
||||
color,
|
||||
linewidth: 1,
|
||||
transparent: true,
|
||||
opacity: 1.0,
|
||||
depthTest: true,
|
||||
depthWrite: true
|
||||
depthWrite: true,
|
||||
});
|
||||
|
||||
|
||||
const cableLine = new THREE.Line(lineGeometry, lineMaterial);
|
||||
const cableId = properties.cable_id || properties.id || properties.Name || Math.random().toString(36);
|
||||
const cableId =
|
||||
properties.cable_id ||
|
||||
properties.id ||
|
||||
properties.Name ||
|
||||
Math.random().toString(36);
|
||||
cableLine.userData = {
|
||||
type: 'cable',
|
||||
cableId: cableId,
|
||||
name: properties.Name || properties.cableName || 'Unknown',
|
||||
owner: properties.owner || properties.owners || '-',
|
||||
status: properties.status || '-',
|
||||
length: properties.length || '-',
|
||||
coords: '-',
|
||||
rfs: properties.rfs || '-',
|
||||
originalColor: color
|
||||
type: "cable",
|
||||
cableId,
|
||||
name: properties.Name || properties.cableName || "Unknown",
|
||||
owner: properties.owner || properties.owners || "-",
|
||||
status: properties.status || "-",
|
||||
length: properties.length || "-",
|
||||
coords: "-",
|
||||
rfs: properties.rfs || "-",
|
||||
originalColor: color,
|
||||
localCenter:
|
||||
lineGeometry.boundingSphere?.center?.clone() || new THREE.Vector3(),
|
||||
};
|
||||
cableLine.renderOrder = 1;
|
||||
|
||||
|
||||
if (!cableIdMap.has(cableId)) {
|
||||
cableIdMap.set(cableId, []);
|
||||
}
|
||||
cableIdMap.get(cableId).push(cableLine);
|
||||
|
||||
|
||||
return cableLine;
|
||||
}
|
||||
|
||||
function calculateGreatCirclePoints(lat1, lon1, lat2, lon2, radius, segments = 50) {
|
||||
function calculateGreatCirclePoints(
|
||||
lat1,
|
||||
lon1,
|
||||
lat2,
|
||||
lon2,
|
||||
radius,
|
||||
segments = 50,
|
||||
) {
|
||||
const points = [];
|
||||
const phi1 = lat1 * Math.PI / 180;
|
||||
const lambda1 = lon1 * Math.PI / 180;
|
||||
const phi2 = lat2 * Math.PI / 180;
|
||||
const lambda2 = lon2 * Math.PI / 180;
|
||||
|
||||
const dLambda = Math.min(Math.abs(lambda2 - lambda1), 2 * Math.PI - Math.abs(lambda2 - lambda1));
|
||||
const cosDelta = Math.sin(phi1) * Math.sin(phi2) + Math.cos(phi1) * Math.cos(phi2) * Math.cos(dLambda);
|
||||
|
||||
const phi1 = (lat1 * Math.PI) / 180;
|
||||
const lambda1 = (lon1 * Math.PI) / 180;
|
||||
const phi2 = (lat2 * Math.PI) / 180;
|
||||
const lambda2 = (lon2 * Math.PI) / 180;
|
||||
|
||||
const dLambda = Math.min(
|
||||
Math.abs(lambda2 - lambda1),
|
||||
2 * Math.PI - Math.abs(lambda2 - lambda1),
|
||||
);
|
||||
const cosDelta =
|
||||
Math.sin(phi1) * Math.sin(phi2) +
|
||||
Math.cos(phi1) * Math.cos(phi2) * Math.cos(dLambda);
|
||||
|
||||
let delta = Math.acos(Math.max(-1, Math.min(1, cosDelta)));
|
||||
|
||||
|
||||
if (delta < 0.01) {
|
||||
const p1 = latLonToVector3(lat1, lon1, radius);
|
||||
const p2 = latLonToVector3(lat2, lon2, radius);
|
||||
return [p1, p2];
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i <= segments; i++) {
|
||||
const t = i / segments;
|
||||
const sinDelta = Math.sin(delta);
|
||||
const A = Math.sin((1 - t) * delta) / sinDelta;
|
||||
const B = Math.sin(t * delta) / sinDelta;
|
||||
|
||||
|
||||
const x1 = Math.cos(phi1) * Math.cos(lambda1);
|
||||
const y1 = Math.cos(phi1) * Math.sin(lambda1);
|
||||
const z1 = Math.sin(phi1);
|
||||
|
||||
|
||||
const x2 = Math.cos(phi2) * Math.cos(lambda2);
|
||||
const y2 = Math.cos(phi2) * Math.sin(lambda2);
|
||||
const z2 = Math.sin(phi2);
|
||||
|
||||
|
||||
let x = A * x1 + B * x2;
|
||||
let y = A * y1 + B * y2;
|
||||
let z = A * z1 + B * z2;
|
||||
|
||||
const norm = Math.sqrt(x*x + y*y + z*z);
|
||||
x = x / norm * radius;
|
||||
y = y / norm * radius;
|
||||
z = z / norm * radius;
|
||||
|
||||
const lat = Math.asin(z / radius) * 180 / Math.PI;
|
||||
let lon = Math.atan2(y, x) * 180 / Math.PI;
|
||||
|
||||
|
||||
const norm = Math.sqrt(x * x + y * y + z * z);
|
||||
x = (x / norm) * radius;
|
||||
y = (y / norm) * radius;
|
||||
z = (z / norm) * radius;
|
||||
|
||||
const lat = (Math.asin(z / radius) * 180) / Math.PI;
|
||||
let lon = (Math.atan2(y, x) * 180) / Math.PI;
|
||||
|
||||
if (lon > 180) lon -= 360;
|
||||
if (lon < -180) lon += 360;
|
||||
|
||||
const point = latLonToVector3(lat, lon, radius);
|
||||
points.push(point);
|
||||
|
||||
points.push(latLonToVector3(lat, lon, radius));
|
||||
}
|
||||
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
export function clearCableLines(earthObj = null) {
|
||||
cableLines.forEach((line) => disposeObject(line, earthObj));
|
||||
cableLines = [];
|
||||
cableIdMap = new Map();
|
||||
cableStates.clear();
|
||||
}
|
||||
|
||||
export function clearLandingPoints(earthObj = null) {
|
||||
landingPoints.forEach((point) => disposeObject(point, earthObj));
|
||||
landingPoints = [];
|
||||
}
|
||||
|
||||
export function clearCableData(earthObj = null) {
|
||||
clearCableSelection();
|
||||
clearCableLines(earthObj);
|
||||
clearLandingPoints(earthObj);
|
||||
}
|
||||
|
||||
export async function loadGeoJSONFromPath(scene, earthObj) {
|
||||
try {
|
||||
console.log('正在加载电缆数据...');
|
||||
showStatusMessage('正在加载电缆数据...', 'warning');
|
||||
|
||||
const response = await fetch(PATHS.cablesApi);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP错误: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
cableLines.forEach(line => earthObj.remove(line));
|
||||
cableLines = [];
|
||||
|
||||
if (!data.features || !Array.isArray(data.features)) {
|
||||
throw new Error('无效的GeoJSON格式');
|
||||
}
|
||||
|
||||
const cableCount = data.features.length;
|
||||
document.getElementById('cable-count').textContent = cableCount + '个';
|
||||
|
||||
const inServiceCount = data.features.filter(
|
||||
feature => feature.properties && feature.properties.status === 'In Service'
|
||||
).length;
|
||||
|
||||
const statusEl = document.getElementById('cable-status-summary');
|
||||
if (statusEl) {
|
||||
statusEl.textContent = `${inServiceCount}/${cableCount} 运行中`;
|
||||
}
|
||||
|
||||
for (const feature of data.features) {
|
||||
const geometry = feature.geometry;
|
||||
const properties = feature.properties || {};
|
||||
|
||||
if (!geometry || !geometry.coordinates) continue;
|
||||
|
||||
const color = getCableColor(properties);
|
||||
console.log('电缆 properties:', JSON.stringify(properties));
|
||||
|
||||
if (geometry.type === 'MultiLineString') {
|
||||
for (const lineCoords of geometry.coordinates) {
|
||||
if (!lineCoords || lineCoords.length < 2) continue;
|
||||
|
||||
const points = [];
|
||||
for (let i = 0; i < lineCoords.length - 1; i++) {
|
||||
const lon1 = lineCoords[i][0];
|
||||
const lat1 = lineCoords[i][1];
|
||||
const lon2 = lineCoords[i + 1][0];
|
||||
const lat2 = lineCoords[i + 1][1];
|
||||
|
||||
const segment = calculateGreatCirclePoints(lat1, lon1, lat2, lon2, 100.2, 50);
|
||||
if (i === 0) {
|
||||
points.push(...segment);
|
||||
} else {
|
||||
points.push(...segment.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (points.length >= 2) {
|
||||
const line = createCableLine(points, color, properties, earthObj);
|
||||
if (line) {
|
||||
cableLines.push(line);
|
||||
earthObj.add(line);
|
||||
console.log('添加线缆成功');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (geometry.type === 'LineString') {
|
||||
const allCoords = geometry.coordinates;
|
||||
console.log("正在加载电缆数据...");
|
||||
showStatusMessage("正在加载电缆数据...", "warning");
|
||||
|
||||
const response = await fetch(PATHS.cablesApi);
|
||||
if (!response.ok) {
|
||||
throw new Error(`电缆接口返回 HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (!data.features || !Array.isArray(data.features)) {
|
||||
throw new Error("无效的电缆 GeoJSON 格式");
|
||||
}
|
||||
|
||||
clearCableLines(earthObj);
|
||||
|
||||
for (const feature of data.features) {
|
||||
const geometry = feature.geometry;
|
||||
const properties = feature.properties || {};
|
||||
|
||||
if (!geometry || !geometry.coordinates) continue;
|
||||
|
||||
const color = getCableColor(properties);
|
||||
|
||||
if (geometry.type === "MultiLineString") {
|
||||
for (const lineCoords of geometry.coordinates) {
|
||||
if (!lineCoords || lineCoords.length < 2) continue;
|
||||
|
||||
const points = [];
|
||||
|
||||
for (let i = 0; i < allCoords.length - 1; i++) {
|
||||
const lon1 = allCoords[i][0];
|
||||
const lat1 = allCoords[i][1];
|
||||
const lon2 = allCoords[i + 1][0];
|
||||
const lat2 = allCoords[i + 1][1];
|
||||
|
||||
const segment = calculateGreatCirclePoints(lat1, lon1, lat2, lon2, 100.2, 50);
|
||||
if (i === 0) {
|
||||
points.push(...segment);
|
||||
} else {
|
||||
points.push(...segment.slice(1));
|
||||
}
|
||||
for (let i = 0; i < lineCoords.length - 1; i++) {
|
||||
const lon1 = lineCoords[i][0];
|
||||
const lat1 = lineCoords[i][1];
|
||||
const lon2 = lineCoords[i + 1][0];
|
||||
const lat2 = lineCoords[i + 1][1];
|
||||
|
||||
const segment = calculateGreatCirclePoints(
|
||||
lat1,
|
||||
lon1,
|
||||
lat2,
|
||||
lon2,
|
||||
CONFIG.earthRadius + 0.2,
|
||||
50,
|
||||
);
|
||||
points.push(...(i === 0 ? segment : segment.slice(1)));
|
||||
}
|
||||
|
||||
if (points.length >= 2) {
|
||||
const line = createCableLine(points, color, properties, earthObj);
|
||||
if (line) {
|
||||
cableLines.push(line);
|
||||
earthObj.add(line);
|
||||
}
|
||||
|
||||
const line = createCableLine(points, color, properties);
|
||||
if (line) {
|
||||
cableLines.push(line);
|
||||
earthObj.add(line);
|
||||
}
|
||||
}
|
||||
} else if (geometry.type === "LineString") {
|
||||
const points = [];
|
||||
for (let i = 0; i < geometry.coordinates.length - 1; i++) {
|
||||
const lon1 = geometry.coordinates[i][0];
|
||||
const lat1 = geometry.coordinates[i][1];
|
||||
const lon2 = geometry.coordinates[i + 1][0];
|
||||
const lat2 = geometry.coordinates[i + 1][1];
|
||||
|
||||
const segment = calculateGreatCirclePoints(
|
||||
lat1,
|
||||
lon1,
|
||||
lat2,
|
||||
lon2,
|
||||
CONFIG.earthRadius + 0.2,
|
||||
50,
|
||||
);
|
||||
points.push(...(i === 0 ? segment : segment.slice(1)));
|
||||
}
|
||||
|
||||
const line = createCableLine(points, color, properties);
|
||||
if (line) {
|
||||
cableLines.push(line);
|
||||
earthObj.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
updateEarthStats({
|
||||
cableCount: cableLines.length,
|
||||
landingPointCount: landingPoints.length,
|
||||
terrainOn: false,
|
||||
textureQuality: '8K 卫星图'
|
||||
});
|
||||
|
||||
showStatusMessage(`成功加载 ${cableLines.length} 条电缆`, 'success');
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载电缆数据失败:', error);
|
||||
showStatusMessage('加载电缆数据失败: ' + error.message, 'error');
|
||||
}
|
||||
|
||||
const cableCount = data.features.length;
|
||||
const inServiceCount = data.features.filter(
|
||||
(feature) =>
|
||||
feature.properties && feature.properties.status === "In Service",
|
||||
).length;
|
||||
|
||||
const cableCountEl = document.getElementById("cable-count");
|
||||
const statusEl = document.getElementById("cable-status-summary");
|
||||
if (cableCountEl) cableCountEl.textContent = cableCount + "个";
|
||||
if (statusEl) statusEl.textContent = `${inServiceCount}/${cableCount} 运行中`;
|
||||
|
||||
updateEarthStats({
|
||||
cableCount: cableLines.length,
|
||||
landingPointCount: landingPoints.length,
|
||||
terrainOn: false,
|
||||
textureQuality: "8K 卫星图",
|
||||
});
|
||||
|
||||
showStatusMessage(`成功加载 ${cableLines.length} 条电缆`, "success");
|
||||
return cableLines.length;
|
||||
}
|
||||
|
||||
export async function loadLandingPoints(scene, earthObj) {
|
||||
console.log("正在加载登陆点数据...");
|
||||
|
||||
const response = await fetch(PATHS.landingPointsApi);
|
||||
if (!response.ok) {
|
||||
throw new Error(`登陆点接口返回 HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (!data.features || !Array.isArray(data.features)) {
|
||||
throw new Error("无效的登陆点 GeoJSON 格式");
|
||||
}
|
||||
|
||||
clearLandingPoints(earthObj);
|
||||
|
||||
const sphereGeometry = new THREE.SphereGeometry(0.4, 16, 16);
|
||||
let validCount = 0;
|
||||
|
||||
try {
|
||||
console.log('正在加载登陆点数据...');
|
||||
|
||||
const response = await fetch(PATHS.landingPointsApi);
|
||||
if (!response.ok) {
|
||||
console.error('HTTP错误:', response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.features || !Array.isArray(data.features)) {
|
||||
console.error('无效的GeoJSON格式');
|
||||
return;
|
||||
}
|
||||
|
||||
landingPoints = [];
|
||||
let validCount = 0;
|
||||
|
||||
const sphereGeometry = new THREE.SphereGeometry(0.4, 16, 16);
|
||||
const sphereMaterial = new THREE.MeshStandardMaterial({
|
||||
color: 0xffaa00,
|
||||
emissive: 0x442200,
|
||||
emissiveIntensity: 0.5
|
||||
});
|
||||
|
||||
for (const feature of data.features) {
|
||||
if (!feature.geometry || !feature.geometry.coordinates) continue;
|
||||
|
||||
|
||||
const [lon, lat] = feature.geometry.coordinates;
|
||||
const properties = feature.properties || {};
|
||||
|
||||
if (typeof lon !== 'number' || typeof lat !== 'number' ||
|
||||
isNaN(lon) || isNaN(lat) ||
|
||||
Math.abs(lat) > 90 || Math.abs(lon) > 180) {
|
||||
|
||||
if (
|
||||
typeof lon !== "number" ||
|
||||
typeof lat !== "number" ||
|
||||
Number.isNaN(lon) ||
|
||||
Number.isNaN(lat) ||
|
||||
Math.abs(lat) > 90 ||
|
||||
Math.abs(lon) > 180
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const position = latLonToVector3(lat, lon, 100.1);
|
||||
|
||||
if (isNaN(position.x) || isNaN(position.y) || isNaN(position.z)) {
|
||||
|
||||
const position = latLonToVector3(lat, lon, CONFIG.earthRadius + 0.1);
|
||||
if (
|
||||
Number.isNaN(position.x) ||
|
||||
Number.isNaN(position.y) ||
|
||||
Number.isNaN(position.z)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial.clone());
|
||||
|
||||
const sphere = new THREE.Mesh(
|
||||
sphereGeometry.clone(),
|
||||
new THREE.MeshStandardMaterial({
|
||||
color: 0xffaa00,
|
||||
emissive: 0x442200,
|
||||
emissiveIntensity: 0.5,
|
||||
transparent: true,
|
||||
opacity: 1,
|
||||
}),
|
||||
);
|
||||
sphere.position.copy(position);
|
||||
sphere.userData = {
|
||||
type: 'landingPoint',
|
||||
name: properties.name || '未知登陆站',
|
||||
type: "landingPoint",
|
||||
name: properties.name || "未知登陆站",
|
||||
cableNames: properties.cable_names || [],
|
||||
country: properties.country || '未知国家',
|
||||
status: properties.status || 'Unknown'
|
||||
country: properties.country || "未知国家",
|
||||
status: properties.status || "Unknown",
|
||||
};
|
||||
|
||||
|
||||
earthObj.add(sphere);
|
||||
landingPoints.push(sphere);
|
||||
validCount++;
|
||||
}
|
||||
|
||||
console.log(`成功创建 ${validCount} 个登陆点标记`);
|
||||
showStatusMessage(`成功加载 ${validCount} 个登陆点`, 'success');
|
||||
|
||||
const lpCountEl = document.getElementById('landing-point-count');
|
||||
if (lpCountEl) {
|
||||
lpCountEl.textContent = validCount + '个';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载登陆点数据失败:', error);
|
||||
} finally {
|
||||
sphereGeometry.dispose();
|
||||
}
|
||||
|
||||
const landingPointCountEl = document.getElementById("landing-point-count");
|
||||
if (landingPointCountEl) {
|
||||
landingPointCountEl.textContent = validCount + "个";
|
||||
}
|
||||
|
||||
showStatusMessage(`成功加载 ${validCount} 个登陆点`, "success");
|
||||
return validCount;
|
||||
}
|
||||
|
||||
export function handleCableClick(cable) {
|
||||
lockedCable = cable;
|
||||
|
||||
|
||||
const data = cable.userData;
|
||||
showInfoCard('cable', {
|
||||
showInfoCard("cable", {
|
||||
name: data.name,
|
||||
owner: data.owner,
|
||||
status: data.status,
|
||||
length: data.length,
|
||||
coords: data.coords,
|
||||
rfs: data.rfs
|
||||
rfs: data.rfs,
|
||||
});
|
||||
|
||||
showStatusMessage(`已锁定: ${data.name}`, 'info');
|
||||
|
||||
showStatusMessage(`已锁定: ${data.name}`, "info");
|
||||
}
|
||||
|
||||
export function clearCableSelection() {
|
||||
@@ -342,8 +411,6 @@ export function getLandingPoints() {
|
||||
return landingPoints;
|
||||
}
|
||||
|
||||
const cableStates = new Map();
|
||||
|
||||
export function getCableState(cableId) {
|
||||
return cableStates.get(cableId) || CABLE_STATE.NORMAL;
|
||||
}
|
||||
@@ -365,7 +432,9 @@ export function getCableStateInfo() {
|
||||
}
|
||||
|
||||
export function getLandingPointsByCableName(cableName) {
|
||||
return landingPoints.filter(lp => lp.userData.cableNames?.includes(cableName));
|
||||
return landingPoints.filter((lp) =>
|
||||
lp.userData.cableNames?.includes(cableName),
|
||||
);
|
||||
}
|
||||
|
||||
export function getAllLandingPoints() {
|
||||
@@ -375,10 +444,11 @@ export function getAllLandingPoints() {
|
||||
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);
|
||||
|
||||
|
||||
landingPoints.forEach((lp) => {
|
||||
const isRelated =
|
||||
!dimAll && lp.userData.cableNames?.includes(lockedCableName);
|
||||
|
||||
if (isRelated) {
|
||||
lp.material.color.setHex(0xffaa00);
|
||||
lp.material.emissive.setHex(0x442200);
|
||||
@@ -388,8 +458,7 @@ export function applyLandingPointVisualState(lockedCableName, dimAll = false) {
|
||||
} 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.color.setRGB(r / 255, g / 255, 0);
|
||||
lp.material.emissive.setHex(0x000000);
|
||||
lp.material.emissiveIntensity = 0;
|
||||
lp.material.opacity = 0.3;
|
||||
@@ -399,7 +468,7 @@ export function applyLandingPointVisualState(lockedCableName, dimAll = false) {
|
||||
}
|
||||
|
||||
export function resetLandingPointVisualState() {
|
||||
landingPoints.forEach(lp => {
|
||||
landingPoints.forEach((lp) => {
|
||||
lp.material.color.setHex(0xffaa00);
|
||||
lp.material.emissive.setHex(0x442200);
|
||||
lp.material.emissiveIntensity = 0.5;
|
||||
@@ -410,10 +479,10 @@ export function resetLandingPointVisualState() {
|
||||
|
||||
export function toggleCables(show) {
|
||||
cablesVisible = show;
|
||||
cableLines.forEach(cable => {
|
||||
cableLines.forEach((cable) => {
|
||||
cable.visible = cablesVisible;
|
||||
});
|
||||
landingPoints.forEach(lp => {
|
||||
landingPoints.forEach((lp) => {
|
||||
lp.visible = cablesVisible;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user