目录

高级 DXF 主题

本章介绍 DXF 二次开发中涉及的进阶主题,包括句柄参照、扩展数据、子类标记、对象坐标系和任意轴算法等。

句柄与参照

句柄(Handle)概念

句柄(组码 5)是 DXF 文件中每个对象/图元的唯一标识符,格式为最多 16 个十六进制数字的字符串。句柄在整个 DXF 文件中唯一,由 AutoCAD 自动分配。

句柄的关键特性:

句柄参照类型

DXF 使用不同的组码范围来表示不同类型的句柄参照:

组码范围 参照类型 说明
320-329 任意句柄 “按原样”获取,在 INSERT/XREF 操作期间不进行转换
330-339 软指针 指向其他对象,不表示所有权关系
340-349 硬指针 指向其他对象的强引用
350-359 软所有者 所有者可以删除被所有者,但不强制执行
360-369 硬所有者 所有者可以删除被所有者,强制执行
390-399 PlotStyle 句柄 用于打印样式对象

指针与所有权的区别

组码 1005 的特殊用途

组码 1005 在扩展数据中用于存储句柄值,其特殊之处在于不进行 INSERT/XREF 转换。在扩展数据中使用句柄时,需使用 1005 组码而非 330-369 组码。

子类标记

子类标记的概念

组码 100 用于存储子类数据标记(Subclass Marker),该标记指示从哪个 ObjectARX 派生类定义了后续的数据。子类标记是理解 DXF 对象继承关系的关键。

子类标记示例:

继承链与子类标记

一个对象的完整继承链通过多个子类标记体现。以直线为例:

0           ; 图元开始
LINE
5
42
100
AcDbEntity  ; 通用图元数据(图层、颜色、线型等)
100
AcDbLine    ; 直线特定数据(起点、终点坐标)
10
0.0
20
0.0
11
100.0
21
100.0

从 ObjectARX 派生的每个具体类必须拥有子类标记。

扩展数据(XDATA)

扩展数据(Extended Data,简称 XDATA)允许应用程序在 DXF 对象或图元中存储自定义数据。所有扩展数据都以组码 -3 为标记。

XDATA 结构

-3           ; 扩展数据开始标记(固定)
1001
APP_NAME     ; 注册的应用程序名
1000
...          ; 扩展数据内容

XDATA 支持的组码

组码 说明
1000 ASCII 字符串(最多 255 字节)
1001 注册的应用程序名(最多 31 字节)
1002 控制字符串(“{” 开始, “}” 结束)
1003 图层名
1004 二进制数据块(最多 127 字节)
1005 图元句柄
1010 三维点
1011 三维世界空间位置
1012 三维世界空间位移
1013 三维空间方向
1040 双精度浮点值
1041 距离值
1042 缩放比例
1070 16 位有符号整数
1071 32 位有符号长整数

XDATA 组织方式

XDATA 使用 1002 组码来组织数据层次:

-3
1001
MY_APP         ; 应用程序名
1002
{              ; 开始一个列表
1000
Item 1
1000
Item 2
1002
{              ; 嵌套列表
1040
1.5
1040
2.5
1002
}              ; 结束嵌套
1002
}              ; 结束列表

注册应用程序名

使用自定义 XDATA 前,应用程序名必须在 APPID 符号表中注册。例如:

 0
 APPID
 2
 MY_APP
 70
 0

对象坐标系(OCS)

OCS 简介

对象坐标系(Object Coordinate System,OCS)是通过拉伸方向(组码 210/220/230)和任意轴算法建立的坐标系。在 OCS 中定义点的图元,其点坐标使用该图元特有的坐标系。

使用 OCS 的图元类型:LINE、CIRCLE、ARC、TEXT 等。

不使用 OCS 的图元类型:LWPOLYLINE(使用标高+OCS)、3DFACE(使用世界坐标系)、POLYLINE(使用世界坐标系)。

OCS 与 WCS 的转换

拉伸方向(组码 210/220/230)默认为 (0, 0, 1),表示图元位于世界坐标系的 XY 平面。当拉伸方向为单位矢量 (0, 0, 1) 时,OCS 与 WCS 一致。

