Modeling Bottle Tutorial

Overview概述

This tutorial will teach you how to use Open CASCADE Technology services to model a 3D object. The purpose of this tutorial is not to describe all Open CASCADE Technology classes but to help you start thinking in terms of Open CASCADE Technology as a tool.

本教程将教你如何使用Open CASCADE Technology服务来建模3D对象。本教程的目的不是描述Open CASCADE Technology的所有类,而是帮助您开始将Open CASCADE Technology作为一种工具进行思考。

Prerequisites前提

This tutorial assumes that you have experience in using and setting up C++. From a programming standpoint, Open CASCADE Technology is designed to enhance your C++ tools with 3D modeling classes, methods and functions. The combination of all these resources will allow you to create substantial applications.

本教程假设您具有使用和安装C++的经验。从编程的角度来看,Open CASCADE Technology旨在通过3D建模类、方法和函数来增强您的C++工具。整合这些资源可以帮助您创建有价值的应用程序。

The Model模型

To illustrate the use of classes provided in the 3D geometric modeling toolkits, you will create a bottle as shown:

为了说明如何使用3D几何建模工具包中提供的类,我们将创建一个瓶子,如图所示:

In the tutorial we will create, step-by-step, a function that will model a bottle as shown above. You will find the complete source code of this tutorial, including the very function MakeBottle in the distribution of Open CASCADE Technology. The function body is provided in the file samples/qt/Tutorial/src/MakeBottle.cxx.

在本教程中,我们将一步一步地完成一个函数,该函数将对上图中示的瓶子进行建模。您可以找到本教程的完整源代码,包括Open CASCADE Technology发行版中的MakeBottle函数。该函数实现在文件samples/qt/Tutorial/src/MakeBottle.cxx中。

Model Specifications模型规格

We first define the bottle specifications as follows:

我们首先定义瓶子的规格如下:

Object ParameterParameter NameParameter Value

Bottle height

MyHeight

70mm

Bottle width

MyWidth

50mm

Bottle thickness

MyThickness

30mm

In addition, we decide that the bottle's profile (base) will be centered on the origin of the global Cartesian coordinate system.

此外,我们希望瓶子的轮廓(底座)以全局笛卡尔坐标系的原点为中心。

This modeling requires four steps:

建模包括四个步骤:

  • build the bottle's Profile

  • 构建瓶子的轮廓

  • build the bottle's Body

  • 构建瓶身

  • build the Threading on the bottle's neck

  • 构建瓶口上的螺纹

  • build the result compound

  • 构建组合结果

Building the Profile构建瓶子的轮廓

Defining Support Points定义支撑点

To create the bottle's profile, you first create characteristic points with their coordinates as shown below in the (XOY) plane. These points will be the supports that define the geometry of the profile.

要创建瓶子的轮廓,首先要在(XOY)平面中创建特征点及其坐标,如下所示。这些点将作为支撑来定义轮廓的几何形状。

There are two classes to describe a 3D Cartesian point from its X, Y and Z coordinates in Open CASCADE Technology:

在Open CASCADE Technology中,从X, Y和Z坐标描述三维笛卡尔点有两个类:

  • the primitive geometric gp_Pnt class

  • 原始几何类gp_Pnt

  • the transient Geom_CartesianPoint class manipulated by handle

  • 由句柄操纵的瞬态类Geom_CartesianPoint

A handle is a type of smart pointer that provides automatic memory management. To choose the best class for this application, consider the following:

句柄是一种提供自动内存管理的智能指针。要为此应用程序选择最佳类,请考虑以下因素:

  • gp_Pnt is manipulated by value. Like all objects of its kind, it will have a limited lifetime.

  • gp_Pnt由值操作。像所有同类的物体一样,它的生命周期是有限的。

  • Geom_CartesianPoint is manipulated by handle and may have multiple references and a long lifetime.

  • Geom_CartesianPoint由句柄操纵,可以有多个引用和很长的生命周期。

Since all the points you will define are only used to create the profile's curves, an object with a limited lifetime will do. Choose the gp_Pnt class. To instantiate a gp_Pnt object, just specify the X, Y, and Z coordinates of the points in the global Cartesian coordinate system:

因为你将定义的所有点只用于创建轮廓的曲线,所以具有有限生命周期的对象就可以了。选择gp_Pnt类。要实例化一个gp_Pnt对象,只需在全局笛卡尔坐标系中指定点的X, Y和Z坐标:

gp_Pnt aPnt1(-myWidth / 2., 0, 0);
gp_Pnt aPnt2(-myWidth / 2., -myThickness / 4., 0);
gp_Pnt aPnt3(0, -myThickness / 2., 0);
gp_Pnt aPnt4(myWidth / 2., -myThickness / 4., 0);
gp_Pnt aPnt5(myWidth / 2., 0, 0);

Once your objects are instantiated, you can use methods provided by the class to access and modify its data. For example, to get the X coordinate of a point:

对象实例化后,就可以使用类提供的方法来访问和修改其数据。例如,要获取一个点的X坐标:

Standard_Real xValue1 = aPnt1.X();

Profile: Defining the Geometry轮廓:定义几何形状

With the help of the previously defined points, you can compute a part of the bottle's profile geometry. As shown in the figure below, it will consist of two segments and one arc.

使用前面定义的点,您可以计算一部分瓶子的轮廓几何形状。如下图所示,由两个直线段和一个弧线段组成。

To create such entities, you need a specific data structure, which implements 3D geometric objects. This can be found in the Geom package of Open CASCADE Technology. In Open CASCADE Technology a package is a group of classes providing related functionality. The classes have names that start with the name of a package they belong to. For example, Geom_Line and Geom_Circle classes belong to the Geom package. The Geom package implements 3D geometric objects: elementary curves and surfaces are provided as well as more complex ones (such as Bezier and BSpline). However, the Geom package provides only the data structure of geometric entities. You can directly instantiate classes belonging to Geom, but it is easier to compute elementary curves and surfaces by using the GC package. This is because the GC provides two algorithm classes which are exactly what is required for our profile:

要创建这样的实体,您需要一个实现了3D几何对象的特定数据结构。它可以在Open CASCADE Technology的Geom包中找到。在Open CASCADE Technology中,包是一组提供相关功能的类。类的名称以它们所属的包的名称开头。例如,Geom_LineGeom_Circle类属于Geom包。Geom包实现3D几何对象:提供基本曲线和曲面以及更复杂的曲线和曲面(如BezierBSpline)。但是,Geom包只提供几何实体的数据结构。您可以直接实例化属于Geom的类,但使用GC包计算基本曲线和曲面更容易。这是因为GC提供了两个算法类,这正是我们的轮廓所需要的:

  • Class GC_MakeSegment to create a segment. One of its constructors allows you to define a segment by two end points P1 and P2

  • GC_MakesSegment创建一个直线段。有一个构造函数可通过两个端点P1和P2构建一个直线段。

  • Class GC_MakeArcOfCircle to create an arc of a circle. A useful constructor creates an arc from two end points P1 and P3 and going through P2.

  • GC_MakeArcOfCircle创建一个圆的弧线段。有一个构造函数可以从两个端点P1和P3到P2创建一个弧线段。

