- 图形学
【免费下载链接】ezdxf
Python interface to DXF
导读
本文以 ezdxf 官方文档的 Table Classes(表格类) 为主体,深入剖析 DXF 文件 TABLES 段中所有符号表(Layer、Linetype、Textstyle、DimStyle、AppID、UCS、View、Viewport、BlockRecord)的统一抽象与专属能力。读完本文,你将掌握Table基类的通用 API(含大小写不敏感机制与 Python 容器协议)、每张表的add()参数细节,以及 Viewport 多视图配置、SHX 形文件文字样式等特殊场景的完整实战方案。
一、认识 TABLES 段与 ezdxf 的表格抽象
DXF 文件中,TABLES段(SECTION TABLES)集中存放绘图所需的符号定义:图层、线型、文字样式、标注样式、视图、视口等。ezdxf 在 src/ezdxf/sections/table.py 中将其抽象为一套统一的类层次:
- 基类
Table(泛型类,table.py):提供所有表的通用增删查改能力; - 九个具体子类:
LayerTable、LinetypeTable、TextstyleTable、DimStyleTable、AppIDTable、UCSTable、ViewTable、ViewportTable、BlockRecordTable,各自对应一种 DXF 表。
这些子类均由 TablesSection 统一管理,导出时按固定顺序写出(VPORT → LTYPE → LAYER → STYLE → VIEW → UCS → APPID → DIMSTYLE → BLOCK_RECORD),且BLOCK_RECORD表仅在 DXF R2000 及以上版本导出,R12 没有该表(见 sections/tables.py)。
1.1 用户入口:doc 级属性
普通用户无需直接接触TablesSection,Drawing文档对象提供了九个便捷属性(见 src/ezdxf/document.py):
| 属性 | 返回类型 | 对应 DXF 表 |
|---|---|---|
doc.layers | LayerTable | LAYER |
doc.linetypes | LinetypeTable | LTYPE |
doc.styles | TextstyleTable | STYLE |
doc.dimstyles | DimStyleTable | DIMSTYLE |
doc.appids | AppIDTable | APPID |
doc.ucs | UCSTable | UCS |
doc.views | ViewTable | VIEW |
doc.viewports | ViewportTable | VPORT |
doc.block_records | BlockRecordTable | BLOCK_RECORD |
1.2 表头(TableHead)
每张表在 DXF 中以TABLE表头实体开始、ENDTAB结束。ezdxf 的 TableHead 仅在导出时维护(计数、句柄、owner),运行时并不依赖它的一致性;R12 的TABLE不需要句柄,R2000 及以上则需要句柄与 owner 标签(见 table.py)。ezdxf 在加载时会忽略表头计数(dxf.count = 0),导出时再重新计算count = len(self)(见 sections/table.py)。
二、Table 基类:所有符号表的通用 API
Table是泛型集合类,几乎所有表都继承它的行为,因此先吃透基类是掌握全部分支的关键。
2.1 表项名称大小写不敏感
文档明确:表项名称是大小写不敏感的,"Test" == "TEST"。其底层实现是key()静态方法调用 validator.make_table_key,核心逻辑只有一行:name.lower()。所有内部存储与查找(has_entry、get、remove、discard、duplicate_entry)都先经过key()统一键,因此你可以放心地用任意大小写组合访问表项。
doc.layers.get("MyLines") # 等价于 doc.layers.get("mylines") # 等价于 doc.layers.get("MYLINES")2.2 完整通用方法清单
| 方法 | 说明 |
|---|---|
key(name) | 生成统一的表项键(内部使用,大小写归一化) |
has_entry(name) | 表项是否存在,返回True/False |
__contains__(name) | 支持"Name" in doc.layers写法,等价于has_entry |
__len__() | 表项总数,支持len(doc.layers) |
__iter__() | 迭代全部表项(跳过已销毁对象),支持for layer in doc.layers |
new(name, dxfattribs) | 创建新表项,名称已存在时抛出DXFTableEntryError |
get(name) | 按名称取表项,不存在时抛出DXFTableEntryError |
remove(name) | 从表与实体库中删除表项,不存在时抛出DXFTableEntryError |
duplicate_entry(name, new_name) | 复制表项并改名为new_name,若new_name已存在则替换之 |
基类实现细节(见 src/ezdxf/sections/table.py):
new():先检查重名,重名即抛DXFTableEntryError;新表项自动写入name与owner(owner 指向表头句柄);get():按归一化键从内部OrderedDict查找,找不到抛DXFTableEntryError;remove():先从实体库entitydb.delete_entity(entry)删除实体,再从内部字典摘除;duplicate_entry():通过entitydb.duplicate_entity(entry)在实体库中复制出独立实体(非浅拷贝别名),再改写dxf.name为新名称。测试 test_410_table.py 验证了复制后两份实体互不影响(修改flags各自独立)。
2.3 表项创建流程
new()→new_entry(dxfattribs)→factory.create_db_entry(TABLE_TYPE, dxfattribs, doc)→_append(entry)。其中_append会断言entry.dxftype() == self.TABLE_TYPE,保证只有正确类型的实体能进入对应表(sections/table.py)。子类通过覆写new_entry或add注入各自专属逻辑。
三、LayerTable:图层定义表
LayerTable是Table[Layer]的子类,存放Layer实体(src/ezdxf/sections/table.py)。
3.1 add() 完整签名与参数
doc.layers.add( name: str, *, color: int = 256, # ACI 色号,默认 BYLAYER(256) true_color: Optional[int] = None, # 真彩色 int,可用 ezdxf.rgb2int() 由 RGB 生成 linetype: str = "Continuous", # 线型名,默认 Continuous lineweight: int = -1, # 线宽,默认 BYLAYER(-1) plot: bool = True, # 是否可打印 transparency: Optional[float] = None, # 透明度 [0, 1],1=全透明,0=不透明 dxfattribs=None, # 其他 DXF 属性 ) -> Layer参数校验(源码可验证):
color必须是合法 ACI 颜色值,否则抛DXFValueError;lineweight必须合法,否则抛DXFValueError;true_color通过ezdxf.rgb2int()由 RGB 三元组转为整数;transparency通过layer.transparency = value写入,范围 [0, 1]。
3.2 实战:创建带默认属性的图层
import ezdxf doc = ezdxf.new(setup=True) # setup=True 会初始化必要的线型 msp = doc.modelspace() # 创建图层:白色、虚线、默认线宽 doc.layers.add(name="MyLines", color=7, linetype="DASHED") # 实体只需指定 layer,即可继承图层的颜色与线型 msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "MyLines"})上述用法对应官方教程 Tutorial for Layers:新实体的默认线型是"BYLAYER"、默认颜色是256(BYLAYER),因此只要实体位于某图层,就会自动继承该图层的颜色和线型,无需重复指定。
3.3 常用操作模式
# 迭代所有图层定义 for layer in doc.layers: if layer.dxf.name != "0": layer.off() # 除 0 层外全部关闭 # 检查与获取 if "MyLines" in doc.layers: # __contains__ layer = doc.layers.get("MyLines") layer_count = len(doc.layers) # 图层定义总数 # 状态控制(Layer 实体的便利方法) layer.is_off() / layer.is_on() / layer.is_locked() layer.off() / layer.lock() # 修改属性:注意 color 属性会保留开关状态(DXF 用负数表示关闭) layer.dxf.linetype = "DOTTED" layer.color = 13另外LayerTable还提供create_referenced_layers():扫描实体库中所有被引用但尚未定义的图层并自动补建默认定义(table.py),可用于修复“实体引用了不存在的图层”的场景。
四、LinetypeTable:线型表
LinetypeTable存放Linetype实体,其add()支持简单线型与复杂线型两种定义方式(src/ezdxf/sections/table.py)。
4.1 add() 签名
doc.linetypes.add( name: str, pattern: Union[Sequence[float], str], # 简单线型用浮点列表,复杂线型用字符串 *, description: str = "", length: float = 0.0, # 仅复杂线型需要:总图案长度 dxfattribs=None, ) -> Linetype4.2 简单线型 pattern 规则
pattern 是浮点列表[total_pattern_length, elem1, elem2, ...]:
- 元素> 0:画线段(长度)
- 元素< 0:空档(长度)
- 元素== 0.0:点
# 虚线:"DASHED":8 单位总长,5 单位线 + 3 单位空档 doc.linetypes.add("DASHED", pattern=[8.0, 5.0, -3.0])4.3 复杂线型(形/文字嵌入)
复杂线型的 pattern 是字符串,例如文档给出的:
'A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25'含义:线段 + 空档后,嵌入文字"GAS"(使用 STANDARD 文字样式,缩放 S、旋转 U、偏移 X/Y),再跟一个空档。这种格式与.lin文件中的线型定义一致。文档同时提醒:并非所有 CAD 应用与 DXF 查看器都支持复杂线型,使用前需评估兼容性。可参考教程 linetypes.rst。
new_entry()会从dxfattribs中取出pattern与length并调用ltype.setup_pattern(pattern, length),length为复杂线型所必需(table.py)。
五、TextstyleTable:文字样式表(含 SHX 形文件)
TextstyleTable存放Textstyle实体,与其他表不同,它内部维护了两个字典:普通命名样式entries与形文件样式shx_files(src/ezdxf/sections/table.py)。
5.1 add():添加 TTF 字体样式
doc.styles.add(name="NEW_STYLE", font="Arial.ttf", dxfattribs={"flags": 3})font必须是真实存在的字体文件名(如"Arial.ttf"),ezdxf 只写入名称,查找字体文件是 DXF 查看器的任务;- 自动写入
last_height = 2.5(AutoCAD 可能需要的默认值); - 名称已存在时抛
DXFTableEntryError。
5.2 SHX 形文件:无名称的特殊表项
形文件(SHX)样式是没有名字的表项(dxf.name == ""),以flags = 1(shape file 标志)区分,以font属性保存形文件名。因此不能用get()按名称查找,而是使用专门的四个方法:
| 方法 | 行为 |
|---|---|
add_shx(shx_file_name) | 添加形文件表项,已存在则抛DXFTableEntryError |
get_shx(shx_file_name) | 存在则返回,不存在则自动创建(get-or-create) |
find_shx(shx_file_name) | 按文件名(大小写不敏感)查找,找不到返回None |
discard_shx(shx_file_name) | 摘除表项,不存在也不抛异常 |
# 添加形文件文字样式 doc.styles.add_shx("gdt.shx") # 查找:找不到返回 None entry = doc.styles.find_shx("unknown.shx") # None # get-or-create 模式 entry = doc.styles.get_shx("ltypeshp.shx") # 没有则自动创建_append()根据name == ""且flags & 1判断为形文件,从而进入shx_files字典(以归一化后的 font 为键);导出时两个字典的表项都会写出(table.py)。测试 test_404a_tables.py 验证了:形文件dxf.name为空、重复add_shx抛异常、discard_shx对不存在条目静默通过、导出时形文件条目与默认样式同时出现在 code 3(font)标签中。
在复杂线型渲染(tools/complex_ltype.py)与跨文档导入(addons/importer.py)中,get_shx()是自动补齐形文件样式的主要手段。
六、DimStyleTable / AppIDTable / UCSTable / ViewTable
这四个表结构简单,add()均为new(name, dxfattribs)的薄封装,这里一并给出:
# 标注样式表 DIMSTYLE doc.dimstyles.add("ISO-25", dxfattribs={...}) # 如 DIMTXT、DIMASZ 等标注变量 # 应用 ID 表 APPID(XDATA 与扩展字典中 app 标识) doc.appids.add("EZDXF") # UCS 表 doc.ucs.add("MyUCS", dxfattribs={...}) # 视图表 doc.views.add("FrontView", dxfattribs={...})实现见 src/ezdxf/sections/table.py。其中DimStyleTable.add()返回DimStyle(entities/dimstyle.py),标注样式变量(DIMTXT、DIMASZ 等)通过dxfattribs传入;AppIDTable是 XDATA / XRECORD 引用的注册表,ezdxf 创建新文档时默认生成HATCHBACKGROUNDCOLOR与EZDXF两个 AppID(见 document.py)。
七、ViewportTable:多视口配置表
ViewportTable(VPORT 表)是最特殊的表(src/ezdxf/sections/table.py),文档明确指出它的三条特性:
- 允许同名多表项:一个多视口配置由多个同名 VPORT 条目组成,内部每个键对应一个 VPort 列表;
- 当前激活视口配置名固定为
"*ACTIVE"("*Active"); - 不支持表项复制:
duplicate_entry()直接抛出NotImplementedError。
7.1 多视口配置的创建与获取
import ezdxf doc = ezdxf.new() len(doc.viewports) # 1:新文档默认含 "*Active" 配置 "*Active" in doc.viewports # True # 创建多视口配置:同名的两个 VPORT 条目构成一个配置 vp1 = doc.viewports.new("V1") vp2 = doc.viewports.new("V1") len(doc.viewports) # 3(Active 1 个 + V1 2 个) # 取整个配置(返回 VPort 对象列表) conf = doc.viewports.get_config("V1") assert len(conf) == 2get_config(name)返回List[VPort],配置不存在时抛DXFTableEntryError;delete_config(name)删除配置中所有 VPort 对象,行为等同remove(name)。
7.2 内部结构
ViewportTable._append()将同名条目追加到列表中(entries[key].append(entry)),因此__iter__/__len__会先扁平化所有配置;get_config("*Active")在 appsettings.py 中被用于读取活动视口的设置,文档级操作(如重建页面设置)通过 document.py 的doc.viewports.delete_config("*Active")清理旧配置。完整的多视口行为可对照测试 test_410_table.py。
八、BlockRecordTable:块记录表
BlockRecordTable存放BlockRecord实体(src/ezdxf/sections/table.py),与图块布局(BLOCKS 段)一一对应,是模型空间/图纸空间布局与块定义的核心索引:
doc.block_records.add("MyBlock", dxfattribs={...})BlockRecordTable仅在 DXF R2000+ 导出;加载 R12 文件时该表会被自动重置为空表并分配句柄(sections/tables.py)。块布局的创建与引用通常不直接操作该表,而是通过 layouts/blocks 的布局 API(doc.blocks.new())完成,表格自动维护。
九、综合实战:一张完整的“表操作”示例
将前文知识点串成可运行片段:
import ezdxf doc = ezdxf.new(setup=True) # 1) 图层:颜色、线型、线宽、透明度 doc.layers.add("Walls", color=7, linetype="CONTINUOUS", lineweight=25) # 2) 线型:简单虚线 + 复杂线型(嵌入文字 GAS) doc.linetypes.add("DASHED", pattern=[8.0, 5.0, -3.0], description="Dashed") doc.linetypes.add( "GAS_LINE", pattern='A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25', length=1.0, ) # 3) 文字样式:TTF 字体 + SHX 形文件 doc.styles.add("Custom", font="Arial.ttf") doc.styles.get_shx("gdt.shx") # get-or-create # 4) 通用容器协议 if "Walls" in doc.layers: layer = doc.layers.get("walls") # 大小写不敏感 print(len(doc.layers), layer.dxf.name) # 5) 复制表项:复制 DASHED 为 DASHED2(已存在则替换) doc.linetypes.duplicate_entry("DASHED", "DASHED2") # 6) 删除表项 doc.layers.remove("Walls") # 不存在会抛 DXFTableEntryError # 7) 视口配置 conf = doc.viewports.get_config("*Active") # 当前激活配置 doc.viewports.delete_config("V1") # 删除多视口配置 doc.saveas("tables_demo.dxf")十、异常与注意事项速查
| 场景 | 行为 |
|---|---|
new()/add()创建重名表项 | 抛DXFTableEntryError |
get()/remove()访问不存在的表项 | 抛DXFTableEntryError |
ViewportTable.duplicate_entry() | 抛NotImplementedError(多视口配置不支持复制) |
add_shx()重复添加同一形文件 | 抛DXFTableEntryError |
discard_shx()删除不存在的形文件 | 静默通过,不抛异常 |
| 非法 ACI 颜色 / 非法线宽 | 抛DXFValueError(LayerTable.add) |
| 加载时表中出现错误实体类型 | 记录 warning 并忽略(Table.load) |
从源码结构可以推断:由于名称统一归一化为小写键,同名不同大小写的表项在内部永远只有一份;这也是为何文档强调“表项名称大小写不敏感”且重名检测会拦截"Test"与"TEST"这类组合。
十一、进一步阅读
- 表类参考:tables.rst 与各表项详解(layer_table_entry.rst、linetype_table_entry.rst、style_table_entry.rst、dimstyle_table_entry.rst、vport_table_entry.rst)
- 核心实现:src/ezdxf/sections/table.py、src/ezdxf/sections/tables.py、src/ezdxf/entities/table.py
- 用户入口:src/ezdxf/document.py
- 实战教程:layers.rst、linetypes.rst
- 测试佐证:test_410_table.py、test_404a_tables.py
- 图形学
【免费下载链接】ezdxf
Python interface to DXF
相关推荐
ezdxf DXF 符号表(TABLES 段)权威解析:Table 基类与九大表格条目详解
ezdxf DXF 符号表(TABLES 段)权威解析:Table 基类与九大表格条目详解 导读 本文系统解析 ezdxf 中 DXF 文件的 TABLES(符
图形学mruby 符号(Symbol)系统指南:mrb_sym 内部表示、C API 与预分配符号实战
mruby 符号(Symbol)系统指南:mrb_sym 内部表示、C API 与预分配符号实战 mruby 的符号(Symbol)在 C 侧由 mrb_sym
编程语言语言运行时编译器解释器嵌入式umy-ui u-table 基础表格与斑马纹表格实战指南
umy ui u table 基础表格与斑马纹表格实战指南 本文围绕 umy ui 桌面端 Vue 2.0 组件库中 u table 表格组件的基础用法展开,以
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考