如果拉伸方向不是 (0, 0, 1),则需要使用任意轴算法将 OCS 坐标转换为 WCS 坐标。

任意轴算法

任意轴算法(Arbitrary Axis Algorithm,AAA)用于计算 OCS 的 X 轴和 Y 轴方向。该算法是处理非平面图元的关键。

算法步骤

假设拉伸方向为 N(单位矢量):

1. 如果 |N| 非常接近 (0, 0, 1)(容差 1/64):
   X_axis = (1, 0, 0)
   Y_axis = (0, 1, 0)
   结束

2. 如果 |N| 非常接近 (0, 0, -1)(容差 1/64):
   X_axis = (-1, 0, 0)
   Y_axis = (0, 1, 0)
   结束

3. 否则:
   W = (0, 0, 1)  (世界坐标 Z 轴)
   X_axis = W × N   (叉积,归一化)
   Y_axis = N × X_axis  (叉积,归一化)

算法实现(Python)

import math
 
def arbitrary_axis_algorithm(normal):
    """计算任意轴算法,返回 OCS 的 X 轴和 Y 轴方向"""
    x, y, z = normal
 
    # 检查是否接近 (0,0,1) 或 (0,0,-1)
    if abs(x) < 1/64 and abs(y) < 1/64 and abs(z) > 0:
        if z > 0:
            return (1, 0, 0), (0, 1, 0)
        else:
            return (-1, 0, 0), (0, 1, 0)
 
    # 计算 X 轴 = W × N
    wx, wy, wz = 0, 0, 1
    x_axis = (
        wy * z - wz * y,   # Y*Z - Z*Y
        wz * x - wx * z,   # Z*X - X*Z
        wx * y - wy * x    # X*Y - Y*X
    )
 
    # 归一化 X 轴
    length = math.sqrt(x_axis[0]**2 + x_axis[1]**2 + x_axis[2]**2)
    if length > 0:
        x_axis = (x_axis[0]/length, x_axis[1]/length, x_axis[2]/length)
 
    # 计算 Y 轴 = N × X_axis
    y_axis = (
        y * x_axis[2] - z * x_axis[1],
        z * x_axis[0] - x * x_axis[2],
        x * x_axis[1] - y * x_axis[0]
    )
 
    # 归一化 Y 轴
    length = math.sqrt(y_axis[0]**2 + y_axis[1]**2 + y_axis[2]**2)
    if length > 0:
        y_axis = (y_axis[0]/length, y_axis[1]/length, y_axis[2]/length)
 
    return x_axis, y_axis
 
 
def ocs_to_wcs(point_ocs, normal):
    """将 OCS 坐标转换为 WCS 坐标"""
    x_axis, y_axis = arbitrary_axis_algorithm(normal)
 
    # OCS point = (u, v, w)
    # WCS point = origin + u*X_axis + v*Y_axis + w*normal
    u, v, w = point_ocs
    wx = u * x_axis[0] + v * y_axis[0] + w * normal[0]
    wy = u * x_axis[1] + v * y_axis[1] + w * normal[1]
    wz = u * x_axis[2] + v * y_axis[2] + w * normal[2]
 
    return (wx, wy, wz)

扩展词典与永久反应器

扩展词典

扩展词典(Extension Dictionary)允许在对象上附加自定义词典。使用组码 102 后跟 {ACAD_REACTORS{ACAD_XDICTIONARY 来标识。

102
{ACAD_XDICTIONARY    ; 扩展词典开始
360
FD                  ; 硬所有者句柄(指向词典对象)
102
}                    ; 扩展词典结束

永久反应器

永久反应器(Persistent Reactor)使得对象之间可以建立事件响应关系。当被监控的对象发生变化时,反应器对象会自动收到通知。

102
{ACAD_REACTORS      ; 反应器链开始
330
F0                  ; 软指针句柄(指向所有者)
102
}                    ; 反应器链结束

本章小结

本章介绍了 DXF 开发中的高级话题。句柄管理确保了对象间的正确引用关系;子类标记使得 DXF 能够表示复杂的类继承结构;扩展数据为应用程序提供了自定义存储能力;对象坐标系和任意轴算法则是处理三维空间中非平面图元的基础。掌握这些高级概念是开发专业 DXF 应用程序的必要条件。