How to check if gp_Ax1 contains gp_Pnt in OpenCASCADE

OCCUtils provides convenience functions for computing the orthogonal direction to two directions:

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

gp_Ax1 axis = /* ... */;
gp_Png point = /* ... */;
bool pointIsOnAxis = Axis::Contains(axis, point);

In case you can’t use OCCUtils, here’s the code to do it manually:

gp_Lin(axis).Contains(pnt, Precision::Confusion());
Posted by Uli Köhler in C/C++, OpenCASCADE

How to get gp_Dir orthogonal to two gp_Dirs in OpenCASCADE

OCCUtils provides convenience functions for computing the orthogonal direction to two directions:

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

gp_Dir dir1 = /* ... */;
gp_Dir dir2 = /* ... */;
gp_Dir orthogonalDirection = Direction::Orthogonal(dir1, dir2);

In case you can’t use OCCUtils, here’s the code to do it manually:

gp_Dir orthogonalDirection = dir1.Crossed(dir2);

The function used is called Crossed() since the mathematical operation being used is the cross product between the two direction vectors.

 

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

How to get midpoint/center between points in OpenCASCADE

OCCUtils provides convenience functions for getting the midpoint (also called the center) between 2 or more points:

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

gp_Pnt p1 = /* ... */;
gp_Pnt p2 = /* ... */;
gp_Pnt midpointOfP1AndP2 = Point::Midpoint({p1, p2});

You can also call Point::Midpoint() with a std::vector<gp_Pnt>.

In case you can’t use OCCUtils, here’s the code to do it manually:

double x = 0.0, y = 0.0, z = 0.0;
for (const gp_Pnt &pnt : points) {
    x += pnt.X();
    y += pnt.Y();
    z += pnt.Z();
}
size_t size = points.size();
gp_Pnt midpoint(x / size, y / size, z / size);

 

 

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

How to compute volume of TopoDS_Shape / TopoDS_Solid in OpenCASCADE

OCCUtils provides a convenience function to do this:

#include <occutils/Shape.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

double volume = Shape::Volume(myShape);

In case you need to do this without OCCUtils, use

GProp_GProps gprops;
BRepGProp::VolumeProperties(shape, gprops);
double volume = gprops.Mass();

 

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

Towards a docker-based build of C/C++ applications

Note: Based on this post I have published buildock on GitHub.

Many C/C++ programmers and project managers know the pain of creating a reproducible build environment for all developers: Works for me is a common meme not without a reason.

My approach is to dockerize not neccessarily the application itself but the build system, encapsulating both the specific compiler version and the system around it plus all required system-level libraries in a Docker image.

Take the obligatory Hello World in C++:

// main.cpp
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, World!" << endl;
    return 0;
}

and the corresponding Makefile:

all:
        g++ -o helloworld main.cpp

How can we compile this simple project without installing a compiler and GNU make on the local computer (no cheating by using build servers allowed)?

Actually it’s rather simple:

docker run --user $(id -u):$(id -g) -v $PWD:/app -it ulikoehler/ubuntu-gcc-make make

Breaking it down:

  • docker run: Create a new docker container and run a command in it
  • --user $(id -u):$(id -g): This makes the docker container run with the current user’s ID and the current user’s group – both for preventing the compiler to create output files as root and to safeguard against some IT security risks. Also see How to run docker container as current user & group
  • -v $PWD:/app: Mount the current directory ($PWD) on /app in the container. Since the Dockerfile used to build the container contains the WORKDIR /app directive, whatever command we run in the container will by default be executed in the /app directory – and therefore in the current local directory on the host.
  • -it runs the container in interactive mode, i.e. keypressed are passed down to the command you are running. Also, this means that our command will only finish when the container has finished executing.
  • ulikoehler/ubuntu-gcc-make: This is the image we’re using for that example. It’s nothing more than an ubuntu:18.04 base image with build-essentials and make installed and WORKDIR set to /app
  • make: This is the command we’ll run in the container. You can use any command here, even no command is possible (in which case the container’s default command will be used – in case of ulikoehler/ubuntu-gcc-make that is CMD [ "/usr/bin/make" ])

Here’s the complete Dockerfile used to generate ulikoehler/ubuntu-gcc-make:

FROM ubuntu:18.04
RUN apt update && apt -y install build-essential make && rm -rf /var/lib/apt/lists/*
WORKDIR /app
CMD [ "/usr/bin/make" ]
Posted by Uli Köhler in Build systems, C/C++, Container, Docker

How to have multiple Dockerfiles in one directory

Usually you build a docker image like

docker build -t myimagename .

but using this method you can only have one Dockerfile in each directory.

In case you don’t want to have separate directories for your Dockerfiles you can use the -f argument to docker build:

docker build -f FirstDockerfile .

Note that you still need to add . at the end so docker build knows where to COPY files from if you have COPY or similar statements in your Dockerfile.

Posted by Uli Köhler in Docker

How to run docker container as current user & group

If you want to prevent your docker container creating files as root, use

--user $(id -u):$(id -g)

as an argument to docker run. Example:

docker run --user $(id -u):$(id -g) -it -v $(pwd):/app myimage

 

Posted by Uli Köhler in Container, Docker, Linux

How to compute surface normal in OpenCASCADE

OCCUtils provides a convenient utility to compute the Normal of a surface (represented by a GeomAdaptor_Surface) in OpenCASCADE:

#include <occutils/Surface.hxx>

using namespace OCCUtils;

GeomAdaptor_Surface surf = /* ... */;

