[ANN] `ConstructiveGeometry.jl`: a package for CAD

As announced a few weeks ago already, I started a package for defining CAD.

The package is here and it should be able to perform a few simple designs already; there are a few examples included in the directory.


The design is quite inspired by OpenSCAD:

s1 = sphere(20)
s2 = cube(20)
mesh(s1 ∪ s2)
mesh(s1 ∩ s2)
mesh(s1 \ s2)
mesh(hull(s1, s2))

(ConstructiveGeometry wrote explicit polyhedra for these four shapes, and OpenSCAD was used for rendering the image).

Current status

  • Primitives are implemented: square, circle, cube, sphere, cylinder, surface, polygon.
  • Some basic CSG operations work in 2d and 3d: union, intersection, difference, convex hull, offset.
  • Basic linear extrusion should work (no twist or rescale though), and there is some code for path extrusion (which is something OpenSCAD cannot do :slight_smile: ):
  • Minkowski is currently half-working in 2d and not yet implemented in 3d.
  • Text is not yet implemented.
  • Output is possible as an OpenSCAD file.
  • Most 3d algorithms could be quite improved for speed (most notably: resolving self-intersections in a surface is not optimized at all).

Differences with OpenSCAD

Why write a package where there’s a perfectly useable CAD language out there? I believe that using Julia gives a few long-term advantages:

  • leveraging an existing programming language (and one which is well-adapted to that kind of computations, too);
  • provide introspection into geometry objects inside the language (OpenSCAD’s modules are totally opaque, the program cannot even determine their dimension);
  • give the capability of interfacing with external libraries if needed;
  • in the long term, I also believe that this could be more efficient.

Also, I used simpler and, I believe, less irritating algorithms for 3d computations: where OpenSCAD uses Nef polyhedra, ConstructiveGeometry uses regularized meshes. Concretely, this means that, whereas in OpenSCAD, difference() { cube(1); cube(1); } returns infinitely thin walls, in Julia cube(1) \ cube(1) returns an empty object.

(…or so it should. I just checked and currently it returns an error; oh well, >>TODO I guess. But the algorithm does remove opposite faces).

This means that, when removing something or glueing two objects, with this package there should be no need to add an extra 0.01 millimeter just to prevent razor-thin walls (or worse, razor-thin gaps, which can ruin a 3d print!).

Also, while we are there, I believe that computing on meshes gives a bit more tools compared to signed distance functions (e.g. the ability to include a STL file, or an image), hence the interest of having something different from ImplicitCAD or Descartes.jl. (But also note that the package design allows using marching cubes as a backend for meshing if so desired).


There is already a ConstructiveSolidGeometry.jl package, with a last commit dating from almost 4 years ago. I don’t believe that the name similitude will be much of a hindrance.

Next goals

  • reach feature parity with OpenSCAD, most notably minkowski, text, import.
  • add low-hanging features absent from OpenSCAD: Minkowski difference, path extrusion, functional sweep.
  • add built-in visualization (e.g. via Makie). I would be very happy to receive any contributions on this part in particular (I don’t know anything about visualization in Julia).
  • direct export to STL, SVG etc.
  • improve efficiency of some critical 3d algorithms (I’m looking at you, self_intersect).
  • later: port the functionality of various standard OpenSCAD libraries (it will be much less work to write this in a decent language).

Thank you @circonflexe , as I mentioned in that GitHub issue, it would be nice to use a common set of types to build this functionality you are building. We have all these primitives and more in Meshes.jl and ideally we would be able to converge on this codebase.

Feel free to ping me in private if you want to discuss a convergence plan. It is good to centralize the geometric work as a team because the current state of the geometric packages in Julia is quite fragmented and things don’t play well together.


New release 0.2.0 is up.

This is a major performance update: I basically rewrote from scratch the 3d engine, using more efficient data structures. (More precisely: triangle-triangle intersection and mesh insertion used to be quadratic; now everything is at most O(n log(n) (i.e. asymptotically optimal)), and often much less). Compared to the precedent release, the (small) model I use for benchmarking saw more than 100-fold speed improvement.

I took advantage of this to reorganize the code in what I hope will be a clearer way; some parts of this package might have some interest as independent modules (such as generic triangle-triangle intersection or spatial sorting).

There remains work to do though. This release did not add many (if any) new features. I still plan to add, in the next few ones:

  • inbuilt mesh visualization,
  • direct STL export and import,
  • allowing exact arithmetic for geometry computations,
  • Minkowski sum and difference (at least for 2d objects).