C/C++

How to add boost::program_options to your CMake build

Simply add these lines to the end of your CMakeLists.txt and replace myTarget by the name of your build target (usually the first argument to add_executable(...) or add_library(...)):

# Include boost
find_package( Boost 1.30 COMPONENTS program_options REQUIRED )
target_include_directories( myTarget PRIVATE ${Boost_INCLUDE_DIR})
target_link_libraries( myTarget ${Boost_LIBRARIES} )

If you have multiple targets, copy & paste the last two lines for each target.

If you need a specific version of boost, replace 1.30 by the minimum version you need.

Posted by Uli Köhler in Boost, C/C++, CMake

How to create TopoDS_Wire from TopoDS_Edge(s) in OpenCASCADE

OCCUtils provides easy-to-use conveniece functions to convert multiple TopoDS_Edges to a TopoDS_Wire:

#include <occutils/Wire.hxx>

using namespace OCCUtils;

TopoDS_Wire& wire = Wire::FromEdges({edge1, edge2})

You can also pass a std::vector<TopoDS_Edge> to Wire::FromEdges().

If you want to do it manually without using OCCUtils, you can use BRepLib_MakeWire like this:

BRepLib_MakeWire wireMaker;
wireMaker.Add(edge1);
wireMaker.Add(edge2);
TopoDS_Wire wire = wireMaker.Wire();
Posted by Uli Köhler in C/C++, OpenCASCADE

Overview of all standard colors available in OpenCASCADE

This table shows you all the available standard colors in OpenCASCADE.

Use like this:

Quantity_Color myColor(Quantity_NOC_ALICEBLUE);

See below for the source code used to generate this table!

Continue reading →

Posted by Uli Köhler in C/C++, OpenCASCADE

How to export colored STEP files in OpenCASCADE

OCCUtils provides an easy way of exporting a STEP with colored elements:

#include <occutils/ExtendedSTEP.hxx>
#include <occutils/Primitive.hxx>

TopoDS_Shape cube = Primitive::MakeCube(5 /* mm */);

STEP::ExtendedSTEPExporter stepExporter;
stepExporter.AddShapeWithColor(cube, Quantity_NOC_RED);
stepExporter.Write("ColoredCube.step");

The resulting STEP file looks like this:

You can also add non-colored shapes:

stepExporter.AddShape(myShape);

Doing it without OCCUtils is possible but might make your life miserable since it’s rather hard to get to work correctly.

Here’s a minimal example:

// Get global application
Handle(TDocStd_Application) application = XCAFApp_Application::GetApplication();
// Create document
Handle(TDocStd_Document) document;
application->NewDocument("MDTV-XCAF", document);
// Get shape & color tools
Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(document->Main());
Handle(XCAFDoc_ColorTool) colorTool = XCAFDoc_DocumentTool::ColorTool(document->Main());
// Create shape
// IMPORTANT: DO NOT use shapeTool->AddShape(TopoDS_Shape)!
// This WILL NOT PRESERVE the color!
TDF_Label partLabel = shapeTool->NewShape();
shapeTool->SetShape(partLabel, filletedBody);

//TDF_Label redColor = colorTool->AddColor();
colorTool->SetColor(partLabel, Quantity_NOC_RED, XCAFDoc_ColorGen);

STEPCAFControl_Writer writer;
writer.SetColorMode(true);
writer.Perform(document, "ColoredShape.step");

What colors can you use?

Either define the Quantity_Color yourself using RGB values (from 0.0 to 1.0) like this:

Quantity_Color red(1.0 /* R */, 0.0 /* G */, 0.0 /* B */, Quantity_TypeOfColor::Quantity_TOC_RGB);

alternatively you can do the same in the HSL colorspace:

Quantity_Color brownishOrange(1.0 /* H */, 0.5 /* L */, 0.5 /* S */, Quantity_TypeOfColor::Quantity_TOC_HLS);

or you can use the predefined colors in the Quantity_NameOfColor enum – see Overview of all standard colors available in OpenCASCADE for a table of all available colors.

Posted by Uli Köhler in C/C++, OpenCASCADE

How to return NaN in C++

Since C++11 returning NaN as double is as simple as

#include <cmath>

return std::nan("");

In case you want to return a float use

#include <cmath>

return std::nanf("");

In the rare case of a long double use

#include <cmath>

return std::nan("");

 

Posted by Uli Köhler in C/C++

How to check if float or double is NaN in C++

Checking for NaN is simple since C++11:

#include <numeric>

bool isNaN = std::isnan(myNumber);

See the std::isnan docs for reference.

You can also use the C99 function isnan from <cmath>:

