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

OCCT 学习笔记:创建瓶子教程的三个关键知识点

对OCCT已经有了多年了解,但时不时还是要翻一翻它的官方文档。今天重读了:Bottle Tutorial

教程概况

在这里插入图片描述
这篇教程文档围绕使用Open CASCADE Technology进行3D建模展开,以创建一个瓶子模型为例,逐步介绍建模过程及相关技术要点,主要内容如下:

  1. 教程概述
    • 目的:教会读者使用Open CASCADE Technology服务对3D对象建模,帮助读者将其作为工具来思考和应用,并非介绍所有类。
    • 前提条件:假定读者具备C++使用和设置经验,Open CASCADE Technology旨在增强C++的3D建模能力。
  2. 模型规格:定义了瓶子的关键参数,包括高度(70mm)、宽度(50mm)、厚度(30mm),且瓶子轮廓(底部)以全局笛卡尔坐标系原点为中心。
  3. 建模步骤
    • 构建轮廓:先定义支撑点,选用gp_Pnt类创建点对象;接着利用这些点计算轮廓几何,涉及线段和圆弧;再通过TopoDS和BRepBuilderAPI等相关类构建拓扑结构;最后通过反射现有导线并合并的方式完成轮廓。
    • 构建瓶身:使用BRepBuilderAPI_MakeFace和BRepPrimAPI_MakePrism类将轮廓拉伸为实体;利用BRepFilletAPI_MakeFillet类对边缘倒圆角;通过创建圆柱体并与瓶身融合添加瓶颈;借助BRepOffsetAPI_MakeThickSolid类创建空心实体。
    • 构建螺纹:计算两个不同半径的圆柱面;在圆柱面的参数化空间定义2D曲线,包括椭圆弧和线段;使用BRepBuilderAPI_MakeEdge和BRepBuilderAPI_MakeWire类构建边缘和导线;调用BRepLib::BuildCurves3d方法计算3D曲线,通过BRepOffsetAPI_ThruSections类创建螺纹实体。
    • 构建最终组合体:运用TopoDS_Compound和BRep_Builder类将瓶身和螺纹组合成单一形状,完成瓶子建模。
  4. 附录:给出了MakeBottle函数的完整定义,展示了整个建模过程在代码层面的实现细节。

关键知识点

几何和拓扑

在OCC中,几何和拓扑经常成对出现。例如:

    // Profile : Define the Geometry
    Handle(Geom_TrimmedCurve) anArcOfCircle = GC_MakeArcOfCircle(aPnt2,aPnt3,aPnt4);
    Handle(Geom_TrimmedCurve) aSegment1 = GC_MakeSegment(aPnt1, aPnt2);
    Handle(Geom_TrimmedCurve) aSegment2 = GC_MakeSegment(aPnt4, aPnt5);
 
    // Profile : Define the Topology
    TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aSegment1);
    TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(anArcOfCircle);
    TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge(aSegment2);
    TopoDS_Wire aWire  = BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3);

OpenCasCade是一个开源的CAD/CAM/CAE几何建模内核,它广泛应用于各种工业设计和工程领域。在OpenCasCade中,几何(Geometry)和拓扑(Topology)是两个核心概念,它们紧密相关且相互协作,共同构成了复杂的三维模型表示。以下从基本概念、相互关系和协同工作机制几个方面介绍它们的关系:

基本概念

  • 几何:几何主要关注的是物体的形状和尺寸等数学描述。在OpenCasCade中,几何元素由精确的数学方程定义,用于表示点、线、面、体等基本形状。例如,一个点可以用三维空间中的坐标 ( x , y , z ) (x, y, z) (x,y,z) 来表示;一条直线可以用线性方程描述;一个平面可以用平面方程表示;而像圆柱、圆锥等复杂曲面则由更复杂的数学函数来定义。几何元素提供了模型的精确几何信息,是构建模型的基础。
  • 拓扑:拓扑关注的是几何元素之间的连接关系和相对位置,而不考虑具体的形状和尺寸。OpenCasCade中的拓扑元素包括顶点(Vertex)、边(Edge)、面(Face)、壳(Shell)、体(Solid)等。例如,一个边连接两个顶点,一个面由多条边围成,一个体由多个面组成。拓扑结构定义了几何元素之间的邻接关系和层次结构,它描述了模型的整体结构和组织方式。

