feat(plan): 날개벽 카드 타일에 현재 형식을 반영한 그림 추가
- 좌우: 평면 그림. 같게 = 좌측 형식의 날개벽 두 개와 "=", 따로 = 현재 좌우 형식 (같으면 긴 것 · 짧은 것으로 예시) - 편집할 측: 현재 좌우 형식대로 두 날개벽을 그리고, 고른 측을 굵게, 다른 측은 흐린 점선. 글자는 "좌 · ① 쪽"만 남김 - 형식: 측면 그림. 일반형 = 길고 아랫면이 비스듬한 사다리꼴, 단축형 = 짧은 직사각형, 없음 = 벽체 선과 점선 윤곽 - 그림은 48 × 24, 선 색 = 글자 색 (선택 파랑 · 비활성 회색). 테스트 669건 통과, 빌드 통과. 브라우저 시각 확인은 미실시 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
80e5302192
commit
4ef3650454
1 file changed
+40
-3
+40
-3
@@ -966,6 +966,34 @@ function fillAbutBearingCard(
|
|||||||
box.append(el('p', `검사 · ${abutBearingChecks(model, members, rule, H).join(' · ')}`, 'muted small abut-checks'));
|
box.append(el('p', `검사 · ${abutBearingChecks(model, members, rule, H).join(' · ')}`, 'muted small abut-checks'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 날개벽 타일 그림 (2026-11-04, 48 × 24, 선 색 = 글자 색). 평면 그림은 위가 흉벽 · 벽체, 아래로 날개벽이 뻗는다.
|
||||||
|
* 날개벽 모양은 현재 형식을 따른다: 일반형 = 길게, 단축형 = 짧게(뒷굽 끝까지), 없음 = 흐린 점선.
|
||||||
|
*/
|
||||||
|
const WING_ICON = {
|
||||||
|
plan(left: WingForm, right: WingForm, focus?: 'left' | 'right', equal = false): string {
|
||||||
|
const stroke = (on: boolean) => (on ? 'stroke="currentColor" stroke-width="2.6"' : 'stroke="currentColor" stroke-width="1.6" stroke-dasharray="2 2" opacity="0.45"');
|
||||||
|
const wing = (side: 'left' | 'right', form: WingForm) => {
|
||||||
|
const x = side === 'left' ? 10 : 38;
|
||||||
|
const dx = side === 'left' ? -1 : 1;
|
||||||
|
const on = form !== 'none' && (focus === undefined || focus === side);
|
||||||
|
const len = form === 'general' ? 12 : 5;
|
||||||
|
const style = form === 'none' ? stroke(false) : stroke(on);
|
||||||
|
return `<path d="M${x} 8l${dx * (len / 4)} ${len}" fill="none" stroke-linecap="round" ${style}/>`;
|
||||||
|
};
|
||||||
|
const wall = '<path d="M8 4h32v4H8z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>';
|
||||||
|
const eq = equal ? '<path d="M21 14h6M21 17.5h6" stroke="currentColor" stroke-width="1.5"/>' : '';
|
||||||
|
return wall + wing('left', left) + wing('right', right) + eq;
|
||||||
|
},
|
||||||
|
side(form: WingForm): string {
|
||||||
|
const solid = 'fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"';
|
||||||
|
const faint = 'fill="none" stroke="currentColor" stroke-width="1.3" stroke-dasharray="2 2" opacity="0.45"';
|
||||||
|
if (form === 'general') return `<path d="M40 4v16h-8L8 13V4z" ${solid}/>`;
|
||||||
|
if (form === 'short') return `<path d="M40 4v16h-9V4z" ${solid}/>`;
|
||||||
|
return `<path d="M40 4v16" ${solid}/><path d="M40 4H8v9l24 7h8" ${faint}/>`;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/** skew (deg) as 95°02′52″. */
|
/** skew (deg) as 95°02′52″. */
|
||||||
function dms(deg: number): string {
|
function dms(deg: number): string {
|
||||||
const total = Math.round(Math.abs(deg) * 3600);
|
const total = Math.round(Math.abs(deg) * 3600);
|
||||||
@@ -993,13 +1021,21 @@ function fillAbutWingCard(
|
|||||||
const sideName = (s: 'left' | 'right') => (s === 'left' ? '좌 · ① 쪽' : `우 · ${circled(lastNo)} 쪽`);
|
const sideName = (s: 'left' | 'right') => (s === 'left' ? '좌 · ① 쪽' : `우 · ${circled(lastNo)} 쪽`);
|
||||||
box.append(
|
box.append(
|
||||||
optionTiles('좌우', [
|
optionTiles('좌우', [
|
||||||
{ label: '좌우 같게', on: linked, isDefault: true, pick: () => apply(setWingsLinked(rec, true)) },
|
// 같게: the left form on both sides with "="; 따로: the current forms, or long / short when they happen to match.
|
||||||
{ label: '따로 정하기', on: !linked, pick: () => apply(setWingsLinked(rec, false)) },
|
{ label: '좌우 같게', icon: WING_ICON.plan(forms.left, forms.left, undefined, true), on: linked, isDefault: true, pick: () => apply(setWingsLinked(rec, true)) },
|
||||||
|
{
|
||||||
|
label: '따로 정하기',
|
||||||
|
icon: forms.left === forms.right ? WING_ICON.plan('general', 'short') : WING_ICON.plan(forms.left, forms.right),
|
||||||
|
on: !linked,
|
||||||
|
pick: () => apply(setWingsLinked(rec, false)),
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
optionTiles(
|
optionTiles(
|
||||||
'편집할 측',
|
'편집할 측',
|
||||||
(['left', 'right'] as const).map((s) => ({
|
(['left', 'right'] as const).map((s) => ({
|
||||||
label: `${sideName(s)} · ${NAME[forms[s]]}`,
|
// The picture shows both wings in their current form, with this side drawn bold.
|
||||||
|
label: sideName(s),
|
||||||
|
icon: WING_ICON.plan(forms.left, forms.right, s),
|
||||||
on: side === s,
|
on: side === s,
|
||||||
pick: () => {
|
pick: () => {
|
||||||
state.abutWingSide = s;
|
state.abutWingSide = s;
|
||||||
@@ -1012,6 +1048,7 @@ function fillAbutWingCard(
|
|||||||
`${side === 'left' ? '좌' : '우'} 날개벽 (${sideName(side).split(' · ')[1]}) 형식`,
|
`${side === 'left' ? '좌' : '우'} 날개벽 (${sideName(side).split(' · ')[1]}) 형식`,
|
||||||
(['general', 'short', 'none'] as const).map((f) => ({
|
(['general', 'short', 'none'] as const).map((f) => ({
|
||||||
label: NAME[f],
|
label: NAME[f],
|
||||||
|
icon: WING_ICON.side(f),
|
||||||
on: forms[side] === f,
|
on: forms[side] === f,
|
||||||
isDefault: f === 'general',
|
isDefault: f === 'general',
|
||||||
pick: () => apply(setWingForm(rec, side, f)),
|
pick: () => apply(setWingForm(rec, side, f)),
|
||||||
|
|||||||
Reference in new issue
Block a user