Both of these classes return a Geom_TrimmedCurve manipulated by handle. This entity represents a base curve (line or circle, in our case), limited between two of its parameter values. For example, circle C is parameterized between 0 and 2PI. If you need to create a quarter of a circle, you create a Geom_TrimmedCurve on C limited between 0 and M_PI/2.

这两个类都返回一个由句柄操纵的Geom_TrimmedCurve。这个实体表示一条由2个参数值约束的基本曲线(在我们的例子中是直线或圆)。例如,圆C在0到2PI之间参数化。如果你需要创建一个圆的四分之一,你可以在C上创建一个Geom_TrimmedCurve,限制在0和M_PI/2之间。

Handle(Geom_TrimmedCurve) aArcOfCircle = GC_MakeArcOfCircle(aPnt2,aPnt3,aPnt4);
Handle(Geom_TrimmedCurve) aSegment1    = GC_MakeSegment(aPnt1, aPnt2);
Handle(Geom_TrimmedCurve) aSegment2    = GC_MakeSegment(aPnt4, aPnt5);

All GC classes provide a casting method to obtain a result automatically with a function-like call. Note that this method will raise an exception if construction has failed. To handle possible errors more explicitly, you may use the IsDone and Value methods. For example:

所有GC类都提供了一个类型转换方法,通过类似函数的调用自动获得结果。请注意,如果构造失败,此方法将引发异常。要更显式地处理可能的错误,您可以使用IsDoneValue方法。例如:

GC_MakeSegment mkSeg (aPnt1, aPnt2);
Handle(Geom_TrimmedCurve) aSegment1;
if(mkSegment.IsDone()){
    aSegment1 = mkSeg.Value();
}
else {
// handle error
}

Profile: Defining the Topology轮廓:定义拓扑

You have created the support geometry of one part of the profile but these curves are independent with no relations between each other. To simplify the modeling, it would be right to manipulate these three curves as a single entity. This can be done by using the topological data structure of Open CASCADE Technology defined in the TopoDS package: it defines relationships between geometric entities which can be linked together to represent complex shapes. Each object of the TopoDS package, inheriting from the TopoDS_Shape class, describes a topological shape as described below:

我们已经创建了一部分轮廓的基础几何形状,但这些曲线是独立的,彼此之间没有关系。为了简化建模,可以将这三条曲线作为一个实体来操作。这可以通过使用TopoDS包中定义的Open CASCADE Technology的拓扑数据结构来实现:它定义了将各种几何实体连接在一起表示复杂形状的关系。TopoDS包的每个对象,继承自TopoDS_Shape类,各个对象所描述的拓扑形状如下表:

ShapeOpen CASCADE Technology ClassDescription

Vertex顶点

TopoDS_Vertex

Zero dimensional shape corresponding to a point in geometry.零维形状,一个点。

Edge边

TopoDS_Edge

One-dimensional shape corresponding to a curve and bounded by a vertex at each extremity.一维形状,一条曲线,在每一端都有一个顶点。

Wire线条

TopoDS_Wire

Sequence of edges connected by vertices.由顶点连接的边序列。

Face面

TopoDS_Face

Part of a surface bounded by a closed wire(s).,由封闭的线条围起来的面。

Shell壳

TopoDS_Shell

Set of faces connected by edges.由边连接的面的集合。

Solid实体

TopoDS_Solid

Part of 3D space bounded by Shells.由shell包围的3D空间。

CompSolid组合实体

TopoDS_CompSolid

Set of solids connected by their faces.由面相连的一组实体。

Compound组合形状

TopoDS_Compound

Set of any other shapes described above.上述任何其他形状的集合。

Referring to the previous table, to build the profile, you will create:

参考上表,要构建轮廓,需创建:

  • Three edges out of the previously computed curves.

  • 用先前计算的曲线构建三条边。

  • One wire with these edges.

  • 用这三条边构建一根线条。

However, the TopoDS package provides only the data structure of the topological entities. Algorithm classes available to compute standard topological objects can be found in the BRepBuilderAPI package. To create an edge, you use the BRepBuilderAPI_MakeEdge class with the previously computed curves:

但是,TopoDS包只提供拓扑实体的数据结构。可用于计算标准拓扑对象的算法类可以在BRepBuilderAPI包中找到。要创建一条边,你可以使用BRepBuilderAPI_MakeEdge类和之前计算的曲线:

TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aSegment1);
TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle);
TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge(aSegment2);

In Open CASCADE Technology, you can create edges in several ways. One possibility is to create an edge directly from two points, in which case the underlying geometry of this edge is a line, bounded by two vertices being automatically computed from the two input points. For example, anEdge1 and anEdge3 could have been computed in a simpler way:

在Open CASCADE Technology中,您可以通过几种方式创建边。一种方法是直接从两个点创建一条边,在这种情况下,这条边的底层几何形状是一条直线,由两个从两个输入点自动计算的两个顶点作为边界。例如,anEdge1和anEdge3可以用一种更简单的方式计算:

TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aPnt1, aPnt3);
TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(aPnt4, aPnt5);

To connect the edges, you need to create a wire with the BRepBuilderAPI_MakeWire class. There are two ways of building a wire with this class:

为了连接这些边,您需要使用BRepBuilderAPI_MakeWire类创建一条线条。有两种方法可以用这个类构建一个线条:

  • directly from one to four edges

  • 直接用一到四条边创建

  • by adding other wire(s) or edge(s) to an existing wire (this is explained later in this tutorial)

  • 通过在现有线条上添加其他线条或边(本教程稍后将对此进行解释)

When building a wire from less than four edges, as in the present case, you can use the constructor directly as follows:

当从少于四条边构建一条线条时,就像在本例中一样,你可以直接使用构造函数,如下所示:

TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3);

Profile: Completing the Profile轮廓:完成轮廓

Once the first part of your wire is created you need to compute the complete profile. A simple way to do this is to:

一旦创建了线条的第一部分,就需要计算完整的轮廓。一个简单的方法是:

  • compute a new wire by reflecting the existing one.

  • 通过镜像现有的线条来计算新的线条。

  • add the reflected wire to the initial one.

  • 将镜像的线条添加到初始线条。