相互关系

  • 拓扑依赖于几何:拓扑元素需要基于几何元素来定义其具体形状。例如,一个拓扑边(TopoDS_Edge)必须依赖于一个几何曲线(如Geom_Line、Geom_Circle等)来确定其在空间中的形状和位置。没有几何曲线的支持,拓扑边就只是一个抽象的连接关系,没有实际的形状。同样,一个拓扑面(TopoDS_Face)需要基于一个几何曲面(如Geom_Plane、Geom_CylindricalSurface等)来定义其表面形状。
  • 几何通过拓扑组织:几何元素通过拓扑结构进行组织和管理,形成复杂的三维模型。拓扑结构为几何元素提供了一种结构化的表示方式,使得可以方便地对模型进行操作和分析。例如,通过拓扑结构可以快速找到与某个面相邻的其他面,或者找到组成一个体的所有面。这种组织方式使得模型的构建、修改和查询更加高效和灵活。

协同工作机制

  • 模型构建:在创建三维模型时,首先需要定义几何元素,如点、线、面等,然后通过拓扑结构将这些几何元素组合起来。例如,要创建一个立方体,需要先定义六个平面作为几何元素,然后通过拓扑结构将这些平面连接起来,形成一个封闭的体。在OpenCasCade中,可以使用各种API来完成这些操作,如BRepBuilderAPI_MakeEdge用于创建拓扑边,BRepBuilderAPI_MakeFace用于创建拓扑面,BRepPrimAPI_MakeBox用于创建立方体等基本体素。
  • 模型操作:在对模型进行操作(如平移、旋转、缩放、布尔运算等)时,几何和拓扑需要协同工作。例如,在进行布尔运算(如并、交、差)时,不仅要对几何形状进行计算,还要更新拓扑结构以反映新的连接关系。OpenCasCade提供了一系列的算法和工具来处理这些操作,确保几何和拓扑的一致性。
  • 模型分析:在对模型进行分析(如计算体积、表面积、曲率等)时,需要同时利用几何和拓扑信息。例如,计算一个体的体积需要知道其表面的几何形状和拓扑结构,通过对各个面的积分来得到体积值。OpenCasCade提供了各种分析工具和算法,利用几何和拓扑信息来完成这些计算任务。

示例代码说明

以下是一个简单的OpenCasCade代码示例,展示了如何创建一个简单的拓扑边并关联几何曲线:

#include <gp_Pnt.hxx>
#include <GC_MakeSegment.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <TopoDS_Edge.hxx>

int main() {
    // 定义两个点作为几何信息
    gp_Pnt p1(0, 0, 0);
    gp_Pnt p2(10, 0, 0);

    // 创建一个几何线段
    Handle(Geom_TrimmedCurve) segment = GC_MakeSegment(p1, p2);

    // 基于几何线段创建一个拓扑边
    BRepBuilderAPI_MakeEdge edgeBuilder(segment);
    TopoDS_Edge edge = edgeBuilder.Edge();

    return 0;
}

在这个示例中,首先定义了两个点 p1p2,然后使用 GC_MakeSegment 创建了一个几何线段。接着,使用 BRepBuilderAPI_MakeEdge 基于这个几何线段创建了一个拓扑边。这体现了几何和拓扑的紧密结合,几何为拓扑提供了具体的形状信息,而拓扑则将几何元素组织成有意义的结构。

拓扑数据结构的遍历

在 OpenCasCade 这个开源的 CAD/CAM/CAE 几何建模内核中,TopExp_Explorer 类是一个非常重要的工具,主要用于遍历拓扑数据结构中的元素。下面将从其功能、成员函数、工作原理以及使用示例等方面进行详细介绍。

功能概述

TopExp_Explorer 类的核心功能是对 OpenCasCade 中的拓扑数据结构(如 TopoDS_Shape 及其派生类)进行遍历操作。通过该类,可以方便地访问拓扑形状中的各种拓扑元素,例如顶点(TopAbs_VERTEX)、边(TopAbs_EDGE)、面(TopAbs_FACE)等,这在模型分析、修改以及布尔运算等操作中非常有用。

成员函数

  • 构造函数
    • TopExp_Explorer(const TopoDS_Shape& S, const TopAbs_ShapeEnum ToFind, const TopAbs_ShapeEnum ToAvoid = TopAbs_SHAPE):初始化一个 TopExp_Explorer 对象,用于遍历形状 S 中类型为 ToFind 的拓扑元素,同时可以选择跳过类型为 ToAvoid 的元素。
  • 遍历控制函数
    • Standard_Boolean More():检查是否还有更多的元素可供遍历。如果还有未访问的元素,返回 Standard_True;否则返回 Standard_False
    • void Next():将迭代器移动到下一个元素。
  • 元素访问函数
    • const TopoDS_Shape& Current():返回当前正在访问的拓扑元素。

工作原理

