feat: CAD 解析第一次验证
This commit is contained in:
@@ -212,3 +212,8 @@ docs/_book
|
||||
# TODO: where does this rule come from?
|
||||
test/
|
||||
|
||||
# DXF parser output
|
||||
**/experiments/*/output/**
|
||||
|
||||
|
||||
**/Prompt_Task/**
|
||||
@@ -1,26 +1,44 @@
|
||||
# ai-cad-quant
|
||||
|
||||
# AI CAD自动算量项目
|
||||
|
||||
## 项目目标
|
||||
|
||||
通过CAD图纸解析技术,
|
||||
结合AI辅助识别,
|
||||
实现工程量自动计算和清单输出。
|
||||
通过CAD图纸解析、AI辅助识别和工程量计算规则,
|
||||
实现CAD图纸自动识别和工程量清单生成。
|
||||
|
||||
## 当前阶段
|
||||
|
||||
阶段1:
|
||||
CAD文件解析能力验证。
|
||||
阶段一:CAD数据解析能力验证
|
||||
|
||||
目标:
|
||||
|
||||
- 读取CAD/DXF文件
|
||||
- 提取图层
|
||||
- 提取线段
|
||||
- 提取文字
|
||||
- 提取尺寸
|
||||
- 验证工程量计算基础数据
|
||||
1. 验证CAD/DXF文件是否可以程序化解析
|
||||
2. 提取图层、线段、文字、尺寸、块等数据
|
||||
3. 分析是否可以用于墙体、房间、构件识别
|
||||
4. 输出第一版Demo验证结果
|
||||
|
||||
|
||||
## 技术路线
|
||||
|
||||
CAD/DXF
|
||||
↓
|
||||
文件解析
|
||||
↓
|
||||
数据提取
|
||||
↓
|
||||
构件识别
|
||||
↓
|
||||
工程量计算
|
||||
↓
|
||||
清单输出
|
||||
|
||||
|
||||
## 当前进度
|
||||
|
||||
- [x] 项目仓库初始化
|
||||
- [ ] CAD数据结构分析
|
||||
- [ ] DXF解析验证
|
||||
- [ ] 简单图纸Demo
|
||||
- [ ] 工程量计算验证
|
||||
|
||||
目录结构
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# CAD解析第一次验证
|
||||
|
||||
## 测试文件
|
||||
|
||||
工程制图图框标准文件
|
||||
|
||||
decimal-inch-drawing-sheet-size-ASME-Y14.1-cad-block-dwg.dxf
|
||||
|
||||
|
||||
## 测试结果
|
||||
|
||||
成功读取:
|
||||
|
||||
- 文件版本
|
||||
- 单位
|
||||
- 图层
|
||||
- 图元
|
||||
- 文字
|
||||
- 尺寸
|
||||
- 块
|
||||
|
||||
|
||||
## 结论
|
||||
|
||||
DXF文件可以通过程序解析。
|
||||
|
||||
下一步需要使用建筑平面CAD图进行验证。
|
||||
@@ -0,0 +1,2 @@
|
||||
工具
|
||||
- 在线DWG->DXF https://cloudconvert.com/dwg-to-dxf
|
||||
@@ -0,0 +1,17 @@
|
||||
# 任务执行摘要
|
||||
|
||||
## 会话 ID: 1
|
||||
- [2026-07-08]
|
||||
- **执行原因**: 实现 ezdxf DXF 解析测试程序,读取并输出 samples 目录下 DXF 文件的内容。
|
||||
- **执行过程**:
|
||||
1. 安装 ezdxf 库(v1.4.4)。
|
||||
2. 编写 requirements.txt,添加 ezdxf 依赖。
|
||||
3. 实现 main.py,包含以下功能模块:
|
||||
- 文档基本信息输出(DXF 版本、编码、单位、图形范围)
|
||||
- 图层列表及状态(颜色、线型、线宽、ON/OFF/FROZEN/LOCKED)
|
||||
- 模型空间实体类型统计
|
||||
- 实体详细信息(LINE、CIRCLE、ARC、LWPOLYLINE、MTEXT、TEXT、DIMENSION、INSERT 等类型的专属属性解析)
|
||||
- 块定义列表
|
||||
- 布局/图纸空间列表
|
||||
4. 运行程序验证,成功解析目标 DXF 文件,输出 20 个实体(9 个 DIMENSION、6 个 MTEXT、5 个 LWPOLYLINE)、13 个块定义、3 个布局。
|
||||
- **执行结果**: 程序正常运行,完整输出了 samples/decimal-inch-drawing-sheet-size-ASME-Y14.1-cad-block-dwg.dxf 的全部结构和内容信息。
|
||||
@@ -0,0 +1,32 @@
|
||||
# 图纸样例分析
|
||||
|
||||
## 文件信息
|
||||
|
||||
文件:
|
||||
|
||||
工程制图图框标准文件 decimal-inch-drawing-sheet-size-ASME-Y14.1-cad-block-dwg.dxf
|
||||
|
||||
|
||||
|
||||
类型:
|
||||
DWG
|
||||
|
||||
来源:
|
||||
|
||||
用途:
|
||||
|
||||
## 初步观察
|
||||
|
||||
包含:
|
||||
- 平面布局?
|
||||
- 尺寸标注?
|
||||
- 图例?
|
||||
- 图层?
|
||||
|
||||
## 验证目标
|
||||
|
||||
1. 是否可以解析
|
||||
2. 是否可以读取图层
|
||||
3. 是否可以读取线段
|
||||
4. 是否可以读取文字
|
||||
5. 是否可以获取坐标
|
||||
@@ -0,0 +1,41 @@
|
||||
# CAD自动算量技术验证路线
|
||||
|
||||
## 1. 验证目标
|
||||
|
||||
确认CAD图纸中的结构化数据是否可以被程序提取。
|
||||
|
||||
|
||||
## 2. 首批验证内容
|
||||
|
||||
- 图层
|
||||
- 线段
|
||||
- 多段线
|
||||
- 文字
|
||||
- 尺寸标注
|
||||
- 块参照
|
||||
|
||||
|
||||
## 3. Demo目标
|
||||
|
||||
输入:
|
||||
|
||||
CAD/DXF文件
|
||||
|
||||
|
||||
输出:
|
||||
|
||||
- 文件基本信息
|
||||
- 图层列表
|
||||
- 图元数量
|
||||
- 文字内容
|
||||
- 坐标信息
|
||||
|
||||
|
||||
## 4. 后续扩展
|
||||
|
||||
根据解析结果,
|
||||
进一步验证:
|
||||
|
||||
- 墙体识别
|
||||
- 房间面积计算
|
||||
- 材料用量计算
|
||||
@@ -0,0 +1,450 @@
|
||||
"""DXF 解析测试程序 —— 使用 ezdxf 读取并输出 DXF 文件内容。"""
|
||||
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import ezdxf
|
||||
|
||||
# 目录
|
||||
BASE_DIR = Path(__file__).parent.parent.parent
|
||||
SAMPLE_DIR = BASE_DIR / "samples"
|
||||
OUTPUT_DIR = Path(__file__).parent / "output"
|
||||
|
||||
#DXF_FILE = SAMPLE_DIR / "decimal-inch-drawing-sheet-size-ASME-Y14.1-cad-block-dwg.dxf"
|
||||
DXF_FILE = SAMPLE_DIR / "洗浴中心C-48.dxf"
|
||||
|
||||
class OutputRecorder:
|
||||
"""同时输出到 stdout 和内存缓冲,最终写入文件。"""
|
||||
|
||||
def __init__(self):
|
||||
self._buffer = io.StringIO()
|
||||
self._terminal = sys.stdout
|
||||
|
||||
def write(self, message):
|
||||
self._terminal.write(message)
|
||||
self._buffer.write(message)
|
||||
|
||||
def flush(self):
|
||||
self._terminal.flush()
|
||||
self._buffer.flush()
|
||||
|
||||
def getvalue(self):
|
||||
return self._buffer.getvalue()
|
||||
|
||||
|
||||
def extract_entity_props(entity):
|
||||
"""提取单个实体的关键属性为 JSON 友好格式。"""
|
||||
dxftype = entity.dxftype()
|
||||
props = {}
|
||||
|
||||
if dxftype == "LINE":
|
||||
props["start"] = list(entity.dxf.start)
|
||||
props["end"] = list(entity.dxf.end)
|
||||
elif dxftype == "CIRCLE":
|
||||
props["center"] = list(entity.dxf.center)
|
||||
props["radius"] = round(entity.dxf.radius, 4)
|
||||
elif dxftype == "ARC":
|
||||
props["center"] = list(entity.dxf.center)
|
||||
props["radius"] = round(entity.dxf.radius, 4)
|
||||
props["start_angle"] = round(entity.dxf.start_angle, 1)
|
||||
props["end_angle"] = round(entity.dxf.end_angle, 1)
|
||||
elif dxftype == "LWPOLYLINE":
|
||||
pts = entity.get_points()
|
||||
props["vertex_count"] = len(entity)
|
||||
props["closed"] = entity.closed
|
||||
props["points"] = [[round(p[0], 4), round(p[1], 4)] for p in pts]
|
||||
elif dxftype == "POLYLINE":
|
||||
verts = list(entity.vertices())
|
||||
props["vertex_count"] = len(verts)
|
||||
props["points"] = [[round(v.dxf.location[0], 4), round(v.dxf.location[1], 4)] for v in verts]
|
||||
elif dxftype == "INSERT":
|
||||
props["block_name"] = entity.dxf.name
|
||||
props["insert"] = list(entity.dxf.insert)
|
||||
props["scale"] = [round(entity.dxf.xscale, 2), round(entity.dxf.yscale, 2), round(entity.dxf.zscale, 2)]
|
||||
props["rotation"] = round(entity.dxf.rotation, 2)
|
||||
elif dxftype in ("MTEXT", "TEXT"):
|
||||
text = entity.plain_text() if dxftype == "MTEXT" else entity.dxf.text
|
||||
props["text"] = text
|
||||
if hasattr(entity.dxf, "insert"):
|
||||
props["insert"] = list(entity.dxf.insert)
|
||||
if hasattr(entity.dxf, "height"):
|
||||
props["height"] = round(entity.dxf.height, 2)
|
||||
elif dxftype == "DIMENSION":
|
||||
props["text"] = entity.dxf.text
|
||||
if hasattr(entity.dxf, "dimtype"):
|
||||
props["dimtype"] = entity.dxf.dimtype
|
||||
elif dxftype == "HATCH":
|
||||
props["pattern"] = entity.dxf.pattern_name
|
||||
elif dxftype == "SOLID" or dxftype == "TRACE":
|
||||
for vi in range(4):
|
||||
try:
|
||||
v = getattr(entity.dxf, f"vtx{vi}")
|
||||
props[f"vtx{vi}"] = list(v) if v else None
|
||||
except Exception:
|
||||
break
|
||||
elif dxftype == "POINT":
|
||||
props["location"] = list(entity.dxf.location)
|
||||
elif dxftype == "ELLIPSE":
|
||||
props["center"] = list(entity.dxf.center)
|
||||
props["major_axis"] = list(entity.dxf.major_axis)
|
||||
props["ratio"] = round(entity.dxf.ratio, 4)
|
||||
elif dxftype == "SPLINE":
|
||||
props["fit_points"] = [list(p) for p in entity.fit_points]
|
||||
elif dxftype == "3DFACE":
|
||||
for vi in range(4):
|
||||
try:
|
||||
v = getattr(entity.dxf, f"vtx{vi}")
|
||||
props[f"vtx{vi}"] = list(v) if v else None
|
||||
except Exception:
|
||||
break
|
||||
else:
|
||||
for attr in entity.dxf.all_existing_dxf_attribs():
|
||||
if attr in ("handle", "owner", "layer", "linetype", "color", "lineweight"):
|
||||
continue
|
||||
val = getattr(entity.dxf, attr)
|
||||
if val is not None:
|
||||
props[attr] = list(val) if hasattr(val, "__iter__") and not isinstance(val, str) else val
|
||||
|
||||
return props
|
||||
|
||||
|
||||
def extract_to_dict(doc: ezdxf.document.Drawing, filename: str, parse_time: str):
|
||||
"""提取 DXF 文档全部内容为 JSON 可序列化的 dict。"""
|
||||
result = {
|
||||
"file": filename,
|
||||
"parse_time": parse_time,
|
||||
"header": {
|
||||
"dxf_version": doc.dxfversion,
|
||||
"encoding": doc.encoding,
|
||||
"acad_ver": doc.header.get("$ACADVER", None),
|
||||
},
|
||||
}
|
||||
|
||||
# 单位
|
||||
units = doc.header.get("$INSUNITS", None)
|
||||
unit_names = {1: "inches", 2: "feet", 4: "millimeters", 5: "centimeters", 6: "meters"}
|
||||
result["header"]["units"] = unit_names.get(units, str(units)) if units else None
|
||||
|
||||
# 图形范围
|
||||
extmin = doc.header.get("$EXTMIN", None)
|
||||
extmax = doc.header.get("$EXTMAX", None)
|
||||
if extmin and extmax:
|
||||
result["header"]["extents"] = {"min": list(extmin), "max": list(extmax)}
|
||||
|
||||
# 图层
|
||||
layers = []
|
||||
for layer in doc.layers:
|
||||
layers.append({
|
||||
"name": layer.dxf.name,
|
||||
"color": layer.dxf.color,
|
||||
"linetype": layer.dxf.linetype,
|
||||
"lineweight": layer.dxf.lineweight,
|
||||
"on": layer.is_on(),
|
||||
"frozen": layer.is_frozen(),
|
||||
"locked": layer.is_locked(),
|
||||
})
|
||||
result["layers"] = layers
|
||||
|
||||
# 实体
|
||||
entities = []
|
||||
entity_type_counts = {}
|
||||
for entity in doc.modelspace():
|
||||
dxftype = entity.dxftype()
|
||||
entity_type_counts[dxftype] = entity_type_counts.get(dxftype, 0) + 1
|
||||
entities.append({
|
||||
"index": len(entities) + 1,
|
||||
"type": dxftype,
|
||||
"handle": entity.dxf.handle,
|
||||
"layer": entity.dxf.layer,
|
||||
"properties": extract_entity_props(entity),
|
||||
})
|
||||
result["entity_summary"] = entity_type_counts
|
||||
result["entities"] = entities
|
||||
|
||||
# 块定义
|
||||
blocks = []
|
||||
for block in doc.blocks:
|
||||
blocks.append({
|
||||
"name": block.name,
|
||||
"entity_count": len(list(block)),
|
||||
})
|
||||
result["blocks"] = blocks
|
||||
|
||||
# 布局
|
||||
layouts = []
|
||||
for layout in doc.layouts:
|
||||
try:
|
||||
pw = layout.dxf.paper_width if hasattr(layout.dxf, "paper_width") else None
|
||||
ph = layout.dxf.paper_height if hasattr(layout.dxf, "paper_height") else None
|
||||
layouts.append({"name": layout.name, "paper_width": pw, "paper_height": ph})
|
||||
except Exception:
|
||||
layouts.append({"name": layout.name, "paper_width": None, "paper_height": None})
|
||||
result["layouts"] = layouts
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def print_header(title: str):
|
||||
print(f"\n{'=' * 70}")
|
||||
print(f" {title}")
|
||||
print(f"{'=' * 70}")
|
||||
|
||||
|
||||
def print_dxf_info(doc: ezdxf.document.Drawing):
|
||||
"""打印 DXF 文档基本信息。"""
|
||||
print(f" DXF 版本 : {doc.dxfversion}")
|
||||
print(f" 编码 : {doc.encoding}")
|
||||
print(f" 创建者 : {doc.header.get('$ACADVER', 'N/A')}")
|
||||
|
||||
# 绘图单位
|
||||
units = doc.header.get("$INSUNITS", None)
|
||||
unit_map = {
|
||||
1: "英寸 (Inches)",
|
||||
2: "英尺 (Feet)",
|
||||
4: "毫米 (Millimeters)",
|
||||
5: "厘米 (Centimeters)",
|
||||
6: "米 (Meters)",
|
||||
}
|
||||
unit_name = unit_map.get(units, f"未知 ({units})") if units else "未指定"
|
||||
print(f" 绘图单位 : {unit_name}")
|
||||
|
||||
# 图形范围
|
||||
extmin = doc.header.get("$EXTMIN", None)
|
||||
extmax = doc.header.get("$EXTMAX", None)
|
||||
if extmin and extmax:
|
||||
print(f" 图形范围 : {extmin} -> {extmax}")
|
||||
|
||||
|
||||
def print_layers(doc: ezdxf.document.Drawing):
|
||||
"""打印所有图层信息。"""
|
||||
layers = list(doc.layers)
|
||||
if not layers:
|
||||
print(" (无图层)")
|
||||
return
|
||||
|
||||
print(f" 共 {len(layers)} 个图层:")
|
||||
print(f" {'名称':<30} {'颜色':<8} {'线型':<20} {'线宽':<8} {'状态'}")
|
||||
print(f" {'-' * 80}")
|
||||
for layer in layers:
|
||||
name = layer.dxf.name
|
||||
color = layer.dxf.color
|
||||
linetype = layer.dxf.linetype
|
||||
# 线宽:-1 表示 DEFAULT
|
||||
lineweight = layer.dxf.lineweight
|
||||
lw_display = "默认" if lineweight == -1 else str(lineweight)
|
||||
flags = []
|
||||
if layer.is_on():
|
||||
flags.append("ON")
|
||||
else:
|
||||
flags.append("OFF")
|
||||
if layer.is_frozen():
|
||||
flags.append("FROZEN")
|
||||
if layer.is_locked():
|
||||
flags.append("LOCKED")
|
||||
print(f" {name:<30} {str(color):<8} {linetype:<20} {lw_display:<8} {', '.join(flags)}")
|
||||
|
||||
|
||||
def print_entity_summary(doc: ezdxf.document.Drawing):
|
||||
"""统计模型空间中各类型实体数量。"""
|
||||
msp = doc.modelspace()
|
||||
entity_types = {}
|
||||
for entity in msp:
|
||||
dtype = entity.dxftype()
|
||||
entity_types[dtype] = entity_types.get(dtype, 0) + 1
|
||||
|
||||
if not entity_types:
|
||||
print(" (模型空间无实体)")
|
||||
return
|
||||
|
||||
print(f" 共 {sum(entity_types.values())} 个实体:")
|
||||
print(f" {'类型':<25} {'数量':<8}")
|
||||
print(f" {'-' * 35}")
|
||||
for dtype, count in sorted(entity_types.items(), key=lambda x: -x[1]):
|
||||
print(f" {dtype:<25} {count:<8}")
|
||||
|
||||
|
||||
def print_entity_details(doc: ezdxf.document.Drawing):
|
||||
"""打印模型空间中每个实体的详细信息。"""
|
||||
msp = doc.modelspace()
|
||||
entities = list(msp)
|
||||
if not entities:
|
||||
print(" (模型空间无实体)")
|
||||
return
|
||||
|
||||
print(f" 共 {len(entities)} 个实体:")
|
||||
print(f" {'序号':<6} {'类型':<25} {'句柄':<12} {'图层':<20} {'关键属性'}")
|
||||
print(f" {'-' * 100}")
|
||||
|
||||
for i, entity in enumerate(entities):
|
||||
dxftype = entity.dxftype()
|
||||
handle = entity.dxf.handle
|
||||
layer = entity.dxf.layer
|
||||
|
||||
# 提取各类型的关键属性
|
||||
key_attrs = []
|
||||
if dxftype == "LINE":
|
||||
key_attrs.append(f"起点={entity.dxf.start}, 终点={entity.dxf.end}")
|
||||
elif dxftype == "CIRCLE":
|
||||
key_attrs.append(f"圆心={entity.dxf.center}, 半径={entity.dxf.radius:.4f}")
|
||||
elif dxftype == "ARC":
|
||||
key_attrs.append(f"圆心={entity.dxf.center}, 半径={entity.dxf.radius:.4f}, 角度={entity.dxf.start_angle:.1f}~{entity.dxf.end_angle:.1f}")
|
||||
elif dxftype == "LWPOLYLINE":
|
||||
count = len(entity)
|
||||
closed = "闭合" if entity.closed else "开放"
|
||||
pts = entity.get_points()
|
||||
first_pt = pts[0] if pts else "N/A"
|
||||
key_attrs.append(f"顶点数={count}, {closed}, 起点={first_pt[:2]}")
|
||||
elif dxftype == "POLYLINE":
|
||||
count = len(list(entity.vertices()))
|
||||
key_attrs.append(f"顶点数={count}")
|
||||
elif dxftype == "INSERT":
|
||||
key_attrs.append(f"块名={entity.dxf.name}, 插入点={entity.dxf.insert}, 缩放={entity.dxf.xscale:.2f},{entity.dxf.yscale:.2f}")
|
||||
elif dxftype == "MTEXT":
|
||||
text = entity.plain_text()[:50]
|
||||
key_attrs.append(f'内容="{text}..."' if len(entity.plain_text()) > 50 else f'内容="{text}"')
|
||||
elif dxftype == "TEXT":
|
||||
text = entity.dxf.text[:50]
|
||||
key_attrs.append(f'内容="{text}..."' if len(entity.dxf.text) > 50 else f'内容="{entity.dxf.text}"')
|
||||
elif dxftype == "DIMENSION":
|
||||
key_attrs.append(f"测量值={entity.dxf.text}")
|
||||
elif dxftype == "HATCH":
|
||||
key_attrs.append(f"图案={entity.dxf.pattern_name}")
|
||||
elif dxftype == "SOLID" or dxftype == "TRACE":
|
||||
key_attrs.append(f"顶点={entity.dxf.vtx0} {entity.dxf.vtx1} {entity.dxf.vtx2} {entity.dxf.vtx3}")
|
||||
elif dxftype == "POINT":
|
||||
key_attrs.append(f"位置={entity.dxf.location}")
|
||||
elif dxftype == "ELLIPSE":
|
||||
key_attrs.append(f"圆心={entity.dxf.center}, 长轴={entity.dxf.major_axis}")
|
||||
elif dxftype == "SPLINE":
|
||||
key_attrs.append(f"拟合点数={len(entity.fit_points)}")
|
||||
elif dxftype == "3DFACE":
|
||||
key_attrs.append(f"顶点={entity.dxf.vtx0} {entity.dxf.vtx1} {entity.dxf.vtx2} {entity.dxf.vtx3}")
|
||||
else:
|
||||
# 通用:列出非默认的 dxf 属性
|
||||
for attr in entity.dxf.all_existing_dxf_attribs():
|
||||
if attr in ("handle", "owner", "layer", "linetype", "color", "lineweight"):
|
||||
continue
|
||||
val = getattr(entity.dxf, attr)
|
||||
if val is not None:
|
||||
key_attrs.append(f"{attr}={val}")
|
||||
|
||||
attrs_str = "; ".join(key_attrs[:3]) if key_attrs else "(无额外属性)"
|
||||
print(f" {i + 1:<6} {dxftype:<25} {handle:<12} {layer:<20} {attrs_str}")
|
||||
|
||||
|
||||
def print_blocks(doc: ezdxf.document.Drawing):
|
||||
"""打印所有块定义。"""
|
||||
blocks = list(doc.blocks)
|
||||
if not blocks:
|
||||
print(" (无自定义块)")
|
||||
return
|
||||
|
||||
print(f" 共 {len(blocks)} 个块定义:")
|
||||
print(f" {'名称':<35} {'实体数':<10} {'说明'}")
|
||||
print(f" {'-' * 70}")
|
||||
for block in blocks:
|
||||
name = block.name
|
||||
count = len(list(block))
|
||||
desc = ""
|
||||
if name.startswith("*"):
|
||||
if name.startswith("*Model_Space"):
|
||||
desc = "(模型空间)"
|
||||
elif name.startswith("*Paper_Space"):
|
||||
desc = "(图纸空间)"
|
||||
elif name.startswith("*D"):
|
||||
desc = "(标注块)"
|
||||
elif name.startswith("*X"):
|
||||
desc = "(外部参照)"
|
||||
elif name.startswith("*U"):
|
||||
desc = "(匿名块)"
|
||||
else:
|
||||
desc = "(特殊块)"
|
||||
print(f" {name:<35} {count:<10} {desc}")
|
||||
|
||||
|
||||
def print_layouts(doc: ezdxf.document.Drawing):
|
||||
"""打印所有布局(图纸空间)。"""
|
||||
layouts = list(doc.layouts)
|
||||
if not layouts:
|
||||
print(" (无布局)")
|
||||
return
|
||||
|
||||
print(f" 共 {len(layouts)} 个布局:")
|
||||
print(f" {'名称':<30} {'尺寸 (宽 x 高)'}")
|
||||
print(f" {'-' * 60}")
|
||||
for layout in layouts:
|
||||
name = layout.name
|
||||
try:
|
||||
page_w = layout.dxf.paper_width if hasattr(layout.dxf, 'paper_width') else "?"
|
||||
page_h = layout.dxf.paper_height if hasattr(layout.dxf, 'paper_height') else "?"
|
||||
print(f" {name:<30} {page_w} x {page_h}")
|
||||
except Exception:
|
||||
print(f" {name:<30} N/A")
|
||||
|
||||
|
||||
def main():
|
||||
if not DXF_FILE.exists():
|
||||
print(f"错误:文件不存在 -> {DXF_FILE}")
|
||||
return
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
parse_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
output_txt = OUTPUT_DIR / f"{DXF_FILE.stem}_{timestamp}.txt"
|
||||
output_json = OUTPUT_DIR / f"{DXF_FILE.stem}_{timestamp}.json"
|
||||
|
||||
recorder = OutputRecorder()
|
||||
sys.stdout = recorder
|
||||
|
||||
try:
|
||||
print(f"解析文件: {DXF_FILE.name}")
|
||||
print(f"路径: {DXF_FILE}")
|
||||
print(f"输出文件: {output_txt.relative_to(BASE_DIR)}")
|
||||
print(f"JSON 文件: {output_json.relative_to(BASE_DIR)}")
|
||||
print(f"解析时间: {parse_time}")
|
||||
|
||||
doc = ezdxf.readfile(str(DXF_FILE))
|
||||
|
||||
# 1. 基本信息
|
||||
print_header("一、文档基本信息")
|
||||
print_dxf_info(doc)
|
||||
|
||||
# 2. 图层
|
||||
print_header("二、图层信息")
|
||||
print_layers(doc)
|
||||
|
||||
# 3. 实体统计
|
||||
print_header("三、模型空间实体统计")
|
||||
print_entity_summary(doc)
|
||||
|
||||
# 4. 实体详情
|
||||
print_header("四、模型空间实体详情")
|
||||
print_entity_details(doc)
|
||||
|
||||
# 5. 块定义
|
||||
print_header("五、块定义")
|
||||
print_blocks(doc)
|
||||
|
||||
# 6. 布局
|
||||
print_header("六、布局(图纸空间)")
|
||||
print_layouts(doc)
|
||||
|
||||
print_header("解析完成")
|
||||
finally:
|
||||
sys.stdout = recorder._terminal
|
||||
|
||||
# 写入文本文件
|
||||
output_txt.write_text(recorder.getvalue(), encoding="utf-8")
|
||||
print(f"\n结果已保存到: {output_txt}")
|
||||
|
||||
# 写入 JSON 文件
|
||||
json_data = extract_to_dict(doc, DXF_FILE.name, parse_time)
|
||||
output_json.write_text(json.dumps(json_data, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
print(f"JSON 已保存到: {output_json}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
ezdxf>=1.4.0
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
_______________________________________________________________
|
||||
|
||||
################# 图纸使用说明 ###################
|
||||
1.本图纸为AutoCAD所绘制的DWG文件,您需要安装AutoCAD R2000及以上版本才
|
||||
能正常浏览修改,如果您没有安装AutoCAD软件,您也可以使用“筑龙CAD工
|
||||
具箱”中的“DWG图形浏览器”来查看图纸,但不能进行修改,也可能不能体
|
||||
现图纸原貌。
|
||||
2.筑龙网部分图纸必须安装“筑龙CAD工具箱”才能正常浏览,如果您浏览不正
|
||||
确,请到筑龙网下载并安装“筑龙网CAD工具箱”,下载地址为:
|
||||
http://public.sinoaec.com/tools/cadtool.rar
|
||||
3.筑龙网图纸来源于网络投稿,仅供您学习参考使用,请勿用于商业目的,
|
||||
否则您将承担由此引发的法律责任。
|
||||
__________________________________________________________________
|
||||
|
||||
######## 筑龙网CAD工具箱的安装、设置与卸载 ###########
|
||||
1、双击从网上下载的筑龙网CAD工具箱软件,立即开始安装并根据提示完成;
|
||||
2、安装后点击“筑龙网CAD工具箱设置”,设置程序会找出您计算机上所安装
|
||||
的所有AutoCAD版本,您可以选择在哪些版本上使用“筑龙CAD工具箱”,以
|
||||
后您也可以随时启动“筑龙网CAD工具箱设置”来更改。
|
||||
3、如果您不想继续使用“筑龙网CAD工具箱”,您可以随时点击“卸载筑龙网
|
||||
CAD工具箱”,将此软件完全删除。
|
||||
|
||||
__________________________________________________________________
|
||||
|
||||
################# 筑龙网CAD工具箱功能说明 ###################
|
||||
1、在绘图区域下方实现了标签页浏览功能,方便不同图纸间的切换;
|
||||
2、实现了将命令中的关键词选项转化为按钮的功能,您在绘图时可以直接
|
||||
点击命令行中的选项按钮。如您在画线时,命令行中会出现“闭合”与
|
||||
“放弃”两个按钮,直接点击即可实现与键盘一样的功能;
|
||||
3、将您的AutoCAD菜单转化为XP风格的菜单,更美观更舒适;
|
||||
4、配合热键动态缩放窗口,您按着键盘上的SHIFT键并点鼠标左键,会
|
||||
缩小图纸,按着键盘上的CTRL键并点鼠标右键,会放大图纸,同时按
|
||||
着SHIFT键与CTRL键,实现窗口放大的功能,这些键您也可以自定义;
|
||||
5、DWG图形浏览器是一个可以脱离AutoCAD独立运行的小工具,您可以用它
|
||||
来快速查看DWG文件。
|
||||
6、DWG文件版本转换也是一个可以脱离AutoCAD独立运行的小工具,您可以
|
||||
用它来将您的AutCAD文件更好地实现共享。如对于使用AutoCAD R14版本的
|
||||
用户,可以使用DWG文件版本转换工具将R2000的资料转换为R14使用。
|
||||
|
||||
所有以上功能您都可以独立使用与设置取消,不影响其他功能的使用。我们
|
||||
如果将不断努力开发更多使用功能,如果您有好的建议,欢迎告诉我们。
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+109734
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user