feat(core,view): ③ 공통 설정 — fck and fy as inputs (spec §6.2)
- Material {fck, fyH, fyS}, defaults 27 / 400 / 500 as assumed values (I02).
The rebar calculations take the material: the C7/C8 splice, the P2 development
length, the P3 lap, and the B2 split use it instead of fixed numbers.
- ③ screen: 공통 설정 inputs with a note that the defaults are assumed (I02).
- Project file stores the material as an optional field; older files open with
the defaults.
- Tests: fck 27 → 35 shortens the laps by √(27/35); the C7 piece follows fck;
a non-default fy drops I02; the file round trip.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
64d415f891
commit
9ba7b55eab
11 files changed
+123
-16
No files matched your search
@@ -64,3 +64,12 @@ describe('project file round trip (spec §8, plan B3)', () => {
|
||||
expect(reopened.piers[0].draft).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('③ 공통 설정 in the project file', () => {
|
||||
it('fck and fy are kept through save and open; older files get the defaults through the app', () => {
|
||||
const p = sampleProject();
|
||||
const withCommon = { ...p, common: { fck: 35, fyH: 400, fyS: 500 } };
|
||||
expect(parseProject(serializeProject(withCommon)).common).toEqual({ fck: 35, fyH: 400, fyS: 500 });
|
||||
expect(parseProject(serializeProject(p)).common).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildPier } from '../src/core/geometry';
|
||||
import { DEFAULT_MATERIAL, isAssumedMaterial } from '../src/core/rebar/common';
|
||||
import { columnRebar } from '../src/core/rebar/column';
|
||||
import { rebarSummary } from '../src/core/rebar/summary';
|
||||
import { loadP1 } from './helpers';
|
||||
|
||||
describe('③ 공통 설정: fck · fy 입력 (spec §6.2)', () => {
|
||||
const model = buildPier(loadP1());
|
||||
|
||||
it('defaults are assumed (I02); changed values are not', () => {
|
||||
expect(isAssumedMaterial(DEFAULT_MATERIAL)).toBe(true);
|
||||
expect(isAssumedMaterial({ ...DEFAULT_MATERIAL, fck: 35 })).toBe(false);
|
||||
});
|
||||
|
||||
it('a higher fck shortens the laps: P3 lap scales with 1/√fck (27 → 35)', () => {
|
||||
const base = columnRebar();
|
||||
const high = columnRebar(undefined, { ...DEFAULT_MATERIAL, fck: 35 });
|
||||
expect(high.lapP3 / base.lapP3).toBeCloseTo(Math.sqrt(27 / 35), 3);
|
||||
expect(high.zTop2).toBeLessThan(base.zTop2);
|
||||
});
|
||||
|
||||
it('the rebar summary follows the material: the C7 splice piece changes with fck', () => {
|
||||
const base = rebarSummary(model).rows.find((r) => r.name === 'C7')!.length!;
|
||||
const high = rebarSummary(model, { ...DEFAULT_MATERIAL, fck: 35 }).rows.find((r) => r.name === 'C7')!.length!;
|
||||
expect(high).toBeLessThan(base);
|
||||
});
|
||||
|
||||
it('a non-default material drops the I02 warning', () => {
|
||||
const codes = rebarSummary(model, { ...DEFAULT_MATERIAL, fyS: 600 }).warnings.map((w) => w.code);
|
||||
expect(codes).not.toContain('I02');
|
||||
});
|
||||
});
|
||||
@@ -45,7 +45,7 @@ describe('③ 철근표 요약 (P1)', () => {
|
||||
|
||||
it('B9: 320 bars; warnings: B2 needs a splice (13646 > 12000)', () => {
|
||||
expect(count('B9')).toBe(320);
|
||||
expect(warnings.map((w) => w.code)).toEqual(['RB-F08']);
|
||||
expect(warnings.map((w) => w.code)).toEqual(['I02', 'RB-F08']); // defaults are assumed values (I02)
|
||||
// B2 is split into two pieces (추천안): each piece is about half the 13646 bar plus half the lap.
|
||||
expect(rows.find((r) => r.name === 'B2')!.length!).toBeCloseTo(7776, 0);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user