Files
sunrise/tests/coast.test.ts
T

58 lines
3.0 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { Vector3 } from 'three';
import { isCoastalLand, seaHeight, createOceanGeometry } from '../src/scene/coast.ts';
import type { CoastData } from '../src/scene/coast.ts';
import { terrainHeightAt, validateTerrain } from '../src/scene/terrainGeometry.ts';
import { COAST } from '../src/constants/coast.ts';
import { LOCATIONS } from '../src/constants/locations.ts';
import { walkingHeight } from '../src/controls/walking.ts';
import { structurePosition } from '../src/scene/structures.ts';
const base = new URL('../public/terrain/hajodae/', import.meta.url);
const coast: CoastData = JSON.parse(readFileSync(new URL('coast.json', base), 'utf8'));
const meta = JSON.parse(readFileSync(new URL('metadata.json', base), 'utf8'));
const b = readFileSync(new URL('heights.f32', base));
const heights = new Float32Array(b.buffer.slice(b.byteOffset,b.byteOffset+b.byteLength));
test('Hajodae extraction has complete bounded coverage and a dry pavilion origin', () => {
validateTerrain(meta, heights, COAST);
assert.equal(meta.radiusMeters,1500);
assert.equal(heights.byteLength,362404);
assert.ok(isCoastalLand(coast,0,0));
assert.ok(terrainHeightAt(meta, heights,0,0)>0);
assert.ok(heights.every(Number.isFinite));
assert.equal(meta.corrections.osmHeightCorrection,false);
const shore = structurePosition(38.0231,128.72599,coast.origin);
assert.ok(isCoastalLand(coast,shore.x,shore.z));
assert.ok(walkingHeight(meta,heights,shore.x,shore.z) >= seaHeight(shore.x,shore.z,meta.observerSurfaceElevation)-0.001,
'the near-shore land sample must not be pulled down by offshore vertices');
assert.equal(isCoastalLand(coast,400,0),false,'east of the beach is sea');
const cape=structurePosition(38.021987,128.7355911,coast.origin);
assert.ok(isCoastalLand(coast,cape.x,cape.z),'lighthouse headland is land');
assert.equal(isCoastalLand(coast,1600,0),false,'walking is limited to surveyed coverage');
});
test('Hajodae view uses the pavilion and faces the pine reference east-northeast', () => {
assert.deepEqual(meta.origin, {latitude:38.020813,longitude:128.7352564});
assert.deepEqual(LOCATIONS.hajodae.coast.lookTarget, COAST.pine);
const pine = structurePosition(COAST.pine.latitude, COAST.pine.longitude, meta.origin);
const azimuth = Math.atan2(pine.x,-pine.z)*180/Math.PI;
assert.ok(azimuth > 75 && azimuth < 80);
});
test('ocean follows terrain curvature and faces upward', () => {
const h=meta.observerSurfaceElevation;
assert.equal(seaHeight(0,0,h),-h);
assert.ok(seaHeight(1000,0,h)<-h);
const g=createOceanGeometry(h);
const p=g.getAttribute('position'), n=g.getAttribute('normal');
assert.ok(n.getY(Math.floor(n.count/2))>0);
for (const i of [0,Math.floor(p.count/2),p.count-1]) {
assert.ok(Math.abs(p.getY(i)-seaHeight(p.getX(i),p.getZ(i),h))<0.001);
}
const v=new Vector3().fromBufferAttribute(p,0);
assert.ok(Number.isFinite(v.length()));
g.dispose();
});