Klima 3D: Flugzeug-Test-Seite + Airport-Ausrichtung vom Vulkan weg

- Neue Datei: App/sims/klima/plane-test.html
  Three.js-Sandbox mit dem makePlane-Mesh, Slidern für rotation.x/y/z,
  Achsen-Helper (X rot, Y grün, Z blau), großem roten Pfeil als
  Bewegungsrichtung (+X), "Flug simulieren"-Button und "Werte kopieren".
  Thomas kann damit die korrekte Flug-Rotation finden und zurückmelden.
- Airport-Ausrichtung: finalizeBuy überschreibt die zufällige
  placementRotation bei id='airport' mit atan2(-dz, dx) zum Vulkan —
  Runway (lokales +X) zeigt nun IMMER vom Vulkan weg, Start und
  Landung über Ozean statt Bergflanke.
- airportLocalToWorld: Vorzeichen an Three.js-Konvention angeglichen
  (x_w += lz·sinR, z_w -= lx·sinR), damit rotierte Airports ihre
  internen Offsets korrekt in Welt-Koordinaten übertragen.
- Plane-Zyklus: +60 s Grund-Offset entfernt, Flugzeug ist bei
  Airport-Bau sofort sichtbar (Phase 0 = parken auf der Runway).

Test-URL: http://localhost/geograsim/App/sims/klima/plane-test.html

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 14:22:34 +02:00
parent 665e86d485
commit 96fb75ffdf
2 changed files with 252 additions and 7 deletions
+20 -7
View File
@@ -1539,7 +1539,16 @@ function buyMeasure(id) {
}
function finalizeBuy(id, hitPos) {
const rotation = +placementRotation.toFixed(3);
let rotation = +placementRotation.toFixed(3);
// Flughafen-Ausrichtung: Runway (lokales +X = Start-Richtung) zeigt
// IMMER vom Vulkan weg, damit Starts und Landungen in den offenen Ozean
// gehen und nicht in die Bergflanke. Überschreibt die zufällige
// placementRotation für Airports.
if (id === 'airport') {
const dx = hitPos.x - VOLCANO_X;
const dz = hitPos.z - VOLCANO_Z;
rotation = +Math.atan2(-dz, dx).toFixed(3);
}
const zone = MEASURE_ZONES_3D[id];
const zoneId = zone ? zone.kind : 'land';
const resolveMeta = () => ({ pos: hitPos, rotation, zoneId });
@@ -3980,14 +3989,18 @@ function updateAirportVehicles(tNow) {
}
}
// Lokale→Welt-Transformation für Airport-relative Punkte (inkl. Airport-Rotation)
// Lokale→Welt-Transformation für Airport-relative Punkte. Entspricht exakt
// dem, was Three.js intern für Child-Meshes macht (rotation.y um Y-Achse):
// (lx, ly, lz) → (Px + lx·cosR + lz·sinR, Py + ly, Pz lx·sinR + lz·cosR)
// Frühere Version hatte falsche Vorzeichen → Flugzeug flog bei rotierten
// Flughäfen rückwärts, Heli-Lande-Position war schräg versetzt.
function airportLocalToWorld(airportMesh, lx, ly, lz) {
const cosR = Math.cos(airportMesh.rotation.y);
const sinR = Math.sin(airportMesh.rotation.y);
return {
x: airportMesh.position.x + lx * cosR - lz * sinR,
x: airportMesh.position.x + lx * cosR + lz * sinR,
y: airportMesh.position.y + ly,
z: airportMesh.position.z + lx * sinR + lz * cosR,
z: airportMesh.position.z - lx * sinR + lz * cosR,
};
}
@@ -4072,9 +4085,9 @@ function updateSinglePlane(v, tNow, airportMesh) {
const RUNWAY_END = 2.2; // lokal, nach 2x-Scale also 4.4 in Welt
const RUNWAY_Y = 0.50; // auf Plateau-Oberkante (LIFT+Scale²≈0.26)
// Zyklus-Phase (Sekunden) mit individuellem Offset pro Airport, plus
// +60 s Grund-Offset damit Plane nicht sofort beim Level-Start startet.
const tPhase = (tNow + v.phaseOffset + 60) % PLANE_CYCLE;
// Zyklus-Phase — beginnt sofort in Phase 0 (Plane steht auf Runway),
// damit beim Bau des Airports das Flugzeug direkt sichtbar ist.
const tPhase = (tNow + v.phaseOffset) % PLANE_CYCLE;
plane.visible = true;
const prop = plane.userData.propRef;