Open Cascade is an open source surface and solid modeling kernel. It is typically used in design (CAD), manufacturing (CAM) and numerical simulation (CAE). Most of its functionality comes in the form of C++ libraries, providing 3D modeling classes, methods and functions. Source code can be downloaded from the Open Cascade website. In order to compile the current Open Cascade kernel on a Linux system, you'll need GNU gcc 4.3 or later. Viewing of 3D models relies on the power of your graphics card, which for the purpose should support OpenGL 3.3 or higher. For ray tracing, which is the creation of photo-realistic rendering from a model, you'll need OpenGL 4.0 or higher.

## Example: Bottle

The following is an example from OpenCascade documentation on how the kernel can be used to build a simple 3D model, in this case a bottle. It first goes to setting out a number of base points, from which curves are generated and the body of the bottle extruded. Fillets are generated on all edges to give it a more natural appearance. Then a neck is added and the bottle is hollowed out, after which a thread is added to the neck. Following variables with bottle dimensions are used throughout the code.

Standard_Real myHeight = 70;
Standard_Real myWidth = 50;
Standard_Real myThickness = 30;


### Base

We'll draw the base of the bottle at the origin of the Cartesian coordinate system, width following the X-axis and thickness the Y-axis. To save some effort, only one half of this base is drawn and the other created later as a mirror image. Drawing is done by setting out points and connecting them with construction geometry, after which shapes are created and joined. Geometric primitives like below points have a limited lifetime in memory, which can be extended by creating a "Handle".

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);
// Creating construction geometry
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);
// Conversion to (topological) shapes and joining
TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aSegment1);
TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle);
TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge(aSegment2);
TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(anEdge1,anEdge2,anEdge3);


A number of transformations can be applied to shapes, including translation, rotation, scale and reflection. In this case a reflection is used, taking the x-axis as mirror line. One could define the transformation matrix manually, but it is reasonably more easy to let the program do this for you. Applying the transformation to previous wire returns a shape object, which needs to be cast as a wire before adding it to its mirror twin. Next we create another wire, and add the two wire segments to it. Then the shape is cast as a single wire.

gp_Pnt aOrigin(0,0,0);
// Defining the transformation matrix
gp_Trsf;
aTrsf.SetMirror(xAxis);
// Applying the transformation, casting as a wire
BRepBuilderAPI_Transform aBRepTrsf(aWire,aTrsf);
TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();
TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);
// Joining wires
BRepBuilderAPI_MakeWire mkWire;
TopoDS_Wire myWireProfile = mkWire.Wire();


### Body

Now the previous wire can be swept upwards to create the body of the bottle. However, depending on shape type such sweeping operation gives rise to different topology: a vertex becomes an edge, an edge becomes a face, a wire becomes a shell, a face becomes a solid and a shell becomes a compound of solids. As we would like the bottle to be modeled as a solid, our profile still needs to be transformed from a wire into a face. Next MakePrism is used to sweep the face upwards; it takes a face and a vector defining direction and distance as inputs.

TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile);
// Sweeping operation
gp_Vec aPrismVec(0,0,myHeight);
TopoDS_Shape myBody = BRepPrismAPI_MakePrism(myFaceProfile,aPrismVec);


### Fillets

We want to round the edges of above extrusion to make it look more like a bottle. Define the body to which the fillet operation is applied, then specify the edges that are going to be filleted. This is done by creating a so-called topology explorer, which extracts the required sub-shapes. The created structure can be traversed, and edges extracted for applying a fillet to them. In this case a fillet of myThickness/12 was chosen. Finally you ask the filtering operation to return the created shape.

BRepFilletAPI_MakeFillet mkFillet(myBody);
// Topology explorer
TopExp_Explorer anEdgeExplorer(myBody,TopAbs_EDGE);
while (anEdgeExplorer.More(){
TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.currect());
// Adding edges to fillet operation
anEdgeExplorer.Next();
}
// Extracting shape
myBody = mkFillet.Shape();


### Neck

Now a neck is added to the bottle, which is first created as a separate solid and then fused with the rest of the body. To create the neck cylinder, we determine its desired location and direction, set dimensions, create the shape and extract it. Finally body and neck are fused into one solid.

gp_Pnt neckLocation(0,0,myHeight);
gp_Dir neckAxis = gp::DZ();
gp_Ax2 neckAx2(neckLocation,neckAxis);
// Dimensions
Standard_Real myNeckHeight = myHeight/10;
// Creating neck, fusing with body
TopoDS_Shape myNeck = MKCylinder.Shape();
myBody = BRepAlgoAPI_Fuse(myBody, myNeck);


### Hollowing Out

As the final product will be a bottle, our solid will now be hollowed out by removing the top face of the neck cylinder and then thickening all other surfaces. First the top surface needs to be found, for which we'll let an explorer iterate through the bottle's faces. The thickening constructor expects a list of faces to be removed, not a single face. The thickening constructor is called with as parameters the shape in question, faces to be removed, thickness and tolerance for the operation.

// Initialisation
TopoDS_Face   faceToRemove;
Standard_Real zMax = -1;
// Finding the to face
for(TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE); aFaceExplorer.More(); aFaceExplorer.Next()){
TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current());
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;
}
}
}
// Define face to remove, thickening operation
TopTools_ListOfShape facesToRemove;
facesToRemove.Append(faceToRemove);
myBody = BRepOffsetAPI_MakeThickSolid(myBody, facesToRemove, -myThickness / 50, 1.e-3);


Threading is applied by creating cylindrical surfaces for minor and major diameters, wrapping 2D curves in a spiral around them, and finally using these curves to create a solid. The cylinders are positioned using the neck's coordinate system, and the inner cylinder is made a little smaller than the neck so they overlap and can be merged. The thread is wide at the bottom and narrow at the top, so the respective ellipses are dimensioned accordingly.

Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99);
Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05);
// Cylinder dimensions
gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.);
gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.);
Standard_Real aMajor = 2. * M_PI;
Standard_Real aMinor = myNeckHeight / 10;
// Creating ellipses
Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor);
Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4);


Only the top of each ellipse is used, the bottom is replaced by a straight line. For this ellipses are trimmed to only keep half, points at the end of one of the curves choses and connected by a straight line. As ellipses have equal major diameters, this straight line is the same for both and only created once. Then curves are wrapped around their respective cylinders, joined into a wire and built as 3D curves.

Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI);
Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI);
// Points at ends of curve
gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0);
gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI);
// Straight line
Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2);
// Wrapping 2D geometry around cylinders
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);
// Join edges into a wire
// Build curves in 3D


Based on previously built curves, a solid thread is generated using a lofting feature. The tool is first initialised, then wires are added and a solid generated.

BRepOffsetAPI_ThruSections aTool(Standard_True);
aTool.CheckCompatibility(Standard_False);


### Compound

Finally, body and thread are merged in a compound shape.

TopoDS_Compound aRes;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aRes);