- 图形学
【免费下载链接】ezdxf
Python interface to DXF
本篇指南以 ezdxf 官方教程《Tutorial for OCS/UCS Usage》(ocs_usage.rst)为主线,系统讲解 WCS、UCS、OCS 三大坐标系统的定义与相互关系,并通过 CIRCLE、LWPOLYLINE、3D POLYLINE、TEXT、ARC、INSERT 六个可运行的实战示例,演示如何借助ezdxf.math.OCS与ezdxf.math.UCS类把平面二维实体准确放置到三维空间中。读完本文,你将掌握挤出向量(extrusion)、标高(elevation)、厚度(thickness)三个关键 DXF 属性的用法,理解 Arbitrary Axis Algorithm(任意轴算法)的底层原理,并能在任意朝向的平面上放置和旋转文本、圆弧与块引用。
坐标系统预备知识
在动手写代码之前,先梳理 ezdxf 涉及的四种坐标系统。完整说明见仓库中的 坐标系统概念文档,OCS 的深入分析见 对象坐标系统文档。
WCS:世界坐标系统
WCS(World Coordinate System)是参照坐标系统,其他所有坐标系统都相对于它定义,且 WCS 本身永不改变。以 WCS 度量的数值在其它坐标系统变化时保持稳定。DXF 文件中的单位可以是任意真实世界单位,AutoCAD 曾为标注与文本实体引入过缩放机制,但这更多属于 AutoCAD 主题而非 DXF 主题,ezdxf 教程并未深入展开。
UCS:用户坐标系统
UCS(User Coordinate System)是用户为了简化绘图任务而定义的工作坐标系统。所有存储于 DXF 文件中的坐标始终是 WCS 或 OCS,永远不会是 UCS——因为没有任何方法能够确定创建 UCS 坐标时激活的是哪个 UCS。因此 ezdxf 提供 UCS 类 负责 UCS 与 WCS 之间的双向换算,但用户必须牢记:只能把 WCS 或 OCS 坐标写入 DXF。
OCS:对象坐标系统
OCS(Object Coordinate System)是相对于对象自身的坐标系统,其核心目标是"在三维空间中放置二维元素"。OCS 由实体的**挤出向量(extrusion vector)**定义:只要挤出向量为(0, 0, 1)(即 WCS 的 z 轴),OCS 就与 WCS 重合,OCS 坐标等于 WCS 坐标——大多数 2D 实体都属于这种情况。
使用 OCS 的实体包括:ARC、CIRCLE、TEXT、LWPOLYLINE、HATCH、SOLID、TRACE、INSERT、IMAGE 等平面实体;而 LINE、POINT、3DFACE、3D POLYLINE、POLYMESH、POLYFACE、VIEWPORT 等实体所有点都用 WCS 表达,不属于 OCS 实体。
ezdxf 只是 DXF 的接口层,不会自动把 OCS 转换为 WCS,这是用户/应用程序的职责。每个图形实体都提供ocs()方法返回其对象坐标系统,例如 dxfgfx.py 中的实现:
def ocs(self) -> OCS: if self.dxf.is_supported("extrusion"): extrusion = self.dxf.get("extrusion", default=(0, 0, 1)) return OCS(extrusion) else: return OCS() # pass-through OCS对应地,把圆心的 OCS 坐标转换为 WCS 只需两行:
ocs = circle.ocs() wcs_center = ocs.to_wcs(circle.dxf.center)DCS:显示坐标系统
DCS(Display Coordinate System)是对象显示前被转换到的坐标系统,其原点为 AutoCAD 系统变量 TARGET 存储的点,z 轴为视线方向。ezdxf不以任何方式使用或支持 DCS,此处列出仅为概念完整。
决定二维实体空间形态的三个 DXF 属性
OCS 实体的所有点都位于同一平面内,即使该平面由 OCS 定位在三维空间中也依然如此。有 3 个基本 DXF 属性共同赋予二维实体空间形态:
挤出向量(Extrusion)
挤出向量定义 OCS,它是平面实体基平面(base plane)的法向量。这个基平面始终位于 WCS 原点。但需要特别注意的是:有些实体如 ELLIPSE 虽有挤出向量,却并不建立 OCS——对这类实体而言,挤出向量只定义挤出方向和距离(厚度),其余点与方向均用 WCS 表达。
标高(Elevation)
标高值定义平面实体所有点的 z 轴值,它是 OCS 值,表示实体平面到基平面的距离。
该值仅存在于R11 之前版本的 DXF 输出中,作为独立属性(组码 38)存在;在 DXF R12 及以后版本中,标高作为每个点的 z 轴值提供。但这条简单规则并不适用于所有实体:LWPOLYLINE 和 HATCH 的elevation是一个 3D 点属性,其中 z 值为标高高度,x 值与 y 值恒为 0。
厚度(Thickness)
厚度定义实体的挤出距离(extrusion distance)。AutoCAD 对 TEXT 实体仅在.shx字体下支持厚度,TrueType 字体不支持。
关于本教程的版本说明
原教程标注:ezdxf v0.11 之后提供了基于 UCS 变换的新版教程(ucs_transform.rst),其中 v0.13 引入的实体transform()方法可以自动处理 OCS 与挤出向量,大幅简化操作。而本教程展示的是用底层操作完成变换的"硬核方式",理解它有助于深入掌握坐标系统的本质。
Arbitrary Axis Algorithm:OCS 的 x/y 轴从何而来
对于一个给定的 z 轴(挤出)方向,三维空间中存在无穷多个坐标系统(可通过平移原点、绕 z 轴旋转 x/y 轴得到)。但对同一个 z 轴方向,只有一个 OCS,它具备以下性质(详见 ocs.rst):
- 原点与 WCS 原点重合;
- xy 平面内 x/y 轴的方向以一种"任意但一致"的方式计算——AutoCAD 使用任意轴算法完成该计算;
- 由于任意轴算法的缘故,OCS 只能表示右手坐标系。
任意轴算法的核心是:给定单位长度的 z 轴向量Az,生成对应的 x 轴向量Ax,再由右手定则得出 y 轴向量Ay。用Vec3表达如下:
Az = Vec3(entity.dxf.extrusion).normalize() # 法向(挤出)向量 if (abs(Az.x) < 1/64.) and (abs(Az.y) < 1/64.): Ax = Vec3(0, 1, 0).cross(Az).normalize() else: Ax = Vec3(0, 0, 1).cross(Az).normalize() Ay = Az.cross(Ax).normalize()WCS→OCS 的坐标变换公式:
def wcs_to_ocs(point): px, py, pz = Vec3(point) # WCS 中的点 x = px * Ax.x + py * Ax.y + pz * Ax.z y = px * Ay.x + py * Ay.y + pz * Ay.z z = px * Az.x + py * Az.y + pz * Az.z return Vec3(x, y, z)OCS→WCS 的坐标变换公式:
Wx = wcs_to_ocs((1, 0, 0)) Wy = wcs_to_ocs((0, 1, 0)) Wz = wcs_to_ocs((0, 0, 1)) def ocs_to_wcs(point): px, py, pz = Vec3(point) # OCS 中的点 x = px * Wx.x + py * Wx.y + pz * Wx.z y = px * Wy.x + py * Wy.y + pz * Wy.z z = px * Wz.x + py * Wz.y + pz * Wz.z return Vec3(x, y, z)ezdxf 中的实现:OCS 类
ezdxf 的 OCS 类 直接实现了上述算法,构造时传入挤出向量即可:
class OCS: def __init__(self, extrusion: UVec = Z_AXIS): Az = Vec3(extrusion).normalize() self.transform = not Az.isclose(Z_AXIS) if self.transform: if (abs(Az.x) < _1_OVER_64) and (abs(Az.y) < _1_OVER_64): Ax = Y_AXIS.cross(Az) else: Ax = Z_AXIS.cross(Az) Ax = Ax.normalize() Ay = Az.cross(Ax).normalize() self.matrix = Matrix44.ucs(Ax, Ay, Az)源码中_1_OVER_64 = 1.0 / 64.0,与算法标准一致。注意一个性能细节:当挤出向量就是 WCS z 轴时(绝大多数 2D 实体的情况),transform为False,from_wcs/to_wcs直接原样返回点,不做矩阵乘法。
该实现由单元测试验证,见 test_610_ocs.py:例如以实际 DXF 文件中的挤出方向(0.7081979129501316, 0.0754851955385861, 0.7019670229772758)建立 OCS,断言ocs.from_wcs((-9.56460754, 8.44764172, 9.97894327))得到(9.41378764657076, 13.15481838975576, 0.8689258932616031),双向换算精度达 6 位小数。
场景一:在三维空间放置 2D 圆(CIRCLE)
完整示例代码见 src/ocs/circle.py,核心片段如下:
import ezdxf from ezdxf.math import OCS doc = ezdxf.new('R2010') msp = doc.modelspace() # 本例中 OCS 绕 x 轴旋转 45 度 # OCS z 轴: x=0, y=1, z=1 # 此处挤出向量无需归一化 ocs = OCS((0, 1, 1)) msp.add_circle( # 可以把 2D 圆放置在 3D 空间中, # 但必须把 WCS 坐标转换为 OCS 坐标 center=ocs.from_wcs((0, 2, 2)), # center in OCS: (0.0, 0.0, 2.82842712474619) radius=1, dxfattribs={ # 这里的挤出向量应归一化, # 使用 ocs.uz 可以保证这一点 'extrusion': ocs.uz, 'color': 1, }) # 在 WCS 中标记圆心 msp.add_point((0, 2, 2), dxfattribs={'color': 1}) print(f"center in OCS: {ocs.from_wcs((0, 2, 2))}") ocs.render_axis(msp) doc.saveas(OUT_DIR / 'ocs_circle.dxf')要点拆解:
OCS((0, 1, 1))构造一个绕 x 轴旋转 45° 的对象坐标系统,构造时传入的向量无需归一化(Vec3.normalize()会在内部完成);- 圆心在 WCS 中位于
(0, 2, 2),必须先用ocs.from_wcs()转换为 OCS 坐标(0.0, 0.0, 2.82842712474619)再写入实体,否则圆会放错位置; - 挤出向量写入时应归一化,直接使用属性
ocs.uz即可拿到归一化后的 z 轴单位向量; ocs.render_axis(msp)把 OCS 的 x/y/z 轴以带颜色的 3D 直线渲染到模型空间(红色 x 轴、绿色 y 轴、蓝色 z 轴,遵循 AutoCAD 轴色标准),便于在 CAD 中核对。
图中蓝色线即为 OCS 的 z 轴(挤出方向),标高为原点到圆心的距离(本例 2.828),且可以看到 OCS 的 x、y 轴与 WCS 的 x、y 轴并不对齐。
场景二:在三维空间放置 LWPolyline
LWPOLYLINE 只接受 2D 点,并拥有独立的elevationDXF 属性,所有点共享同一个 OCS z 值。为了计算简便,本示例使用 UCS 类 先把 2D 五边形放到一个用户坐标系统中,再统一转换到 OCS。完整代码见 src/ocs/lwpolyline.py:
import ezdxf from ezdxf.math import Vec3, UCS from pathlib import Path OUT_DIR = Path('~/Desktop/Outbox').expanduser() doc = ezdxf.new('R2010') msp = doc.modelspace() # 五边形中心应位于 (0, 2, 2),图形绕 x 轴旋转 45 度, # 为此使用一个 z 轴为 (0, 1, 1)、x 轴平行于 WCS x 轴的 UCS。 ucs = UCS( origin=(0, 2, 2), # 五边形中心 ux=(1, 0, 0), # x 轴平行于 WCS x 轴 uz=(0, 1, 1), # z 轴 ) # 在局部(UCS)坐标中计算角点 points = [Vec3.from_deg_angle((360 / 5) * n) for n in range(5)] # 把 UCS 坐标转换为 OCS 坐标 ocs_points = list(ucs.points_to_ocs(points)) # LWPOLYLINE 只接受 2D 点,并有独立的 DXF 属性 elevation。 # 所有点在 OCS 中具有相同的 z 值(标高)! elevation = ocs_points[0].z msp.add_lwpolyline( points=ocs_points, format='xy', # 忽略 z 轴 close=True, dxfattribs={ 'elevation': elevation, 'extrusion': ucs.uz, 'color': 1, }) from ezdxf.math import OCS OCS(ucs.uz).render_axis(msp) ucs.render_axis(msp) doc.saveas(OUT_DIR / 'ocs_lwpolyline.dxf')要点拆解:
- UCS 与 OCS 的关系:本示例中 UCS 的 z 轴与 OCS 的 z 轴(挤出方向)同向,UCS 的 x 轴与 WCS 的 x 轴同向,而三者 y 轴互不对齐;
ucs.points_to_ocs()内部先经 WCS 中转,再以OCS(self.uz)完成到 OCS 的换算(见 ucs.py 中的实现); - 由于 LWPOLYLINE 只有 2D 点,
format='xy'让 ezdxf 丢弃 z 值,标高则单独写入elevation属性; elevation = ocs_points[0].z直接取第一个角点的 z 值即可,因为所有角点在 OCS 中拥有相同标高;- 同时渲染 OCS 与 UCS 的轴便于对比:五边形中心的 3 条线是 UCS 轴,原点处的彩色线是 OCS 轴,原点处的白色线是 WCS 轴。
场景三:使用 UCS 放置 3D Polyline
对于真正的三维图形,直接使用 3D POLYLINE 更加简单——它不需要 OCS,所有点都是 WCS 坐标。UCS 在此类三维操作中非常趁手。完整代码见 src/ocs/polyline3d.py:
import math import ezdxf from ezdxf.math import UCS, Matrix44 from pathlib import Path OUT_DIR = Path('~/Desktop/Outbox').expanduser() doc = ezdxf.new('R2010') msp = doc.modelspace() # 使用 UCS 简化 3D 操作,UCS 可以在稍后定义 # 在局部(UCS)坐标中计算角点,无需 Vec3 类 angle = math.radians(360 / 5) corners_ucs = [(math.cos(angle * n), math.sin(angle * n), 0) for n in range(5)] # 做一些变换 tmatrix = Matrix44.chain( # 创建变换矩阵 Matrix44.z_rotate(math.radians(15)), # 1. 绕 z 轴旋转 Matrix44.translate(0, .333, .333), # 2. 平移 ) transformed_corners_ucs = tmatrix.transform_vertices(corners_ucs) # 把 UCS 变换为 WCS ucs = UCS( origin=(0, 2, 2), # 五边形中心 ux=(1, 0, 0), # x 轴平行于 WCS x 轴 uz=(0, 1, 1), # z 轴 ) corners_wcs = list(ucs.points_to_wcs(transformed_corners_ucs)) msp.add_polyline3d( points=corners_wcs, close=True, ) # 从中心到各角点添加连线 center_wcs = ucs.to_wcs((0, .333, .333)) for corner in corners_wcs: msp.add_line(center_wcs, corner, dxfattribs={'color': 1}) ucs.render_axis(msp) doc.saveas(OUT_DIR / 'ucs_polyline3d.dxf')要点拆解:
Matrix44.chain按参数顺序级联多个 4×4 变换矩阵:先绕局部 z 轴旋转 15°,再平移(0, 0.333, 0.333),得到变换后的五边形顶点;ucs.points_to_wcs()一次性把多个 UCS 点变换到 WCS,得到的顶点直接写入add_polyline3d(),无需任何 OCS 换算;- 最后
ucs.render_axis(msp)渲染 UCS 坐标轴用于可视化验证。
场景四:在三维空间放置 2D 文本(TEXT)
文本在三维空间放置的难点在于旋转角度:TEXT 的旋转总是绕 OCS z 轴逆时针进行,0度是 OCS x 轴正方向,而 OCS x 轴由任意轴算法计算得出。因此把 UCS(或 WCS)中的文本方向换算成 OCS 旋转角度的标准流程是:
- 把 UCS 中的文本旋转角度转换为方向向量(或直接以方向向量为起点);
- 用
UCS.to_ocs()把方向向量变换到 OCS; - 取 OCS 向量在 xy 平面内的角度(
angle_deg)作为旋转角。
这一流程已被封装为UCS.to_ocs_angle_deg()与UCS.to_ocs_angle_rad()两个便捷方法(见 ucs.py 中的实现),二者内部都通过ucs_direction_to_ocs_direction()完成方向向量的 UCS→WCS→OCS 两级变换。
完整代码见 src/ocs/text.py:
import ezdxf from ezdxf.math import UCS, Vec3 from pathlib import Path OUT_DIR = Path('~/Desktop/Outbox').expanduser() doc = ezdxf.new('R2010') msp = doc.modelspace() # 文本厚度仅对 shx 字体有效,对 TrueType 字体无效 doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'}) ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1)) # 把文本方向计算为 OCS 中的角度: # 先把 UCS 中的文本旋转角度(度数)转换为向量 text_direction = Vec3.from_deg_angle(-45) # 把向量变换到 OCS,并求向量在 xy 平面内的角度 rotation = ucs.to_ocs(text_direction).angle_deg text = msp.add_text( text="TEXT", dxfattribs={ # 文本旋转角度(度数,OCS 内) 'rotation': rotation, 'extrusion': ucs.uz, 'thickness': .333, 'color': 1, 'style': 'TXT', }) # 在 OCS 中设置文本位置 text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER') ucs.render_axis(msp) doc.saveas(OUT_DIR / 'ocs_text.dxf')提示:从 UCS 计算 OCS 角度时务必注意,TEXT、ARC 这类 2D 实体是平行于 UCS 的 xy 平面放置的,角度换算必须基于该平面内的方向向量进行。
场景五:在三维空间放置 2D 圆弧(ARC)
ARC 与文本面临同样的问题:需要以度数给出 OCS 内的起始角与终止角。本示例同时展示了计算 OCS 角度的快捷方式——直接调用ucs.to_ocs_angle_deg()。完整代码见 src/ocs/arc.py:
import ezdxf from ezdxf.math import UCS, Vec3 from pathlib import Path OUT_DIR = Path('~/Desktop/Outbox').expanduser() doc = ezdxf.new('R2010') msp = doc.modelspace() ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1)) msp.add_arc( center=ucs.to_ocs((0, 0)), radius=1, start_angle=ucs.to_ocs_angle_deg(45), end_angle=ucs.to_ocs_angle_deg(270), dxfattribs={ 'extrusion': ucs.uz, 'color': 1, }) center = ucs.to_wcs((0, 0)) msp.add_line( start=center, end=ucs.to_wcs(Vec3.from_deg_angle(45)), dxfattribs={'color': 1}, ) msp.add_line( start=center, end=ucs.to_wcs(Vec3.from_deg_angle(270)), dxfattribs={'color': 1}, ) ucs.render_axis(msp) doc.saveas(OUT_DIR / 'ocs_arc.dxf')与文本示例对比:这里不再手动构造方向向量再取角度,而是把 UCS 内的45°与270°直接交给to_ocs_angle_deg()完成变换,代码更简洁;圆心的处理则是ucs.to_ocs((0, 0))(UCS 点 → OCS 点),验证用的辅助直线端点仍以 WCS 表达(ucs.to_wcs(...))。
场景六:在三维空间放置块引用(INSERT)
尽管块引用(INSERT)内部可以包含 LINE、MESH 等真正的三维实体,但 INSERT 实体本身的放置原理与 TEXT、ARC 相同:用 OCS 坐标定位,绕 OCS z 轴旋转。Insert.dxf.rotation让块引用绕块的 z 轴旋转,而块的 z 轴位于Block.dxf.base_point处。
完整示例见 src/ocs/insert.py,以下逐一拆解其中关键片段。
绕 WCS x 轴旋转块引用
若要把块引用绕 WCS x 轴旋转,需要先把块的 z 轴变换到 WCS x 轴方向——即用 UCS 把块 z 轴绕 y 轴逆时针旋转 90°。示例先定义一个通用的 UCS 旋转辅助函数:
# 绕任意轴旋转 UCS: def ucs_rotation(ucs: UCS, axis: Vec3, angle: float): # ezdxf v0.11 起可直接使用 UCS.rotate(axis, angle) t = Matrix44.axis_rotate(axis, math.radians(angle)) ux, uy, uz = t.transform_vertices([ucs.ux, ucs.uy, ucs.uz]) return UCS(origin=ucs.origin, ux=ux, uy=uy, uz=uz)然后创建绕Y_AXIS旋转 90° 的 UCS,把插入位置变换到 OCS,并把 WCS x 轴方向的旋转角度 15° 变换为 OCS 角度:
ucs = ucs_rotation(UCS(), axis=Y_AXIS, angle=90) # 把插入位置变换到 OCS insert = ucs.to_ocs((0, 0, 0)) # 绕 z 轴(= WCS x 轴)的旋转角度 rotation = ucs.to_ocs_angle_deg(15) msp.add_blockref('CSYS', insert, dxfattribs={ 'extrusion': ucs.uz, 'rotation': rotation, })绕块 x 轴旋转块引用
要绕除块 z 轴之外的任意轴旋转块引用,必须求出旋转后块 z 轴(挤出向量)的方向。下面的示例绕块 x 轴旋转 15°:
# t 是绕 x 轴旋转 15 度的变换矩阵 t = Matrix44.axis_rotate(axis=X_AXIS, angle=math.radians(15)) # 把块 z 轴变换为新的 UCS z 轴(= 挤出向量) uz = Vec3(t.transform(Z_AXIS)) # 在插入点创建新 UCS;因为是绕 x 轴旋转, # ux 仍为 WCS x 轴,uz 是旋转后的 z 轴。 ucs = UCS(origin=(1, 2, 0), ux=X_AXIS, uz=uz) # 把插入位置变换到 OCS,块 base_point=(0, 0, 0) insert = ucs.to_ocs((0, 0, 0)) # 本例无需绕 z 轴旋转 rotation = 0 blockref = msp.add_blockref('CSYS', insert, dxfattribs={ 'extrusion': ucs.uz, 'rotation': rotation, })平移已建立 OCS 的块引用
先通过blockref.ocs()取回实体既有的 OCS(其挤出向量已存储于实体中),把 OCS 插入点转回 WCS 做平移,再转回 OCS 写回:
translation = Vec3(-3, -1, 1) # 取回既有 OCS ocs = blockref.ocs() # 取得 WCS 中的插入位置 actual_wcs_location = ocs.to_wcs(blockref.dxf.insert) # 平移位置 new_wcs_location = actual_wcs_location + translation # 把 WCS 位置转换回 OCS 位置 blockref.dxf.insert = ocs.from_wcs(new_wcs_location)仅设置新的插入位置也是同样的流程:把新位置变换进 OCS 即可(不加平移向量)。
绕块 y 轴旋转已建立 OCS 的块引用
这个操作代表"绕任意轴旋转带 OCS 的块引用"的完整套路,共分四步:
第 1 步:把块 y 轴(旋转轴)与块 z 轴(挤出向量)从 OCS 变换到 WCS:
ocs = blockref.ocs() # 把块 y 轴(= 旋转轴)变换为 WCS 向量 rotation_axis = ocs.to_wcs((0, 1, 0)) # 把局部 z 轴(= 挤出向量)变换为 WCS 向量 local_z_axis = ocs.to_wcs((0, 0, 1))第 2 步:构建绕该旋转轴旋转 -90° 的变换矩阵,变换挤出向量,并构建新 UCS(块引用原点位置不变,无需旋转):
t = Matrix44.axis_rotate(axis=rotation_axis, angle=math.radians(-90)) uz = t.transform(local_z_axis) uy = rotation_axis # 块引用原点保持在同一位置,无需旋转 wcs_insert = ocs.to_wcs(blockref.dxf.insert) # 构建新 UCS,用于把 WCS 位置与角度转换到 OCS ucs = UCS(origin=wcs_insert, uy=uy, uz=uz)第 3 步:设置新的 OCS 属性——注意即使没有绕局部 z 轴旋转块引用,也必须设置 rotation 属性,因为新块的 x 轴(0 度方向)与 OCS 的 x 轴不同,需要修正:
# 设置新的 OCS blockref.dxf.extrusion = ucs.uz # 设置新的插入位置 blockref.dxf.insert = ucs.to_ocs((0, 0, 0)) # 设置新的旋转:虽然没有绕局部 z 轴旋转块引用, # 但新块 x 轴(0 度)与 OCS x 轴不同,必须修正 blockref.dxf.rotation = ucs.to_ocs_angle_deg(0)至此,块引用的平移与任意轴旋转都可以在"OCS 坐标定位 + OCS 角度旋转"的框架内完成。这也是原教程作者所言的"数学知识边界"——更高级的 CAD 操作需要结合矩阵论等更深的知识自行探索。
进阶路线与参考资料
- 新版 UCS 变换教程:本教程展示的是底层"硬核"操作;若使用 ezdxf v0.13+ 的实体
transform()接口,OCS 与挤出向量会被自动处理,参见 ucs_transform.rst; - 坐标系统概念:coordinates.rst 汇总了 WCS/UCS/OCS/DCS 的定义与"只存储 WCS 或 OCS 坐标"的核心原则;
- OCS 深入原理:ocs.rst 给出了任意轴算法的完整推导、WCS↔OCS 变换公式以及全部 OCS 实体清单;
- 源码实现:UCS 与 OCS 类 是坐标换算的底层实现;图形实体的
ocs()方法见 dxfgfx.py; - 单元测试:test_610_ocs.py 验证 OCS 双向换算精度,test_611_ucs.py 覆盖 UCS 的构造、平移、旋转与角度变换,可作回归参考。
- 图形学
【免费下载链接】ezdxf
Python interface to DXF
相关推荐
ezdxf 对象坐标系(OCS)完全指南:任意轴算法、坐标变换与三维实体放置实战
ezdxf 对象坐标系(OCS)完全指南:任意轴算法、坐标变换与三维实体放置实战 对象坐标系(Object Coordinate System,OCS)是 DX
图形学ezdxf 坐标系完全指南:WCS、UCS、OCS 与 DCS 的原理与转换实战
ezdxf 坐标系完全指南:WCS、UCS、OCS 与 DCS 的原理与转换实战 本指南以 ezdxf 官方概念文档 docs/source/concepts/
图形学MMDetection3D中的三维坐标系系统详解
MMDetection3D中的三维坐标系系统详解 引言 在三维目标检测领域,坐标系系统的理解是基础中的基础。本文将深入剖析MMDetection3D框架中采用的
人工智能计算机视觉深度学习自动驾驶
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考