尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FreeCAD Placement 对象完全指南:位置与姿态的 Python API 详解

FreeCAD Placement 对象完全指南:位置与姿态的 Python API 详解 FreeCAD Placement 对象完全指南位置与姿态的 Python API 详解【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD导读本文聚焦 FreeCAD 中最核心的几何变换数据类型之一 ——Base.Placement放置对象。它用一个位置向量Base加一个旋转Rotation唯一描述三维空间中对象的平移与姿态是设置对象坐标、移动零件、装配约束乃至动画插值的基石。阅读完本文你将掌握 Placement 的全部构造函数、属性与变换方法理解其底层 C 实现原理与测试验证方式并能在 FreeCAD Python 控制台与脚本中熟练运用它。本文内容以仓库中的 API 文档入口 src/Doc/sphinx/Placement.rst 为骨架。该文档是 FreeCAD Python API 参考的一部分见 index.rst通过 Sphinx 的automodule/autoclass指令从源码中的类型注解与 docstring 自动生成Placement类的完整接口文档其真实内容即由 src/Base/Placement.pyi 中的声明与文档字符串定义。本文在完整继承这些接口说明的基础上结合 C 实现 src/Base/Placement.cpp、头文件 src/Base/Placement.h 以及单元测试 tests/src/Base/Placement.cpp 进行纵深讲解。一、什么是 Placement三维空间中的位置 姿态从 src/Base/Placement.pyi 的类文档可以看出A Placement defines an orientation (rotation) and a position (base) in 3D space. It is used when no scaling or other distortion is needed.Placement 由两部分组成Base一个Base.Vector表示对象在三维空间中的基点位置Rotation一个Base.Rotation内部使用四元数表示对象的朝向。它在无需缩放或其他畸变的场景下使用 —— 也就是说 Placement 描述的是刚体变换旋转 平移这与支持任意仿射变换的Base.Matrix形成互补Matrix 更通用Placement 更直观、更适合日常的对象定位。对应地C 侧的Base::Placement类src/Base/Placement.h内部只保存两个成员private: Vector3double _pos; // 位置 Base::Rotation _rot; // 旋转四元数从源码结构看这是典型的组合优于继承设计Placement 不自行存储矩阵而是由位置向量与旋转四元数组合而成需要矩阵时再通过toMatrix()计算。二、六种构造函数从空对象到中心点旋转Placement共支持 6 种构造方式签名定义见 src/Base/Placement.pyi构造方式说明Placement()空构造等价于恒等变换位置原点、旋转单位Placement(placement)拷贝构造从另一个 Placement 复制Placement(matrix)从 4D 矩阵旋转 平移构造matrix: Base.MatrixPlacement(base, rotation)从位置和旋转构造base: Base.Vectorrotation: Base.RotationPlacement(base, rotation, center)带旋转中心的位置 旋转构造Placement(base, axis, angle)从位置、旋转轴和角度构造Python 中典型用法import FreeCAD as App from FreeCAD import Base # 1. 恒等 Placement p0 Base.Placement() # 2. 位置 旋转 p1 Base.Placement(Base.Vector(10, 20, 30), Base.Rotation()) # 3. 位置 轴角绕 Z 轴旋转 90 度 p2 Base.Placement(Base.Vector(1, 2, 3), Base.Vector(0, 0, 1), 90) # 4. 从矩阵构造 m Base.Matrix() m.rotateZ(45) p3 Base.Placement(m)关于带 center 的构造旋转中心如何影响位置第 5 种构造Placement(base, rotation, center)是理解 Placement 数学本质的关键。查看其 C 实现src/Base/Placement.cppPlacement::Placement(const Vector3d Pos, const Rotation Rot, const Vector3d Cnt) : _rot(Rot) { Vector3d RotC Cnt; Rot.multVec(RotC, RotC); this-_pos Pos Cnt - RotC; }其含义是先绕center点旋转再平移到Pos。最终存储的位置由公式_pos Pos Cnt - Rot(Cnt)计算得出其中Rot(Cnt)是旋转作用于中心点后的结果。注意最终保存的_pos并不是你传入的Pos本身而是经过中心点补偿后的值。这一点在单元测试 tests/src/Base/Placement.cpp 中有直接验证TEST(Placement, TestPosRotCnt) { Base::Vector3d pos(1, 2, 3); Base::Rotation rot(1, 0, 0, 0); // 绕 X 轴旋转 180 度 Base::Vector3d cnt(4, 5, 6); Base::Placement plm(pos, rot, cnt); EXPECT_EQ(plm.getPosition(), Base::Vector3d(1, 12, 15)); ... }即pos(1,2,3)、绕 X 轴 180°、中心(4,5,6)时最终位置是(1, 12, 15)—— 中心点补偿公式的结果。三、核心属性Base、Rotation 与 MatrixPlacement暴露三个可读写属性1.Base—— 位置类型Base.Vector说明Placement 的基点Base Position可写支持直接赋Vector或Sequence[float]如[1, 2, 3]plm Base.Placement() plm.Base Base.Vector(5, 0, 0) print(plm.Base) # Vector (5, 0, 0)2.Rotation—— 姿态类型Base.Rotation说明Placement 的朝向内部以四元数表达可写支持赋Rotation对象或(x, y, z, w)四元数元组plm.Rotation Base.Rotation(Base.Vector(0, 0, 1), 45) # 绕 Z 轴 45 度 plm.Rotation (0.0, 0.0, 0.3826834323650898, 0.9238795325112867) # 等价四元数3.Matrix—— 矩阵表示类型Base.Matrix说明Placement 的 4D 矩阵表示旋转 平移可读可写mat plm.Matrix # 读出为矩阵 plm.Matrix new_mat # 写入矩阵等效于 Placement(matrix)Rotation 的构造细节由于 Rotation 是 Placement 的核心组件这里补充其常用构造方式完整声明见 src/Base/Rotation.pyiRotation()单位旋转Rotation(axis, angle)绕轴旋转angle可按关键字区分Radian弧度/ Degree角度Rotation(v_start, v_end)由两个向量定义旋转从起始向量转到目标向量Rotation(yaw, pitch, roll)以 yaw-pitch-rollXYZ 约定三个浮点数定义欧拉角旋转Rotation(seq, a1, a2, a3)按指定欧拉序列如ZYX定义可用toEulerAngles()查询支持的序列Rotation(x, y, z, w)直接给出四元数其中w为实部q xi yj zk wRotation(matrix)/Rotation(*coef)从 4D 矩阵16 元素或 3D 矩阵9 元素构造。例如将对象绕自身 Z 轴旋转 90 度plm Base.Placement() plm.Rotation Base.Rotation(Base.Vector(0, 0, 1), 90) # 注意默认按弧度解释若希望按度数传入可使用Rotation(axis, angle)与关键字依据 src/Base/Rotation.pyi 中Rotation(Axis, Degree)的说明或直接使用setYawPitchRoll(yaw, pitch, roll)度数XYZ 约定。四、变换方法移动、旋转、复合与求逆4.1move(vector)/translate(vector)平移作用沿给定向量移动 Placementtranslate()是move()的别名目的是与TopoShape.translate()保持 API 兼容见 src/Base/Placement.pyi。plm.move(Base.Vector(1, 0, 0)) # 沿 X 轴移动 1 plm.translate(Base.Vector(0, 2, 0)) # 等价写法C 实现中move即_pos MovVec测试 TestMove 验证了移动的向量叠加效果。4.2rotate(center, axis, angle, compFalse)旋转作用绕指定center和axis旋转当前 Placementangle单位为度comp为仅限关键字参数当compTrue时行为与TopoShape.rotate()一致两者结果可互换默认False。plm.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 0, 1), 90) # 绕原点 Z 轴转 90° plm.rotate([0, 0, 0], [1, 0, 0], 45, compTrue) # 兼容 TopoShape.rotate()4.3multiply(placement)/*运算符右乘复合作用将当前 Placement 与另一 Placement 右乘复合等价于*运算符注意顺序语义plm.multiply(other)表示先应用other再应用plm右乘。p_a Base.Placement(Base.Vector(1, 0, 0), Base.Rotation()) p_b Base.Placement(Base.Vector(0, 0, 1), Base.Rotation()) p_c p_a.multiply(p_b) # 或 p_a * p_bC 层对应operator*/multRight/multLeftsrc/Base/Placement.h测试 TestMultRight / TestMultLeft 验证了左右乘顺序导致的位移差异同样两个 PlacementmultRight得到(4, 0, 2)而multLeft得到(2, 4, -2)直观体现了先旋转后平移与先平移后旋转的差别。4.4multVec(vector)变换向量作用用当前 Placement 变换一个向量旋转 平移返回变换结果。v plm.multVec(Base.Vector(1, 1, 1))测试 TestMultVec 验证位置(1,2,3)、绕 X 轴 180° 的 Placement 作用于(1,1,1)得到(2,1,2)。4.5inverse()求逆作用计算当前 Placement 的逆变换返回新对象不改动自身。plm_inv plm.inverse() # 验证plm * plm.inverse() 应为恒等变换 assert (plm * plm_inv).isIdentity()C 实现src/Base/Placement.cpp先对旋转求逆再用逆旋转变换位置后取负void Placement::invert() { this-_rot this-_rot.inverse(); this-_rot.multVec(this-_pos, this-_pos); this-_pos -this-_pos; }测试 TestIdentity 断言plm * plm.inverse()恒等于单位变换。4.6toMatrix()/Matrix矩阵互转toMatrix()计算并返回 Placement 的 4D 矩阵表示。C 实现src/Base/Placement.cpp将旋转写入矩阵左上 3×3 部分位置写入第 4 列Base::Matrix4D Placement::toMatrix() const { Base::Matrix4D matrix; _rot.getValue(matrix); matrix[0][3] this-_pos.x; matrix[1][3] this-_pos.y; matrix[2][3] this-_pos.z; return matrix; }反向fromMatrix()则从矩阵提取旋转并读取第 4 列作为位置 —— 这正是Placement(matrix)构造函数的底层实现测试 TestMatrix 验证了矩阵往返转换。4.7 幂与插值pow、sclerp、slerp这是 Placement 类中最具进阶价值的一组方法常用于动画路径生成与运动插值方法说明pow(t, shortenTrue)将 Placement 提升到实数次幂基于 ScLERP 插值**运算符等价t为实数幂shortenTrue时保证旋转四元数净为正以缩短路径sclerp(p2, t, shortenTrue)Screw Linear Interpolation螺旋线性插值沿螺旋路径做等步长连续运动t0返回自身t1返回p2t可超出[0,1]用于外推若两旋转四元数符号相反插值会走长路径shortenTrue可先统一符号走短路径slerp(p2, t)Spherical Linear Interpolation球面线性插值对旋转与位移独立插值结果可能不符合应用预期适合简单场景或小间隔插值复杂场景建议使用sclerp()start Base.Placement(Base.Vector(0, 0, 0), Base.Rotation()) end Base.Placement(Base.Vector(10, 0, 0), Base.Rotation(Base.Vector(0, 0, 1), 180)) mid start.sclerp(end, 0.5) # 螺旋路径中点 p start.pow(0.5) # 半程变换** 0.5 等价测试 TestPow / TestSlerp / TestSclerp 验证了pow(1.5)使旋转角度放大 1.5 倍且旋转轴不变slerp/sclerp在t0、t1、t0.5时均满足端点与中点的正确性中点四元数为两端四元数之和的归一化。4.8 比较与判定isIdentity、isSameisIdentity(tol0.0)返回该 Placement 是否无位移且无旋转矩阵表示为 4D 单位矩阵。tol为比较容差tol 0时不使用容差。isSame(other, tol0.0)判断与给定 Placement 是否相同默认容差 0.0。另有copy()返回该 Placement 的副本运算符/!亦可用见 src/Base/Placement.pyi。plm.isIdentity() # True/False plm.isSame(other, 1e-7) # 容差比较 plm.copy() # 副本五、底层原理从 Python API 到 C 实现Placement 的 Python 绑定由 src/Base/PlacementPyImp.cpp 实现类型声明与文档字符串则维护在 src/Base/Placement.pyi。整个调用链为Python: FreeCAD.Base.Placement │ ▼ PlacementPyImp.cppPyObjectBase 派生见 .pyi 中的 class_declarations │ ▼ C: Base::Placementsrc/Base/Placement.cpp │ 成员Vector3double _pos Base::Rotation _rot ▼ 数学内核四元数 Rotation 矩阵 Matrix4D值得注意的几个实现要点四元数是旋转的真身Placement 不存欧拉角也不存矩阵姿态统一以四元数Rotation保存避免万向锁问题并支撑slerp/sclerp等四元数插值算法支持对偶四元数Placement提供toDualQuaternion()与静态工厂fromDualQuaternion()src/Base/Placement.h对偶四元数同时编码旋转与平移是高级运动学与插值如 ScLERP的数学基础。测试 TestDualQuat 验证了往返转换的一致性中心点补偿在构造期完成Placement(base, rotation, center)在构造时就把中心点效应折算进_pos之后所有运算统一走位置 旋转二元组简化了后续数学处理。六、实际应用把 Placement 用起来6.1 在 Python 控制台/宏中操作对象每个具有空间属性的 FreeCAD 对象都带有Placement属性对应DocumentObject的Placement典型脚本如下import FreeCAD as App doc App.newDocument() box doc.addObject(Part::Box, Box) # 读取 print(box.Placement.Base) # Vector (0, 0, 0) print(box.Placement.Rotation) # Rotation (1, 0, 0, 0) # 修改移动到 (10, 20, 30) box.Placement.Base App.Vector(10, 20, 30) # 修改绕 Z 轴旋转 45 度 box.Placement.Rotation App.Rotation(App.Vector(0, 0, 1), 45) doc.recompute()6.2 在 Sketcher 草图中使用草图工作台亦广泛使用 Placement。可以通过草图对象的 Placement 调整其所在平面与原点例如让草图绕 X 轴翻转 180°sketch.Placement App.Placement( App.Vector(0, 0, 0), App.Rotation(App.Vector(1, 0, 0), 180), )6.3 组合变换与逆变换装配类场景如 Part 工作台的变换、Assembly 模块的约束求解中父子层级间的坐标换算经常用到复合与求逆# 世界坐标 父Placement * 子Placement world parent_plm * child_plm # 把世界坐标的向量变换回局部坐标 local parent_plm.inverse().multVec(world_vec)6.4 动画插值利用sclerp可在两个 Placement 之间生成平滑的螺旋运动轨迹等步长刚体运动适合相机飞行动画、机构运动仿真等场景frames 30 for i in range(frames 1): t i / frames pose start.sclerp(end, t) obj.Placement pose七、验证与测试如何确认你的理解正确仓库为 Placement 提供了完整的单元测试套件 tests/src/Base/Placement.cpp覆盖默认构造、位置旋转构造、带中心点构造、矩阵构造、恒等判定、求逆、移动、相等比较、乘法右乘/左乘、向量变换、对偶四元数往返、幂运算、SLERP 与 ScLERP 插值。这些测试是理解语义的最佳教材——例如 TestPosRotCnt 用具体数值演示了中心点补偿公式TestMultRight 则展示了右乘的位移叠加顺序。参考资料与延伸阅读本文骨架文档src/Doc/sphinx/Placement.rstPython 类型声明与 API 文档实际接口来源src/Base/Placement.pyiC 头文件类结构与运算符重载src/Base/Placement.hC 实现矩阵互转、求逆、中心点补偿src/Base/Placement.cppPython 绑定实现src/Base/PlacementPyImp.cpp旋转组件 APIsrc/Base/Rotation.pyi矩阵组件 APIsrc/Base/Matrix.pyi向量组件 APIsrc/Base/Vector.pyi单元测试tests/src/Base/Placement.cppAPI 文档总入口src/Doc/sphinx/index.rst【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表