TopExp_Explorer 类通过维护一个内部的迭代器来实现对拓扑形状的遍历。当创建 TopExp_Explorer 对象时,它会根据指定的形状和要查找的元素类型进行初始化。在调用 More() 函数时,它会检查是否还有未访问的元素;调用 Next() 函数时,迭代器会移动到下一个元素;而 Current() 函数则返回当前迭代器指向的元素。

使用示例

以下是一个简单的示例,展示了如何使用 TopExp_Explorer 类来遍历一个拓扑形状中的所有边:

#include <TopoDS_Shape.hxx>
#include <TopExp_Explorer.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <iostream>

int main() {
    // 创建一个立方体形状
    BRepPrimAPI_MakeBox boxMaker(10.0, 10.0, 10.0);
    TopoDS_Shape box = boxMaker.Shape();

    // 创建一个 TopExp_Explorer 对象,用于遍历立方体中的所有边
    TopExp_Explorer edgeExplorer(box, TopAbs_EDGE);

    // 遍历所有边并输出边的数量
    int edgeCount = 0;
    for (; edgeExplorer.More(); edgeExplorer.Next()) {
        // 获取当前边
        const TopoDS_Shape& currentEdge = edgeExplorer.Current();
        edgeCount++;
    }

    std::cout << "The number of edges in the box is: " << edgeCount << std::endl;

    return 0;
}

代码解释

  1. 创建拓扑形状:使用 BRepPrimAPI_MakeBox 类创建一个立方体形状。
  2. 初始化 TopExp_Explorer 对象:创建一个 TopExp_Explorer 对象 edgeExplorer,指定要遍历的形状为立方体 box,要查找的元素类型为 TopAbs_EDGE(即边)。
  3. 遍历拓扑元素:使用 for 循环结合 More()Next() 函数遍历立方体中的所有边。在每次循环中,使用 Current() 函数获取当前正在访问的边。
  4. 输出结果:统计边的数量并输出。

通过这个示例,可以看到 TopExp_Explorer 类提供了一种简单而有效的方式来遍历拓扑形状中的元素,方便进行各种拓扑分析和操作。

创建螺旋线720度

这里的重点是如何创建720度的螺旋线。先看看官方的代码,然后逐行解释,最后是关键点的分析。

    myBody = aSolidMaker.Shape();
    // Threading : Create Surfaces
    Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
    Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);
 
    // Threading : Define 2D Curves
    gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
    gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
    gp_Ax2d anAx2d(aPnt, aDir);
 
    Standard_Real aMajor = 2. * M_PI;
    Standard_Real aMinor = myNeckHeight / 10;
 
    Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
    Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4);
    Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
    Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);
    gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
    gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI);
 
    Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);
    // Threading : Build Edges and Wires
    TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
    TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
    TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2);
    TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2);
    TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
    TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2);
    BRepLib::BuildCurves3d(threadingWire1);
    BRepLib::BuildCurves3d(threadingWire2);
 
    // Create Threading 
    BRepOffsetAPI_ThruSections aTool(Standard_True);
    aTool.AddWire(threadingWire1);
    aTool.AddWire(threadingWire2);
    aTool.CheckCompatibility(Standard_False);
 
    TopoDS_Shape myThreading = aTool.Shape();

代码注释

对上面的代码进行解释。

1. 获取瓶身实体
myBody = aSolidMaker.Shape();

这行代码的作用是从 aSolidMaker 对象中获取最终的瓶身实体形状,并将其赋值给 myBody 变量。aSolidMaker 通常是之前用于构建瓶身的操作对象,比如可能是通过拉伸、布尔运算等操作来创建瓶身的类实例。

2. 创建螺纹所需的圆柱面
Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);
  • 这里创建了两个 Geom_CylindricalSurface 类型的圆柱面对象 aCyl1aCyl2
  • neckAx2 是一个 gp_Ax2 类型的对象,它定义了圆柱面的位置和方向(轴)。
  • myNeckRadius 是瓶颈的半径,aCyl1 的半径为 myNeckRadius * 0.99aCyl2 的半径为 myNeckRadius * 1.05,这两个不同半径的圆柱面将用于后续定义螺纹的内外边界。
3. 定义二维曲线
gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
gp_Ax2d anAx2d(aPnt, aDir);

Standard_Real aMajor = 2. * M_PI;
Standard_Real aMinor = myNeckHeight / 10;

Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4);
Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);
gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI);

Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);
  • 定义局部坐标系
    • gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.); 定义了一个二维点 aPnt,作为局部坐标系的原点。
    • gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.); 定义了一个二维方向 aDir
    • gp_Ax2d anAx2d(aPnt, aDir); 基于上述点和方向创建了一个二维坐标系 anAx2d
  • 创建椭圆曲线
    • aMajoraMinor 分别表示椭圆的长半轴和短半轴。
    • anEllipse1anEllipse2 是两个不同短半轴的椭圆曲线,它们都基于 anAx2d 坐标系。
  • 截取椭圆弧
    • anArc1anArc2 分别是从 anEllipse1anEllipse2 上截取的 0 到 π \pi π 范围内的椭圆弧。
  • 创建线段
    • anEllipsePnt1anEllipsePnt2anEllipse1 上参数为 0 和 π \pi π 的点。
    • aSegment 是连接这两个点的线段。
