diff --git a/out/viewer-correct.html b/out/viewer-correct.html index 2bb5fed..bb3e246 100644 --- a/out/viewer-correct.html +++ b/out/viewer-correct.html @@ -3,7 +3,7 @@ - 올바른 3D 모델 - 계획도 + 상세도 통합 + 가시설 3D 모델 뷰어 @@ -230,15 +171,13 @@

📊 모델 정보

- 가시설 계획도 3D
⏳ 모델 로드 중...
- -
+

📈 부재 수량

총 부재: @@ -250,37 +189,20 @@
-

🏗️ 부재 구성

-
-
- 가시설4 (H-빔)
- 52개 -
-
- h-pile2 (기초파일)
- 244개, H-400×400×8000mm -
-
- 토류판 (흙막이판)
- 240개, PL-700×360×14mm -
-
- H-PILE (파일)
- 26개 -
-
- 스터럿 (버팀목)
- 26개 -
+
+
가시설4 52개
+
h-pile2 244개
+
토류판 240개
+
H-PILE 26개
+
스터럿 26개
-

🎨 범례

-
+
H-빔 @@ -300,19 +222,11 @@
-

⌨️ 조작

-
- 마우스:
- • 좌클릭 드래그 = 회전
- • 휠 스크롤 = 확대/축소
-
- 화면:
- • 3D 배치 확인
- • 부재 형상 검증
- • 구조 파악 -
+ 좌클릭 드래그: 회전
+ 우클릭 드래그: 이동
+ 휠: 확대/축소
@@ -328,8 +242,6 @@ scene.background = new THREE.Color(0x1a3a52); const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 500000); - // 부재 중심을 향하도록 설정 (정확한 좌표 범위) - // 중심: (-216, -2554), 폭: 1373, 높이: 552 camera.position.set(-216, -2554, 3000); camera.lookAt(-216, -2554, 0); @@ -350,6 +262,26 @@ const hemis = new THREE.HemisphereLight(0x87ceeb, 0x333333, 0.4); scene.add(hemis); + // 추가 조명 + const pointLight = new THREE.PointLight(0xffffff, 0.8, 10000); + pointLight.position.set(500, 500, 500); + scene.add(pointLight); + + // OrbitControls (먼저 초기화!) + const controls = new THREE.OrbitControls(camera, canvas); + controls.target.set(-216, -2554, 0); + controls.autoRotate = false; + controls.enableDamping = true; + controls.dampingFactor = 0.05; + controls.enableZoom = true; + controls.zoomSpeed = 1.0; + controls.enablePan = true; + controls.panSpeed = 0.5; + controls.update(); + + console.log('=== 3D 뷰어 초기화 ==='); + console.log('✓ OrbitControls 준비 완료'); + // 재질 const getMaterial = (type) => { const colors = { @@ -362,133 +294,15 @@ return new THREE.MeshStandardMaterial({ color, roughness: 0.7, metalness: 0.2 }); }; - const DISPLAY_SCALE = 0.01; // mm → cm (1:100) + const DISPLAY_SCALE = 0.01; - // 디버깅 정보 추가 - console.log('=== 3D 뷰어 초기화 ==='); - console.log('카메라 위치:', camera.position); - console.log('카메라 타겟:', controls.target); - - // 배경 밝게 변경해서 테스트 - scene.background = new THREE.Color(0x1a3a52); - console.log('배경색 설정 완료'); - - // 샘플 부재 추가 (테스트용) - console.log('샘플 부재 생성 중...'); - const testGeometry = new THREE.BoxGeometry(4, 4, 80); // 400×400×8000mm → 4×4×80 - const testMaterial = new THREE.MeshStandardMaterial({ - color: 0x7ed321, - roughness: 0.7, - emissive: 0x2d5a2d - }); - const testMesh = new THREE.Mesh(testGeometry, testMaterial); - testMesh.position.set(0, -2554, 100); // 부재 중심 좌표 + // 샘플 부재 (테스트용) + const testGeo = new THREE.BoxGeometry(4, 4, 80); + const testMat = new THREE.MeshStandardMaterial({ color: 0x7ed321, roughness: 0.7, emissive: 0x2d5a2d }); + const testMesh = new THREE.Mesh(testGeo, testMat); + testMesh.position.set(0, -2554, 100); scene.add(testMesh); - console.log('✓ 샘플 부재 @ (0, -2554, 100) - 녹색'); - - // 추가 조명 - const testLight = new THREE.PointLight(0xffffff, 1.0, 10000); - testLight.position.set(500, 500, 500); - scene.add(testLight); - console.log('✓ 테스트 조명 추가됨'); - - // stats.json 로드 및 부재 생성 - console.log('stats.json 로드 시작...'); - fetch('gasiseol-correct-v2-stats.json') - .then(r => { - console.log('응답 상태:', r.status); - return r.json(); - }) - .then(data => { - console.log('📊 JSON 파싱 완료'); - console.log('총 부재:', data.totalParts); - console.log('배치 부재:', data.parts.length); - - let addedCount = 0; - // 각 부재를 3D 메시로 생성 - data.parts.forEach((part, idx) => { - let geometry; - const { blockType, type, spec, position, volume } = part; - - // 부재 타입별 3D 형상 생성 - if (type === 'Pile') { - // H-PILE 형상 (H-beam 박스) - geometry = new THREE.BoxGeometry( - 400 * DISPLAY_SCALE, - 400 * DISPLAY_SCALE, - 8000 * DISPLAY_SCALE - ); - } else if (type === 'Panel') { - // 판재 - 규격에서 가로×세로×두께 추출 - let w = 700, h = 360, d = 14; - if (spec && spec.includes('×')) { - const match = spec.match(/PL\.-(\d+)×(\d+)×(\d+)/); - if (match) { - w = parseInt(match[1]); - h = parseInt(match[2]); - d = parseInt(match[3]); - } - } - geometry = new THREE.BoxGeometry( - w * DISPLAY_SCALE, - h * DISPLAY_SCALE, - d * DISPLAY_SCALE - ); - } else if (type === 'H-Beam') { - // H-빔 - H-400×400×13×21 - let w = 400, h = 400, d = 6000; - if (spec && spec.includes('H-')) { - const match = spec.match(/H-(\d+)×(\d+)/); - if (match) { - w = parseInt(match[1]); - h = parseInt(match[2]); - } - } - geometry = new THREE.BoxGeometry( - w * DISPLAY_SCALE, - h * DISPLAY_SCALE, - d * DISPLAY_SCALE - ); - } else if (type === 'Strut') { - // 버팀목 - 200×200×4000 - geometry = new THREE.BoxGeometry( - 200 * DISPLAY_SCALE, - 200 * DISPLAY_SCALE, - 4000 * DISPLAY_SCALE - ); - } else { - geometry = new THREE.BoxGeometry( - 300 * DISPLAY_SCALE, - 300 * DISPLAY_SCALE, - 3000 * DISPLAY_SCALE - ); - } - - const mesh = new THREE.Mesh(geometry, getMaterial(type)); - mesh.position.set(position.x, position.y, position.z); - mesh.userData = { blockType, type, spec, volume }; - - scene.add(mesh); - addedCount++; - - if (addedCount <= 3 || addedCount % 100 === 0) { - console.log(`[${addedCount}] ${blockType} @ (${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z})`); - } - }); - - console.log('✅ ' + addedCount + '개 부재 씬에 추가됨'); - - // UI 업데이트 - document.getElementById('totalParts').textContent = data.totalParts + '개'; - document.getElementById('totalVolume').textContent = Math.round(data.totalVolume).toLocaleString() + ' m³'; - document.getElementById('loadingMsg').style.display = 'none'; - - console.log('✅ 3D 모델 생성 완료'); - }) - .catch(err => { - console.error('❌ 로드 오류:', err); - document.getElementById('loadingMsg').innerHTML = '❌ 부재 데이터 로드 실패
' + err.message; - }); + console.log('✓ 샘플 부재 추가됨'); // 그리드 & 축 const gridHelper = new THREE.GridHelper(3000, 20, 0x444444, 0x222222); @@ -498,18 +312,56 @@ const axisHelper = new THREE.AxesHelper(500); scene.add(axisHelper); - // OrbitControls로 카메라 제어 - const controls = new THREE.OrbitControls(camera, canvas); - controls.target.set(-216, -2554, 0); // 부재 중심을 타겟으로 - controls.autoRotate = false; - controls.autoRotateSpeed = 2; - controls.enableDamping = true; - controls.dampingFactor = 0.05; - controls.enableZoom = true; - controls.zoomSpeed = 1.0; - controls.enablePan = true; - controls.panSpeed = 0.5; - controls.update(); + // stats.json 로드 + console.log('stats.json 로드 시작...'); + fetch('gasiseol-correct-v2-stats.json') + .then(r => { + console.log('응답:', r.status); + return r.json(); + }) + .then(data => { + console.log('✓ JSON 파싱 완료'); + console.log('총 부재:', data.totalParts); + + let count = 0; + data.parts.forEach(part => { + let geometry; + const { blockType, type, spec, position, volume } = part; + + if (type === 'Pile') { + geometry = new THREE.BoxGeometry(4, 4, 80); + } else if (type === 'Panel') { + geometry = new THREE.BoxGeometry(7, 3.6, 0.14); + } else if (type === 'H-Beam') { + geometry = new THREE.BoxGeometry(4, 4, 60); + } else if (type === 'Strut') { + geometry = new THREE.BoxGeometry(2, 2, 40); + } else { + geometry = new THREE.BoxGeometry(3, 3, 30); + } + + const mesh = new THREE.Mesh(geometry, getMaterial(type)); + mesh.position.set(position.x, position.y, position.z); + scene.add(mesh); + count++; + + if (count <= 3 || count % 100 === 0) { + console.log(`[${count}] ${blockType} @ (${position.x.toFixed(0)}, ${position.y.toFixed(0)})`); + } + }); + + console.log('✓ ' + count + '개 부재 추가됨'); + + document.getElementById('totalParts').textContent = data.totalParts + '개'; + document.getElementById('totalVolume').textContent = Math.round(data.totalVolume).toLocaleString() + ' m³'; + document.getElementById('loadingMsg').style.display = 'none'; + + console.log('✅ 완료!'); + }) + .catch(err => { + console.error('❌ 오류:', err); + document.getElementById('loadingMsg').innerHTML = '❌ 로드 실패
' + err.message; + }); // 렌더링 function animate() { @@ -519,7 +371,7 @@ } animate(); - // 윈도우 리사이징 + // 리사이징 window.addEventListener('resize', () => { const newWidth = canvas.clientWidth; const newHeight = canvas.clientHeight;