0025729: algorith BRepOffset_MakeOffset(...) produces wrong result for join type...
[occt.git] / dox / tutorial / tutorial.md
CommitLineData
ba06f8bb 1 Tutorial {#occt__tutorial}
765b3e07 2=======
3
e5bd0d98 4@tableofcontents
5
765b3e07 6@section sec1 Overview
7
8
9This 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.
10
11
12@subsection OCCT_TUTORIAL_SUB1_1 Prerequisites
13
14This tutorial assumes that you have experience in using and setting up C++.
15From 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.
16
17@subsection OCCT_TUTORIAL_SUB1_2 The Model
18
19To illustrate the use of classes provided in the 3D geometric modeling toolkits, you will create a bottle as shown:
20
e5bd0d98 21@image html /tutorial/images/tutorial_image001.png
22@image latex /tutorial/images/tutorial_image001.png
765b3e07 23
24In 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.
25
26@subsection OCCT_TUTORIAL_SUB1_3 Model Specifications
27
28We first define the bottle specifications as follows:
29
30| Object Parameter | Parameter Name | Parameter Value |
31| :--------------: | :------------: | :-------------: |
32| Bottle height | MyHeight | 70mm |
33| Bottle width | MyWidth | 50mm |
34| Bottle thickness | MyThickness | 30mm |
35
36In addition, we decide that the bottle's profile (base) will be centered on the origin of the global Cartesian coordinate system.
37
e5bd0d98 38@image html /tutorial/images/tutorial_image002.png
39@image latex /tutorial/images/tutorial_image002.png
765b3e07 40
41This modeling requires four steps:
42
43 * build the bottle's Profile
44 * build the bottle's Body
45 * build the Threading on the bottle's neck
46 * build the result compound
47
48
49@section sec2 Building the Profile
50
51@subsection OCCT_TUTORIAL_SUB2_1 Defining Support Points
52
53To 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.
54
ba06f8bb 55@figure{tutorial/images/tutorial_image003.svg}
765b3e07 56
57There are two classes to describe a 3D Cartesian point from its X, Y and Z coordinates in Open CASCADE Technology:
58
59 * the primitive geometric *gp_Pnt* class
60 * the transient *Geom_CartesianPoint* class manipulated by handle
61
62A handle is a type of smart pointer that provides automatic memory management.
63To choose the best class for this application, consider the following:
64
65 * *gp_Pnt* is manipulated by value. Like all objects of its kind, it will have a limited lifetime.
66 * *Geom_CartesianPoint* is manipulated by handle and may have multiple references and a long lifetime.
67
68Since 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.
3d68eaf5 69To instantiate a *gp_Pnt* object, just specify the X, Y, and Z coordinates of the points in the global Cartesian coordinate system:
765b3e07 70
71~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
72 gp_Pnt aPnt1(-myWidth / 2., 0, 0);
73 gp_Pnt aPnt2(-myWidth / 2., -myThickness / 4., 0);
74 gp_Pnt aPnt3(0, -myThickness / 2., 0);
75 gp_Pnt aPnt4(myWidth / 2., -myThickness / 4., 0);
76 gp_Pnt aPnt5(myWidth / 2., 0, 0);
77~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78
79Once 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:
80
81~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
82Standard_Real xValue1 = aPnt1.X();
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84
85@subsection OCCT_TUTORIAL_SUB2_2 Profile: Defining the Geometry
86With 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.
87
e5bd0d98 88@image html /tutorial/images/tutorial_image004.png
89@image latex /tutorial/images/tutorial_image004.png
765b3e07 90
91To 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.
92In 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*).
93However, 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.
94This is because the *GC* provides two algorithm classes which are exactly what is required for our profile:
95
96 * Class *GC_MakeSegment* to create a segment. One of its constructors allows you to define a segment by two end points P1 and P2
97 * 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.
98
99Both 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.
100
101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
102 Handle(Geom_TrimmedCurve) aArcOfCircle = GC_MakeArcOfCircle(aPnt2,aPnt3,aPnt4);
103 Handle(Geom_TrimmedCurve) aSegment1 = GC_MakeSegment(aPnt1, aPnt2);
104 Handle(Geom_TrimmedCurve) aSegment2 = GC_MakeSegment(aPnt4, aPnt5);
105~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106
107All *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:
108
109~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
110 GC_MakeSegment mkSeg (aPnt1, aPnt2);
111 Handle(Geom_TrimmedCurve) aSegment1;
112 if(mkSegment.IsDone()){
113 aSegment1 = mkSeg.Value();
114 }
115 else {
116 // handle error
117 }
118~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119
120
121@subsection OCCT_TUTORIAL_SUB2_3 Profile: Defining the Topology
122
123
124You have created the support geometry of one part of the profile but these curves are independent with no relations between each other.
125To simplify the modeling, it would be right to manipulate these three curves as a single entity.
126This 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.
127Each object of the *TopoDS* package, inheriting from the *TopoDS_Shape* class, describes a topological shape as described below:
128
129| Shape | Open CASCADE Technology Class | Description |
130| :-------- | :---------------------------- | :------------------------------------------------------------ |
131| Vertex | TopoDS_Vertex | Zero dimensional shape corresponding to a point in geometry. |
132| Edge | TopoDS_Edge | One-dimensional shape corresponding to a curve and bounded by a vertex at each extremity.|
133| Wire | TopoDS_Wire | Sequence of edges connected by vertices. |
134| Face | TopoDS_Face | Part of a surface bounded by a closed wire(s). |
135| Shell | TopoDS_Shell | Set of faces connected by edges. |
136| Solid | TopoDS_Solid | Part of 3D space bounded by Shells. |
137| CompSolid | TopoDS_CompSolid | Set of solids connected by their faces. |
138| Compound | TopoDS_Compound | Set of any other shapes described above. |
139
140Referring to the previous table, to build the profile, you will create:
141
142 * Three edges out of the previously computed curves.
143 * One wire with these edges.
144
e5bd0d98 145@image html /tutorial/images/tutorial_image005.png
146@image latex /tutorial/images/tutorial_image005.png
765b3e07 147
148However, 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.
149To create an edge, you use the BRepBuilderAPI_MakeEdge class with the previously computed curves:
150
151~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
152 TopoDS_Edge aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1);
153 TopoDS_Edge aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle);
154 TopoDS_Edge aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2);
155~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156
157In 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, aEdge1 and aEdge3 could have been computed in a simpler way:
158
159~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
160 TopoDS_Edge aEdge1 = BRepBuilderAPI_MakeEdge(aPnt1, aPnt3);
161 TopoDS_Edge aEdge2 = BRepBuilderAPI_MakeEdge(aPnt4, aPnt5);
162~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
163
164To 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:
165
166 * directly from one to four edges
167 * by adding other wire(s) or edge(s) to an existing wire (this is explained later in this tutorial)
168
169When building a wire from less than four edges, as in the present case, you can use the constructor directly as follows:
170
171~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
172 TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(aEdge1, aEdge2, aEdge3);
173~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174
175
176@subsection OCCT_TUTORIAL_SUB2_4 Profile: Completing the Profile
177
178
179Once the first part of your wire is created you need to compute the complete profile. A simple way to do this is to:
180
181 * compute a new wire by reflecting the existing one.
182 * add the reflected wire to the initial one.
183
e5bd0d98 184@image html /tutorial/images/tutorial_image006.png
185@image latex /tutorial/images/tutorial_image006.png
765b3e07 186
187To 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.
188In 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.
189The first way is to define it from scratch, using its geometric definition:
190
191 * X axis is located at (0, 0, 0) - use the *gp_Pnt* class.
192 * 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.
193
194~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
195 gp_Pnt aOrigin(0, 0, 0);
196 gp_Dir xDir(1, 0, 0);
197 gp_Ax1 xAxis(aOrigin, xDir);
198~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
199
200The 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:
201
202~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
203 gp_Ax1 xAxis = gp::OX();
204~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
205
206As previously explained, the 3D geometric transformation is defined with the *gp_Trsf* class. There are two different ways to use this class:
207
208 * by defining a transformation matrix by all its values
209 * by using the appropriate methods corresponding to the required transformation (SetTranslation for a translation, SetMirror for a reflection, etc.): the matrix is automatically computed.
210
211Since the simplest approach is always the best one, you should use the SetMirror method with the axis as the center of symmetry.
212
213~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
214 gp_Trsf aTrsf;
215 aTrsf.SetMirror(xAxis);
216~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
217
218You now have all necessary data to apply the transformation with the BRepBuilderAPI_Transform class by specifying:
219
220 * the shape on which the transformation must be applied.
221 * the geometric transformation
222
223~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
224 BRepBuilderAPI_Transform aBRepTrsf(aWire, aTrsf);
225~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
226
227*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:
228
229~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
230 TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();
231~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
232
233What 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.
234
235~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
236 TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);
237~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238
239The 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:
240
241 * create an instance of *BRepBuilderAPI_MakeWire*.
242 * add all edges of the two wires by using the *Add* method on this object.
243
244~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
245 BRepBuilderAPI_MakeWire mkWire;
246 mkWire.Add(aWire);
247 mkWire.Add(aMirroredWire);
248 TopoDS_Wire myWireProfile = mkWire.Wire();
249~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
250
251
252@section sec3 Building the Body
253
254
255@subsection OCCT_TUTORIAL_SUB3_1 Prism the Profile
256
257
258To 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 to 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:
259
260| Shape | Generates |
261| :----- | :----------------- |
262| Vertex | Edge |
263| Edge | Face |
264| Wire | Shell |
265| Face | Solid |
266| Shell | Compound of Solids |
267
e5bd0d98 268@image html /tutorial/images/tutorial_image007.png
269@image latex /tutorial/images/tutorial_image007.png
765b3e07 270
271Your 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.
272To 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.
273When the wire lies on a plane, the surface is automatically computed.
274
275~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
276 TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile);
277~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
278
279The *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:
280
281 * the basis shape to sweep;
282 * a vector for a finite prism or a direction for finite and infinite prisms.
283
284You 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:
285
286~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
287 gp_Vec aPrismVec(0, 0, myHeight);
288~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
289
290All the necessary data to create the main body of your bottle is now available. Just apply the *BRepPrimAPI_MakePrism* class to compute the solid:
291
292~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
293 TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec);
294~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
295
296
297@subsection OCCT_TUTORIAL_SUB3_2 Applying Fillets
298
299
300The edges of the bottle's body are very sharp. To replace them by rounded faces, you use the *Fillet* functionality of Open CASCADE Technology.
301For our purposes, we will specify that fillets must be:
302
303 * applied on all edges of the shape
304 * have a radius of *myThickness* / 12
305
e5bd0d98 306@image html /tutorial/images/tutorial_image008.png
307@image latex /tutorial/images/tutorial_image008.png
765b3e07 308
309To apply fillets on the edges of a shape, you use the *BRepFilletAPI_MakeFillet* class. This class is normally used as follows:
310
311 * Specify the shape to be filleted in the *BRepFilletAPI_MakeFillet* constructor.
312 * Add the fillet descriptions (an edge and a radius) using the *Add* method (you can add as many edges as you need).
313 * Ask for the resulting filleted shape with the *Shape* method.
314
315~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
316BRepFilletAPI_MakeFillet mkFillet(myBody);
317~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
318
319To 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.
320Generally, this explorer is created by providing the following information:
321
322 * the shape to explore
323 * the type of sub-shapes to be found. This information is given with the *TopAbs_ShapeEnum* enumeration.
324
325~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
326TopExp_Explorer anEdgeExplorer(myBody, TopAbs_EDGE);
327~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328
329An explorer is usually applied in a loop by using its three main methods:
330
331 * *More()* to know if there are more sub-shapes to explore.
332 * *Current()* to know which is the currently explored sub-shape (used only if the *More()* method returns true).
333 * *Next()* to move onto the next sub-shape to explore.
334
335
336~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
337 while(anEdgeExplorer.More()){
338 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current());
339 //Add edge to fillet algorithm
340 ...
341 anEdgeExplorer.Next();
342 }
343~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
344
345In 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.
346
347~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
348 mkFillet.Add(myThickness / 12., anEdge);
349~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
350
351Once this is done, you perform the last step of the procedure by asking for the filleted shape.
352
353~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
354 myBody = mkFillet.Shape();
355~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
356
357
358@subsection OCCT_TUTORIAL_SUB3_3 Adding the Neck
359
360
361To 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.
362
e5bd0d98 363@image html /tutorial/images/tutorial_image009.png
364@image latex /tutorial/images/tutorial_image009.png
765b3e07 365
366To 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).
367To 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:
368
369~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
370 gp_Pnt neckLocation(0, 0, myHeight);
371 gp_Dir neckAxis = gp::DZ();
372 gp_Ax2 neckAx2(neckLocation, neckAxis);
373~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
374
375To create a cylinder, use another class from the primitives construction package: the *BRepPrimAPI_MakeCylinder* class. The information you must provide is:
376
377 * the coordinate system where the cylinder will be located;
378 * the radius and height.
379
380~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
381 Standard_Real myNeckRadius = myThickness / 4.;
382 Standard_Real myNeckHeight = myHeight / 10;
383 BRepPrimAPI_MakeCylinder MKCylinder(neckAx2, myNeckRadius, myNeckHeight);
384 TopoDS_Shape myNeck = MKCylinder.Shape();
385~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
386
387You now have two separate parts: a main body and a neck that you need to fuse together.
388The *BRepAlgoAPI* package provides services to perform Boolean operations between shapes, and especially: *common* (Boolean intersection), *cut* (Boolean subtraction) and *fuse* (Boolean union).
389Use *BRepAlgoAPI_Fuse* to fuse the two shapes:
390
391~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
392 myBody = BRepAlgoAPI_Fuse(myBody, myNeck);
393~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
394
395
396@subsection OCCT_TUTORIAL_SUB3_4 Creating a Hollowed Solid
397
398
399Since a real bottle is used to contain liquid material, you should now create a hollowed solid from the bottle's top face.
400In Open CASCADE Technology, a hollowed solid is called a *Thick* *Solid* and is internally computed as follows:
401
402 * Remove one or more faces from the initial solid to obtain the first wall W1 of the hollowed solid.
403 * 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.
404 * Compute a solid from the two walls W1 and W2.
405
e5bd0d98 406@image html /tutorial/images/tutorial_image010.png
407@image latex /tutorial/images/tutorial_image010.png
765b3e07 408
409To compute a thick solid, you create an instance of the *BRepOffsetAPI_MakeThickSolid* class by giving the following information:
410
411 * The shape, which must be hollowed.
412 * The tolerance used for the computation (tolerance criterion for coincidence in generated shapes).
413 * The thickness between the two walls W1 and W2 (distance D).
414 * The face(s) to be removed from the original solid to compute the first wall W1.
415
416The challenging part in this procedure is to find the face to remove from your shape - the top face of the neck, which:
417
418 * has a plane (planar surface) as underlying geometry;
419 * is the highest face (in Z coordinates) of the bottle.
420
421To 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.
422
423~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
424 for(TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE) ; aFaceExplorer.More() ; aFaceExplorer.Next()){
425 TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current());
426 }
427~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
428
429For 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:
430
431 * *Surface* to access the surface of a face;
432 * *Curve* to access the 3D curve of an edge;
433 * *Point* to access the 3D point of a vertex.
434
435~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
436Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);
437~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
438
439As 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.
440All objects manipulated by handle, like *Geom_Surface*, inherit from the *Standard_Transient* class which provides two very useful methods concerning types:
441
442 * *DynamicType* to know the real type of the object
443 * *IsKind* to know if the object inherits from one particular type
444
445DynamicType 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.
446To compare a given type with the type you seek, use the *STANDARD_TYPE* macro, which returns the type of a class:
447
448~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
449 if(aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)){
450 //
451 }
452~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
453
454If 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:
455
456~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
457 Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface);
458~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
459
460Remember 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:
461
462~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
463 TopoDS_Face faceToRemove;
464 Standard_Real zMax = -1;
465~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466
467You 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:
468
469~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
470 gp_Pnt aPnt = aPlane->Location();
471 Standard_Real aZ = aPnt.Z();
472 if(aZ > zMax){
473 zMax = aZ;
474 faceToRemove = aFace;
475 }
476~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
477
478You 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.
479Open 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.
480The collection for shapes can be found in the *TopTools* package. As *BRepOffsetAPI_MakeThickSolid* requires a list, use the *TopTools_ListOfShape* class.
481
482~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
483 TopTools_ListOfShape facesToRemove;
484 facesToRemove.Append(faceToRemove);
485~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
486
487All the necessary data are now available so you can create your hollowed solid by calling the *BRepOffsetAPI_MakeThickSolid* constructor:
488
489~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
490 MyBody = BRepOffsetAPI_MakeThickSolid(myBody, facesToRemove, -myThickness / 50, 1.e-3);
491~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
492
493
494@section sec4 Building the Threading
495
496
497@subsection OCCT_TUTORIAL_SUB4_1 Creating Surfaces
498
499
500Up to now, you have learned how to create edges out of 3D curves.
501You will now learn how to create an edge out of a 2D curve and a surface.
502To 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.
503As a first step, you compute these cylindrical surfaces. You are already familiar with curves of the *Geom* package. Now you can create a cylindrical surface (*Geom_CylindricalSurface*) using:
504
505 * a coordinate system;
506 * a radius.
507
508Using the same coordinate system *neckAx2* used to position the neck, you create two cylindrical surfaces *Geom_CylindricalSurface* with the following radii:
509
e5bd0d98 510@image html /tutorial/images/tutorial_image011.png
511@image latex /tutorial/images/tutorial_image011.png
765b3e07 512
513Notice 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.
514
515~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
516 Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
517
518 Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);
519~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
520
521
522@subsection OCCT_TUTORIAL_SUB4_2 Defining 2D Curves
523
524
525To 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.
526All geometries defined in the *Geom* package are parameterized. This means that each curve or surface from Geom is computed with a parametric equation.
527A *Geom_CylindricalSurface* surface is defined with the following parametric equation:
528
529P(U, V) = O + R * (cos(U) * xDir + sin(U) * yDir) + V * zDir, where :
530
531 * P is the point defined by parameters (U, V).
532 * O, *Dir, yDir and zDir are respectively the origin, the X direction, Y direction and Z direction of the cylindrical surface local coordinate system.
533 * R is the radius of the cylindrical surface.
534 * U range is [0, 2PI] and V is infinite.
535
e5bd0d98 536@image html /tutorial/images/tutorial_image012.png
537@image latex /tutorial/images/tutorial_image012.png
765b3e07 538
539The advantage of having such parameterized geometries is that you can compute, for any (U, V) parameters of the surface:
540
541 * the 3D point;
542 * the derivative vectors of order 1, 2 to N at this point.
543
544There 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:
545
e5bd0d98 546@image html /tutorial/images/tutorial_image013.png
547@image latex /tutorial/images/tutorial_image013.png
765b3e07 548
549Suppose 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:
550
551| Case | Parametric Equation | Parametric Curve |
552| :------------ | :----------------------------------------------------------- | :---------------------------------------------------------------------------- |
553| U = 0 | P(V) = O + V * zDir | Line parallel to the Z direction |
554| V = 0 | P(U) = O + R * (cos(U) * xDir + sin(U) * yDir) | Circle parallel to the (O, X, Y) plane |
555| 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 |
556
557The helicoidal curve type is exactly what you need. On the neck's surface, the evolution laws of this curve will be:
558
559 * In V parameter: between 0 and myHeighNeck for the height description
560 * 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:
561
e5bd0d98 562@image html /tutorial/images/tutorial_image014.png
563@image latex /tutorial/images/tutorial_image014.png
765b3e07 564
565In 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:
566
567 * A center located in the middle of the neck's cylinder parametric space at (2*PI, myNeckHeight / 2) in U, V coordinates.
568 * 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.
569
e5bd0d98 570@image html /tutorial/images/tutorial_image015.png
571@image latex /tutorial/images/tutorial_image015.png
765b3e07 572
573To 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:
574
575 * To define a 2D point from its X and Y coordinates, use the *gp_Pnt2d* class.
576 * To define a 2D direction (unit vector) from its X and Y coordinates, use the gp_Dir2d class. The coordinates will automatically be normalized.
577 * 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.
578
579~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
580 gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
581 gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
582 gp_Ax2d anAx2d(aPnt, aDir);
583~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
584
585You 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).
586
e5bd0d98 587@image html /tutorial/images/tutorial_image016.png
588@image latex /tutorial/images/tutorial_image016.png
765b3e07 589
590You 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:
591
592 * a coordinate system whose origin is the ellipse center;
593 * a major radius on the major axis defined by the X direction of the coordinate system;
594 * a minor radius on the minor axis defined by the Y direction of the coordinate system.
595
596Supposing that:
597
598 * Both ellipses have the same major radius of 2*PI,
599 * Minor radius of the first ellipse is myNeckHeight / 10,
600 * And the minor radius value of the second ellipse is a fourth of the first one,
601
602Your ellipses are defined as follows:
603
604~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
605 Standard_Real aMajor = 2. * M_PI;
606 Standard_Real aMinor = myNeckHeight / 10;
607 Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
608 Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4);
609~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
610
611To 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.
612As 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.
613
614~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
615 Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
616 Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);
617~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
618
619The 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.
620To 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 first derivative, D2 for the second one.
621
622~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
623 gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
624 gp_Pnt2d anEllipsePnt2;
625 anEllipse1->D0(M_PI, anEllipsePnt2);
626~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
627
628When creating the bottle's profile, you used classes from the *GC* package, providing algorithms to create elementary geometries.
629In 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:
630
631~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
632 Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);
633~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
634
635
636@subsection OCCT_TUTORIAL_SUB4_3 Building Edges and Wires
637
638
639As you did when creating the base profile of the bottle, you can now:
640
641 * compute the edges of the neck's threading.
642 * compute two wires out of these edges.
643
e5bd0d98 644@image html /tutorial/images/tutorial_image017.png
645@image latex /tutorial/images/tutorial_image017.png
765b3e07 646
647Previously, you have built:
648
649 * two cylindrical surfaces of the threading
650 * three 2D curves defining the base geometry of the threading
651
652To 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.
653
654~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
655 TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
656 TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
657 TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2);
658 TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2);
659~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
660
661Now, you can create the two profiles of the threading, lying on each surface.
662
663~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
664 TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
665 TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2);
666~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
667
668Remember that these wires were built out of a surface and 2D curves.
669One 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.
670When 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.
671
672~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
673 BRepLib::BuildCurves3d(threadingWire1);
674 BRepLib::BuildCurves3d(threadingWire2);
675~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
676
677
678@subsection OCCT_TUTORIAL_SUB4_4 Creating Threading
679
680
681You 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.
682There 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.
683The loft function is implemented in the *BRepOffsetAPI_ThruSections* class, which you use as follows:
684
e5bd0d98 685@image html /tutorial/images/tutorial_image018.png
686@image latex /tutorial/images/tutorial_image018.png
765b3e07 687
688 * 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.
689 * Add the successive wires using the AddWire method.
690 * 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.
691 * Ask for the resulting loft shape with the Shape method.
692
693~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
694 BRepOffsetAPI_ThruSections aTool(Standard_True);
695 aTool.AddWire(threadingWire1); aTool.AddWire(threadingWire2);
696 aTool.CheckCompatibility(Standard_False);
697 TopoDS_Shape myThreading = aTool.Shape();
698~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
699
700
701@section sec5 Building the Resulting Compound
702
703
704You are almost done building the bottle. Use the *TopoDS_Compound* and *BRep_Builder* classes to build single shape from *myBody* and *myThreading*:
705
706~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
707 TopoDS_Compound aRes;
708 BRep_Builder aBuilder;
709 aBuilder.MakeCompound (aRes);
710 aBuilder.Add (aRes, myBody);
711 aBuilder.Add (aRes, myThreading);
712~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
713
714Congratulations! Your bottle is complete. Here is the result snapshot of the Tutorial application:
715
e5bd0d98 716@image html /tutorial/images/tutorial_image019.png
717@image latex /tutorial/images/tutorial_image019.png
765b3e07 718
719We hope that this tutorial has provided you with a feel for the industrial strength power of Open CASCADE Technology.
720If 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 http://www.opencascade.org/support. Our professional services can maximize the power of your Open CASCADE Technology applications.
721
722
723@section sec6 Appendix
724
725
726Complete definition of MakeBottle function (defined in the file src/MakeBottle.cxx of the Tutorial):
727
728~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
729 TopoDS_Shape MakeBottle(const Standard_Real myWidth, const Standard_Real myHeight,
730 const Standard_Real myThickness)
731 {
732 // Profile : Define Support Points
733 gp_Pnt aPnt1(-myWidth / 2., 0, 0);
734 gp_Pnt aPnt2(-myWidth / 2., -myThickness / 4., 0);
735 gp_Pnt aPnt3(0, -myThickness / 2., 0);
736 gp_Pnt aPnt4(myWidth / 2., -myThickness / 4., 0);
737 gp_Pnt aPnt5(myWidth / 2., 0, 0);
738
739 // Profile : Define the Geometry
740 Handle(Geom_TrimmedCurve) anArcOfCircle = GC_MakeArcOfCircle(aPnt2,aPnt3,aPnt4);
741 Handle(Geom_TrimmedCurve) aSegment1 = GC_MakeSegment(aPnt1, aPnt2);
742 Handle(Geom_TrimmedCurve) aSegment2 = GC_MakeSegment(aPnt4, aPnt5);
743
744 // Profile : Define the Topology
745 TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aSegment1);
746 TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(anArcOfCircle);
747 TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge(aSegment2);
748 TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3);
749
750 // Complete Profile
751 gp_Ax1 xAxis = gp::OX();
752 gp_Trsf aTrsf;
753
754 aTrsf.SetMirror(xAxis);
755 BRepBuilderAPI_Transform aBRepTrsf(aWire, aTrsf);
756 TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();
757 TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);
758
759 BRepBuilderAPI_MakeWire mkWire;
760 mkWire.Add(aWire);
761 mkWire.Add(aMirroredWire);
762 TopoDS_Wire myWireProfile = mkWire.Wire();
763
764 // Body : Prism the Profile
765 TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile);
766 gp_Vec aPrismVec(0, 0, myHeight);
767 TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec);
768
769 // Body : Apply Fillets
770 BRepFilletAPI_MakeFillet mkFillet(myBody);
771 TopExp_Explorer anEdgeExplorer(myBody, TopAbs_EDGE);
772 while(anEdgeExplorer.More()){
773 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current());
774 //Add edge to fillet algorithm
775 mkFillet.Add(myThickness / 12., anEdge);
776 anEdgeExplorer.Next();
777 }
778
779 myBody = mkFillet.Shape();
780
781 // Body : Add the Neck
782 gp_Pnt neckLocation(0, 0, myHeight);
783 gp_Dir neckAxis = gp::DZ();
784 gp_Ax2 neckAx2(neckLocation, neckAxis);
785
786 Standard_Real myNeckRadius = myThickness / 4.;
787 Standard_Real myNeckHeight = myHeight / 10.;
788
789 BRepPrimAPI_MakeCylinder MKCylinder(neckAx2, myNeckRadius, myNeckHeight);
790 TopoDS_Shape myNeck = MKCylinder.Shape();
791
792 myBody = BRepAlgoAPI_Fuse(myBody, myNeck);
793
794 // Body : Create a Hollowed Solid
795 TopoDS_Face faceToRemove;
796 Standard_Real zMax = -1;
797
798 for(TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE); aFaceExplorer.More(); aFaceExplorer.Next()){
799 TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current());
800 // Check if <aFace> is the top face of the bottle's neck
801 Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);
802 if(aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)){
803 Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface);
804 gp_Pnt aPnt = aPlane->Location();
805 Standard_Real aZ = aPnt.Z();
806 if(aZ > zMax){
807 zMax = aZ;
808 faceToRemove = aFace;
809 }
810 }
811 }
812
813 TopTools_ListOfShape facesToRemove;
814 facesToRemove.Append(faceToRemove);
815 myBody = BRepOffsetAPI_MakeThickSolid(myBody, facesToRemove, -myThickness / 50, 1.e-3);
816 // Threading : Create Surfaces
817 Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
818 Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);
819
820 // Threading : Define 2D Curves
821 gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
822 gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
823 gp_Ax2d anAx2d(aPnt, aDir);
824
825 Standard_Real aMajor = 2. * M_PI;
826 Standard_Real aMinor = myNeckHeight / 10;
827
828 Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
829 Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4);
830 Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
831 Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);
832 gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
833 gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI);
834
835 Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);
836 // Threading : Build Edges and Wires
837 TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
838 TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
839 TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2);
840 TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2);
841 TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1);
842 TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2);
843 BRepLib::BuildCurves3d(threadingWire1);
844 BRepLib::BuildCurves3d(threadingWire2);
845
846 // Create Threading
847 BRepOffsetAPI_ThruSections aTool(Standard_True);
848 aTool.AddWire(threadingWire1);
849 aTool.AddWire(threadingWire2);
850 aTool.CheckCompatibility(Standard_False);
851
852 TopoDS_Shape myThreading = aTool.Shape();
853
854 // Building the Resulting Compound
855 TopoDS_Compound aRes;
856 BRep_Builder aBuilder;
857 aBuilder.MakeCompound (aRes);
858 aBuilder.Add (aRes, myBody);
859 aBuilder.Add (aRes, myThreading);
860
861 return aRes;
862 }
863~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~