#include <cmath>

bool isNaN = isnan(myDouble);

 

Posted by Uli Köhler in C/C++

How to iterate TopTools_IndexedMapOfShape

In OpenCASCADE, you can get e.g. a list of edges for a TopoDS_Shape using

TopTools_IndexedMapOfShape edges;
TopExp::MapShapes (shape, TopAbs_EDGE, edges);

How can you iterate edges?

The easiest way is to use indexing like this:

for (size_t i = 1; i <= edges.Extent(); i++) {
    TopoDS_Shape& edge = edges(i);
    /* ... */
}

If you want to get the TopoDS_Edge from the TopoDS_Shape in the above example, use TopoDS::Edge(edge) inside the loop.

Posted by Uli Köhler in C/C++, OpenCASCADE

How to fuse TopoDS_Shapes in OpenCASCADE (boolean OR)

The OCCUtils library provides an easy way to fuse two shapes in OpenCASCADE.

First, let’s generate a box and a cylinder using OCCUtil’s primitive generation functions:

#include <occutils/Primitive.hxx>

using namespace OCCUtils;
  
TopoDS_Shape solid1 = Primitive::MakeBox(18 /* X */, 8 /* Y */, 14 /* Z */,
    Primitive::CenterX | Primitive::CenterY);

TopoDS_Shape solid2 = Primitive::MakeCylinder(5 /* d */, 35 /* L */,
    Primitivs::Orientation::Z,
    Primitive::CenterD);

Now we can fuse the primitives using this snippet:

#include <occutils/Boolean.hxx>

using namespace OCCUtils;

TopoDS_Shape fused = Boolean::Fuse({solid1, solid2});

Boolean::Fuse() can take a number of different argument types. In this example, we’are using a std::initializer_list (this is the curly-bracket syntax) – but it can also take a TopTools_ListOfShape or a std::vector<TopoDS_Shape> (and also most other STL- or non-STL containers).

If you want to perform a fuse without using OCCUtils, you might be tempted to use this syntax:

BRepAlgoAPI_Fuse fuse(solid1, solid2);
fuse.Build();
TopoDS_Shape result = fuse.Shape();

However, the BRepAlgoAPI_Fuse(TopoDS, TopoDS) constructor is deprecated and should therefore not be used. Instead, the following syntax should be used:

// Configure fuse
BRepAlgoAPI_Fuse fuse;
fuse.SetArguments(arguments);
fuse.SetTools(tools);
// Run fuse
fuse.Build();
TopoDS_Shape shape = fuse.Shape(); // Raises NotDone if not done.

where arguments and tools are two TopTools_ListOfShape instances. For other boolean algorithms like BRepAlgoAPI_Cut (boolean difference) the two have distinct meanings, but for BRepAlgoAPI_Fuse it’s just important that both arguments and tools have at least one element each!

You can use ListUtils::SplitIntoHeadAndTail from OCCUtils to generate a std::pair of lists (arguments and tools), with arguments having one element and tools having the rest like this:

auto toolsAndArgs = ListUtils::SplitIntoHeadAndTail(shapes, 1);
auto tools = toolsAndArgs.first;
auto arguments = toolsAndArgs.second;

However, if you use ListUtils::SplitIntoHeadAndTail(), you can just use Boolean::Fuse() right away.

Posted by Uli Köhler in C/C++, OpenCASCADE

How to export STEP file in OpenCASCADE

My OCCUtils library provides a super-easy way of exporting your TopoDS_Shape to a STEP AP203 file:

#include <occutils/STEPExport.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;
STEP::ExportSTEP(myShape, "myShape.step");

In case you want to do it manually, it’s much more complicated to do right, but here are the basic steps to do it:

STEPControl_Writer writer;
writer.Transfer(shape, STEPControl_AsIs);
writer.Write(filename.c_str());

The full STEP::ExportSTEP code from OCCUtils is:

if (shape.IsNull () == true) {
    throw new invalid_argument("Can't export null shape to STEP");
}

STEPControl_Writer writer;
Interface_Static::SetCVal ("xstep.cascade.unit", unit.c_str());
Interface_Static::SetCVal ("write.step.unit", unit.c_str ());
Interface_Static::SetIVal ("write.step.nonmanifold", 1);
// "Transfer" = convert
IFSelect_ReturnStatus transferStatus = writer.Transfer(shape, STEPControl_AsIs);

if (transferStatus != IFSelect_RetDone) {
    throw std::logic_error ("Error while transferring shape to STEP");
}
// Write transferred structure to STEP file
IFSelect_ReturnStatus writeStatus = writer.Write(filename.c_str());

