Uli Köhler

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 Build systems, C/C++

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++

How to iterate TopTools_ListOfShape in OpenCASCADE

TopTools_ListOfShape is a NCollection_List<T> and hence supports iteration using the C++11 foreach loop (also called range-based for loop):
TopTools_ListOfShape myShapes = /* ... */;

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

Remember to compile with at least --std=c++11 or equivalent for your compiler to allow using the range-based for loop.

 

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

How to iterate NCollection_List in OpenCASCADE

NCollection_List<T> supports iteration using the C++11 foreach loop (also called range-based for loop):
NCollection_List<T> myList = /* ... */;

// Iterate myList
for(const T& value : myList) {
    /* ... */
}

Remember to compile with at least --std=c++11 or equivalent for your compiler to allow using the range-based for loop.

 

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

How to iterate all edges in TopoDS_Face using OpenCASCADE

You can use the OCCUtils library to iterate all TopoDS_Face instances in a TopoDS_Solid

#include <occutils/ShapeComponents.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

auto edges = ShapeComponents::AllEdgesWithin(myShape);

// Iterate all solids
for(const TopoDS_Edge& edge : edges) {
    /* ... */
}

Alternatively, you can use this raw OpenCASCADE source code without OCCUtils:

#include <TopTools_IndexedMapOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopExp.hxx>

TopoDS_Shape myShape = /* ... */;

TopTools_IndexedMapOfShape faces;
TopExp::MapShapes (myShape, TopAbs_EDGE, faces);

for (int i = 1; i <= faces.Extent (); i++) {
    TopoDS_Edge face = TopoDS::Edge(edges(i));
    /* ... */
}

If you have the choice, I recommend using OCCUtils since it makes your code much more readable than using the raw OpenCASCADE API.

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

How to iterate all faces in TopoDS_Solid using OpenCASCADE

You can use the OCCUtils library to iterate all TopoDS_Face instances in a TopoDS_Solid

#include <occutils/ShapeComponents.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

auto faces = ShapeComponents::AllFacesWithin(myShape);

// Iterate all solids
for(const TopoDS_Face& face : faces) {
    /* ... */
}

Alternatively, you can use this source code without OCCUtils:

#include <TopTools_IndexedMapOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopExp.hxx>

TopoDS_Shape myShape = /* ... */;

TopTools_IndexedMapOfShape faces;
TopExp::MapShapes (myShape, TopAbs_FACE, faces);

for (int i = 1; i <= faces.Extent (); i++) {
    TopoDS_Face face = TopoDS::Face(faces(i));
    /* ... */
}

If you have the choice, I recommend using OCCUtils since it makes your code much more readable than using the raw OpenCASCADE API.

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

How to get TopoDS_Solid(s) from TopoDS_Shape in OpenCASCADE

There are two important cases if you want to get a TopoDS_Solid object from a TopoDS_Shape:

A: The TopoDS_Shape is a solid

You can check if that is the case using

#include <TopoDS_Shape.hxx>

TopoDS_Shape myShape = /* ... */

bool isSolid = myShape.ShapeType() == TopAbs_SOLID;

Alternatively, you can use the Shape::IsSolid() function from OCCUtils:

#include <occutils/Shape.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

if(Shape::IsSolid(myShape)) {
    /* ... */
}

If it’s a solid, you can convert it to a TopoDS_Solid directly using:

TopoDS::Solid(myShape);

Full example:

#include <TopoDS_Shape.hxx>
#include <TopoDS.hxx>
#include <occutils/Shape.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

if (Shape::IsSolid(myShape)) {
    TopoDS_Solid solid = TopoDS::Solid(myShape);
    /* ... */
}

B: The shape is not itself a TopoDS_Solid but contains one or more TopoDS_Solids

This is often the case for TopoDS_Compounds. Use Shape::IsCompound() from OCCUtils to check if your TopoDS_Shape is actually a TopoDS_Compound.

#include <occutils/Shape.hxx>
using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;
if(Shape::IsCompound(myShape)) { /* ... */ }

Using OCCUtils, you have now several options to get the TopoDS_Solids from the Compound:

If there is a chance that there are zero or more than one TopoDS_Solids in your compound:

Use ShapeComponents::AllSolidsWithin() from OCCUtils to get a std::vector<TopoDS_Solid> of all solids within the TopoDS_Compound:

#include <occutils/Shape.hxx>
#include <occutils/ShapeComponents.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

auto solids = ShapeComponents::AllSolidsWithin(myShape);

