import { Vector3, Quaternion } from 'three'; import { Geodetic, PointOfView, radians } from '@takram/three-geospatial'; const EARTH_RADIUS = 6378137; export const worldState = { position: new Vector3(0, EARTH_RADIUS + 100000, 0), quaternion: new Quaternion(), speed: 1000.0, stageRotationY: 0, currentHour: 12, currentLocation: 'Tokyo', }; // Pre-allocated temp objects (avoid GC in useFrame) const _up = new Vector3(); const _quat = new Quaternion(); const _unitY = new Vector3(0, 1, 0); export function getSurfaceBasis(position) { if (!position) return _quat.identity(); _up.copy(position).normalize(); if (_up.lengthSq() < 0.1) return _quat.identity(); return _quat.setFromUnitVectors(_unitY, _up); } // Non-mutating version for cases that need a copy const _basisOut = new Quaternion(); export function getSurfaceBasisCopy(position) { getSurfaceBasis(position); return _basisOut.copy(_quat); } export function getEllipsoidRadius(position) { const a = 6378137.0; const b = 6356752.314245; const r = position.length(); if (r < 100) return a; const sinPhi = position.z / r; const cosPhi = Math.sqrt(1 - sinPhi * sinPhi); const aCos = a * cosPhi; const bSin = b * sinPhi; return Math.sqrt( ((a * aCos) ** 2 + (b * bSin) ** 2) / (aCos ** 2 + bSin ** 2) ); } export const LOCATIONS = [ { name: 'Tokyo', longitude: 139.7671, latitude: 35.6812, heading: 180, pitch: -5, distance: 1100 }, { name: 'Fuji', longitude: 138.7278, latitude: 35.3206, heading: 0, pitch: -10, distance: 4000 }, { name: 'Space', longitude: 139.7671, latitude: 35.6812, heading: 0, pitch: -90, distance: 100000 }, ]; const LOCATION_MULT = { Tokyo: 1, Fuji: 2, Space: 3 }; export function teleportTo(location) { worldState.currentLocation = location.name; const { longitude, latitude, heading, pitch, distance } = location; const position = new Vector3(); const globalQuaternion = new Quaternion(); const up = new Vector3(0, 1, 0); const truePosition = new Geodetic(radians(longitude), radians(latitude), distance).toECEF(); new PointOfView(distance, radians(heading), radians(pitch)).decompose( new Geodetic(radians(longitude), radians(latitude)).toECEF(), position, globalQuaternion, up ); worldState.position.copy(truePosition); const basis = getSurfaceBasisCopy(truePosition); worldState.quaternion.copy(basis.invert().multiply(globalQuaternion)); }