
CAD 里执行“圆角”命令只需要点两下鼠标、输入一个半径一条平滑的曲线就出来了。但你有没有想过软件在背后到底做了什么计算如果让你自己写一个函数输入两条相交直线和一个圆角半径你能不能生成这条曲线我第一次接触这类任务时以为它只是在考绘图命令的熟练度。后来才发现真正要理解的是两点一是圆角曲线本质上不是“画一个圆弧”而是“求一段与两条边同时相切的圆弧”二是这个几何约束关系可以直接用三角函数和向量表达出来写成代码也就几十行。这篇文章不打算只讲按钮位置而是从几何原理出发把创建圆角曲线的完整逻辑讲清楚。你会看到圆角命令的参数为什么只有半径圆弧的圆心和切点如何计算用 Python 实现一个最小可用版需要哪些步骤以及 AutoCAD 这类软件中圆角失败的常见原因。无论你是 CAD 使用者、机械制图初学者还是想用代码实现几何建模的程序员这篇文章都值得读完并收藏备用。1. 这个任务到底在考什么BC13-7-2 这个编号通常来自教材或实训平台的某个练习模块。任务名称是“创建圆角曲线”看起来很简单但很多初学者会把它当成纯操作题打开软件选中圆角命令输入半径完成。这么做能通过操作层面的检查但有一个问题——你并不清楚圆角命令在什么情况下会失败也不清楚为什么有的圆角结果和你想象的不一样。举个例子两条线段长度都是 10你输入半径 20软件会提示“无法创建圆角”。原因很简单圆角半径为 20 时切点到交点的距离至少需要 20但线段只有 10圆弧根本没有空间落位。这类失败提示恰好暴露了圆角操作的本质它不是一个“画弧”命令而是一个“几何约束求解”命令。软件要做的是在满足相切条件的前提下计算出一个半径给定的圆弧然后自动完成裁剪和延伸。所以这个任务真正的考点是你是否理解圆角的几何意义你是否知道圆弧圆心和切点与半径、夹角之间的数学关系你是否能在实际绘制中处理半径过大、修剪模式等边界条件。把这一层想清楚圆角就不再是一道“点鼠标”的题而是一个真正可迁移的技术能力。无论是机械制图中的轴肩过渡、PCB 布线中的走线拐角还是 UI 设计里卡片的圆角背后都是同一个几何模型。2. 圆角曲线的核心概念与几何原理2.1 什么是圆角曲线圆角曲线是指在两条线段或曲线的交汇处用一段指定半径的圆弧替代原来的尖角使连接处平滑过渡。注意“平滑”这个词。它意味着圆弧和相邻的两条边之间不是随便搭上去的而是在连接点处满足相切关系。相切的数学含义是圆弧在切点处的切线方向与原始直线或曲线的方向完全一致。只有这样连接处的方向不会发生突变。如果只是把两条线用一段半径任意的弧连起来但不满足相切视觉上就会出现一个“折点”在机械加工中还会造成应力集中。2.2 两个关键参数半径与相切圆角命令通常只需要一个核心参数圆角半径 R。为什么只有一个参数因为“与两条已知边相切”本身已经提供了足够的约束条件。给定半径 R 后圆弧的位置就被唯一确定了。软件计算时需要求解的是三个未知量圆心坐标两个未知数圆弧的圆心角或起止角度一个未知数。三个未知数对应三个约束关系圆心到第一条边的距离等于 R圆心到第二条边的距离等于 R两条边的方向是已知的。所以从数学上看这个问题是可求解的而且解是唯一的。2.3 两条直线夹角的圆角公式为了便于理解先看最简单的情况两条直线相交夹角为 θ圆角半径为 R。设两条直线交点为 O圆角圆弧的圆心为 C两个切点分别为 T1 和 T2。由于圆弧分别与两条直线相切圆心 C 到两条直线的距离都等于 R因此 C 必然位于角平分线上。根据几何关系可以推导出两个常用公式圆心到交点的距离OC R / sin(θ/2)切点到交点的距离OT R / tan(θ/2)圆弧对应的圆心角为 π - θ。当两条直线的夹角为 90° 时公式更直观OC R / sin(45°) R × √2 ≈ 1.414R OT R / tan(45°) R也就是说直角圆角的切点恰好距离交点一个半径的长度这是一个非常容易记忆的特例。2.4 圆角与倒角的区别很多初学者分不清圆角和倒角这里用一张表说明对比项圆角Fillet倒角Chamfer连接形式圆弧过渡直线斜面过渡核心参数半径 R距离或角度平滑程度平滑方向连续存在尖点方向突变机械性能减少应力集中加工方便便于涂装典型场景轴肩、孔口、受力零件零件边缘去毛刺、配合导向从运动学角度看圆角是 G1 连续切线连续而倒角只是 G0 连续位置连续。如果是一条运动轨迹走圆角可以避免速度方向的突变倒角则不行。3. 创建圆角曲线的三种典型方式“创建圆角曲线”这个概念在不同工具链里有不同的落地方式。理解它们之间的差异有助于你在实际项目中选择正确的方法。3.1 CAD 交互式操作在 AutoCAD、CAXA、SolidWorks 等软件中创建圆角曲线的通用流程如下启动圆角命令如 AutoCAD 中的FILLET设置圆角半径依次选择两条边软件自动计算圆心、切点生成圆弧并完成裁剪。这里的核心操作是“选择两条边”。软件会读取边的几何信息将圆角问题转化为一个几何求解问题然后自动生成结果。需要注意AutoCAD 的 FILLET 命令默认会修剪原始线段如果只需要圆角区域、不改变原线段的长度需要把修剪模式改为“不修剪”。3.2 SVG 与前端场景的实现如果你做前端或 Web 图形开发其实也经常遇到圆角曲线。但前端里的“圆角”有两种完全不同的含义CSS 中的border-radius用于盒模型的圆角显示SVG 路径中的圆弧命令 A用于绘制真正的曲线路径。SVG 中用圆弧命令创建圆角曲线的形式如下svg width200 height200 xmlnshttp://www.w3.org/2000/svg path dM 20 20 L 100 20 A 30 30 0 0 1 130 50 L 130 130 fillnone strokeblue stroke-width2/ /svg这里的A 30 30 0 0 1 130 50表示从当前点画一段半径为 30 的圆弧到达点 (130, 50)。圆弧命令有 7 个参数rx、ry、旋转角度、大小弧标志、扫掠标志、终点 x、终点 y。但要注意SVG 的圆弧命令并不自动保证“与前后线段相切”。要做出圆角效果需要自己计算切点位置或者借助绘图工具的自动圆角功能。3.3 编程实现编程实现是理解圆角原理的最佳方式。通过代码你不再依赖软件的黑盒而是能明确看到每一个几何量是如何算出来的。后续章节我会用 Python 从零实现一个最小可运行的圆角曲线生成器。三种方式的对比实现方式适用场景优势劣势CAD 交互操作工程制图、机械设计快速、直观、自动裁剪不便于批量处理和二次开发SVG/CSSWeb 图形、UI 设计轻量、跨平台不自动满足相切约束需自行计算编程实现几何算法、离线批量建模可控性强可嵌入系统需要自己处理边界条件和数值精度4. 环境准备与基础工具本文的编程示例使用 Python核心依赖是numpy和matplotlib。前者用于向量运算后者用于可视化验证。4.1 安装 Python 依赖建议在项目目录下创建虚拟环境再安装依赖python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 source venv/bin/activate激活虚拟环境后安装依赖pip install numpy matplotlib安装完成后可以用以下命令验证核心库是否可用python -c import numpy, matplotlib; print(numpy.__version__, matplotlib.__version__)能输出版本号就说明环境就绪。如果你用的 Python 版本是 3.8 以上一般不会有兼容性问题低于 3.8 建议先升级解释器。4.2 CAD 软件环境如果你更关注 CAD 操作不需要额外安装特定版本的软件。AutoCAD、CAXA CAD、中望 CAD 等主流工具的圆角命令逻辑基本一致。我用 2020 年之后常见版本的默认界面为例但操作路径在不同版本中保持兼容先输入命令名或点击修改工具栏中的圆角图标再按提示输入半径最后选择对象。5. 完整示例用 Python 手动实现两直线圆角曲线这是本文的核心部分。我会分三步完成一个最小可运行的圆角曲线生成器并逐步解释每段代码的作用。5.1 计算圆角的圆心和切点首先定义一个函数输入两条直线的交点、两条边的方向向量和圆角半径输出圆心和两个切点的坐标。# 文件路径fillet_core.py import numpy as np def create_fillet(vertex, dir1, dir2, radius): 根据两条相交直线创建圆角曲线。 参数: vertex: 两条直线交点坐标 (x, y) dir1 : 第一条直线的方向向量 (dx, dy)从交点指向线内侧 dir2 : 第二条直线的方向向量 (dx, dy)从交点指向线内侧 radius: 圆角半径必须为正数 返回: center : 圆心坐标 p1 : 第一条直线上的切点 p2 : 第二条直线上的切点 if radius 0: raise ValueError(radius 必须为正数) # 归一化方向向量 u1 np.asarray(dir1, dtypefloat) u2 np.asarray(dir2, dtypefloat) u1 u1 / np.linalg.norm(u1) u2 u2 / np.linalg.norm(u2) # 计算两条方向向量的夹角弧度 cos_theta np.clip(np.dot(u1, u2), -1.0, 1.0) theta np.arccos(cos_theta) # 夹角不能在 0 或 pi 附近否则退化 if np.isclose(theta, 0.0) or np.isclose(theta, np.pi): raise ValueError(两条直线平行无法创建圆角) # 圆心到交点的距离 d_center radius / np.sin(theta / 2.0) # 切点到交点的距离 d_tangent radius / np.tan(theta / 2.0) # 角平分线方向u1 u2 的归一化 bisector u1 u2 bisector bisector / np.linalg.norm(bisector) # 圆心坐标 center np.asarray(vertex, dtypefloat) bisector * d_center # 两个切点坐标 p1 np.asarray(vertex, dtypefloat) u1 * d_tangent p2 np.asarray(vertex, dtypefloat) u2 * d_tangent return center, p1, p2这段代码的核心逻辑分为四步将方向向量归一化保证后续计算不受向量长度影响用点积反推出两条边的夹角 θ根据公式计算圆心到交点的距离、切点到交点的距离利用角平分线方向计算圆心坐标。这里最容易出错的是角平分线方向。当 u1 和 u2 是归一化向量时u1 u2 指向的是两条方向向量夹角较小的内侧角平分线。如果方向向量取反圆心会跑到外侧生成一个错误的大圆弧。5.2 生成圆弧上的点集有了圆心和两个切点还需要生成圆弧上的离散点才能绘制出曲线。由于圆角圆弧的圆心角为 π - θ且一定小于 180°我们只需要在切点对应的两个角度之间走“劣弧”方向。def arc_points(center, p1, p2, num_points100): 生成从 p1 到 p2 的圆弧点集经过内侧劣弧。 参数: center : 圆心坐标 p1, p2 : 圆弧上的两个端点 num_points: 生成的采样点数量 返回: points : shape 为 (num_points, 2) 的 numpy 数组 r np.linalg.norm(np.asarray(p1) - np.asarray(center)) a1 np.arctan2(p1[1] - center[1], p1[0] - center[0]) a2 np.arctan2(p2[1] - center[1], p2[0] - center[0]) # 计算有符号的角度差限制在 (-pi, pi] 范围内 delta (a2 - a1) % (2 * np.pi) if delta np.pi: delta - 2 * np.pi angles a1 np.linspace(0, delta, num_points) xs center[0] r * np.cos(angles) ys center[1] r * np.sin(angles) return np.column_stack([xs, ys])为什么这样能保证画的是正确的那段圆弧因为圆角圆弧的圆心角为 π - θ而 θ 的取值范围是 (0, π)所以 π - θ 一定小于 π。取角度差的绝对值最小方向自然就是我们要走的劣弧。5.3 完整绘图脚本把上面的函数组合起来生成一个直角圆角的可视化图形。# 文件路径fillet_demo.py import matplotlib.pyplot as plt import numpy as np from fillet_core import create_fillet, arc_points def main(): # 直角顶点在原点两条边分别沿 x 轴正方向和 y 轴正方向 vertex np.array([0.0, 0.0]) dir1 np.array([1.0, 0.0]) # 水平向右 dir2 np.array([0.0, 1.0]) # 垂直向上 radius 2.0 center, p1, p2 create_fillet(vertex, dir1, dir2, radius) arc arc_points(center, p1, p2, num_points100) print(圆心:, center) print(切点1:, p1) print(切点2:, p2) print(圆心到切点距离:, np.linalg.norm(p1 - center)) print(输入半径:, radius) # 绘制原始直线 # 第一条边从交点向 dir1 方向延伸 5 个单位 line1_end vertex np.array(dir1) * 5.0 # 第二条边从交点向 dir2 方向延伸 5 个单位 line2_end vertex np.array(dir2) * 5.0 plt.plot([vertex[0], line1_end[0]], [vertex[1], line1_end[1]], colorgray, linewidth1.5, linestyle--, label原始直线 1) plt.plot([vertex[0], line2_end[0]], [vertex[1], line2_end[1]], colorgray, linewidth1.5, linestyle--, label原始直线 2) # 绘制圆角曲线 plt.plot(arc[:, 0], arc[:, 1], colorblue, linewidth2.5, label圆角曲线) # 标注切点 plt.scatter([p1[0], p2[0]], [p1[1], p2[1]], colorred, zorder5, label切点) # 标注圆心 plt.scatter([center[0]], [center[1]], colorgreen, markerx, s80, zorder5, label圆心) plt.axis(equal) plt.grid(True, linestyle:, alpha0.6) plt.legend() plt.title(创建圆角曲线示例半径 R2) plt.show() if __name__ __main__: main()运行前请确认fillet_core.py和fillet_demo.py在同一个目录下然后执行python fillet_demo.py5.4 扩展到任意夹角上面示例是 90° 直角。如果两条边不是直角只需修改dir1和dir2。例如两条边夹角为 60°vertex np.array([0.0, 0.0]) # 第一条边沿 x 轴正方向 dir1 np.array([1.0, 0.0]) # 第二条边与第一条边夹角 60 度 angle_deg 60.0 angle_rad np.deg2rad(angle_deg) dir2 np.array([np.cos(angle_rad), np.sin(angle_rad)]) radius 1.5其他代码完全不用改。这正好验证了算法的通用性只要输入两条边在交点处的方向向量就能正确生成圆角。6. 运行结果与效果验证运行fillet_demo.py后你会看到类似这样的输出圆心: [1.41421356 1.41421356] 切点1: [2. 0.] 切点2: [0. 2.] 圆心到切点距离: 2.0 输入半径: 2.0图形窗口中会显示一个灰色虚线的直角、一条蓝色圆角曲线、两个红色切点和一个绿色圆心。圆心坐标约在 (1.414, 1.414)正好是公式中 OC R × √2 的结果两个切点分别位于 (2, 0) 和 (0, 2)与交点的距离都是 R 2完全符合公式。但“看起来对”还不够最好用专门的验证代码来检查相切关系。相切的判定标准是圆心到切点的连线与切点所在直线方向垂直。# 文件路径verify_fillet.py import numpy as np from fillet_core import create_fillet # 构建 60 度夹角的测试 vertex np.array([0.0, 0.0]) dir1 np.array([1.0, 0.0]) dir2 np.array([np.cos(np.deg2rad(60)), np.sin(np.deg2rad(60))]) radius 1.5 center, p1, p2 create_fillet(vertex, dir1, dir2, radius) # 验证 1切点到圆心的距离是否等于半径 r1 np.linalg.norm(p1 - center) r2 np.linalg.norm(p2 - center) print(f切点1到圆心距离: {r1:.6f}, 切点2到圆心距离: {r2:.6f}) assert np.isclose(r1, radius, atol1e-9) assert np.isclose(r2, radius, atol1e-9) # 验证 2切点是否在原始直线上 t1 np.dot(p1 - vertex, dir1) / np.dot(dir1, dir1) t2 np.dot(p2 - vertex, dir2) / np.dot(dir2, dir2) print(f切点1在直线1上的参数: {t1:.6f}, 切点2在直线2上的参数: {t2:.6f}) assert t1 0 and t2 0 # 验证 3相切条件圆心到切点向量与直线方向垂直 radial1 p1 - center radial2 p2 - center dot1 np.dot(radial1, dir1) dot2 np.dot(radial2, dir2) print(f径向向量与直线方向点积: {dot1:.6e}, {dot2:.6e}) assert np.isclose(dot1, 0.0, atol1e-9) assert np.isclose(dot2, 0.0, atol1e-9) print(所有验证通过切点位置正确相切关系成立)运行python verify_fillet.py如果所有断言通过说明生成的圆角曲线在几何上是正确的。这也是工程中验证几何算法最常用的方式不要只看图形要输出数值并做容差断言。7. 常见问题与排查方法在实际使用中无论你是用 CAD 软件还是写代码都会遇到一些问题。这里整理了一张排查表。问题现象可能原因排查方式解决方案CAD 提示无法创建圆角圆角半径大于线段可容纳长度检查两边长度是否大于半径减小半径或先延长线段圆角方向与预期相反选择对象时点击的位置不对观察预览注意点击点在要保留的一侧重新选择在保留侧点击圆角后原始线段被裁掉FILLET 默认修剪模式为开启查看命令提示中的修剪模式命令中输入 T设置为不修剪生成的圆弧画到了外侧编程时方向向量取反打印圆心坐标检查圆心是否在角平分线内侧确认 dir1/dir2 从交点指向线内侧绘制的圆弧是优弧而非劣弧角度差计算错误打印 delta 值确认在 (-π, π] 内使用最小角度差逻辑matplotlib 图形中圆角看起来变形坐标轴纵横比例不一致检查是否使用了 axis equal添加 plt.axis(equal)圆心距离计算结果异常夹角为 0 或 π 时公式分母接近 0检查角度是否接近 0 或 π提前抛出异常或单独处理平行线场景重点解释第一个问题。当两条线段长度都是 10而你输入的圆角半径是 20CAD 会直接报错。这不是软件 bug而是几何限制圆心到交点的距离 OC R / sin(θ/2)切点到交点的距离 OT R / tan(θ/2)两个值都随半径增大而增大。当 OT 超过线段可用长度时圆弧无法落位只能提示失败。编程实现时也会遇到同样的边界条件。所以create_fillet函数中应增加合法性判断在半径非法或几何退化时及时抛出异常避免产出错误数据。8. 最佳实践与工程建议8.1 进入生产代码前先做参数校验在算法函数中加入参数校验能避免很多隐蔽问题。以下是一个建议的校验逻辑if radius 0: raise ValueError(radius 必须大于 0) cos_theta np.clip(np.dot(u1, u2), -1.0, 1.0) theta np.arccos(cos_theta) if np.isclose(theta, 0.0) or np.isclose(theta, np.pi): raise ValueError(两直线平行不能创建圆角)如果不加校验碰到平行线时sin(theta/2)接近 0d_center会变成一个巨大的数最终得到偏离十万八千里的错误坐标。8.2 使用容差验证几何结果浮点运算中不要用 0判断相切。正确做法是设置一个较小的容差比如1e-9或1e-6。assert np.isclose(np.dot(radial, dir1), 0.0, atol1e-9)这个判断的含义是圆心到切点方向的向量与直线方向的内积足够接近 0。内积为 0 意味着两个向量垂直也就是相切条件成立。8.3 CAD 使用中的工程习惯如果你主要使用 CAD 软件这里有几个实用建议大图纸中建议使用“不修剪”模式先预览圆角位置确认无误后再统一修剪多段线可以一条命令连续创建多个圆角注意观察命令行是否支持“多个”循环每次圆角前先双击查看对象属性确认线段是否属于同一图层、是否闭合如果圆角对象是圆弧或样条线不同软件的算法差异较大务必在测试文件中验证效果。8.4 圆角在不同工程领域中的意义在机械设计中圆角的作用是减少应力集中避免零件在尖角处开裂在 PCB 布线中走线的圆角可以减少信号反射在 UI 设计中圆角让界面元素更柔和。虽然这些领域使用的工具完全不同但几何本质是一样的用一段与两边相切的圆弧替换掉一个方向突变的尖角。理解了这个本质你在任何工具里都能快速判断一个“圆角”操作是否正确。8.5 记录算法输入输出方便回归测试如果做二次开发建议为圆角算法建立一组回归测试用例90° 直角60° 锐角120° 钝角半径接近零的极端情况两条线长度不等的场景。每个用例记录输入的顶点、方向向量、半径以及预期的圆心、切点和切点参数。后续修改代码时跑一遍测试就能发现是否破坏了原有逻辑。9. 总结与后续学习方向创建圆角曲线并不是一个复杂的操作但它的背后是一套清晰的几何求解过程给定圆弧半径在相切约束下计算圆心位置和切点位置。理解了这套原理你不但能在 CAD 软件中熟练使用圆角命令还能用代码自主实现它。本文的核心收获有三个圆角曲线的本质是“求一段与两条边同时相切的圆弧”圆心一定位于角平分线上切点到交点的距离由半径和夹角共同决定。两条直线的圆角计算可以完全用初等三角函数实现完整的 Python 代码只有几十行包含圆心计算、切点计算、圆弧点集生成和图形验证。实际使用中最常踩的坑是半径过大导致几何失败以及方向向量取反导致圆弧生成到外侧。如果你想把这个问题研究得更深下一步可以尝试给两条圆弧而非直线创建圆角这需要求解圆心到两条圆弧距离都为 R 的非线性方程学习贝塞尔曲线和 B 样条曲线理解“平滑连接”在更高阶曲线中的含义研究 CAD 内核如 OpenCascade中 fillet 功能的实现思路看看工业级代码如何处理拓扑变化和误差累积。建议你先跑通本文的 Python 示例再回到 CAD 软件中手动画一次直角圆角。当你看到软件自动生成的圆弧能够准确说出它的圆心在哪里、切点距交点多远时这个知识点就真正变成你自己的了。