2025-11-29 15:10:00 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Position calculator for celestial bodies
|
|
|
|
|
|
* Returns the scaled rendering position without artificial offsets
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import { scalePosition } from './scaleDistance';
|
2025-11-30 15:04:04 +00:00
|
|
|
|
import { getCelestialSize } from '../config/celestialSizes';
|
2025-11-29 15:10:00 +00:00
|
|
|
|
import type { CelestialBody } from '../types';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Calculate rendering position using true scaled coordinates
|
2025-11-30 15:04:04 +00:00
|
|
|
|
* For satellites and probes near planets, add a radial offset relative to PARENT PLANET
|
2025-11-29 15:10:00 +00:00
|
|
|
|
*/
|
|
|
|
|
|
export function calculateRenderPosition(
|
|
|
|
|
|
body: CelestialBody,
|
|
|
|
|
|
allBodies: CelestialBody[]
|
2025-11-29 16:58:58 +00:00
|
|
|
|
): { x: number; y: number; z: number; hasOffset: boolean } {
|
2025-11-29 15:10:00 +00:00
|
|
|
|
const pos = body.positions[0];
|
|
|
|
|
|
if (!pos) {
|
2025-11-29 16:58:58 +00:00
|
|
|
|
return { x: 0, y: 0, z: 0, hasOffset: false };
|
2025-11-29 15:10:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
// 1. Calculate base scaled position (fallback)
|
2025-11-29 15:10:00 +00:00
|
|
|
|
const scaled = scalePosition(pos.x, pos.y, pos.z);
|
|
|
|
|
|
|
2025-11-30 15:04:04 +00:00
|
|
|
|
// 2. Special handling for satellites (like Moon) and probes near planets
|
|
|
|
|
|
if (body.type === 'satellite' || body.type === 'probe') {
|
2025-11-29 16:58:58 +00:00
|
|
|
|
const parent = findParentPlanet(body, allBodies);
|
|
|
|
|
|
if (parent) {
|
|
|
|
|
|
const parentPos = parent.positions[0];
|
|
|
|
|
|
// Calculate parent's scaled position (where it is rendered)
|
|
|
|
|
|
const parentScaled = scalePosition(parentPos.x, parentPos.y, parentPos.z);
|
2025-11-30 15:04:04 +00:00
|
|
|
|
|
|
|
|
|
|
// Calculate vector from Parent to body (in True AU coordinates)
|
2025-11-29 16:58:58 +00:00
|
|
|
|
const dx = pos.x - parentPos.x;
|
|
|
|
|
|
const dy = pos.y - parentPos.y;
|
|
|
|
|
|
const dz = pos.z - parentPos.z;
|
2025-11-30 15:04:04 +00:00
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
const dist = Math.sqrt(dx*dx + dy*dy + dz*dz);
|
2025-11-30 15:04:04 +00:00
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
if (dist > 0) {
|
|
|
|
|
|
// Normalize the direction vector
|
|
|
|
|
|
const nx = dx / dist;
|
|
|
|
|
|
const ny = dy / dist;
|
|
|
|
|
|
const nz = dz / dist;
|
2025-11-29 15:10:00 +00:00
|
|
|
|
|
2025-11-30 15:04:04 +00:00
|
|
|
|
// Calculate dynamic offset based on parent planet's rendering size
|
|
|
|
|
|
// Formula: planetRadius × 1.5 + 0.3 (fixed gap)
|
|
|
|
|
|
// This ensures larger planets (Jupiter, Saturn) have larger offsets
|
|
|
|
|
|
// while smaller planets (Earth, Mars) have smaller offsets
|
|
|
|
|
|
const parentSize = getCelestialSize(parent.name, parent.type);
|
|
|
|
|
|
const visualOffset = parentSize * 1.5 + 0.3;
|
2025-11-29 16:58:58 +00:00
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
x: parentScaled.x + nx * visualOffset,
|
|
|
|
|
|
y: parentScaled.y + ny * visualOffset,
|
|
|
|
|
|
z: parentScaled.z + nz * visualOffset,
|
|
|
|
|
|
hasOffset: true
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-11-29 15:10:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
return { x: scaled.x, y: scaled.y, z: scaled.z, hasOffset: false };
|
2025-11-29 15:10:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Find the parent planet for a celestial body (e.g., Moon orbits Earth)
|
2025-11-29 16:58:58 +00:00
|
|
|
|
* Returns the planet that this body is closest to
|
2025-11-29 15:10:00 +00:00
|
|
|
|
*/
|
|
|
|
|
|
export function findParentPlanet(
|
|
|
|
|
|
body: CelestialBody,
|
|
|
|
|
|
allBodies: CelestialBody[]
|
|
|
|
|
|
): CelestialBody | null {
|
|
|
|
|
|
const pos = body.positions[0];
|
|
|
|
|
|
if (!pos) return null;
|
|
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
// Look for planets or dwarf planets
|
2025-11-29 15:10:00 +00:00
|
|
|
|
const planets = allBodies.filter(b => b.type === 'planet' || b.type === 'dwarf_planet');
|
|
|
|
|
|
|
|
|
|
|
|
let closestPlanet: CelestialBody | null = null;
|
|
|
|
|
|
let minDistance = Infinity;
|
|
|
|
|
|
|
|
|
|
|
|
for (const planet of planets) {
|
|
|
|
|
|
const planetPos = planet.positions[0];
|
|
|
|
|
|
if (!planetPos) continue;
|
|
|
|
|
|
|
|
|
|
|
|
const distance = Math.sqrt(
|
|
|
|
|
|
Math.pow(pos.x - planetPos.x, 2) +
|
|
|
|
|
|
Math.pow(pos.y - planetPos.y, 2) +
|
|
|
|
|
|
Math.pow(pos.z - planetPos.z, 2)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-11-29 16:58:58 +00:00
|
|
|
|
// Consider as "parent" if within 0.1 AU
|
|
|
|
|
|
// Moon is ~0.0026 AU from Earth
|
|
|
|
|
|
// Io is ~0.0028 AU from Jupiter
|
|
|
|
|
|
if (distance < 0.1 && distance < minDistance) {
|
2025-11-29 15:10:00 +00:00
|
|
|
|
closestPlanet = planet;
|
|
|
|
|
|
minDistance = distance;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return closestPlanet;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get description for bodies that are close to planets
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getOffsetDescription(body: CelestialBody, allBodies: CelestialBody[]): string | null {
|
2025-11-30 15:04:04 +00:00
|
|
|
|
if (body.type !== 'satellite' && body.type !== 'probe') {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const parent = findParentPlanet(body, allBodies);
|
|
|
|
|
|
if (!parent) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const pos = body.positions[0];
|
|
|
|
|
|
const parentPos = parent.positions[0];
|
|
|
|
|
|
if (!pos || !parentPos) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate actual distance
|
|
|
|
|
|
const dx = pos.x - parentPos.x;
|
|
|
|
|
|
const dy = pos.y - parentPos.y;
|
|
|
|
|
|
const dz = pos.z - parentPos.z;
|
|
|
|
|
|
const dist = Math.sqrt(dx*dx + dy*dy + dz*dz);
|
|
|
|
|
|
|
|
|
|
|
|
// Return proximity description
|
|
|
|
|
|
const distanceStr = dist < 0.01
|
|
|
|
|
|
? `${(dist * 149597870.7).toFixed(0)} km` // Convert AU to km for very close objects
|
|
|
|
|
|
: `${dist.toFixed(4)} AU`;
|
|
|
|
|
|
|
|
|
|
|
|
return `近${parent.name_zh || parent.name} (${distanceStr})`;
|
2025-11-29 15:10:00 +00:00
|
|
|
|
}
|