feat(ground): draw the terrain grid around the piers in the 3D view

- ground-model.ts: read schema 2 terrain_grid (origin, step, nx, ny, z),
  checked the same way as the stored project form; schema 1 is still read.
- view/terrain.ts: the grid as a mesh in pier-scene coordinates
  (x = E − pivot E, z = −(N − pivot N), y = EL), same as the pier frame.
  Cells with a missing corner are not drawn.
- scene.ts: draws the terrain in place of the 60 m plane when the model has a
  grid; the camera fits the members, not the terrain.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-23 17:57:30 +09:00
1 parent be76425c8f
commit bfd41d7c8d
6 files changed
+200 -16

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
import * as THREE from 'three';
import type { TerrainGrid } from '../core/ground-model';
/**
* Terrain grid → mesh in scene coordinates. The scene origin is the pier centre (pivot), with y up:
* x = X − pivot.e, y = EL, z = −(Y − pivot.n). This is the straight-frame matrix of the pier scene (stretchMatrix, k = 0),
* so the terrain lines up with the footings and copings. A cell is drawn only when its four corners have data.
*/
export function terrainGeometry(grid: TerrainGrid, pivot: { e: number; n: number }): THREE.BufferGeometry {
const { origin, step, nx, ny, z } = grid;
const positions: number[] = [];
const index: number[] = [];
const vertexOf = new Int32Array(nx * ny).fill(-1);
for (let j = 0; j < ny; j++) {
for (let i = 0; i < nx; i++) {
const h = z[j * nx + i];
if (h === null) continue;
vertexOf[j * nx + i] = positions.length / 3;
positions.push(origin[0] + i * step - pivot.e, h, -(origin[1] + j * step - pivot.n));
}
}
for (let j = 0; j < ny - 1; j++) {
for (let i = 0; i < nx - 1; i++) {
const a = vertexOf[j * nx + i];
const b = vertexOf[j * nx + i + 1];
const c = vertexOf[(j + 1) * nx + i];
const d = vertexOf[(j + 1) * nx + i + 1];
if (a < 0 || b < 0 || c < 0 || d < 0) continue;
index.push(a, c, b, b, c, d);
}
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setIndex(index);
geometry.computeVertexNormals();
return geometry;
}