4. 构建边缘和导线
TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2);
TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2);
TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2);
BRepLib::BuildCurves3d(threadingWire1);
BRepLib::BuildCurves3d(threadingWire2);
  • 创建边缘
    • BRepBuilderAPI_MakeEdge 用于将二维曲线(如椭圆弧和线段)映射到三维圆柱面上,创建对应的拓扑边缘。例如,anEdge1OnSurf1 是将椭圆弧 anArc1 映射到圆柱面 aCyl1 上得到的边缘。
  • 创建导线
    • BRepBuilderAPI_MakeWire 用于将多个边缘组合成一个导线。threadingWire1threadingWire2 分别是由两个边缘组合而成的导线。
  • 计算三维曲线
    • BRepLib::BuildCurves3d 用于为导线中的边缘计算三维曲线,确保导线在三维空间中有明确的几何表示。
5. 创建螺纹实体
BRepOffsetAPI_ThruSections aTool(Standard_True);
aTool.AddWire(threadingWire1);
aTool.AddWire(threadingWire2);
aTool.CheckCompatibility(Standard_False);

TopoDS_Shape myThreading = aTool.Shape();
  • 创建放样工具
    • BRepOffsetAPI_ThruSections 是一个用于通过一系列导线创建实体的工具类,Standard_True 表示创建封闭的实体。
  • 添加导线
    • aTool.AddWire(threadingWire1)aTool.AddWire(threadingWire2) 将之前创建的两个导线添加到放样工具中。
  • 检查兼容性
    • aTool.CheckCompatibility(Standard_False) 表示不进行导线之间的兼容性检查。
  • 获取螺纹实体
    • aTool.Shape() 调用工具类的 Shape 方法,生成最终的螺纹实体,并将其赋值给 myThreading 变量。

综上所述,这段代码通过创建圆柱面、定义二维曲线、构建边缘和导线,最后使用放样工具创建了瓶子瓶颈部分的螺纹实体。

720度

在这里插入图片描述
圆柱面本身展开是360度的,也就是2PI,但圆柱面本身是无穷的,或者说越过了2PI,就又从0开始了。上面这个二维空间需要一定的想象能力,是把圆柱展开了两次。
在这里插入图片描述
在这个二维空间进行绘制的结果如上图,代码如下:

    Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
    Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
    gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
    gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI);
    Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);

在这里插入图片描述
把上述二维的线投到圆柱面的结果如上图所示,代码如下:

    // Threading : Build Edges and Wires
    TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
    TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
    TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
    BRepLib::BuildCurves3d(threadingWire1);

相关文章:

  • 【金融量化】Ptrade中交易环境支持的业务类型
  • Compose Multiplatform开发记录之文件选择器封装
  • Rust 面向对象特性解析:对象、封装与继承
  • 手机号码归属地的实现
  • jwt 存在的无状态的安全问题与解决方案
  • 解锁高效编程:深度剖析C++11核心语法与标准库实战精要
  • python的运行--命令行
  • 安卓开发相机功能
  • Linux 下查看 CPU 使用率
  • Springboot中,Mybatis集成PageHelper进行分页
  • Redis 指令备忘清单(超级详细!)
  • 【文献阅读】The Efficiency Spectrum of Large Language Models: An Algorithmic Survey
  • 任务9:交换机基础及配置
  • JavaEE_多线程(一)
  • ESP32 IDF的触摸按键例子
  • word如何跳过封面、目录,从正文开始设置页码
  • JVM常用概念之对象初始化的成本
  • 每日OJ_牛客_游游的字母串_枚举_C++_Java
  • StarRocks-fe工程在Cursor中不能识别为Java项目
  • Html5学习教程,从入门到精通,HTML `<div>` 和 `<span>` 标签:语法知识点与案例代码(12)
  • 做网站和做推广有什么区别/seo关键词优化推广报价表
  • wordpress 中文 图片/南昌seo搜索排名
  • 网络营销策划的基本原则是什么/seo技术培训宁波
  • 网站建设与管理培训活动总结/朋友圈推广怎么收费
  • 网站设计字体最好用/苏州seo关键词优化价格
  • 公司网站的设计与实现/长沙电商优化