To apply a transformation on shapes (including wires), you first need to define the properties of a 3D geometric transformation by using the gp_Trsf class. This transformation can be a translation, a rotation, a scale, a reflection, or a combination of these. In our case, we need to define a reflection with respect to the X axis of the global coordinate system. An axis, defined with the gp_Ax1 class, is built out of a point and has a direction (3D unitary vector). There are two ways to define this axis. The first way is to define it from scratch, using its geometric definition:

要对形状(包括线条)应用转换,首先需要使用gp_Trsf类定义3D几何转换的属性。这种变换可以是平移、旋转、缩放、镜像或这些的组合。在我们的例子中,我们需要定义一个关于全局坐标系X轴的反射。用gp_Ax1类定义的轴由一个点构建,并具有一个方向(3D单位向量)。有两种方法来定义这个轴。第一种方法是从头开始定义它,使用它的几何定义:

  • X axis is located at (0, 0, 0) - use the gp_Pnt class.

  • X轴位于(0,0,0)-使用gp_Pnt类。

  • X axis direction is (1, 0, 0) - use the gp_Dir class. A gp_Dir instance is created out of its X, Y and Z coordinates.

  • X轴方向为(1,0,0)-使用gp_Dir类。一个gp_Dir实例是根据它的X, Y和Z坐标创建的。

gp_Pnt aOrigin(0, 0, 0);
gp_Dir xDir(1, 0, 0);
gp_Ax1 xAxis(aOrigin, xDir);

The second and simplest way is to use the geometric constants defined in the gp package (origin, main directions and axis of the global coordinate system). To get the X axis, just call the gp::OX method:

第二种也是最简单的方法是使用gp包中定义的几何常数(全局坐标系的原点、主方向和轴)。要获取X轴,只需调用gp::OX方法:

gp_Ax1 xAxis = gp::OX();

As previously explained, the 3D geometric transformation is defined with the gp_Trsf class. There are two different ways to use this class:

如前所述,3D几何变换是用gp_Trsf类定义的。有两种不同的方法来使用这个类:

  • by defining a transformation matrix by all its values

  • 通过矩阵的所有值定义一个变换矩阵

  • by using the appropriate methods corresponding to the required transformation (SetTranslation for a translation, SetMirror for a reflection, etc.): the matrix is automatically computed.

  • 通过使用与所需转换相对应的适当方法(SetTranslation用于平移,SetMirror用于镜像等):矩阵被自动计算。

Since the simplest approach is always the best one, you should use the SetMirror method with the axis as the center of symmetry.

因为最简单的方法总是最好的方法,所以你应该使用SetMirror方法,将轴作为对称的中心。

gp_Trsf aTrsf;
aTrsf.SetMirror(xAxis);

You now have all necessary data to apply the transformation with the BRepBuilderAPI_Transform class by specifying:

你现在有了所有必要的数据,通过指定BRepBuilderAPI_Transform类来应用转换:

  • the shape on which the transformation must be applied.

  • 被应用变换的形状。

  • the geometric transformation

  • 几何变换

BRepBuilderAPI_Transform aBRepTrsf(aWire, aTrsf);

BRepBuilderAPI_Transform does not modify the nature of the shape: the result of the reflected wire remains a wire. But the function-like call or the BRepBuilderAPI_Transform::Shape method returns a TopoDS_Shape object:

BRepBuilderAPI_Transform不修改原始形状:镜像线的结果仍然是线。但是函数式调用或BRepBuilderAPI_Transform::Shape方法返回一个TopoDS_Shape对象:

TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();

What you need is a method to consider the resulting reflected shape as a wire. The TopoDS global functions provide this kind of service by casting a shape into its real type. To cast the transformed wire, use the TopoDS::Wire method.

您需要一种方法,将得到的反射形状转换成线条。TopoDS全局函数通过将形状转换为其实际类型来提供这种服务。要转换转换后的连线,请使用*TopoDS:: wire *方法。

TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);

The bottle's profile is almost finished. You have created two wires: aWire and aMirroredWire. You need to concatenate them to compute a single shape. To do this, you use the BRepBuilderAPI_MakeWire class as follows:

瓶子的轮廓块完成了。您已经创建了两条线条:aWireaMirroredWire。您需要将它们连接起来以计算单个形状。要做到这一点,你可以像下面这样使用BRepBuilderAPI_MakeWire类:

  • create an instance of BRepBuilderAPI_MakeWire.

  • 创建一个BRepBuilderAPI_MakeWire实例。

  • add all edges of the two wires by using the Add method on this object.

  • 使用这个对象的add方法添加两根线条的所有边。

BRepBuilderAPI_MakeWire mkWire;
mkWire.Add(aWire);
mkWire.Add(aMirroredWire);
TopoDS_Wire myWireProfile = mkWire.Wire();

Building the Body构建瓶身

Prism the Profile扫描轮廓

To compute the main body of the bottle, you need to create a solid shape. The simplest way is to use the previously created profile and sweep it along a direction. The Prism functionality of Open CASCADE Technology is the most appropriate for that task. It accepts a shape and a direction as input and generates a new shape according to the following rules:

为了计算瓶子的主体,你需要创建一个实体形状。最简单的方法是使用前面创建的轮廓并沿着一个方向扫描它。Open CASCADE Technology的Prism功能最适合该任务。它使用一个形状和一个方向作为输入,并根据以下规则生成一个新的形状:

ShapeGenerates

Vertex

Edge

Edge

Face

Wire

Shell

Face

Solid

Shell

Compound of Solids

Your current profile is a wire. Referring to the Shape/Generates table, you need to compute a face out of its wire to generate a solid. To create a face, use the BRepBuilderAPI_MakeFace class. As previously explained, a face is a part of a surface bounded by a closed wire. Generally, BRepBuilderAPI_MakeFace computes a face out of a surface and one or more wires. When the wire lies on a plane, the surface is automatically computed.

你现在的轮廓是一根线条。参考Shape/ generate表,我们用线条计算出一个面从而生成一个实体。要创建一个面,使用BRepBuilderAPI_MakeFace类。如前所述,面是表面的一部分,由封闭的线条围起来。一般来说,BRepBuilderAPI_MakeFace从一个表面和一条或多条线条中计算出一个面。当线条位于一个平面上时,该平面将自动计算。

TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile);

The BRepPrimAPI package provides all the classes to create topological primitive constructions: boxes, cones, cylinders, spheres, etc. Among them is the BRepPrimAPI_MakePrism class. As specified above, the prism is defined by:

BRepPrimAPI包提供了创建拓扑基本结构的所有类:盒,锥,圆柱体,球体等。其中包括BRepPrimAPI_MakePrism类。如上所述,扫描体定义为:

  • the basis shape to sweep;

  • 被扫描的基础形状;

  • a vector for a finite prism or a direction for finite and infinite prisms.

  • 有限扫描体的向量或有限和无限扫描体的方向。

