- 지형 격자가 없으면 교각 지반고 위치에 얇은 선(코핑 길이 + 여유 2 m)만 그림 - 전체 보기에서도 지형이 없으면 교각별 지반고 선을 표시, 지형이 있으면 공유 격자만 표시 - 부재 표시 '지반' 체크박스는 두 경우 모두 동작 - 테스트: 얇은 선 위치와 길이, 지형 있을 때 선 미표시 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
54 lines
2.6 KiB
TypeScript
54 lines
2.6 KiB
TypeScript
import * as THREE from 'three';
|
||
import type { PierModel, Vec2 } from '../core/geometry';
|
||
import type { TerrainGrid } from '../core/ground-model';
|
||
import { buildPierScene, type PierScene } from './scene';
|
||
import { terrainGeometry } from './terrain';
|
||
|
||
/**
|
||
* Scene offset of a pier's group inside the shared frame of the reference pier. Each pier's scene is centred on its own
|
||
* pivot, so moving it by the pivot difference puts it at its national-grid place (x = E, z = −N, as in stretchMatrix).
|
||
*/
|
||
export function pierOffset(pivot: Vec2, reference: Vec2): { x: number; z: number } {
|
||
return { x: pivot.e - reference.e, z: reference.n - pivot.n };
|
||
}
|
||
|
||
export interface AllPiers {
|
||
/** Holds every pier's group, placed by pierOffset. Used for the camera fit and picking. */
|
||
piers: THREE.Group;
|
||
/** Shared terrain grid in the reference frame, or null without a terrain model. */
|
||
terrain: THREE.Mesh | null;
|
||
/** Scene of each pier, keyed by the pier name. Parts are shown per pier. */
|
||
scenes: Map<string, PierScene>;
|
||
/** Scene with the same shape the single-pier view expects (root = pier group, size = whole span). */
|
||
view: PierScene;
|
||
}
|
||
|
||
/**
|
||
* Builds the concrete members of several piers in one frame (전체 보기, 콘크리트만: no rebar). The first entry is the
|
||
* reference. With a terrain grid it is drawn once and the per-pier ground lines are hidden.
|
||
*/
|
||
export function buildAllPiers(entries: { name: string; model: PierModel }[], terrain?: TerrainGrid): AllPiers {
|
||
const piers = new THREE.Group();
|
||
const scenes = new Map<string, PierScene>();
|
||
const reference = entries[0].model.pivot;
|
||
for (const { name, model } of entries) {
|
||
const scene = buildPierScene(model);
|
||
// Without terrain each pier keeps its own 지반고 line; with terrain the shared grid replaces them.
|
||
scene.parts.ground.visible = terrain === undefined;
|
||
const { x, z } = pierOffset(model.pivot, reference);
|
||
scene.root.position.set(x, 0, z);
|
||
scene.root.userData.pier = name;
|
||
piers.add(scene.root);
|
||
scenes.set(name, scene);
|
||
}
|
||
let terrainMesh: THREE.Mesh | null = null;
|
||
if (terrain) {
|
||
const material = new THREE.MeshStandardMaterial({ color: 0xb8c7b0, roughness: 0.9, metalness: 0, transparent: true, opacity: 0.35, side: THREE.DoubleSide });
|
||
terrainMesh = new THREE.Mesh(terrainGeometry(terrain, reference), material);
|
||
}
|
||
const box = new THREE.Box3().setFromObject(piers);
|
||
const size = box.getSize(new THREE.Vector3()).length();
|
||
const view: PierScene = { root: piers, parts: scenes.get(entries[0].name)!.parts, size };
|
||
return { piers, terrain: terrainMesh, scenes, view };
|
||
}
|