PythonOCC 在二维平面上实现圆角(Fillet)
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : core_2d_fillet.py
@Time : 2025/09/21 21:02:16
@Author : XuMing
@Version : v1.0
@Contact : 920972751@qq.com
@License : Copyright (c) 2021-2025 XuMing. All Rights Reserved.
@Desc : 使用 PythonOCC 在二维平面上实现圆角(Fillet)的示例。-------------------------------------------------
【示例说明】
- OpenCASCADE (OCC) 是一个强大的 CAD 内核库,支持几何建模、布尔运算、网格划分、几何分析等。
- 本示例展示如何在 2D 平面上,利用 OCC 的 `ChFi2d_AnaFilletAlgo`,对两条直线边在交点处生成圆角(Fillet)。【运行效果】
- 创建两条直线 (p3→p2, p2→p1)。
- 在交点处生成半径为 radius 的圆角。
- 最终结果是由直线和圆角组合成的线框 (Wire),并在窗口中显示。运行代码后,会弹出基于 Qt/VTK 的交互窗口,支持缩放、旋转、平移。
-------------------------------------------------
'''# ========== 底层库导入 ==========
from OCC.Core.gp import gp_Pnt, gp_Pln # 几何点 & 平面
from OCC.Core.ChFi2d import ChFi2d_AnaFilletAlgo # 2D 圆角算法
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge # 创建边
from OCC.Extend.ShapeFactory import make_wire # 创建线框 (Wire)
from OCC.Display.SimpleGui import init_display # 显示工具class Fillet2DExample:"""一个简单的 2D 圆角 (Fillet) 示例类使用 OpenCASCADE (OCC) 库在 2D 平面上创建两条直线,并在交点处生成圆角。"""def __init__(self, radius=2.0):"""初始化 Fillet 示例类:param radius: float圆角半径,决定圆弧大小。"""self.radius = radius# 初始化显示器 (基于 Qt/VTK 的交互窗口)self.display, self.start_display, self.add_menu, self.add_functionto_menu = init_display()def make_edges(self):"""创建两条直线边,并返回。:return: (TopoDS_Edge, TopoDS_Edge)ed1: 第一条直线 (p3 → p2)ed2: 第二条直线 (p2 → p1)"""# 定义三个点(位于 XY 平面)p1 = gp_Pnt(0, 0, 0) # 原点p2 = gp_Pnt(5, 5, 0) # 右上点p3 = gp_Pnt(-5, 5, 0) # 左上点# 创建两条直线:p3→p2 和 p2→p1ed1 = BRepBuilderAPI_MakeEdge(p3, p2).Edge()ed2 = BRepBuilderAPI_MakeEdge(p2, p1).Edge()return ed1, ed2def make_fillet(self, ed1, ed2):"""在两条边之间生成一个 2D 圆角。:param ed1: TopoDS_Edge第一条边:param ed2: TopoDS_Edge第二条边:return: TopoDS_Edge圆角边 (圆弧)"""# 定义一个 2D 圆角算法对象f = ChFi2d_AnaFilletAlgo()# 在 XY 平面上初始化两条边f.Init(ed1, ed2, gp_Pln())# 执行圆角计算f.Perform(self.radius)# 返回圆角结果(一个圆弧边)return f.Result(ed1, ed2)def build_wire(self, ed1, ed2, fillet_edge):"""把直线和圆角组合成一个线框 (Wire)。:param ed1: TopoDS_Edge第一条直线:param ed2: TopoDS_Edge第二条直线:param fillet_edge: TopoDS_Edge圆角边:return: TopoDS_Wire组合后的线框"""return make_wire([ed1, fillet_edge, ed2])def show(self):"""主入口:创建直线、生成圆角并显示。"""# 1. 创建两条直线ed1, ed2 = self.make_edges()# 2. 生成圆角fillet_edge = self.make_fillet(ed1, ed2)# 3. 组合成线框wire = self.build_wire(ed1, ed2, fillet_edge)# 4. 显示结果self.display.DisplayShape(wire, update=True)# 启动显示窗口(阻塞运行,直到用户关闭窗口)self.start_display()# ========== 程序入口 ==========
if __name__ == "__main__":# 创建一个示例对象,圆角半径 = 1.0example = Fillet2DExample(radius=1.0)# 显示结果example.show()
二维圆角(Fillet)算法原理
设两条边分别是 E1,E2E_1, E_2E1,E2,它们的交点为 PPP。我们希望构造一个半径为 rrr 的圆弧来替换尖锐的交点。
情况 A:直线 – 直线
设两条直线的单位方向向量分别是 v1⃗,v2⃗\vec{v_1}, \vec{v_2}v1,v2。
- 计算夹角
θ=arccos(v1⃗⋅v2⃗) \theta = \arccos \big( \vec{v_1} \cdot \vec{v_2} \big) θ=arccos(v1⋅v2)
- 计算切点
沿直线退距离:
d=r⋅tan(θ2) d = r \cdot \tan\left(\frac{\theta}{2}\right) d=r⋅tan(2θ)
得到切点:
P1=P+d⋅v1⃗,P2=P+d⋅v2⃗ P_1 = P + d \cdot \vec{v_1}, \quad P_2 = P + d \cdot \vec{v_2} P1=P+d⋅v1,P2=P+d⋅v2
- 计算圆心
圆心在角平分线方向:
n⃗=v1⃗+v2⃗∣v1⃗+v2⃗∣ \vec{n} = \frac{\vec{v_1} + \vec{v_2}}{|\vec{v_1} + \vec{v_2}|} n=∣v1+v2∣v1+v2
位置为:
O=P+rsin(θ/2)⋅n⃗ O = P + \frac{r}{\sin(\theta/2)} \cdot \vec{n} O=P+sin(θ/2)r⋅n
情况 B:直线 – 圆弧
要求圆与给定直线、圆弧都相切。
- 已知圆弧所在圆心为 CCC,半径为 RRR。
- 待求圆的圆心为 OOO,半径为 rrr。
几何约束条件:
- 圆与圆弧所在圆相切:
∣O−C∣=∣R±r∣ |O - C| = |R \pm r| ∣O−C∣=∣R±r∣
(外切或内切)
- 圆与直线相切:
dist(O,line)=r \text{dist}(O, \text{line}) = r dist(O,line)=r
解这组方程,即可得到候选圆心 OOO。
情况 C:圆弧 – 圆弧
要求一个新圆弧同时与两已知圆弧相切。
- 已知两个圆弧的圆心为 C1,C2C_1, C_2C1,C2,半径分别为 R1,R2R_1, R_2R1,R2。
- 待求圆心为 OOO,半径为 rrr。
几何约束条件:
∣O−C1∣=R1±r,∣O−C2∣=R2±r |O - C_1| = R_1 \pm r, \quad |O - C_2| = R_2 \pm r ∣O−C1∣=R1±r,∣O−C2∣=R2±r
解此方程组,得到候选圆心 OOO,再根据边的方向和交点位置筛选出正确解。
结果输出
一旦得到圆心 OOO,即可计算切点 P1,P2P_1, P_2P1,P2:
- 在直线情况:切点是圆心到直线的垂足。
- 在圆弧情况:切点是新圆与已知圆的交点,选择离交点 PPP 最近的那个。
最终输出结果包括:
- 圆角弧边 (fillet edge)
- 修剪后的邻边 (shrinked neighbours) ——即原始两条边裁掉交点附近的部分。