You want the solid to be finite, swept along the Z axis and to be myHeight height. The vector, defined with the gp_Vec class on its X, Y and Z coordinates, is:

你希望这个实体是有限的,沿着Z轴扫过,高度为myHeight。在X, Y和Z坐标上用gp_Vec类定义的向量为:

gp_Vec aPrismVec(0, 0, myHeight);

All the necessary data to create the main body of your bottle is now available. Just apply the BRepPrimAPI_MakePrism class to compute the solid:

创建瓶子主体所需的所有数据都准备好了,只需应用BRepPrimAPI_MakePrism类来计算实体:

TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec);

Applying Fillets应用圆角

The edges of the bottle's body are very sharp. To replace them by rounded faces, you use the Fillet functionality of Open CASCADE Technology. For our purposes, we will specify that fillets must be:

瓶身的边缘很尖锐。要将它们替换为圆滑的面,您可以使用Open CASCADE Technology的Fillet功能。为了达到我们的目的,我们需指定圆角:

  • applied on all edges of the shape

  • 应用于形状的所有边缘

  • have a radius of myThickness / 12

  • 半径为myThickness / 12

To apply fillets on the edges of a shape, you use the BRepFilletAPI_MakeFillet class. This class is normally used as follows:

要在形状的所有边应用圆角,可以使用BRepFilletAPI_MakeFillet类。这个类通常按如下使用:

  • Specify the shape to be filleted in the BRepFilletAPI_MakeFillet constructor.

  • BRepFilletAPI_MakeFillet构造函数中指定要圆角的形状。

  • Add the fillet descriptions (an edge and a radius) using the Add method (you can add as many edges as you need).

  • 使用Add方法添加圆角描述(边缘和半径)(您可以根据需要添加尽可能多的边缘)。

  • Ask for the resulting filleted shape with the Shape method.

  • 使用shape方法得到的圆角形状。

BRepFilletAPI_MakeFillet mkFillet(myBody);

To add the fillet description, you need to know the edges belonging to your shape. The best solution is to explore your solid to retrieve its edges. This kind of functionality is provided with the TopExp_Explorer class, which explores the data structure described in a TopoDS_Shape and extracts the sub-shapes you specifically need. Generally, this explorer is created by providing the following information:

要添加圆角描述,您需要知道形状的边缘。最好的解决办法是遍历实体,找到它的边。这种功能由TopExp_Explorer类提供,该类遍历TopoDS_Shape中描述的数据结构并提取您特别需要的子形状。通常,这个遍历器可通过提供以下信息创建:

  • the shape to explore

  • 被遍历的形状

  • the type of sub-shapes to be found. This information is given with the TopAbs_ShapeEnum enumeration.

  • 要查找的子形状的类型。该信息通过TopAbs_ShapeEnum枚举给出。

TopExp_Explorer anEdgeExplorer(myBody, TopAbs_EDGE);

An explorer is usually applied in a loop by using its three main methods:

遍历器通常在循环中使用它的三个主要方法:

  • More() to know if there are more sub-shapes to explore.

  • *More()*知道是否有更多的子形状可以遍历。

  • Current() to know which is the currently explored sub-shape (used only if the More() method returns true).

  • *Current()知道哪个是当前遍历的子形状(仅当More()*方法返回true时使用)。

  • Next() to move onto the next sub-shape to explore.

  • *Next()*移动到下一个子形状进行遍历。

while(anEdgeExplorer.More()){
    TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current());
    //Add edge to fillet algorithm
    ...
    anEdgeExplorer.Next();
}

In the explorer loop, you have found all the edges of the bottle shape. Each one must then be added in the BRepFilletAPI_MakeFillet instance with the Add() method. Do not forget to specify the radius of the fillet along with it.

在遍历器循环中,您已经找到了瓶子形状的所有边。每一个都必须在BRepFilletAPI_MakeFillet实例中添加*Add()*方法。不要忘记指定圆角的半径。

mkFillet.Add(myThickness / 12., anEdge);

Once this is done, you perform the last step of the procedure by asking for the filleted shape.

遍历完成后,最后一步计算圆角形状。

myBody = mkFillet.Shape();

Adding the Neck添加瓶颈

To add a neck to the bottle, you will create a cylinder and fuse it to the body. The cylinder is to be positioned on the top face of the body with a radius of myThickness / 4. and a height of myHeight / 10.

现在给瓶子添加一个瓶颈,需要创建一个圆柱体并将其融合到瓶身上。圆柱体位于主体的上表面,半径为myThickness / 4。高度为myHeight / 10。

To position the cylinder, you need to define a coordinate system with the gp_Ax2 class defining a right-handed coordinate system from a point and two directions - the main (Z) axis direction and the X direction (the Y direction is computed from these two). To align the neck with the center of the top face, being in the global coordinate system (0, 0, myHeight), with its normal on the global Z axis, your local coordinate system can be defined as follows:

要定位圆柱体,需要使用gp_Ax2类定义一个坐标系统,该系统从一个点和两个方向(主(Z)轴方向和X方向)定义一个右手坐标系(Y方向由这两个方向计算)。在全局坐标系(0,0,myHeight)中,将颈部与顶面中心对齐,其法线在全局Z轴上,您的局部坐标系可以定义如下:

gp_Pnt neckLocation(0, 0, myHeight);
gp_Dir neckAxis = gp::DZ();
gp_Ax2 neckAx2(neckLocation, neckAxis);

To create a cylinder, use another class from the primitives construction package: the BRepPrimAPI_MakeCylinder class. The information you must provide is:

要创建圆柱体,要使用构造包中的另一个类:BRepPrimAPI_MakeCylinder类。需提供以下信息:

  • the coordinate system where the cylinder will be located;

  • 圆柱体所在的坐标系;

  • the radius and height.

  • 半径和高度。

Standard_Real myNeckRadius = myThickness / 4.;
Standard_Real myNeckHeight = myHeight / 10;
BRepPrimAPI_MakeCylinder MKCylinder(neckAx2, myNeckRadius, myNeckHeight);
TopoDS_Shape myNeck = MKCylinder.Shape();

You now have two separate parts: a main body and a neck that you need to fuse together. The BRepAlgoAPI package provides services to perform Boolean operations between shapes, and especially: common (Boolean intersection), cut (Boolean subtraction) and fuse (Boolean union). Use BRepAlgoAPI_Fuse to fuse the two shapes:

现在有两个独立的部分:一个主体和一个瓶颈,需要融合在一起。BRepAlgoAPI包提供了在形状之间执行布尔运算的服务,特别是:common(布尔交集),cut(布尔减法)和fuse(布尔联合)。使用BRepAlgoAPI_Fuse来融合两个形状:

myBody = BRepAlgoAPI_Fuse(myBody, myNeck);

Creating a Hollowed Solid创建一个空心实体

