- 재료표(B5–B8 9150 = 9350 − 2c, B1–B4 7600 = 7800 − 2c)와 같은 방향 배정으로 맞춤 - 격자 키를 물리 방향으로 정리: sL = L 방향 간격, sW = W 방향 간격 (기존 sAxis → sL, sPerp → sW) - B1–B4: L 격자로 개수, 길이 W − 2c. B5–B8: W 격자로 개수, 길이 L − 2c - B9: 열(L)은 sL, 행(W)은 sW 격자 (물리 격자 일치), 개수 불변 - B11은 L 방향 간격(sL), B12는 W 방향 간격(sW) - 3D 확대기초 철근과 단면 그림의 역할을 교환 (B1–B4 선, B5–B8 점) - 철근표 간격과 규칙 값, 설정 라벨을 방향 기준으로 수정 - 테스트 기대값 갱신 (B1–B4 40, B5–B8 31, B6 13646 분할 경고) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
77 lines
3.8 KiB
TypeScript
77 lines
3.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { buildPier } from '../src/core/geometry';
|
|
import { DEFAULT_MATERIAL, materialFor } from '../src/core/rebar/common';
|
|
import { rebarSummary, type RebarRow } from '../src/core/rebar/summary';
|
|
import { parseProject, SCHEMA_VERSION } from '../src/core/project';
|
|
import { loadP1 } from './helpers';
|
|
|
|
const model = buildPier(loadP1());
|
|
const byName = (rows: RebarRow[]) => new Map(rows.map((r) => [r.name, r]));
|
|
const base = rebarSummary(model).rows;
|
|
const members = (rows: RebarRow[], member: RebarRow['member']) => rows.filter((r) => r.member === member);
|
|
/** Rows of one member whose length or count changed against the base. */
|
|
const changedIn = (rows: RebarRow[], member: RebarRow['member']) =>
|
|
members(rows, member)
|
|
.filter((r) => {
|
|
const b = byName(base).get(r.name)!;
|
|
return b.length !== r.length || b.count !== r.count;
|
|
})
|
|
.map((r) => r.name);
|
|
|
|
describe('② 부재별 fck (spec §6.2 · ②)', () => {
|
|
it('a member with its own fck uses it; the others keep the 공통 value', () => {
|
|
const common = { ...DEFAULT_MATERIAL, fck: 30 };
|
|
expect(materialFor(common, { coping: 35 }, 'coping').fck).toBe(35);
|
|
expect(materialFor(common, { coping: 35 }, 'column').fck).toBe(30);
|
|
expect(materialFor(common, { coping: 35 }, 'coping').grade).toEqual(common.grade);
|
|
});
|
|
|
|
it('a coping fck changes only the coping rows (C15 stair legs use the H19 development length)', () => {
|
|
const rows = rebarSummary(model, DEFAULT_MATERIAL, { coping: 20 }).rows;
|
|
expect(changedIn(rows, 'column')).toEqual([]);
|
|
expect(changedIn(rows, 'footing')).toEqual([]);
|
|
expect(changedIn(rows, 'coping')).toContain('C15');
|
|
expect(byName(rows).get('C15')!.length!).toBeGreaterThan(byName(base).get('C15')!.length!);
|
|
});
|
|
|
|
it('a column fck changes only the column rows', () => {
|
|
const rows = rebarSummary(model, DEFAULT_MATERIAL, { column: 35 }).rows;
|
|
expect(changedIn(rows, 'coping')).toEqual([]);
|
|
expect(changedIn(rows, 'footing')).toEqual([]);
|
|
expect(changedIn(rows, 'column').length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('a footing fck changes only the footing rows (B6 splice, 방향 교환)', () => {
|
|
const rows = rebarSummary(model, DEFAULT_MATERIAL, { footing: 35 }).rows;
|
|
expect(changedIn(rows, 'coping')).toEqual([]);
|
|
expect(changedIn(rows, 'column')).toEqual([]);
|
|
expect(changedIn(rows, 'footing')).toContain('B6');
|
|
});
|
|
|
|
it('a per-member fck equal to the 공통 value changes nothing', () => {
|
|
expect(rebarSummary(model, DEFAULT_MATERIAL, { coping: 27, column: 27, footing: 27 }).rows).toEqual(base);
|
|
});
|
|
|
|
it('I02 stays while a member uses the assumed fck; it goes when all three members have their own fck', () => {
|
|
const codes = (byMember: Parameters<typeof rebarSummary>[2]) => rebarSummary(model, DEFAULT_MATERIAL, byMember).warnings.map((w) => w.code);
|
|
expect(codes({})).toContain('I02');
|
|
expect(codes({ coping: 35, column: 35 })).toContain('I02');
|
|
expect(codes({ coping: 35, column: 35, footing: 35 })).not.toContain('I02');
|
|
});
|
|
});
|
|
|
|
describe('② 부재별 fck: 프로젝트 파일', () => {
|
|
const file = (fckByMember: unknown) => JSON.stringify({ schemaVersion: SCHEMA_VERSION, project: {}, source: {}, piers: [], history: [], fckByMember });
|
|
|
|
it('accepts known members with positive numbers, and an absent field', () => {
|
|
expect(parseProject(file({ coping: 35, column: 30 })).fckByMember).toEqual({ coping: 35, column: 30 });
|
|
expect(parseProject(file(undefined)).fckByMember).toBeUndefined();
|
|
});
|
|
|
|
it('refuses an unknown member or a value that is not a positive number', () => {
|
|
expect(() => parseProject(file({ bearing: 35 }))).toThrow('부재별 fck');
|
|
expect(() => parseProject(file({ coping: 0 }))).toThrow('부재별 fck');
|
|
expect(() => parseProject(file({ coping: '35' }))).toThrow('부재별 fck');
|
|
});
|
|
});
|