// Iterate all solids
for(const TopoDS_Solid& solid : solids) {
    /* ... */
}

If you are sure the compound only contains one solid (also works if it’s a solid itself):

Use ShapeComponents::TryGetSingleSolid(shape) which returns a std::optional<TopoDS_Solid> (no value if there is no solid or there are multiple solids in shape) or ShapeComponents::GetSingleSolid(shape) which throws an exception if there is no solid or there are multiple solids in the shape.

Example:

#include <occutils/ShapeComponents.hxx>
#include <iostream> // cerr, endl

using namespace std;
using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

auto solidOpt = ShapeComponents::TryGetSingleSolid(myShape);

if(solidOpt.has_value()) {
    TopoDS_Solid solid = solidOpt.value();
} else {
    cerr << "No solid or multiple solids in shape!" << endl;
}

If you want to use pure OpenCASCADE without OCCUtils:

Use this snippet to directly iterate the TopoDS_Solid instances in the shape

TopTools_IndexedMapOfShape solidShapes;
TopExp::MapShapes (myShape, TopAbs_SOLID, solidShapes);

for (int i = 1; i <= solidShapes.Extent (); i++) {
    TopoDS_Solid solid = TopoDS::Solid(solidShapes(i));
    /* Do what you need with the solid here ! */
}

 

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

Quick tip: How to return std::optional from a function

Here’s a template for returning a std::optional from a function:

#include <optional>
// Remember to compile with --std=c++17 or equivalent

std::optional<double> myOptionalFunction() {
    auto myValue = /* ... */;
    if(myValue.IsNull()) {
        // We don't have a value
        return std::nullopt; // .has_value() => false
    }
    // We have a value, so return the value
    return myValue.AsDouble(); // .has_value() => true
}

std::nullopt is the easy way to return no value as a std::optional. Using this method instead of the default constructor (return std::optional<double>() in this case) you don’t explicitly have to enter the full qualified name including template argument (optional<double> if you use namespace std;). It’s much easier to read and copy&paste this way.

In the last line we can just return a double (myValue.AsDouble() in this example). Why? Because this will implicitly call the implicit constructor of std::optional<double>(const double& value) and therefore convert your double into a std::optional<double>() instance.

Usage example:

#include // std::optional
#include  // std::cerr, std::endl

using namespace std;

std::optional myOptionalFunction() {
    /* Your code goes here ! */
}

int main() {
    auto myOptionalValue = myOptionalFunction;
    if(myOptionalValue.has_value()) {
         // Print error message
         cerr << "The optional has no value!" << endl;
         return;
    }
    // Extract the value
    auto myValue = myOptionalValue.value();
    /* You can do something with myValue here! */
}

Alternatively you can use std::optional<T>::value_or() like this to give either the value or a default value:

#include <optional> // std::optional
#include <iostream> // std::cerr, std::endl

using namespace std;

std::optional<double> myOptionalFunction() {
    /* Your code goes here ! */
}

int main() {
    auto myOptionalValue = myOptionalFunction;
    const double defaultValue = 0.0;
    // Value will be 0.0 if myOptionalFunction() returned <no value>
    auto myValue = myOptionalValue.value_or(defaultValue);
    /* You can do something with myValue here! */
}
Posted by Uli Köhler in C/C++

How to compute surface area of TopoDS_Face in OpenCASCADE

In order to compute the surface area of a TopoDS_Face, in OpenCASCADE, simply use BRepGProp::SurfaceProperties and call .Mass() on the resulting GProp_GProps object:

GProp_GProps gprops;
BRepGProp::SurfaceProperties(face, gprops); // Stores results in gprops
double area = gprops.Mass();

Alternatively, you can use my OCCUtils library which also also providers a lot of other utility functions:

#include <occutils/Surface.hxx>
using namespace OCCUtils;

double Surface::Area(const TopoDS_Shape& face);

Example:

#include <occutils/Surface.hxx>

using namespace OCCUtils;

// ...
double area = Surface::Area(myFace);
// ...

 

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

How to update git submodule to current master or other branch?

Let’s say you have a git submodule in MySubmodule directory. If you have made changes to the repository referred to by MySubmodule, you might want to update your project to refer to the latest commit.

In order to do this, simply go to the MySubmodule directory and run git pull there. You can also git checkout any other branch.

After that, you need to commit the changes (i.e. which commit git submodule is referring to currently) in the outer repository.

git status in the outer repository will show you the changes like this:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   MySubmodule (new commits)

Use git add MySubmodule and git commit normally, or use git commit -a to commit all staged changes.