// Return previous locale
if (writeStatus != IFSelect_RetDone)
{
    throw std::logic_error ("Error while writing transferred shape to STEP file");
}

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to create a Cylinder TopoDS_Solid in OpenCASCADE

Also see How to create a Box TopoDS_Solid in OpenCASCADE and How to create a Cube TopoDS_Solid in OpenCASCADE

Using my OCCUtils library, you can easily create a cylinder of user-defined diameter and length:

#include <occutils/Primitive.hxx>

using namespace OCCUtils;

TopoDS_Solid myCube = Primitive::MakeCylinder(5.0 /* mm diameter */, 25.0 /* mm length */);

You can also define the orientation of the cylinder using Primites::Orientation::X, Primites::Orientation::Y or Primites::Orientation::Z:

#include <occutils/Primitive.hxx>
#include <vector>

using namespace OCCUtils;

TopoDS_Solid myCube = Primitive::MakeCylinder(5.0 /* mm diameter */,
    25.0 /* mm length */, Primitive::Orientation::X);

You can also center this cylinder on the length axis. The origin point (default: (0,0,0)) always lies on the cylinder’s main axis (i.e. along its length.

#include <occutils/Primitive.hxx>
#include <vector>

using namespace OCCUtils;

/*
 * Make a cube that is centered on the X- and Y axes
 */
TopoDS_Solid myCube = Primitive::MakeCylinder(5.0 /* mm diameter */, 25.0 /* mm length */,
    Primitive::Orientation::X,
    Primitive::CenterL);

Also you can use a specific point of origin as the third argument (gp_Pnt).

If you want to do it manually without OCCUtils, have a look at the OCC class BRepPrimAPI_MakeBox which you can use like this:

gp_Ax2 ax = /* Define origin point and direction of the cylinder here */;
BRepPrimAPI_MakeCylinder cyl(ax, diameter / 2.0, length);
cyl.Build();
TopoDS_Solid mySolid = cyl.Solid();

In this case, you have to center the object manually by computing the correct point of origin. In OCCUtils this is done using

// Compute offsets based on centering
if(center & CenterX) {
    origin.SetX(origin.X() - xSize / 2.0);
}
if(center & CenterY) {
    origin.SetY(origin.Y() - ySize / 2.0);
}
if(center & CenterZ) {
    origin.SetZ(origin.Z() - zSize / 2.0);
}

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to create a Box TopoDS_Solid in OpenCASCADE

Also see How to create a Cube TopoDS_Solid in OpenCASCADE and How to create a Cylinder TopoDS_Solid in OpenCASCADE

Using my OCCUtils library, you can easily create a box of user-defined dimensions:

#include <occutils/Primitive.hxx>
#include <vector>

using namespace OCCUtils;

TopoDS_Solid myCube = Primitive::MakeBox(5.0 /* X size */, 7.0 /* Y size */, 9.0 /* Z size */);

You can also center this box on one or more axes (if not centered in any axis, one of the corners is going to be on thre origin point):

#include <occutils/Primitive.hxx>
#include <vector>

using namespace OCCUtils;

/*
 * Make a box that is centered on the X- and Y axes
 */
TopoDS_Solid myCube = Primitive::MakeBox(5.0, 7.0, 9.0
    Primitive::CenterX | Primitive::CenterY);

Also you can use a specific point of origin as the third argument (gp_Pnt).

If you want to do it manually without OCCUtils, have a look at the OCC class BRepPrimAPI_MakeBox which you can use like this:

BRepPrimAPI_MakeBox box(origin, xSize, ySize, zSize);
box.Build();
TopoDS_Solid mySolid = box.Solid();

In this case, you have to center the object manually by computing the correct point of origin. In OCCUtils this is done using

// Compute offsets based on centering
if(center & CenterX) {
    origin.SetX(origin.X() - xSize / 2.0);
}
if(center & CenterY) {
    origin.SetY(origin.Y() - ySize / 2.0);
}
if(center & CenterZ) {
    origin.SetZ(origin.Z() - zSize / 2.0);
}

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to create a Cube TopoDS_Solid in OpenCASCADE

Also see How to create a Box TopoDS_Solid in OpenCASCADE and How to create a Cylinder TopoDS_Solid in OpenCASCADE

Using my OCCUtils library, you can easily create a cube of user-defined dimensions:

#include <occutils/Primitive.hxx>

using namespace OCCUtils;

TopoDS_Solid myCube = Primitive::MakeCube(5.0 /* mm side length */);

You can also center this cube on one or more axes (if not centered in any axis, one of the corners is going to be on thre origin point):

#include <occutils/Primitive.hxx>

using namespace OCCUtils;

/*
 * Make a cube that is centered on the X- and Y axes
 */
TopoDS_Solid myCube = Primitive::MakeCube(5.0 /* mm side length */,
    Primitive::CenterX | Primitive::CenterY);

Also you can use a specific point of origin as the third argument (gp_Pnt).

If you want to do it manually without OCCUtils, have a look at the OCC class BRepPrimAPI_MakeBox which you can use like this:

BRepPrimAPI_MakeBox box(origin, size, size, size);
box.Build();
TopoDS_Solid mySolid = box.Solid();

In this case, you have to center the object manually by computing the correct point of origin. In OCCUtils this is done using

// Compute offsets based on centering
if(center & CenterX) {
    origin.SetX(origin.X() - xSize / 2.0);
}
if(center & CenterY) {
    origin.SetY(origin.Y() - ySize / 2.0);
}
if(center & CenterZ) {
    origin.SetZ(origin.Z() - zSize / 2.0);
}

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to create TopTools_ListOfShape of two or more shapes in OpenCASCADE

TopTools_ListOfShape is just another name for NCollection_List<TopoDS_Shape>.

Using my OCCUtils library this is really easy:

#include <TopTools_ListOfShape.hxx>
#include <occutils/ListUtils.hxx>

using namespace OCCUtils;

/* ... */

TopoDS_Solid solid1 = /* ... */;
TopoDS_Solid solid2 = /* ... */;

TopTools_ListOfShape shapes = ListUtils::ToOCCList({solid1, solid2});

ListUtils::ToOCCList() takes almost anything as an argument, a std::initializer_list (this is the bracket syntax from the example above) but also any type of STL container like a std::vector or a std::list, and converts it into a NCollection_List<T>:

#include <TopTools_ListOfShape.hxx>
#include <occutils/ListUtils.hxx>
#include <vector>

using namespace OCCUtils;

/* ... */

TopoDS_Solid solid1 = /* ... */;
TopoDS_Solid solid2 = /* ... */;

std::vector<TopoDS_Shape> shapeVector({solid1, solid2});

TopTools_ListOfShape shapes = ListUtils::ToOCCList(shapeVector);

In case you don’t want to use OCCUtils, this is how you can create a TopTools_ListOfShape manually:

TopTools_ListOfShape list;
list.Append(shape1);
list.Append(shape2);

Since NCollection_List and therefore also TopTools_ListOfShape is a linked list internally, you can also use list.Prepend(shape); to add a shape to the front of the list without any performance penalty.

In case you want to create the list from a std::vector or any similar STL container, use this snippet:

std::vector<TopoDS_Shape>& shapeVector = /* ... */;

TopTools_ListOfShape list;
for(const TopoDS_Shape& shape : shapeVector) {
    list.Append(arg);
}

After creating the container, you can iterate it using the C++11 range-based for-loop:

TopTools_ListOfShape myShapes = /* ... */;

// Iterate myShapes
for(const TopoDS_Shape& shape : myShapes) {
    /* ... */
}

See How to iterate TopTools_ListOfShape in OpenCASCADE and How to iterate NCollection_List in OpenCASCADE for more details on that.

Posted by Uli Köhler in C/C++, OpenCASCADE

How to negate std::enable_if

Also see std::enable_if minimal example and std::enable_if and std::is_floating_point minimal examp le

Since the template argument to std::enable_if is a boolean, you can easily negate it using the ! operator.

Example:

// This function uses normal (non-negated) std::enable_if:
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

// This function has negated std::enable_if:
template<typename T, typename std::enable_if<!std::is_floating_point<T>::value>::type* = nullptr> 
T mySineNOFloatingPoint(T arg) {
    return sin(arg);
}

Full example:

#include <iostream>
#include <type_traits>
#include <cmath>

using std::cout;
using std::endl;

template<typename T>
T mySine(T arg) {
    return sin(arg);
}

template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

template<typename T, typename std::enable_if<!std::is_floating_point<T>::value>::type* = nullptr> 
T mySineNOFloatingPoint(T arg) {
    return sin(arg);
}

int main() {
    cout << mySine(1.5) << endl;
    // mySine(1) will work
    // mySineFloatingPointOnly(1) will fail to compile
    // mySineNOFloatingPoint(1.5) will fail to compile
    cout << mySineFloatingPointOnly(1.5) << endl;
    cout << mySineNOFloatingPoint(1) << endl;
}

 

Posted by Uli Köhler in C/C++

std::enable_if and std::is_floating_point minimal example

Also see std::enable_if minimal example and std::enable_if and std::is_same minimal example

Example for a template function that is only enabled if the template argument T is any floating point number type using std::enable_if and std::is_floating_point:

template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

Full example:

#include <iostream>
#include <type_traits>
#include <cmath>

using std::cout;
using std::endl;

template<typename T>
T mySine(T arg) {
    return sin(arg);
}

template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

int main() {
    cout << mySine(1.5) << endl;
    // mySine(1) will work
    // mySineFloatingPointOnly(1) will fail to compile
    cout << mySineFloatingPointOnly(1.5) << endl;
}

 

Posted by Uli Köhler in C/C++

std::enable_if and std::is_same minimal example

Also see std::enable_if minimal example and std::enable_if and std::is_floating_point minimal example

Example for a template function that is only enabled if the template argument T is a double using std::enable_if and std::is_same:

template<typename T, typename std::enable_if<std::is_same<T, double>::value>::type* = nullptr> 
T mySineDoubleOnly(T arg) {
    return sin(arg);
}

Full example:

#include <iostream>
#include <type_traits>
#include <cmath>

using std::cout;
using std::endl;

template<typename T>
T mySine(T arg) {
    return sin(arg);
}

template<typename T, typename std::enable_if<std::is_same<T, double>::value>::type* = nullptr> 
T mySineDoubleOnly(T arg) {
    return sin(arg);
}

int main() {
    cout << mySine(1.5) << endl;
    // mySine(1) will work
    // mySineDoubleOnly(1) will fail to compile
    cout << mySineDoubleOnly(1.5) << endl;
}

 

Posted by Uli Köhler in C/C++

std::enable_if minimal example

Also see std::enable_if and std::is_floating_point minimal example and std::enable_if and std::is_same minimal example

Let’s say you have a template function:

template<typename T>
T mySine(T arg) {
    return sin(arg);
}

Now you want to enable this function only if T is a floating point number (i.e. no integer!). Use std::enable_if like this:

template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

Full example:

#include <iostream>
#include <type_traits>
#include <cmath>

using std::cout;
using std::endl;

template<typename T>
T mySine(T arg) {
    return sin(arg);
}

template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> 
T mySineFloatingPointOnly(T arg) {
    return sin(arg);
}

int main() {
    cout << mySine(1.5) << endl;
    // mySine(1) will work
    // mySineFloatingPointOnly(1) will fail to compile
    cout << mySineFloatingPointOnly(1.5) << endl;
}

 

Posted by Uli Köhler in C/C++

How to build debug in CMake

If you want to build an executable / library with debug symbols in CMake, run

cmake -DCMAKE_BUILD_TYPE=Debug .
make

Conversely, if you want to build an executable / library in release mode, run

cmake -DCMAKE_BUILD_TYPE=Release .
make

 

Posted by Uli Köhler in C/C++, CMake

How to write a function that takes any STL container as an argument in C++

STL containers take two template arguments, the type T inside the container and the allocator (which defaults to std::allocator<T>).

Therefore to write a function that takes any STL-like container, you have to do it like in this example function:

/**
 * Convert any STL-like container to a std::vector.
 */
template<template<typename, typename> typename Container, typename T, typename Allocator>
std::vector ToVector(const Container<T, Allocator>& args) {
    std::vector ret;
    ret.reserve(args.size());
    for(const T& arg : args) {
        ret.push_back(arg);
    }
    return ret;
}

This function can take any STL-like container like std::list, std::vector and also STL-compatible containers from third-party libraries and convert it to a std::vector.

Full example:

#include <list> // std::list
#include <vector> // std::vector
#include <iostream> // std::cout, std::endl

using namespace std;

/**
 * Convert any STL-like container to a std::vector.
 */
template<template<typename, typename> typename Container, typename T, typename Allocator>
std::vector ToVector(const Container<T, Allocator>& args) {
    std::vector ret;
    ret.reserve(args.size());
    for(const T& arg : args) {
        ret.push_back(arg);
    }
    return ret;
}

int main() {
    // Create list
    list myList;
    myList.push_back(2);
    myList.push_back(3);
    myList.push_back(5);
    // Convert to vector
    vector myVector = ToVector(myList);
    // Print vector - should print 2, 3 & 5
    for(int val : myVector) {
        cout << val << endl;
    }
}

Thanks to Jesse Good on StackOverflow for publishing hints on how to solve this problem. However, his version only works with STL containers that use std::allocator and not with STL containers without custom allocators. In my experience it’s very rare that you have to use a custom allocator, but if you do, it’s very hard to debug why the template doesn’t match.

Posted by Uli Köhler in C/C++