feat(import): 교대만으로 가져오기 허용
교각 없이 A1 · A2 같은 교대만으로도 가져오고 저장할 수 있게 한다 (A1 + A2 짝 받침 성립, 2026-11-06 검토). - 불러오기 창: 교각 또는 교대가 1기 이상이면 [가져오기] 활성, 안내 "교대만 가져옵니다" - 3D: 교각이 없으면 첫 교대의 IP1을 좌표 기준점으로 교대를 그리고, 카메라를 교대에 맞춤(abutView) - 프로젝트 파일: 교각 0기 + 교대 저장·열기 왕복 테스트 추가 - 브라우저 검증 scripts/verify-abut-only.cjs (CDP 9444 · Vite 5173): A1만 가져오기 → ① ② ③ 이동, 런타임 예외 0, 교대 받침 카드(S −1.910 % 종단경사 · T 30 · h3 245 · E 400)와 ③ 교대 철근 표시 확인. P1 + A1 함께 가져오기 회귀도 통과 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9d357de4d1
commit
2668f17bf2
3 files changed
+108
-5
No files matched your search
+21
-5
@@ -652,12 +652,14 @@ function setupScene(): void {
|
||||
abutGroupByName.clear();
|
||||
// The frame is the same one the piers use: the first shown pier in the all-piers view, otherwise the active pier.
|
||||
const ref = multiSceneOn() ? shownPiers().find((q) => q.model)?.model : (activePier()?.model ?? state.piers.find((q) => q.model)?.model);
|
||||
if (ref) {
|
||||
// 교대만 불러온 경우 (2026-11-06): no pier frame, so the first abutment's IP1 is the frame origin.
|
||||
const pivot = ref?.pivot ?? abutOnlyPivot();
|
||||
if (pivot) {
|
||||
for (const rec of state.abutments) {
|
||||
try {
|
||||
const model = buildAbut(toAbutInput(rec));
|
||||
const members = buildMembers(model, { bottomEl: rec.foundationBottomEl, pileLengthMm: rec.pileLengthMm }, rec.shape);
|
||||
const group = buildAbutGroup(model, members, buildWings(model, members, rec.wings, rec.wingDims), ref.pivot, rec.groundEl, groundModel?.terrainGrid, rec.slab);
|
||||
const group = buildAbutGroup(model, members, buildWings(model, members, rec.wings, rec.wingDims), pivot, rec.groundEl, groundModel?.terrainGrid, rec.slab);
|
||||
group.visible = abutShown(state.stage, state.abutActive, rec.name);
|
||||
// The 부재 표시 toggles hold for a new abutment group too.
|
||||
for (const [name, on] of Object.entries(state.abutVisible)) {
|
||||
@@ -730,6 +732,17 @@ function setupScene(): void {
|
||||
rebar3d.setColorMode(state.rebarColor);
|
||||
world.add(rebar3d.group);
|
||||
}
|
||||
// 교대만 있는 프로젝트: no pier scene framed the camera above, so fit the abutments (setView → abutView).
|
||||
if (!state.scene && !allPiers && state.piers.length === 0 && abutGroups.length) setView(state.view);
|
||||
}
|
||||
|
||||
/** Frame origin when no pier is loaded (교대만 불러오기, 2026-11-06): IP1 of the first abutment that builds. */
|
||||
function abutOnlyPivot(): { e: number; n: number } | undefined {
|
||||
if (state.piers.length) return undefined;
|
||||
for (const rec of state.abutments) {
|
||||
try { return buildAbut(toAbutInput(rec)).ip1; } catch { /* 다음 교대 */ }
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- main list (시안 ① 교각 목록) ----------------------------------------------------
|
||||
@@ -5803,12 +5816,13 @@ function updateApply(): void {
|
||||
const selectedAbuts = p ? abuts.filter((rec) => p.selectedAbutments.has(rec.name)).length : 0;
|
||||
const scope = `교각 ${count}기 + 교대 ${selectedAbuts}기`;
|
||||
$('dlg-selected').textContent = p
|
||||
? `선택 ${scope} · 선택 가능: 교각 ${total}기, 교대 ${abuts.length}기${count === 0 && selectedAbuts > 0 ? ' · 교각도 1기 이상 선택하세요.' : ''}`
|
||||
? `선택 ${scope} · 선택 가능: 교각 ${total}기, 교대 ${abuts.length}기${count === 0 && selectedAbuts > 0 ? ' · 교대만 가져옵니다.' : ''}`
|
||||
: '파일을 선택하면 불러올 교각·교대를 확인할 수 있습니다.';
|
||||
const named = $<HTMLInputElement>('project-name').value.trim().length > 0;
|
||||
const apply = $<HTMLButtonElement>('dlg-apply');
|
||||
apply.textContent = count || selectedAbuts ? `${scope} 가져오기` : '불러올 구조물을 선택하세요';
|
||||
apply.disabled = count === 0 || !named;
|
||||
// 교대만 가져오기도 허용한다 (2026-11-06): 교각 또는 교대가 1기 이상이면 된다.
|
||||
apply.disabled = (count === 0 && selectedAbuts === 0) || !named;
|
||||
}
|
||||
|
||||
function loadBytes(bytes: Uint8Array, fileName: string): void {
|
||||
@@ -5854,7 +5868,9 @@ async function readWorkbook(fileName: string, bytes: () => Promise<Uint8Array>):
|
||||
function applyImport(): void {
|
||||
const p = state.pending;
|
||||
const name = $<HTMLInputElement>('project-name').value.trim();
|
||||
if (!p || !name || !p.entries.some((e) => e.checked && selectable(p, e))) return;
|
||||
const anyPier = !!p && p.entries.some((e) => e.checked && selectable(p, e));
|
||||
const anyAbut = !!p && p.abutments.some((rec) => p.selectedAbutments.has(rec.name) && selectableAbut(p, rec));
|
||||
if (!p || !name || (!anyPier && !anyAbut)) return;
|
||||
state.project = { ...state.project, name, bridge: $<HTMLInputElement>('bridge-name').value.trim() };
|
||||
state.piers = p.entries.filter((e) => e.checked && selectable(p, e));
|
||||
state.abutments = p.abutments.filter((rec) => p.selectedAbutments.has(rec.name) && selectableAbut(p, rec));
|
||||
|
||||
Reference in new issue
Block a user