Since a real bottle is used to contain liquid material, you should now create a hollowed solid from the bottle's top face. In Open CASCADE Technology, a hollowed solid is called a Thick Solid and is internally computed as follows:

因为一个真正的瓶子是用来装液体的,你现在应该从瓶子的顶部创造一个中空的实体。在Open CASCADE Technology中,空心实体被称为“厚实体”,其内部计算如下:

  • Remove one or more faces from the initial solid to obtain the first wall W1 of the hollowed solid.

  • 从初始实体移除一个或多个面,以获得空心实体的第一个壁W1。

  • Create a parallel wall W2 from W1 at a distance D. If D is positive, W2 will be outside the initial solid, otherwise it will be inside.

  • 从W1到W2,在距离D处形成平行壁W2。如果D为正,则W2将在初始实体的外面,否则将在里面。

  • Compute a solid from the two walls W1 and W2.

  • 从两个壁W1和W2计算一个实体。

To compute a thick solid, you create an instance of the BRepOffsetAPI_MakeThickSolid class by giving the following information:

要计算一个厚实体,你需要创建一个BRepOffsetAPI_MakeThickSolid类的实例,并提供以下信息:

  • The shape, which must be hollowed.

  • 将被掏空的形状。

  • The tolerance used for the computation (tolerance criterion for coincidence in generated shapes).

  • 用于计算的公差(生成形状的一致性公差准则)。

  • The thickness between the two walls W1 and W2 (distance D).

  • 两壁W1和W2之间的厚度(距离D)。

  • The face(s) to be removed from the original solid to compute the first wall W1.

  • 要从原始实体中移除的面,用于计算第一面墙W1。

The challenging part in this procedure is to find the face to remove from your shape - the top face of the neck, which:

这个过程中最具挑战性的部分是找到要从形状中去除的面——瓶颈的顶面:

  • has a plane (planar surface) as underlying geometry;

  • 有一个平面(平面表面)作为底层几何形状;

  • is the highest face (in Z coordinates) of the bottle.

  • 是瓶子的最高面(在Z坐标中)。

To find the face with such characteristics, you will once again use an explorer to iterate on all the bottle's faces to find the appropriate one.

为了找到具有这些特征的面,您将再次使用遍历器迭代瓶子的所有面以找到合适的面。

for(TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE) ; aFaceExplorer.More() ; aFaceExplorer.Next()){
    TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current());
}

For each detected face, you need to access the geometric properties of the shape: use the BRep_Tool class for that. The most commonly used methods of this class are:

对于每个检测到的面,需要访问形状的几何属性:为此使用BRep_Tool类。这个类最常用的方法是:

  • Surface to access the surface of a face;

  • Surface访问一个面的表面;

  • Curve to access the 3D curve of an edge;

  • Curve访问某条边的3D曲线;

  • Point to access the 3D point of a vertex.

  • Point访问顶点的3D点。

Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);

As you can see, the BRep_Tool::Surface method returns an instance of the Geom_Surface class manipulated by handle. However, the Geom_Surface class does not provide information about the real type of the object aSurface, which could be an instance of Geom_Plane, Geom_CylindricalSurface, etc. All objects manipulated by handle, like Geom_Surface, inherit from the Standard_Transient class which provides two very useful methods concerning types:

如你所见,BRep_Tool::Surface方法返回一个由handle操纵的Geom_Surface类的实例。然而,Geom_Surface类不提供关于对象aSurface的实际类型的信息,它可以是Geom_PlaneGeom_CylindricalSurface 等的实例。所有由句柄操作的对象,如Geom_Surface*,都继承自*Standard_Transient类,该类提供了两个非常有用的关于类型的方法:

  • DynamicType to know the real type of the object

  • DynamicType获取对象的实际类型

  • IsKind to know if the object inherits from one particular type

  • IsKind查询对象是否继承了一个特定的类型

DynamicType returns the real type of the object, but you need to compare it with the existing known types to determine whether aSurface is a plane, a cylindrical surface or some other type. To compare a given type with the type you seek, use the STANDARD_TYPE macro, which returns the type of a class:

DynamicType返回对象的实际类型,但是您需要将它与现有的已知类型进行比较,以确定aSurface是平面、圆柱形表面还是其他类型。为了比较给定的类型和你所寻找的类型,使用STANDARD_TYPE宏,它返回一个类的类型:

if(aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)){
}

If this comparison is true, you know that the aSurface real type is Geom_Plane. You can then convert it from Geom_Surface to Geom_Plane by using the DownCast() method provided by each class inheriting Standard_Transient. As its name implies, this static method is used to downcast objects to a given type with the following syntax:

如果比较结果是真,那么aSurface的实际类型是Geom_Plane。然后你可以使用每个继承了Standard_Transient的类提供的DownCast()方法将它从Geom_Surface转换为Geom_Plane。顾名思义,这个静态方法使用以下语法将对象向下转换为给定类型:

Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface);

Remember that the goal of all these conversions is to find the highest face of the bottle lying on a plane. Suppose that you have these two global variables:

记住,所有这些转换的目标是找到瓶子在平面上的最高面。假设你有这两个全局变量:

TopoDS_Face faceToRemove;
Standard_Real zMax = -1;

You can easily find the plane whose origin is the biggest in Z knowing that the location of the plane is given with the Geom_Plane::Location method. For example:

你可以很容易地找到原点在Z上最大的平面,知道平面的位置是用Geom_Plane:: location方法给出的。例如:

gp_Pnt aPnt = aPlane->Location();
Standard_Real aZ = aPnt.Z();
if(aZ > zMax){
    zMax = aZ;
    faceToRemove = aFace;
}

You have now found the top face of the neck. Your final step before creating the hollowed solid is to put this face in a list. Since more than one face can be removed from the initial solid, the BRepOffsetAPI_MakeThickSolid constructor takes a list of faces as arguments. Open CASCADE Technology provides many collections for different kinds of objects: see TColGeom package for collections of objects from Geom package, TColgp package for collections of objects from gp package, etc. The collection for shapes can be found in the TopTools package. As BRepOffsetAPI_MakeThickSolid requires a list, use the TopTools_ListOfShape class.

现在你已经找到了瓶颈顶部的面。在创建空心实体之前的最后一步是将这个面放入列表中。由于可以从初始实体中删除多个面,因此BRepOffsetAPI_MakeThickSolid构造函数接受一个面列表作为参数。Open CASCADE Technology为不同类型的对象提供了许多集合:Geom 包中的对象集合参见TColGeom 包, gp包中的对象集合参见TColgp包,等等。形状的集合可以在TopTools包中找到。作为BRepOffsetAPI_MakeThickSolid需要一个列表,使用TopTools_ListOfShape类。

TopTools_ListOfShape facesToRemove;
facesToRemove.Append(faceToRemove);