gp_Ax1 surfaceNormal = Surface::Normal(surf);

// ...or just get the direction
gp_Dir surfaceDirection = Surface::NormalDirection(surf);

This function computes the normal vector at specific U/V coordinates which default to (0,0). You can also give custom U/V coordinates:

gp_Ax1 normal = Surface::Normal(surf, 1.0 /* u */, -4.5 /* v */);

In case you can’t use OCCUtils and you need to do it manually, here’s how you can do it:

#include <GeomLProp_SLProps.hxx>

GeomLProp_SLProps props(surf.Surface(), u, v, 1 /* max 1 derivation */, precision);
gp_Ax1 axis(props.Value(), props.Normal());

props.Value() returns the point on the surface at the given U/V coordinates.

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

How to fix mongorestore ‘E11000 duplicate key error collection’

Problem:

You are trying to run mongorestore my-backup, but you see large numbers of warning messages like this one:

- E11000 duplicate key error collection: mydb.mycollection index: _id_ dup key: { : "MyKey" }

Solution:

By default, mongorestore does not overwrite or delete any existing documents. You need to tell it to drop each collection immediately before importing it from the backup:

mongorestore --drop my-backup

Any documents not in the backup will be permanently lost after running this!

Note that this will not drop collections that are not present in the backup.

Also see mongodump/mongorestore minimal examples

Posted by Uli Köhler in Databases

mongodump/mongorestore minimal examples

Create & restore a database

mongodump --db mydb --out mydb.mongobackup

This will backup the database mydb from the MongoDB running at localhost and store the backup in the newly created DigiKey.mongobackup directory as BSON.

mongorestore mydb.mongobackup

This will restore the backup to localhost (the database name, mydb, is stored in the backup directory).

It will not overwrite or update existing documents, nor delete documents that are currently present but not present in the backup.

Restore backup with drop

mongorestore --drop mydb.mongobackup

This will drop (i.e. delete) each collection before importing from the backup. This means that

  • Existing documents will effectively be overwritten
  • Documents that are currently present but not present in the backup will be deleted

However note that while importing the backup, some documents might be missing from the database until the backup has been fully restored.

Note that this will not drop collections that are not present in the backup.

Posted by Uli Köhler in Databases

How to fix C++ ‘fatal error: stringstream: No such file or directory’

Problem:

Your C++ code contains a line like

#include <stringstream>

since you want to use std::stringstream, but your compiler gives you this error message:

main.cpp:2:10: fatal error: stringstream: No such file or directory
 #include <stringstream>
          ^~~~~~~~~~~~~~
compilation terminated.

Solution:

The header is called sstream, not stringstream! Use this #include directive instead:

#include <sstream>
Posted by Uli Köhler in C/C++, GCC errors

How to parse hex strings in C++ using std::stringstream

This function converts any hex string like 55 to its equivalent decimal value:

#include <sstream>
#include <int>

unsigned int hexToDec(const std::string& str) {
    unsigned int ret;
    std::stringstream ss;
    ss << std::hex << str;
    ss >> ret;
    return ret;
}

e.g.

hexToDec("55"); // returns 85

Note that while the code is somewhat concise, it might be neither the most performant nor the most concise option especially for developers that don’t really know std::stringstream.

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

How to get first three characters of std::string in C++

To get the first three characters of myString use myString.substr() like this:

std::string firstTwo = myString.substr(0, 3);

The first argument ob substr() is the offset (i.e. how many characters to skip) which is 0 in this case since we don’t want to skip any characters.

The second argument of substr() is the number of characters to get. Since we want to get three characters, this is 3.

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

How to get first two characters of std::string in C++

To get the first two characters of myString use myString.substr() like this:

std::string firstTwo = myString.substr(0, 2);

The first argument ob substr() is the offset (i.e. how many characters to skip) which is 0 in this case since we don’t want to skip any characters.

The second argument of substr() is the number of characters to get. Since we want to get two characters, this is 2.

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

C++ std::string equivalent to Python’s rstrip

In Python you can do

"test ".rstrip()

whereas in C++ the easiest way is to use the the Boost String Algorithms library:

#include <boost/algorithm/string/trim.hpp>

using namespace boost::algorithm;

string to_trim = "test ";
string trimmed = trim_right_copy(to_trim);

_copy in trim_right_copy() means that the original string is not modified.

Full example:

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = "test ";
    string trimmed = trim_right_copy(to_trim);
    cout << trimmed << endl; // Prints 'test'
}

In case you want to trim a custom set of characters, use trim_right_copy_if() together with is_any_of():

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = "testXbbca";
    string trimmed = trim_right_copy_if(to_trim, is_any_of("abc"));
    cout << trimmed << endl; // Prints 'testX'
}

 

Posted by Uli Köhler in C/C++
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy