Skip to content

Constructive Solid Geometry

Constructive Solid Geometry (CSG) is an early approach for describing solids via directed acyclic graphs expressing cascading solid Boolean operations. The concept of building hierarchies of Boolean operations is motivated by (a) the desire to parameterize the construction of complex solids from simpler primitives and operations, (b) the need for efficient computation because Boolean operations among solids are often very expensive.

The geometric primitives of CSG include solid objects such as boxes, cylinders and spheres etc, but also more generally solids constructed by extrusion, revolution, sweeping etc of profiles. The Boolean operations include (a) Union, or solid addition, where two or more solids are combined, (b) Difference, or solid subtraction, where one or more solids are removed from another, and (c) Intersection where the common volume between two or more solids is computed.

Rhino's kernel is based on BReps presented later but nevertheless it supports the construction of solid primitives as well as Boolean operations as seen below. Additionally, by performing Boolean operation via a Grasshopper graph is very similar to CSG in the way that updates propagate only downstream in a parametric way.

Basic Primitives

""" Unit Length Cube
"""
cube = Brep.CreateFromBox( BoundingBox(
    Point3d( 0.0, 0.0, 0.0 ),
    Point3d( 1.0, 1.0, 1.0 ) ) )

""" Unit Radius+Height Cone
"""
cone = Brep.CreateFromCone( Cone(
    Plane.WorldXY, 1.0, 1.0 ), True )

""" Unit Radius Sphere
"""
ball = Brep.CreateFromSphere( Sphere(
    Plane.WorldXY, 1.0 ) )

Constructions

Examples of extrusion, revolution and sweeping are presented below. Note that in Rhino we need to manually put end caps to make solids.

""" Solid by Extrusion
"""
profile = PolylineCurve( [
    Point3d(-1.0, 0.0, 0.0 ),
    Point3d( 0.0, 0.0, 1.0 ),
    Point3d( 1.0, 0.0, 0.0 ),
    Point3d( 0.0, 0.0,-1.0 ),
    Point3d(-1.0, 0.0, 0.0 )] )

solid = Extrusion.Create(
    profile, 5.0, True )

""" Solid by Revolution
"""
profile = Polyline( [
    Point3d( 3.0, 0.0, 0.0 ),
    Point3d( 4.0, 0.0, 1.0 ),
    Point3d( 5.0, 0.0, 0.0 ),
    Point3d( 4.0, 0.0,-1.0 ),
    Point3d( 3.0, 0.0, 0.0 )] )

axis = Line(
    Point3d( 0.0, 0.0, 0.0 ),
    Point3d( 0.0, 0.0, 1.0 ) )

solid = Brep.CreateFromRevSurface(
    RevSurface.Create( profile, axis,
        0.0, math.pi * 2 ), False, False )

""" Solid by Sweep
"""
profile = PolylineCurve( [
    Point3d(-1.0, 0.0, 0.0 ),
    Point3d( 0.0, 0.0, 1.0 ),
    Point3d( 1.0, 0.0, 0.0 ),
    Point3d( 0.0, 0.0,-1.0 ),
    Point3d(-1.0, 0.0, 0.0 )] )

rail = NurbsCurve.Create( False, 2,[
    Point3d( 0.0, 0.0, 0.0 ),
    Point3d( 2.0, 3.0, 0.0 ),
    Point3d( 2.0, 0.0, 4.0 )] )

solid = Brep.CreateFromSweep(
    rail, profile, True, 1e-5 )
solid = Brep.CapPlanarHoles(
    solid[0], 1e-5 )

Boolean Operations

Rhino supports the typical solid Boolean operations. They all require a tolerance parameter used internally for approximate operations such as intersections using floating point numbers. They also all return a collection of solids because there may be more than one resulting solids and even possibly no results at all.

Boolean union requires a list of solid objects which if they intersect, they will form a single solid uniting or absorbing their overlapping parts. Union is commutative in the sense that the order of the solids does not matter. On the other hand Boolean difference is not commutative, therefore the first solid, or list of solids, is considered the subject and the second solid, or list of solids, is the object to be removed. The split operation is exactly the same as the difference operation but both the remaining and removed parts of the solid operation are returned. Boolean intersection computes the common solid between its operands, which may be empty if they don't overlap. Intersection is also commutative even though the style of parameter passing appears closer to the difference.

""" Solid Primitives
"""
one = Brep.CreateFromBox( BoundingBox(
    Point3d( 0.0, 0.0, 0.0 ),
    Point3d( 1.0, 1.0, 1.0 ) ) )

two = Brep.CreateFromBox( BoundingBox(
    Point3d( 0.5, 0.5, 0.5 ),
    Point3d( 1.5, 1.5, 1.5 ) ) )

""" Boolean Union
"""
solids = Brep.CreateBooleanUnion( [one, two], 1e-5 )

""" Boolean Difference
"""
solids = Brep.CreateBooleanDifference( one, two, 1e-5 )

""" Boolean Split
"""
solids = Brep.CreateBooleanSplit( one, two, 1e-5 )

""" Boolean Intersection
"""
solids = Brep.CreateBooleanIntersection( one, two, 1e-5 )