跳到主要内容
浏览器
导航
工程图纸浏览器

DXF 文件结构与实体解析

DXF 以「分组码 + 值」的二元组记录图形数据,顶层划分为若干段,实体与对象之间通过句柄表达引用。本文拆解分组码的类型与语义、段落的组织顺序、实体的坐标与图层字段、块插入的展开方式,以及 ASCII 与二进制两种编码下流式解析的容错处理。

发布于 5 分钟阅读 1680 字

DXF 是用于交换二维与三维图纸数据的格式,其设计目标是让不同的程序之间能以结构化方式传递几何、图层与标注信息。与以二进制记录为主的 DWG 相比,DXF 把数据组织为可逐行阅读的记录序列;这一差异只说明两者的编码方式不同,能否读取取决于交换双方各自实现的支持范围,而不构成格式之间的取舍结论。

解析 DXF 的过程,可以理解为从扁平的记录序列还原出带层级关系的图形对象。文件里没有指针或偏移量,段落与对象的边界完全由特定组码标出,因此解析器通常按顺序消费记录、维护一个状态机。下面从记录层、段层与对象层依次展开。

分组码:组码与值构成的二元组

DXF 的基本单位是「分组码加值」的二元组:一行是整数形式的组码,紧接一行是对应的值。组码既指示值的类型,也指示该值在所在对象中的语义位置。常见区间如下:

组码区间值类型常见含义
0–9字符串对象类型与名称
10–39双精度浮点坐标
40–59双精度浮点比例与尺寸
60–7916 位整数开关与计数
90–9932 位整数计数与标志位
100、102字符串子类标记与控制串
105 及 320–369句柄对象引用
210–239双精度浮点拉伸方向
999字符串注释

由于组码与类型绑定,解析器不必做语法推导就能判断一个值的类型。但同一组码在不同对象中的语义可能不同,例如组码 70 在有的对象里是标志位,在另一些对象里是计数,必须结合当前对象类型解释。

段(SECTION)的组织

DXF 顶层由若干段构成,每段以组码 0 的 SECTION 开始,组码 2 给出段名,以组码 0 的 ENDSEC 结束。常见段落包括:

  • HEADER:图形全局变量,例如图形范围、当前图层、单位制与角度方向
  • CLASSES:自定义类的定义
  • TABLES:符号表集合,含图层表、线型表、文字样式表、标注样式表、块记录表等
  • BLOCKS:块定义
  • ENTITIES:模型空间与图纸空间中的实体
  • OBJECTS:非图形对象,例如字典与布局
  • THUMBNAILIMAGE:可选的预览图像

多数实现要求这些段按固定顺序出现,并在读到 EOF 时结束。段的顺序固定带来的好处是解析器可以在读完全文之前,就对后续内容的结构做出预期。

实体记录与坐标值

实体位于 ENTITIES 段内,以组码 0 给出实体类型,例如 LINE、CIRCLE、ARC、LWPOLYLINE、TEXT、INSERT。随后由若干组码给出属性:

  • 组码 8 给出所属图层名
  • 组码 10/20/30 给出起点、中心点等基准点坐标
  • 组码 11/21/31 给出终点或方向点
  • 组码 62、6、370、48 分别给出颜色、线型、线宽与线型比例

坐标值为双精度浮点,多数情况下位于世界坐标系。部分二维实体的坐标则以对象坐标系给出,需要结合组码 210 的拉伸方向换算到世界坐标系。几何之外,实体还会携带厚度、拉伸方向与可见性等字段,解析时需要一并保留。

0
SECTION
2
ENTITIES
0
LINE
8
轮廓
10
0.0
20
0.0
30
0.0
11
100.0
21
50.0
31
0.0
0
ENDSEC
0
EOF

块的展开与 INSERT

块在 BLOCKS 段中由 BLOCK 与 ENDBLK 界定,块内实体的坐标相对块基点保存。ENTITIES 段中出现的 INSERT 通过组码 2 指向块名,并由组码 10 给出插入点、41/42/43 给出轴向比例、50 给出旋转角、70 与 71 给出行列数,用于阵列插入。

展开时,块内每个实体的坐标按缩放、旋转、平移的顺序映射到宿主坐标系,再与 INSERT 自身所在层级的变换相乘。嵌套的 INSERT 会逐层叠加变换,因此展开需要递归处理。相关细节可参考图层管理与坐标系变换。

句柄与所有权

从 R13 起,多数 DXF 为每个对象分配句柄,写在组码 5 中,同一文件内的句柄互不重复。组码 330 记录对象的所有者,通常指向父对象的句柄;符号表记录、字典与布局之间的从属关系都由此表达。组码 1001 及以上的扩展数据还可以引用其他对象,用于挂接自定义信息。

并非所有文件都完整写出句柄。由程序手工生成或由简化导出器产出的文件,可能出现缺失或重复的句柄,因此解析器一般不能把句柄当作必然可靠的索引,需要准备以对象位置为兜底的引用方式。

编码形式与流式解析

DXF 有两种常见编码。ASCII 形式以文本行给出组码与值,文件体积较大,但支持逐行读取;二进制形式在开头带固定签名,随后以定长记录表示组码与值,读写成本较低。两者承载的语义一致,差别只在编码层。

由于记录是顺序排列的,解析器常实现为一个逐条消费的状态机:遇到未知组码就跳过,遇到缺失的 ENDSEC 就按下一个段的起点或文件结尾收尾。

// 逐行状态机:先读组码行,再读值行
function* readPairs(lines) {
  let i = 0;
  while (i < lines.length) {
    const code = parseInt(lines[i].trim(), 10);
    if (Number.isNaN(code)) { i += 1; continue; } // 跳过无法解释的行
    yield { code, value: (lines[i + 1] ?? "").trim() };
    i += 2;
  }
}

对含块引用的文件,可以先把 BLOCKS 段中的块定义收集到一张表中,再处理 ENTITIES 段,这样 INSERT 出现时就能直接查到目标块。这种两遍处理牺牲一点内存,换来展开逻辑的简化。

小结

DXF 的结构可以概括为三层:分组码提供类型与语义标记,段提供顶层分类,实体与对象通过句柄表达引用。解析的关键在于把顺序无关的扁平记录还原成有层级、有引用的对象图,并对未知组码、缺失句柄与截断的段做容错处理。上述结构决定了实体坐标如何被还原,而坐标进入屏幕还需要经过矢量路径与线宽映射所述的那一层换算。

工程图纸浏览器 · 相关文章