feat(core): attribute-copy engine (plan C7)
- planCopy previews the changes and the skipped items for one target; applyCopy applies exactly the planned changes. - Default selection copies only the coping width; coping length and pile length are off by default (spec §9). Pile items are skipped when the foundation type differs. Coordinates, IPs, bearings and elevations are not in any item. - Equal values are not counted, so the preview count equals the applied count. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fae8d7b9b8
commit
4accf1f3be
2 files changed
+111
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import type { EditableKey } from './changes';
|
||||
import type { PierInput } from './types';
|
||||
|
||||
/**
|
||||
* 속성 복사 (spec §9 · plan C7). Copies chosen attributes from one pier to others.
|
||||
* Values the spec never copies (coordinates, IP, elevations, names) are not in any item, so they cannot be copied.
|
||||
*/
|
||||
export type CopyItem = 'coping-width' | 'coping-length' | 'pile-length';
|
||||
|
||||
interface ItemRule {
|
||||
label: string;
|
||||
keys: EditableKey[];
|
||||
/** Off by default (spec: 말뚝 길이·코핑 길이 기본 해제). */
|
||||
defaultOn: boolean;
|
||||
/** Pile items only apply when the foundation type matches (spec §9 건너뜀). */
|
||||
pileItem: boolean;
|
||||
}
|
||||
|
||||
export const COPY_ITEMS: Record<CopyItem, ItemRule> = {
|
||||
'coping-width': { label: '코핑 폭', keys: ['copingWidthMm'], defaultOn: true, pileItem: false },
|
||||
'coping-length': { label: '코핑 길이 L', keys: ['copingLengthMm'], defaultOn: false, pileItem: false },
|
||||
'pile-length': { label: '말뚝 길이', keys: ['pileLengthMm'], defaultOn: false, pileItem: true },
|
||||
};
|
||||
|
||||
export const DEFAULT_COPY_ITEMS: CopyItem[] = (Object.keys(COPY_ITEMS) as CopyItem[]).filter((k) => COPY_ITEMS[k].defaultOn);
|
||||
|
||||
export interface CopyChange {
|
||||
key: EditableKey;
|
||||
from: number;
|
||||
to: number;
|
||||
}
|
||||
|
||||
export interface CopyPlan {
|
||||
changes: CopyChange[];
|
||||
/** Items not applied to this target, with the reason shown in the preview. */
|
||||
skipped: { item: CopyItem; reason: string }[];
|
||||
}
|
||||
|
||||
/** Preview for one target: what would change and what is skipped. Same values are not counted as changes. */
|
||||
export function planCopy(source: PierInput, target: PierInput, items: CopyItem[]): CopyPlan {
|
||||
const changes: CopyChange[] = [];
|
||||
const skipped: CopyPlan['skipped'] = [];
|
||||
for (const item of items) {
|
||||
const rule = COPY_ITEMS[item];
|
||||
if (rule.pileItem && source.foundationType !== target.foundationType) {
|
||||
skipped.push({ item, reason: `기초 형식이 다릅니다 (${target.foundationType})` });
|
||||
continue;
|
||||
}
|
||||
for (const key of rule.keys) {
|
||||
if (source[key] === target[key]) continue;
|
||||
changes.push({ key, from: target[key], to: source[key] });
|
||||
}
|
||||
}
|
||||
return { changes, skipped };
|
||||
}
|
||||
|
||||
/** Applies a plan to a target input. Only the planned keys change. */
|
||||
export function applyCopy(target: PierInput, plan: CopyPlan): PierInput {
|
||||
const next = { ...target };
|
||||
for (const c of plan.changes) next[c.key] = c.to;
|
||||
return next;
|
||||
}
|
||||
Reference in new issue
Block a user