feat: 拆分 DXF 解析为模块化结构,新增图层分析和实体分析模块
- 新增 layer_analysis.py:图层实体统计 + 角色推断(22条启发式规则)
- 新增 entity_analysis.py:实体类型统计、INSERT 块聚合、文本提取
- 重构 main.py:调度分析模块,输出 {文件名}_cad_analysis.json
- 新增 README.md 使用说明
- 输出文件名使用模型名作为前缀,避免多次测试覆盖
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""图层分析模块 —— 统计每层实体数量与类型,并基于图层名称进行角色推断。"""
|
||||
|
||||
# 角色推断规则(启发式,基于常见中文/英文命名)
|
||||
_ROLE_RULES = [
|
||||
(["WALL", "墙", "W", "A-WALL", "A-WALL-"], "墙体"),
|
||||
(["DOOR", "门", "窗", "WINDOW", "D", "M"], "门窗"),
|
||||
(["DIM", "标注", "DEFPOINTS", "PUB_DIM", "PUB_DIM"], "标注"),
|
||||
(["TEXT", "文字", "NOTE"], "文字"),
|
||||
(["COLUMN", "柱", "Z"], "柱"),
|
||||
(["E", "EQUIP", "设备"], "设备"),
|
||||
(["HATCH", "填充", "BH"], "填充"),
|
||||
(["AXIS", "轴", "AXIS"], "轴网"),
|
||||
(["GRID", "网格"], "网格"),
|
||||
(["FURN", "家具", "FURNITURE"], "家具"),
|
||||
(["BEAM", "梁", "B"], "梁"),
|
||||
(["SLAB", "板"], "板"),
|
||||
(["STAIR", "楼梯", "S"], "楼梯"),
|
||||
(["ROOF", "屋顶", "R"], "屋顶"),
|
||||
(["PIPE", "管", "P"], "管道"),
|
||||
(["DUCT", "风管"], "风管"),
|
||||
(["ELEC", "电气", "E-"], "电气"),
|
||||
(["PLUMB", "给排水", "P-"], "给排水"),
|
||||
(["FOUND", "基础", "F"], "基础"),
|
||||
(["SITE", "场地", "总图"], "场地"),
|
||||
(["CEIL", "天花", "吊顶", "C"], "天花"),
|
||||
(["FLOOR", "地面", "FL"], "地面"),
|
||||
(["SECTION", "剖面", "SECT"], "剖面"),
|
||||
(["ELEV", "立面", "ELEVATION"], "立面"),
|
||||
(["0", "A-"], "主体结构"),
|
||||
]
|
||||
|
||||
|
||||
def _infer_role(layer_name: str) -> str:
|
||||
"""根据图层名称推断图层角色(仅作建议)。"""
|
||||
upper_name = layer_name.upper()
|
||||
for keywords, role in _ROLE_RULES:
|
||||
for kw in keywords:
|
||||
if kw in upper_name or kw in layer_name:
|
||||
return role
|
||||
return "其他"
|
||||
|
||||
|
||||
def analyze_layers(doc) -> list:
|
||||
"""分析所有图层,返回每层的实体统计和角色推断。
|
||||
|
||||
Args:
|
||||
doc: ezdxf Drawing 对象
|
||||
|
||||
Returns:
|
||||
list[dict]: 每层信息,格式为 {
|
||||
"name": str,
|
||||
"entity_count": int,
|
||||
"entity_types": list[str],
|
||||
"suggested_role": str
|
||||
}
|
||||
"""
|
||||
msp = doc.modelspace()
|
||||
|
||||
# 按图层聚合实体
|
||||
layer_entities = {} # layer_name -> list of dxftype
|
||||
for entity in msp:
|
||||
layer_name = entity.dxf.layer
|
||||
if layer_name not in layer_entities:
|
||||
layer_entities[layer_name] = []
|
||||
layer_entities[layer_name].append(entity.dxftype())
|
||||
|
||||
# 也包含没有实体的图层(在 doc.layers 中定义但模型空间无实体)
|
||||
result = []
|
||||
seen_layers = set()
|
||||
|
||||
for layer_name, types in layer_entities.items():
|
||||
seen_layers.add(layer_name)
|
||||
unique_types = sorted(set(types))
|
||||
result.append({
|
||||
"name": layer_name,
|
||||
"entity_count": len(types),
|
||||
"entity_types": unique_types,
|
||||
"suggested_role": _infer_role(layer_name),
|
||||
})
|
||||
|
||||
# 补充空图层(在图层定义中存在但无实体)
|
||||
for layer in doc.layers:
|
||||
name = layer.dxf.name
|
||||
if name not in seen_layers:
|
||||
result.append({
|
||||
"name": name,
|
||||
"entity_count": 0,
|
||||
"entity_types": [],
|
||||
"suggested_role": _infer_role(name),
|
||||
})
|
||||
|
||||
# 按实体数降序排列
|
||||
result.sort(key=lambda x: -x["entity_count"])
|
||||
return result
|
||||
Reference in New Issue
Block a user