March 09, 2023
I built the general workflow of replicad to be similar to a standard CAD workflow: draw in 2D, sketch this in a plane in 3D, and then give it some thickness (extrude, revolve or sweep).
Unfortunately, there is no support for some basic 2D CAD operations in open cascade. For instance, there is no 2D boolean operations: fusing shapes together, cutting one with another.
I found multiple libraries to do 2D operations, but they all failed to be the CAD library I expected. Let’s see what they lack (in my opinion, of course), and build my list of requirements.
We can start with the other open source CAD kernel, solvespace. It is a full featured kernel, but lack an important feature for 2D CAD, offsets.
Offsets can be understood as parallel curves. They tend to be very useful to transform a line into a 2D shape (by giving it some kind of stroke width). CAM tools also use these to draw tool paths.
Then let’s have a look at Clipper. This is a very performant library that does boolean operation (i.e. what they call clipping) and offsetting. Unfortunately, it only works with polygons (i.e. shapes built with straight lines).
What is this issue with polygons? Depending on your use case polygons are great. You can approximate any curve by a set of lines, and then use clipper to do your operations on it. This is what this great gear generator does.
This is the analogous of a mesh for 3D objects. The trade off is also the same – you gain some simplicity of computation (and performance), but lose information about the shape itself (the topology). It becomes more difficult to select an edge of your shape (what is an edge then?).
Note that many other libraries that deal with 2D geometries have the same issue. I could find shapely for instance.
Cavalier contours is a rust library for offsets and boolean operations that supports arcs of circle in addition to straight lines. It seems that it is based on well researched algorithms, is fast and has some nice webassembly builds.
The issue I have with it, is its data model. As a very well focussed library and offers a simple API for defining poly lines. But it stops at that point – its data structure does not support anything like translations or rotations. There is no concept of holes within closed poly lines and ways to understand the inclusion logic.
I am looking for a full CAD library. Cavalier contours is not that. It is good at some singular operations - but I would need to be extended a lot to become a proper CAD library.
Flatten offers all the functionality that clippers and cavalier contours are missing. It supports arcs, is meant as a CAD library, with a data model for “islands” and “holes” and APIs around inclusion of shapes within other shapes.
But arcs are not enough – if you want to draw shapes that are slightly organic or need to be smooth, it becomes useful to offer Bézier curves. For instance fonts for text rendering are represented as sets of Bézier curves. This is also a significant part of paths in SVG (or vector graphics in general).
It is possible to approximate Bézier curves with arcs - but we get the same issue that we had with polygons. You loose the semantic relation between what an edge is and how you represent it.
maker.js (that I used to build the paper models in deckinabox) has the same issue. It is a full CAD library, it let you define Bézier curves, but they are just arcs in disguise.
Note that cavalier contours does not support Bézier either.
There are some other typical features of 2D CAD software that I did not mention. For instance, performance is not my main concern now - I am more looking for functionality first (and then, potentially, performance).
Then, solvespace, while it does not have offsets, offers a constraints solver. This is very powerful for visual CAD (where these are more intuitive than raw numbers). I have focussed on the code CAD aspects of a 2D library – and I don’t think that constraints are great for code. Note that open cascade also has a constraints solver.
Within replicad I use open cascade as the kernel. As I mentioned earlier 2D support within open cascade is sparse.
While it does not offer the CAD operations themselves in 2D (not 2D booleans or offsets), it gives the primitives needed (intersections and offsets of a single curve). So I built the complex curves data structures, boolean operations and offsets on top of the open cascade primitives.
This is still not great. A big drawback is that you need to pull a lot of things from open cascade and deal with garbage collection yourself. It is also far from perfect in many ways. For instance offsets of Béziers tend to fail a lot.
But it has other advantages that none of the other libraries provide. Open cascade has an arc of ellipses type of curve, it provides ways to work with BSplines (even better than Béziers!), it supports stretching and shearing transformations and it has built-in approximation routines.
So what do I want from a 2D CAD library:
And there are some other aspects that would be nice to have:
Even with my minimal requirements I could not find any library that fit the bill. Within replicad, the best I could achieve was to extend open cascade so that it worked with its basic 2D primitives.
You can discuss this post on Mastondon