import { DiagramLayout, LogicalModel, ModelId, Point } from './types'; export interface AutoLayoutGrid { cellWidth: number; cellHeight: number; pad: number; headerHeight: number; ungroupedCols: number; } export declare function computeAutoLayout(logical: LogicalModel, layout: DiagramLayout, grid?: Partial): { id: ModelId; location: Point; }[]; /** * 높이 인지(height-aware) 박스 패킹 — 신규 엔티티 다수를 겹침 없이 격자 배치 (순수 함수, 엔진 무관). * * `computeAutoLayout`(고정 셀 격자)는 모든 엔티티가 같은 높이라는 가정이라, 속성 수가 많은 박스가 * 아랫줄을 침범한다. 이 함수는 박스마다 **속성 수에 비례한 높이를 추정**하고, 열별로 누적 Y(`colBottom`)를 * 추적해 다음 박스를 그 아래에 둔다 → 어떤 박스 높이 분포에서도 겹침이 구조적으로 발생하지 않는다. * * 배치 순서(좌→우, 위→아래 라운드로빈)는 입력 순서를 보존한다. 높이 추정은 의도적으로 넉넉히 * (간격이 뜨는 건 무해하나 겹침은 깨져 보임) — EntityNode가 `min-height: min-content`로 콘텐츠 구동이라 * 픽셀 정확이 아닌 선형 추정으로 충분하다. * * 좌표는 절대좌표. 기존 레이아웃 하단 아래에서 시작하려면 `baseY`를 넘긴다(호출자가 계산). */ export interface EntityBoxSpec { id: ModelId; /** 엔티티의 속성(attribute) 개수 — 높이 추정 입력. */ attributeCount: number; } export interface PackedEntityBox { id: ModelId; location: Point; size: { width: number; height: number; }; } export interface PackBoxesOptions { cols: number; boxWidth: number; /** 박스 간(가로·세로) 여백. */ gap: number; baseX: number; baseY: number; /** 헤더(스테레오타입+이름) 추정 높이. */ headerHeight: number; /** 속성 1행 추정 높이. */ rowHeight: number; /** 헤더·행 외 하단 여유(연산/인덱스 섹션 등) 추정 높이. */ footerHeight: number; /** 박스 최소 높이(속성 0개여도 이 높이는 확보). */ minHeight: number; } /** 속성 수 → 박스 추정 높이 (넉넉히 over-reserve). */ export declare function estimateEntityHeight(attributeCount: number, opts?: Partial): number; export declare function packEntityBoxes(boxes: EntityBoxSpec[], options?: Partial): PackedEntityBox[]; /** * 생성 지점 카스케이드 — **이미 점유된 자리에 새 요소를 포개 놓지 않는다.** * * ⚠️★팔레트의 「엔티티 추가」·「메모 추가」는 커서 맥락이 없어 **뷰포트 중앙 고정**인데, 그 자리가 * 비어 있다는 보장이 없다. 회피가 없으면 버튼을 두 번 누른 것만으로 두 노드가 **완전히 포개져** * 화면엔 하나로 보이고, 위 노드를 끌어내야 아래 것이 드러난다(실측 — 2연타 시 두 노드가 같은 * `translate(590px, 410.5px)`). 겹친 두 노드를 잇는 연결선은 양 끝점이 같은 점이 되어 **길이 0** * 으로 붕괴하므로, 「선이 안 그려진다」는 다른 얼굴로도 나타난다. * * ★**커서로 지목한 생성 경로(우클릭 메뉴)에는 걸지 않는다** — 그쪽은 사용자가 자리를 골랐고, 도구가 * 그 지목을 밀면 「누른 자리에 안 생긴다」가 된다. 자리를 «도구가» 고르는 경로만 도구가 책임진다. * * ★**보폭·판정 반경이 같은 값(`headerHeight`)을 쓰는 것이 자기 일관성**이다 — 한 칸 민 자리는 두 축 * 모두 정확히 `step` 만큼 떨어져 판정을 벗어나므로 다음 칸이 항상 비어 있다고 판정된다. 값의 근거는 * 이 파일이 이미 가진 격자 상수이고(새로 발명하지 않는다), 의미는 *「아래 노드의 헤더가 드러나는 * 최소 세로 간격」* 이다. */ export declare function cascadeFreeLocation(desired: Point, occupied: readonly Point[], options?: { step?: number; maxSteps?: number; }): Point;