All the necessary data are now available so you can create your hollowed solid by calling the BRepOffsetAPI_MakeThickSolid MakeThickSolidByJoin method:

所有必要的数据现在都准备好了,可以通过调用BRepOffsetAPI_MakeThickSolid MakeThickSolidByJoin方法来创建空心实体:

BRepOffsetAPI_MakeThickSolid aSolidMaker;
aSolidMaker.MakeThickSolidByJoin(myBody, facesToRemove, -myThickness / 50, 1.e-3);
myBody = aSolidMaker.Shape();

Building the Threading构建螺纹

Creating Surfaces创建表面

Up to now, you have learned how to create edges out of 3D curves. You will now learn how to create an edge out of a 2D curve and a surface. To learn this aspect of Open CASCADE Technology, you will build helicoidal profiles out of 2D curves on cylindrical surfaces. The theory is more complex than in previous steps, but applying it is very simple. As a first step, you compute these cylindrical surfaces. You are already familiar with the curves of the Geom package. Now you can create a cylindrical surface (Geom_CylindricalSurface) using:

到目前为止,您已经学习了如何从3D曲线中创建边。现在开始学习如何从2D曲线和一个表面创建边。要学习Open CASCADE Technology的这一方面,您将使用2D曲线在圆柱形表面上建立螺旋轮廓。这个理论比前面的步骤更复杂,但应用起来很简单。第一步,计算这些圆柱形表面。您已经熟悉了Geom包的曲线。现在你可以创建一个圆柱形表面(Geom_CylindricalSurface),使用如下信息:

  • a coordinate system;

  • 一个坐标系统;

  • a radius.

  • 一个半径。

Using the same coordinate system neckAx2 used to position the neck, you create two cylindrical surfaces Geom_CylindricalSurface with the following radii:

使用相同的坐标系统neckAx2用于定位瓶颈,创建两个圆柱形表面Geom_CylindricalSurface,半径如下:

Notice that one of the cylindrical surfaces is smaller than the neck. There is a good reason for this: after the thread creation, you will fuse it with the neck. So, we must make sure that the two shapes remain in contact.

注意其中一个圆柱形表面比瓶颈小。这样做有一个很好的理由:在创建螺纹之后,您将与瓶颈融合。因此,我们必须确保这两个形状保持接触。

Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);

Defining 2D Curves定义二维曲线

To create the neck of the bottle, you made a solid cylinder based on a cylindrical surface. You will create the profile of threading by creating 2D curves on such a surface. All geometries defined in the Geom package are parameterized. This means that each curve or surface from Geom is computed with a parametric equation. A Geom_CylindricalSurface surface is defined with the following parametric equation:

为了制作瓶颈,你基于圆柱形表面上构造了一个实心圆柱体。您将通过创建2D曲线在这中表面上创建螺纹轮廓。Geom包中定义的所有几何图形都是参数化的。这意味着Geom中的每条曲线或曲面都是用参数方程计算的。A Geom_CylindricalSurface曲面用如下参数方程定义:

P(U, V) = O + R * (cos(U) * xDir + sin(U) * yDir) + V * zDir, where :

  • P is the point defined by parameters (U, V).

  • P是由参数(U, V)定义的点。

  • O, xDir, yDir and zDir are respectively the origin, the X direction, Y direction and Z direction of the cylindrical surface local coordinate system.

  • O, xDir, yDir, zDir分别为柱面局部坐标系的原点,X方向,Y方向,Z方向。

  • R is the radius of the cylindrical surface.

  • R是圆柱面的半径。

  • U range is [0, 2PI] and V is infinite.

  • U的取值范围为[0,2 pi], V为无穷大。

tutorial_image012.png

The advantage of having such parameterized geometries is that you can compute, for any (U, V) parameters of the surface:

这种参数化几何图形的优点是,您可以计算曲面的任何(U, V)参数:

  • the 3D point;

  • 三维点;

  • the derivative vectors of order 1, 2 to N at this point.

  • 向量在这一点的导数(1,2到N)

There is another advantage of these parametric equations: you can consider a surface as a 2D parametric space defined with a (U, V) coordinate system. For example, consider the parametric ranges of the neck's surface:

这些参数方程还有另一个优点:你可以把一个曲面看作一个用(U, V)坐标系定义的二维参数空间。例如,考虑颈部表面的参数范围:

Suppose that you create a 2D line on this parametric (U, V) space and compute its 3D parametric curve. Depending on the line definition, results are as follows:

假设您在这个参数(U, V)空间上创建了一条二维直线,并计算其三维参数曲线。根据行定义,结果如下:

CaseParametric EquationParametric Curve

U = 0

P(V) = O + V * zDir

Line parallel to the Z direction

V = 0

P(U) = O + R * (cos(U) * xDir + sin(U) * yDir)

Circle parallel to the (O, X, Y) plane

U != 0 V != 0

P(U, V) = O + R * (cos(U) * xDir + sin(U) * yDir) + V * zDir

Helicoidal curve describing the evolution of height and angle on the cylinder

The helicoidal curve type is exactly what you need. On the neck's surface, the evolution laws of this curve will be:

螺旋曲线正是你所需要的。在颈部表面,这条曲线的演化规律为:

  • In V parameter: between 0 and myHeighNeck for the height description

  • 在V参数:0和myhighneck之间的高度描述

  • In U parameter: between 0 and 2PI for the angle description. But, since a cylindrical surface is U periodic, you can decide to extend this angle evolution to 4PI as shown in the following drawing:

  • U参数:0 ~ 2PI之间为角度描述。但是,由于柱面是U周期的,你可以决定将这个角度演变扩展到4PI,如下图所示:

In this (U, V) parametric space, you will create a local (X, Y) coordinate system to position the curves to be created. This coordinate system will be defined with:

在这个(U, V)参数空间中,您将创建一个局部(X, Y)坐标系来定位要创建的曲线。这个坐标系将被定义为:

  • A center located in the middle of the neck's cylinder parametric space at (2*PI, myNeckHeight / 2) in U, V coordinates.

  • 在U, V坐标系中,位于颈部圆柱参数空间(2*PI, myNeckHeight / 2)中间的一个中心。

  • A X direction defined with the (2*PI, myNeckHeight/4) vector in U, V coordinates, so that the curves occupy half of the neck's surfaces.

  • 在U, V坐标系中用(2*PI, myNeckHeight/4)向量定义的X方向,这样曲线占据了颈部表面的一半。

To use 2D primitive geometry types of Open CASCADE Technology for defining a point and a coordinate system, you will once again instantiate classes from gp:

