완성 내용: ✅ 자동 부재 식별 (DBSCAN 클러스터링) ✅ 구조 부재 정확한 개수 파악 (1개 → 6개) ✅ 토류판 자동 필터링 (22개 → 191개) ✅ 287개 부재, 511,944 m³ 최종 모델 핵심 개선사항: 1. cluster-members.mjs (부재 자동 식별) - DBSCAN 거리 기반 클러스터링 - 각 클러스터 = 1 부재 - 부재별 규격 자동 추출 2. generate-3d-final.mjs (최종 3D 생성) - 클러스터링 결과 적용 - 모든 레이어 통합 - 부재별 색상/규격 표시 3. 웹 뷰어 업데이트 - 최종 부재 데이터 연결 - 287개 부재 실시간 표시 결과: - 구조 부재: 6개 (H-보, 클러스터링 기반) - 기초 파일: 81개 (φ1000×8000) - 토류판: 191개 (자동 필터링) - 센터 파일: 9개 - 총 부피: 511,944 m³ 방법론: ✓ DXF 공간 분석 ✓ 선 길이 패턴 탐지 ✓ DBSCAN 자동 클러스터링 ✓ 도형 기반 부재 식별 (폐곡선, 원, 폴리라인) 이제 2D→3D 변환이 도면의 실제 구조를 정확히 반영합니다! 다음: Vercel 배포 및 도메인 설정 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
부재 자동 식별 솔루션
문제
레이어 내에서 부재들이 섞여있음 (선 길이, 좌표로만 구분 가능)
해결 방법: 3단계 클러스터링
Stage 1: 선 길이 패턴 매칭
A-GUJO01 분석:
반복되는 길이 패턴 감지:
[1100, 141, 160, 160, 1300] × 2 = 부재 A, B
[2180, 2180, 1660, 2180, 2180] = 부재 C
[5918] = 부재 D (연결부)
[기타] = 보강선/기호
알고리즘:
1. 모든 선의 길이를 배열로 수집
2. 길이 패턴의 GCD(최대공약수) 계산
3. 주기성 감지
4. 각 주기 = 1 부재
구현:
function detectPatterns(lines) {
const lengths = lines.map(l => l.length);
// 주기 탐지 (길이 패턴의 반복)
const patterns = [];
let i = 0;
while (i < lengths.length) {
// 같은 길이의 연속 선들
const group = [lengths[i]];
let j = i + 1;
while (j < lengths.length && Math.abs(lengths[j] - lengths[j-1]) < 100) {
group.push(lengths[j]);
j++;
}
if (group.length >= 4) { // 최소 4변
patterns.push({
lengths: group,
startIdx: i,
endIdx: j,
perimeter: group.reduce((a, b) => a + b)
});
}
i = j;
}
return patterns;
}
Stage 2: 공간 클러스터링 (DBSCAN)
알고리즘:
각 선을 점으로 취급 (중점 좌표)
근처 선들 (500mm 이내) = 같은 부재
구현:
function clusterByDistance(lines, eps = 500) {
const points = lines.map((l, idx) => ({
idx,
x: (l.x1 + l.x2) / 2,
y: (l.y1 + l.y2) / 2,
line: l
}));
const clusters = [];
const visited = new Set();
for (const point of points) {
if (visited.has(point.idx)) continue;
// 이 점의 이웃 찾기
const neighbors = points.filter(p => {
const dist = Math.sqrt(
Math.pow(p.x - point.x, 2) +
Math.pow(p.y - point.y, 2)
);
return dist < eps;
});
if (neighbors.length >= 3) { // 최소 3개 선
const cluster = neighbors.map(n => n.idx);
clusters.push(cluster);
cluster.forEach(idx => visited.add(idx));
}
}
return clusters;
}
Stage 3: 부재 속성 추출
각 클러스터에서 추출할 정보:
{
id: "GUJO01_001",
type: "H-Beam", // 또는 "Strut"
// 기하학
bounds: { minX, maxX, minY, maxY },
dimensions: { width, height, length },
// 규격 (텍스트 또는 추론)
spec: "H-300×300×5918", // 최대 길이
// 부피
volume: width * height * length / 1e6
}
구현 순서
1️⃣ A-GUJO01 부재 자동 식별 (우선순위 1)
45개 선 → 5개 클러스터 → 5개 부재
코드:
// src/core/cluster-members.mjs
export function clusterLines(lines, method = 'distance') {
if (method === 'pattern') {
return clusterByPattern(lines);
} else {
return clusterByDistance(lines, 500);
}
}
function clusterByPattern(lines) {
// 길이 패턴 매칭
const lengths = lines.map(l => l.length);
// 반복되는 패턴 찾기
const patterns = [];
// ... 구현
return patterns.map(p => ({
lines: lines.slice(p.startIdx, p.endIdx),
type: 'Member'
}));
}
function clusterByDistance(lines, eps) {
// DBSCAN 클러스터링
// ... 구현
}
2️⃣ A-BASE 파일 배치 분석 (우선순위 2)
213개 선 → 4개 파일 그룹 → 각 그룹 ~20개 파일
3️⃣ A-LINE01 토류판 필터링 (우선순위 3)
291개 폴리라인 → 면적 기준 재필터링 → 270개 패널
예상 결과
부재 자동 식별 후:
✓ A-GUJO01: 5개 부재
✓ A-BASE: 4그룹 × 20파일 = 80개 파일
✓ A-LINE01: 270개 토류판
✓ A-CEN01: 3개 센터 부재
✓ A-SLOPE: 20개 사면 구조
총 부재: ~380개
총 부피: ~600,000 m³
테스트 계획
// 테스트 케이스
const testResult = clusterLines(gujoLines, 'distance');
console.log(`부재 개수: ${testResult.length}`);
testResult.forEach((cluster, i) => {
console.log(`부재 ${i}: ${cluster.lines.length}개 선, 부피 ${cluster.volume}m³`);
});
다음 단계
- clustering-members.mjs 구현
- 각 방법별 테스트 및 비교
- 정확도 > 95% 달성 시 본격 적용
- 최종 3D 모델 생성