Skip to content
Bruno edited this page Jun 15, 2024 · 11 revisions

Constructive Solid Geometry

Geogram's CSG subsystem is implemented in geogram/mesh/mesh_CSG.h. The main class is the CSGBuilder. It applies boolean operations to a set of meshes, with an API made compatible with OpenSCAD's .csg file format. OpenSCAD is a 3D modeler with a programming language that lets you create objects using basic primitives (spheres, boxes, ...), geometric transforms and boolean operations to combine them. OpenSCAD supports two file formats:

  • .scad, which is its native file format, with all the constructs of the programming language (for loops, conditional statements, functions, modules ...)
  • .csg, which is a file format with only a CSG tree (primitives, transforms and boolean operations).

Geogram's CSGBuilder follows (as closely as possible) OpenSCAD's .csg file format. The example program src/examples/geogram/compute_CSG has four examples ported from OpenSCAD.

The CSGBuilder manipulates CSGMeshes. A CSGMesh is a geogram Mesh plus some additional information used by the CSGBuilder bookkeeping (bounding box, caching...). The type CSGMesh_var corresponds to a smart pointer to a CSGMesh (does memory management for you).

The C++ code to generate the first four OpenSCAD examples (see figure) is as follows. It uses curly-braces constructors for matrices, vectors and CSGScopes (that is, a list of CSGMeshes). The syntax is very close to OpenSCAD .csg files (with the exception of union that writes union_instr in CSGBuilder parlance, because union is a reserved C++ keyword !).

    GEO::CSGMesh_var example001() {
        using namespace GEO;
        CSGBuilder B;
        return B.difference({
                B.sphere(25.0),
                B.multmatrix(
                    {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}},
                    { B.cylinder(62.5, 12.5, 12.5) }
                ),
                B.multmatrix(
                    {{1, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}},
                    { B.cylinder(62.5, 12.5, 12.5) }
                ),
                B.multmatrix(
                    {{0, 0, 1, 0}, {0, 1, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 1}},
                    { B.cylinder(62.5, 12.5, 12.5) }
                )
            });
    }
    GEO::CSGMesh_var example002() {
        using namespace GEO;
        CSGBuilder B;
        return B.intersection({
                B.difference({
                        B.union_instr({
                                B.cube({30,30,30}),
                                B.multmatrix(
                                    {{1, 0, 0,  0},
                                     {0, 1, 0,  0},
                                     {0, 0, 1, -25},
                                     {0, 0, 0, 1}},
                                    {B.cube({15,15,40})}
                                )
                            }),
                        B.union_instr({
                                B.cube({50,10,10}),
                                B.cube({10,50,10}),
                                B.cube({10,10,50})
                            }),
                    }),
                B.multmatrix(
                    {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 5}, {0, 0, 0, 1}},
                    { B.cylinder(50, 20, 5) }
                )
            }); 
    }
    GEO::CSGMesh_var example003() {
        using namespace GEO;
        CSGBuilder B;
        return B.difference({
                B.union_instr({
                        B.cube({30, 30, 30}),
                        B.cube({40, 15, 15}),
                        B.cube({15, 40, 15}),
                        B.cube({15, 15, 40})
                    }),
                B.union_instr({
                        B.cube({50, 10, 10}),
                        B.cube({10, 50, 10}),
                        B.cube({10, 10, 50})
                    })
            });
    }
    GEO::CSGMesh_var example004() {
        using namespace GEO;
        CSGBuilder B;
        return B.difference({
                B.cube({30,30,30}),
                B.sphere(20)
            });
    }

To generate these meshes, one can use:

$ compute_CSG example001

(resp. example002,example003,example004). This will generate the result in out.meshb. Then, to visualize the result, use:

$ vorpaview out.meshb

The optional geogramplus expansion package

To gain more speed and more robustness in the extreme cases, read about GeogramPlus.

Clone this wiki locally