要使用Open CASCADE Technology的2D原始几何类型来定义点和坐标系,您将再次从gp实例化类:

  • To define a 2D point from its X and Y coordinates, use the gp_Pnt2d class.

  • 使用X和Y坐标定义一个2D点,使用gp_Pnt2d类。

  • To define a 2D direction (unit vector) from its X and Y coordinates, use the gp_Dir2d class. The coordinates will automatically be normalized.

  • 使用X和Y坐标定义2D方向(单位矢量),请使用gp_Dir2d类。坐标将自动归一化。

  • To define a 2D right-handed coordinate system, use the gp_Ax2d class, which is computed from a point (origin of the coordinate system) and a direction - the X direction of the coordinate system. The Y direction will be automatically computed.

  • 要定义2D右手坐标系,请使用gp_Ax2d类,它从一个点(坐标系统的原点)和一个方向(坐标系统的X方向)计算。Y方向将自动计算。

gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
gp_Ax2d anAx2d(aPnt, aDir);

You will now define the curves. As previously mentioned, these thread profiles are computed on two cylindrical surfaces. In the following figure, curves on the left define the base (on aCyl1 surface) and the curves on the right define the top of the thread's shape (on aCyl2 surface).

现在您将定义曲线。如前所述,这些螺纹轮廓是在两个圆柱形表面上计算的。下图中,左边的曲线定义了底部(在aCyl1曲面上),右边的曲线定义了螺纹形状的顶部(在aCyl2曲面上)。

You have already used the Geom package to define 3D geometric entities. For 2D, you will use the Geom2d package. As for Geom, all geometries are parameterized. For example, a Geom2d_Ellipse ellipse is defined from:

您已经使用了Geom包来定义3D几何实体。对于2D,您将使用Geom2d包。对于Geom,所有的几何都是参数化的。例如,一个Geom2d_Ellipse椭圆定义自:

  • a coordinate system whose origin is the ellipse center;

  • 原点为椭圆中心的坐标系;

  • a major radius on the major axis defined by the X direction of the coordinate system;

  • 由坐标系的X方向定义的长轴上的长半径;

  • a minor radius on the minor axis defined by the Y direction of the coordinate system.

  • 由坐标系的Y方向定义的小轴上的小半径。

Supposing that:

假设:

  • Both ellipses have the same major radius of 2*PI,

  • 两个椭圆的长半径都是2*PI,

  • Minor radius of the first ellipse is myNeckHeight / 10,

  • 第一个椭圆的小半径是myNeckHeight / 10,

  • And the minor radius value of the second ellipse is a fourth of the first one,

  • 第二个椭圆的小半径是第一个椭圆的四分之一,

Your ellipses are defined as follows:

椭圆定义如下:

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);

To describe portions of curves for the arcs drawn above, you define Geom2d_TrimmedCurve trimmed curves out of the created ellipses and two parameters to limit them. As the parametric equation of an ellipse is P(U) = O + (MajorRadius * cos(U) * XDirection) + (MinorRadius * sin(U) * YDirection), the ellipses need to be limited between 0 and M_PI.

为了描述上面绘制的弧线的曲线部分,您定义了Geom2d_TrimmedCurve从创建的椭圆和两个参数来限制它们的修剪曲线。由于椭圆的参数方程为P(U) = O + (MajorRadius * cos(U) * XDirection) + (MinorRadius * sin(U) * YDirection),因此需要将椭圆限制在0到M_PI之间。

Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);

The last step consists in defining the segment, which is the same for the two profiles: a line limited by the first and the last point of one of the arcs. To access the point corresponding to the parameter of a curve or a surface, you use the Value or D0 method (meaning 0th derivative), D1 method is for the first derivative, D2 for the second one.

最后一步是定义线段,这对两个剖面来说是一样的:一条线被其中一个弧线的第一个点和最后一个点所限制。要访问曲线或曲面参数对应的点,可以使用Value或D0方法(表示第0次导数),D1方法用于第一次导数,D2用于第二次导数。

gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
gp_Pnt2d anEllipsePnt2;
anEllipse1->D0(M_PI, anEllipsePnt2);

When creating the bottle's profile, you used classes from the GC package, providing algorithms to create elementary geometries. In 2D geometry, this kind of algorithms is found in the GCE2d package. Class names and behaviors are similar to those in GC. For example, to create a 2D segment out of two points:

在创建瓶子的轮廓时,使用了来自GC包的类,提供了创建基本几何图形的算法。在二维几何中,这种算法可以在GCE2d包中找到。类名和行为类似于GC。例如,要创建一个由两点组成的二维线段:

Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);

Building Edges and Wires构建边和线条

As you did when creating the base profile of the bottle, you can now:

就像你在创建瓶子的基本轮廓时所做的那样,你现在可以:

  • compute the edges of the neck's threading.

  • 计算颈部螺纹的边。

  • compute two wires out of these edges.

  • 用这些边中计算出两条线条。

Previously, you have built:

在此之前,您已经构建:

  • two cylindrical surfaces of the threading

  • 螺纹的两个圆柱形表面

  • three 2D curves defining the base geometry of the threading

  • 三条2D曲线定义了螺纹的基本几何形状

To compute the edges out of these curves, once again use the BRepBuilderAPI_MakeEdge class. One of its constructors allows you to build an edge out of a curve described in the 2D parametric space of a surface.

为了计算这些曲线的边,再次使用BRepBuilderAPI_MakeEdge类。它的一个构造函数允许您从曲面的二维参数空间中描述的曲线中构建边。

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);

Now, you can create the two profiles of the threading, lying on each surface.

现在,您可以创建螺纹的两个轮廓,位于每个表面上。

TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2);

Remember that these wires were built out of a surface and 2D curves. One important data item is missing as far as these wires are concerned: there is no information on the 3D curves. Fortunately, you do not need to compute this yourself, which can be a difficult task since the mathematics can be quite complex. When a shape contains all the necessary information except 3D curves, Open CASCADE Technology provides a tool to build them automatically. In the BRepLib tool package, you can use the BuildCurves3d method to compute 3D curves for all the edges of a shape.

记住,这些线条是由曲面和二维曲线构成的。就这些线条而言,缺少一个重要的数据项:没有关于3D曲线的信息。幸运的是,您不需要自己计算,这可能是一项艰巨的任务,因为数学可能非常复杂。当一个形状包含除3D曲线以外的所有必要信息时,Open CASCADE Technology提供了一个工具来自动构建它们。在BRepLib工具包中,您可以使用BuildCurves3d方法来计算形状的所有边缘的3D曲线。

BRepLib::BuildCurves3d(threadingWire1);
BRepLib::BuildCurves3d(threadingWire2);

Creating Threading创建螺纹

