当前位置: 首页 > news >正文

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

  1. 计算夹角

θ=arccos⁡(v1⃗⋅v2⃗) \theta = \arccos \big( \vec{v_1} \cdot \vec{v_2} \big) θ=arccos(v1v2)

  1. 计算切点

沿直线退距离:

d=r⋅tan⁡(θ2) d = r \cdot \tan\left(\frac{\theta}{2}\right) d=rtan(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+dv1,P2=P+dv2

  1. 计算圆心

圆心在角平分线方向:

n⃗=v1⃗+v2⃗∣v1⃗+v2⃗∣ \vec{n} = \frac{\vec{v_1} + \vec{v_2}}{|\vec{v_1} + \vec{v_2}|} n=v1+v2v1+v2

位置为:

O=P+rsin⁡(θ/2)⋅n⃗ O = P + \frac{r}{\sin(\theta/2)} \cdot \vec{n} O=P+sin(θ/2)rn


情况 B:直线 – 圆弧

要求圆与给定直线、圆弧都相切。

  • 已知圆弧所在圆心为 CCC,半径为 RRR
  • 待求圆的圆心为 OOO,半径为 rrr

几何约束条件:

  1. 圆与圆弧所在圆相切:

∣O−C∣=∣R±r∣ |O - C| = |R \pm r| OC=R±r

(外切或内切)

  1. 圆与直线相切:

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 OC1=R1±r,OC2=R2±r

解此方程组,得到候选圆心 OOO,再根据边的方向和交点位置筛选出正确解。


结果输出

一旦得到圆心 OOO,即可计算切点 P1,P2P_1, P_2P1,P2

  • 在直线情况:切点是圆心到直线的垂足。
  • 在圆弧情况:切点是新圆与已知圆的交点,选择离交点 PPP 最近的那个。

最终输出结果包括:

  • 圆角弧边 (fillet edge)
  • 修剪后的邻边 (shrinked neighbours) ——即原始两条边裁掉交点附近的部分。
http://www.dtcms.com/a/393718.html

相关文章:

  • Unity 性能优化 之 实战场景简化(LOD策略 | 遮挡剔除 | 光影剔除 | 渲染流程的精简与优化 | Terrain地形优化 | 主光源级联阴影优化)
  • [GXYCTF2019]禁止套娃1
  • 【论文阅读】-《Triangle Attack: A Query-efficient Decision-based Adversarial Attack》
  • 云微短剧小程序系统开发:赋能短剧生态,打造全链路数字化解决方案
  • 《从延迟300ms到80ms:GitHub Copilot X+Snyk重构手游跨服社交系统实录》
  • 力扣2132. 用邮票贴满网格图
  • Halcon学习--视觉深度学习
  • LeetCode:40.二叉树的直径
  • dplyr 是 R 语言中一个革命性的数据操作包,它的名字是 “data plier“ 的缩写,意为“数据折叠器“或“数据操作器“
  • 使用Node.js和PostgreSQL构建数据库应用
  • 设计模式(C++)详解—享元模式(1)
  • C++线程池学习 Day08
  • VALUER倾角传感器坐标系的选择
  • 解决 win+R 运行处以及文件资源管理器处无法使用 wt、wsl 命令打开终端
  • R语言 生物分析 CEL 文件是 **Affymetrix 基因芯片的原始扫描文件**,全称 **Cell Intensity File**。
  • Apache Spark Shuffle 文件丢失问题排查与解决方案实践指南
  • xtuoj 0x05-C 项链
  • STM32F429I-DISC1【读取板载运动传感器数据】
  • 【Kafka面试精讲 Day 21】Kafka Connect数据集成
  • 2025数据资产管理平台深度分析:技术特性、与选型逻辑
  • RabbitMQ Java 解决消息丢失、重复和积压问题
  • 深入解析 Spring AI 系列:解析请求参数处理
  • OpenLayers地图交互 -- 章节五:捕捉交互详解
  • 阿瓦隆1566HA-448T矿机深度解析:性能、效率与冷却技术
  • 平替confluence,推荐一款国产开源免费的知识管理工具 - sward
  • 【开源】基于STM32的智能垃圾桶
  • RuoYi-Cloud问题:访问https的网关地址,实际是访问http的文件服务
  • HttpClientFactory vs new HttpClient:.NET Core HTTP 客户端的正确打开方式
  • MySQL数据库(七)—— 基于主主复制与 Keepalived 非抢占模式的高可用方案
  • 如何提高Java并发编程的实战能力?