Posted by Uli Köhler in git, Version management

How to fix ‘ft2build.h: No such file or directory’

If your compiler shows you build errors like this:

/usr/include/opencascade/Font_FTLibrary.hxx:23:10: fatal error: ft2build.h: No such file or directory

you are missing the ft2build.h header file from libfreetype.

In order to install it on Ubuntu, use

sudo apt-get install libfreetype6-dev

If the error persists, you might want to add /usr/include/freetype2 to the include path. For GCC/G++, add

-I/usr/include/freetype2

to the command line arguments of the compiler.

If you use CMake, you can use a line like this in your CMakeLists.txt:

include_directories (/usr/include/freetype2)
Posted by Uli Köhler in C/C++

How to fix Wireshark "Couldn’t run /usr/bin/dumpcap in child process: Permission denied" on Linux

If you see an error message like this in Wireshark:

this is because your current user doesn’t have permission to capture packets from your network card.

This can be the case even if you have selected to allow normal users to capture packets during the Wireshark installation process. This is because the setting only takes effect after logging out and logging back in (or rebooting).

To fix the issue temporarily without logging out, run Wireshark as root: sudo wireshark

In order to fix the issue permanently, ensure your user is added to the wireshark group:

sudo usermod -a -G wireshark $USER

and then log out and log back in again (or reboot your computer).

Posted by Uli Köhler in Linux

How to fix SDCC ‘at 1: warning 119: don’t know what to do with file ‘main.o’. file extension unsupported’

If you use SDCC to compile your C code for your microcontroller and you encounter an error message like this:

at 1: warning 119: don't know what to do with file 'main.o'. file extension unsupported

you have to configure your build system to use the .rel suffix for object files instead of the standard .o. SDCC expects built object files to have the .rel extension! See How to change CMake object file suffix from default “.o” for details on how to do that in CMake.

Posted by Uli Köhler in Build systems, Embedded

How to fix dput ‘error 58: gpgme_op_verify’

Problem:

You want to upload a package to a PPA using dput <filename>.changes, but you see an error message like this:

Checking signature on .changes
gpg: /home/uli/dev/deb-buildscripts/stm8flash_0.1-git261-deb1-1_amd64.changes: error 58: gpgme_op_verify
gpgme_op_verify: GPGME: No data

Solution:

You need to sign your .changes file before uploading! Do this using

debsign -k 1BBC8BAA <filename>.changes

where 1BBC8BAA is your GPG key ID which you intend to sign with.

Posted by Uli Köhler in Build systems

How to change CMake object file suffix from default ".o"

In order to configure CMake to use an alternate object file suffix (default: .o on Linux) use these lines in your CMakeLists.txt:

set(CMAKE_C_OUTPUT_EXTENSION ".rel")
set(CMAKE_CXX_OUTPUT_EXTENSION ".rel")

This example changes the output extension from .o to .rel (which is required for the SDCC compiler). Be sure to replace ".rel" by your desired output suffix.

Note that in order for these to take effect, you might need to completely remove CMakeCache.txt, CMakeFiles & cmake_install.cmake:

rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake

 

Posted by Uli Köhler in Build systems, C/C++

A working SDCC STM8 CMake configuration

If you have been looking desperately for a working CMake example for the SDCC compiler for STM8 microcontrollers here’s my take on it:

cmake_minimum_required(VERSION 3.2)

set(CMAKE_C_OUTPUT_EXTENSION ".rel")
set(CMAKE_C_COMPILER sdcc)
set(CMAKE_SYSTEM_NAME Generic) # No linux target etc

# Prevent default configuration
set(CMAKE_C_FLAGS_INIT "")
set(CMAKE_EXE_LINKER_FLAGS_INIT "")

project(STM8Blink C)
SET(CMAKE_C_FLAGS "-mstm8 --std-c99")
add_executable(main.ihx main.c)

# Flash targets
add_custom_target(flash ALL COMMAND stm8flash -c stlink -p stm8s105c6 -w main.ihx)

This will build main.ihx from main.c. main.ihx is a Intel Hex file which can be directly flashed using stm8flash.

The last lines setup make flash ; you might need to use the correct microcontroller (stm8s105c6 in this example, run stm8flash -l to show supported devices) and the correct flash adapter (stlink, stlinkv2, stlinkv21, stlinkv3 or espstlink).

The setup example shown here is for the STM8S eval board.

I suppose it can be easily modified for other microcontrollers, but I haven’t tried that so far.

Posted by Uli Köhler in Build systems, Embedded, Hardware