You have computed the wires of the threading. The threading will be a solid shape, so you must now compute the faces of the wires, the faces allowing you to join the wires, the shell out of these faces and then the solid itself. This can be a lengthy operation. There are always faster ways to build a solid when the base topology is defined. You would like to create a solid out of two wires. Open CASCADE Technology provides a quick way to do this by building a loft: a shell or a solid passing through a set of wires in a given sequence. The loft function is implemented in the BRepOffsetAPI_ThruSections class, which you use as follows:

你已经计算过螺纹的线条。螺纹是一个实体形状,所以你现在必须计算线条的面,让你连接线的面,壳从这些面出来,然后是实体本身。这可能是一个漫长的操作。当基本拓扑被定义后,总是有更快的方法来构建一个实体。你想要用两条线创造一个实体。Open CASCADE Technology提供了一种快速的方法,通过建立一个loft:一个壳或固体通过一组给定顺序的线条。loft函数是在BRepOffsetAPI_ThruSections类中实现的,你可以这样使用:

  • Initialize the algorithm by creating an instance of the class. The first parameter of this constructor must be specified if you want to create a solid. By default, BRepOffsetAPI_ThruSections builds a shell.

  • 通过创建类的实例来初始化算法。如果要创建实体,则必须指定此构造函数的第一个参数。默认情况下,BRepOffsetAPI_ThruSections构建一个shell。

  • Add the successive wires using the AddWire method.

  • 使用AddWire方法添加连续的线条。

  • Use the CheckCompatibility method to activate (or deactivate) the option that checks whether the wires have the same number of edges. In this case, wires have two edges each, so you can deactivate this option.

  • 使用CheckCompatibility方法来激活(或取消激活)检查线条是否具有相同数量的边的选项。在这种情况下,每条线都有两条边,因此您可以停用此选项。

  • Ask for the resulting loft shape with the Shape method.

  • 使用Shape方法生成loft形状。

BRepOffsetAPI_ThruSections aTool(Standard_True);
aTool.AddWire(threadingWire1); aTool.AddWire(threadingWire2);
aTool.CheckCompatibility(Standard_False);
TopoDS_Shape myThreading = aTool.Shape();

Building the Resulting Compound构建组合结果

You are almost done building the bottle. Use the TopoDS_Compound and BRep_Builder classes to build single shape from myBody and myThreading:

你即将完成瓶子的制作。使用TopoDS_CompoundBRep_Builder类从myBodymyThreading构建单个形状:

TopoDS_Compound aRes;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aRes);
aBuilder.Add (aRes, myBody);
aBuilder.Add (aRes, myThreading);

Congratulations! Your bottle is complete. Here is the result snapshot of the Tutorial application:

恭喜你!你的瓶子已构建完整。以下是教程应用程序的结果快照:

We hope that this tutorial has provided you with a feel for the industrial strength power of Open CASCADE Technology. If you want to know more and develop major projects using Open CASCADE Technology, we invite you to study our training, support, and consulting services on our site at https://www.opencascade.com/content/technology-support. Our professional services can maximize the power of your Open CASCADE Technology applications.

我们希望本教程能让您感受到Open CASCADE Technology工业实力。如果您想了解更多并使用Open CASCADE Technology开发重大项目,我们邀请您在我们的网站https://www.opencascade.com/content/technology-support上学习我们的培训,支持和咨询服务。我们的专业服务可以最大限度地发挥您的Open CASCADE Technology应用程序的功能。

Appendix附录

Complete definition of MakeBottle function (defined in the file src/MakeBottle.cxx of the Tutorial):

MakeBottle函数的完整定义(在src/MakeBottle文件中定义)。(《教程》第xx页):

TopoDS_Shape MakeBottle(const Standard_Real myWidth, const Standard_Real myHeight,
                        const Standard_Real myThickness)
{
    // Profile : Define Support Points
    gp_Pnt aPnt1(-myWidth / 2., 0, 0);        
    gp_Pnt aPnt2(-myWidth / 2., -myThickness / 4., 0);
    gp_Pnt aPnt3(0, -myThickness / 2., 0);
    gp_Pnt aPnt4(myWidth / 2., -myThickness / 4., 0);
    gp_Pnt aPnt5(myWidth / 2., 0, 0);
    // 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);
    // Complete Profile
    gp_Ax1 xAxis = gp::OX();
    gp_Trsf aTrsf;
    aTrsf.SetMirror(xAxis);
    BRepBuilderAPI_Transform aBRepTrsf(aWire, aTrsf);
    TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();
    TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);
    BRepBuilderAPI_MakeWire mkWire;
    mkWire.Add(aWire);
    mkWire.Add(aMirroredWire);
    TopoDS_Wire myWireProfile = mkWire.Wire();
    // Body : Prism the Profile
    TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile);
    gp_Vec aPrismVec(0, 0, myHeight);
    TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec);
    // Body : Apply Fillets
    BRepFilletAPI_MakeFillet mkFillet(myBody);
    TopExp_Explorer anEdgeExplorer(myBody, TopAbs_EDGE);
    while(anEdgeExplorer.More()){
        TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current());
        //Add edge to fillet algorithm
        mkFillet.Add(myThickness / 12., anEdge);
        anEdgeExplorer.Next();
    }
    myBody = mkFillet.Shape();
    // Body : Add the Neck
    gp_Pnt neckLocation(0, 0, myHeight);
    gp_Dir neckAxis = gp::DZ();
    gp_Ax2 neckAx2(neckLocation, neckAxis);
    Standard_Real myNeckRadius = myThickness / 4.;
    Standard_Real myNeckHeight = myHeight / 10.;
    BRepPrimAPI_MakeCylinder MKCylinder(neckAx2, myNeckRadius, myNeckHeight);
    TopoDS_Shape myNeck = MKCylinder.Shape();
    myBody = BRepAlgoAPI_Fuse(myBody, myNeck);
    // Body : Create a Hollowed Solid
    TopoDS_Face   faceToRemove;
    Standard_Real zMax = -1;
    for(TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE); aFaceExplorer.More(); aFaceExplorer.Next()){
        TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current());
        // Check if <aFace> is the top face of the bottle's neck 
        Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);
        if(aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)){
            Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface);
            gp_Pnt aPnt = aPlane->Location();
            Standard_Real aZ   = aPnt.Z();
            if(aZ > zMax){
                zMax = aZ;
                faceToRemove = aFace;
            }
        }
    }
    TopTools_ListOfShape facesToRemove;
    facesToRemove.Append(faceToRemove);
    BRepOffsetAPI_MakeThickSolid aSolidMaker;
    aSolidMaker.MakeThickSolidByJoin(myBody, facesToRemove, -myThickness / 50, 1.e-3);
    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();
    // Building the Resulting Compound 
    TopoDS_Compound aRes;
    BRep_Builder aBuilder;
    aBuilder.MakeCompound (aRes);
    aBuilder.Add (aRes, myBody);
    aBuilder.Add (aRes, myThreading);
    return aRes;
}