refactor: 전체 코드 정리, 중복 로직 헬퍼 공통화, 미사용 임포트/변수 제거 및 리소스 정리

This commit is contained in:
Antigravity Agent committed 2026-10-22 18:01:56 +09:00
1 parent af65700afd
commit 3cc9afeac8
5 files changed
+45 -50

No files matched your search

+33 -23
View File
@@ -1,5 +1,4 @@
import os import os
import json
import tempfile import tempfile
from flask import Flask, request, jsonify, send_file, Response from flask import Flask, request, jsonify, send_file, Response
from flask_cors import CORS from flask_cors import CORS
@@ -17,6 +16,27 @@ current_drawing_data = None
current_model_data = None current_model_data = None
def _resolve_classification(drawing_name, manual_type=None):
"""도면명 기반 분류 및 사용자 수동 오버라이드 객체 생성 헬퍼"""
res = cad_parser.classify_drawing_by_name(drawing_name)
selected_type = manual_type if manual_type in ('GENERAL', 'REBAR') else res['auto_type']
label_map = {
'GENERAL': '일반도',
'REBAR': '배근도/구조도',
'UNCLASSIFIED': '미분류 (수동 선택 필요)'
}
return {
'autoType': res['auto_type'],
'autoLabel': res['auto_label'],
'matchedKeyword': res['matched_keyword'],
'reason': res['reason'],
'needsManualSelection': res['needs_manual_selection'],
'selectedType': selected_type,
'selectedLabel': label_map.get(selected_type, res['auto_label']),
'isManualOverride': bool(manual_type and manual_type != res['auto_type'])
}
@app.route('/') @app.route('/')
def index(): def index():
return send_file('index.html') return send_file('index.html')
@@ -62,24 +82,7 @@ def api_classify():
drawing_name = body.get('drawingName', '') drawing_name = body.get('drawingName', '')
manual_type = body.get('manualType') # Optional: 'GENERAL' or 'REBAR' manual_type = body.get('manualType') # Optional: 'GENERAL' or 'REBAR'
res = cad_parser.classify_drawing_by_name(drawing_name) classification_obj = _resolve_classification(drawing_name, manual_type)
selected_type = manual_type if manual_type in ('GENERAL', 'REBAR') else res['auto_type']
label_map = {
'GENERAL': '일반도',
'REBAR': '배근도/구조도',
'UNCLASSIFIED': '미분류 (수동 선택 필요)'
}
classification_obj = {
'autoType': res['auto_type'],
'autoLabel': res['auto_label'],
'matchedKeyword': res['matched_keyword'],
'reason': res['reason'],
'needsManualSelection': res['needs_manual_selection'],
'selectedType': selected_type,
'selectedLabel': label_map.get(selected_type, res['auto_label']),
'isManualOverride': bool(manual_type and manual_type != res['auto_type'])
}
# Update active drawing classification in memory and regenerate 3D model # Update active drawing classification in memory and regenerate 3D model
for d in current_drawings_list: for d in current_drawings_list:
@@ -135,12 +138,19 @@ def api_upload():
# 2. Parse each uploaded DWG file # 2. Parse each uploaded DWG file
parsed_drawings = [] parsed_drawings = []
for filename, temp_path in saved_files: try:
try: for filename, temp_path in saved_files:
drawing_data = cad_parser.parse_dwg(temp_path, custom_filename=filename) drawing_data = cad_parser.parse_dwg(temp_path, custom_filename=filename)
parsed_drawings.append(drawing_data) parsed_drawings.append(drawing_data)
except Exception as e: except Exception as e:
return jsonify({'status': 'error', 'message': f'도면 분석 중 오류 발생 ({filename}): {str(e)}'}), 500 return jsonify({'status': 'error', 'message': f'도면 분석 중 오류 발생: {str(e)}'}), 500
finally:
for _, temp_path in saved_files:
try:
if os.path.exists(temp_path):
os.remove(temp_path)
except OSError:
pass
global current_drawing_data, current_model_data, current_drawings_list global current_drawing_data, current_model_data, current_drawings_list
if reset_flag or current_drawings_list is None: if reset_flag or current_drawings_list is None:
-1
View File
@@ -1,7 +1,6 @@
import os import os
import re import re
import math import math
import json
import ezdwg import ezdwg
+1 -2
View File
@@ -1,6 +1,5 @@
import math import math
import numpy as np import numpy as np
import json
import rebar_model import rebar_model
@@ -122,7 +121,6 @@ def get_wingwall_mesh(side='LEFT', custom_params=None, culvert_params=None, num_
pos_str = 'START_RIGHT' pos_str = 'START_RIGHT'
is_left_side = ('LEFT' in pos_str) is_left_side = ('LEFT' in pos_str)
is_start = ('START' in pos_str)
cp = custom_params or {} cp = custom_params or {}
culv = culvert_params or {} culv = culvert_params or {}
@@ -554,6 +552,7 @@ def generate_full_model(params=None, drawings_list=None):
if __name__ == '__main__': if __name__ == '__main__':
import json
res = generate_full_model() res = generate_full_model()
print("Full model generated:") print("Full model generated:")
print(" Total volume:", res['summary']['total_volume'], "m3") print(" Total volume:", res['summary']['total_volume'], "m3")
+10 -23
View File
@@ -887,27 +887,10 @@ class Viewer3D {
new THREE.Vector3(d2.x, d2.y, zDim + tickLen) new THREE.Vector3(d2.x, d2.y, zDim + tickLen)
); );
const geom = new THREE.BufferGeometry().setFromPoints(linePoints); // 치수선 및 텍스트 렌더링
const mat = new THREE.LineBasicMaterial({
color: 0xffffff, // Requirement 4: 모든 치수선 흰색
linewidth: 2,
depthTest: false,
transparent: true,
opacity: 0.95
});
const lineSegs = new THREE.LineSegments(geom, mat);
lineSegs.renderOrder = 999;
this.dimensionGroup.add(lineSegs);
// 치수값 텍스트 라벨 (수평 치수선 상단 중앙 배치)
const mid = new THREE.Vector3().addVectors(d1, d2).multiplyScalar(0.5); const mid = new THREE.Vector3().addVectors(d1, d2).multiplyScalar(0.5);
const spritePos = new THREE.Vector3(mid.x, mid.y, zDim + 0.28); const spritePos = new THREE.Vector3(mid.x, mid.y, zDim + 0.28);
this._renderDimensionEntry(linePoints, spritePos, text);
const sprite = this.createDimensionTextSprite(text);
sprite.position.copy(spritePos);
sprite.renderOrder = 1000;
this.scene.add(sprite);
this.dimensionSprites.push(sprite);
} }
// 높이 측정용 3D 치수선 생성 (Requirement 3 & 4: 흰색 치수선 및 간소화 표기) // 높이 측정용 3D 치수선 생성 (Requirement 3 & 4: 흰색 치수선 및 간소화 표기)
@@ -936,6 +919,14 @@ class Viewer3D {
linePoints.push(d1.clone().addScaledVector(tickDir, tickLen), d1.clone().addScaledVector(tickDir, -tickLen)); linePoints.push(d1.clone().addScaledVector(tickDir, tickLen), d1.clone().addScaledVector(tickDir, -tickLen));
linePoints.push(d2.clone().addScaledVector(tickDir, tickLen), d2.clone().addScaledVector(tickDir, -tickLen)); linePoints.push(d2.clone().addScaledVector(tickDir, tickLen), d2.clone().addScaledVector(tickDir, -tickLen));
// 치수값 텍스트 라벨 (치수선 외측 중앙에 명확히 대응되도록 배치)
const mid = new THREE.Vector3().addVectors(d1, d2).multiplyScalar(0.5);
const spritePos = mid.clone().addScaledVector(offsetDir.clone().normalize(), 0.32);
this._renderDimensionEntry(linePoints, spritePos, text);
}
// 치수선 LineSegments 및 텍스트 Sprite 씬 등록 공통 헬퍼
_renderDimensionEntry(linePoints, spritePos, text) {
const geom = new THREE.BufferGeometry().setFromPoints(linePoints); const geom = new THREE.BufferGeometry().setFromPoints(linePoints);
const mat = new THREE.LineBasicMaterial({ const mat = new THREE.LineBasicMaterial({
color: 0xffffff, // Requirement 4: 모든 치수선 흰색 color: 0xffffff, // Requirement 4: 모든 치수선 흰색
@@ -948,10 +939,6 @@ class Viewer3D {
lineSegs.renderOrder = 999; lineSegs.renderOrder = 999;
this.dimensionGroup.add(lineSegs); this.dimensionGroup.add(lineSegs);
// 치수값 텍스트 라벨 (치수선 외측 중앙에 명확히 대응되도록 배치)
const mid = new THREE.Vector3().addVectors(d1, d2).multiplyScalar(0.5);
const spritePos = mid.clone().addScaledVector(offsetDir.clone().normalize(), 0.32);
const sprite = this.createDimensionTextSprite(text); const sprite = this.createDimensionTextSprite(text);
sprite.position.copy(spritePos); sprite.position.copy(spritePos);
sprite.renderOrder = 1000; sprite.renderOrder = 1000;
+1 -1
View File
@@ -5,7 +5,6 @@ Verifies 2D drawing classification, DWG parsing, 3D solid & rebar modeling,
mesh watertightness, exporter functionality, and Flask API endpoints. mesh watertightness, exporter functionality, and Flask API endpoints.
""" """
import os import os
import sys
import json import json
import unittest import unittest
@@ -156,6 +155,7 @@ class Test3DDrawingPipeline(unittest.TestCase):
# 1. 메인 웹페이지 # 1. 메인 웹페이지
r_index = self.flask_app.get('/') r_index = self.flask_app.get('/')
self.assertEqual(r_index.status_code, 200) self.assertEqual(r_index.status_code, 200)
r_index.close()
# 2. 기본 도면 데이터 조회 API # 2. 기본 도면 데이터 조회 API
r_def = self.flask_app.get('/api/default-drawing') r_def = self.flask_app.get('/api/default-drawing')