Tonight I shipped cylinder booleans. Subtracting cylinders from boxes to make holes. Classic CAD operation.
The problem: a cylinder intersects a cube’s face along a circle. Circles in 3D are annoying. No start, no end, curving through space. Splitting a planar face along one means handling the inner disk separately from the outer ring.
The answer is UV space.
parameter space
Every surface in CAD has a 2D coordinate system that maps to points on the 3D surface. We call the coordinates uu and vv because xx, yy, zz are taken.
A cylinder is just a rectangle that got rolled up:
- uu goes around the circumference (00 to 2π2\pi)
- vv goes up the height
The surface equation:
P(u,v)=center+r⋅(cos(u)⋅x^+sin(u)⋅y^)+v⋅axisP(…
Tonight I shipped cylinder booleans. Subtracting cylinders from boxes to make holes. Classic CAD operation.
The problem: a cylinder intersects a cube’s face along a circle. Circles in 3D are annoying. No start, no end, curving through space. Splitting a planar face along one means handling the inner disk separately from the outer ring.
The answer is UV space.
parameter space
Every surface in CAD has a 2D coordinate system that maps to points on the 3D surface. We call the coordinates uu and vv because xx, yy, zz are taken.
A cylinder is just a rectangle that got rolled up:
- uu goes around the circumference (00 to 2π2\pi)
- vv goes up the height
The surface equation:
P(u,v)=center+r⋅(cos(u)⋅x^+sin(u)⋅y^)+v⋅axisP(u, v) = \text{center} + r \cdot (\cos(u) \cdot \hat{x} + \sin(u) \cdot \hat{y}) + v \cdot \text{axis}
Plug in any (u,v)(u, v), get the exact 3D point. No triangles, no approximation.
circles become lines
When a horizontal plane cuts through a vertical cylinder, the intersection is a circle in 3D. In UV space? A horizontal line.
The circle sits at constant height hh. Height is the vv coordinate. So the circle becomes v=hv = h.
A 3D circle became a 1D line. That’s the trick.
splitting a cylinder
When you subtract a cylinder from a cube, you keep only the part inside the cube. That means splitting at the top and bottom faces.
Say the cube spans z=0 to z=20. The cylinder runs from z=-5 to z=25, poking out both ends. Intersection circles at z=0 and z=20.
In UV space:
-
Original cylinder: rectangle [0,2π]×[−5,25][0, 2\pi] \times [-5, 25]
-
Split at v=0v=0 and v=20v=20
-
Three strips:
-
Bottom [-5, 0]: outside cube, discard
-
Middle [0, 20]: inside cube, keep for hole wall
-
Top [20, 25]: outside cube, discard
"Split a curved 3D surface along two circles" became "draw two horizontal lines on a rectangle."
uv domains
Every curved surface has one:
| Surface | uu domain | vv domain |
|---|---|---|
| Cylinder | [0,2π][0, 2\pi] angle | (−∞,∞)(-\infty, \infty) height |
| Sphere | [0,2π][0, 2\pi] longitude | [−π2,π2][-\frac{\pi}{2}, \frac{\pi}{2}] latitude |
| Cone | [0,2π][0, 2\pi] angle | [0,∞)[0, \infty) distance from apex |
| Torus | [0,2π][0, 2\pi] major | [0,2π][0, 2\pi] minor |
The domain shape tells you about topology. A cylinder’s UV domain is an open rectangle, infinite in vv. A torus is closed, both uu and vv wrap around.
why bother
When building a CAD kernel, you have two choices:
- Work in 3D: intersect surfaces, trace curves through space, handle every edge case
- Work in UV: map to 2D, solve easy problems, map back
Option 2 wins.
Surface-surface intersection? Sample the curve, convert to UV, get a 2D curve on each surface. Trim curves? 2D paths. Face splitting? 2D polygon operations.
Complex 3D geometry becomes simple 2D geometry.
the code
Here’s cylinder splitting in vcad:
pub fn split_cylindrical_face_by_circle(
brep: &mut BRepSolid,
face_id: FaceId,
circle: &Circle3d,
) -> SplitResult {
let cyl = get_cylinder_surface(brep, face_id);
// Convert circle to UV: just compute v coordinate
let v_split = (circle.center - cyl.center).dot(&cyl.axis);
let (v_min, v_max) = get_face_v_bounds(brep, face_id);
// Lower: [0, 2π] × [v_min, v_split]
// Upper: [0, 2π] × [v_split, v_max]
create_split_faces(brep, face_id, v_split, v_min, v_max)
}
Fifteen lines. No 3D circle math. Project to v, split the rectangle.
the seam
One gotcha: cylinders have a seam. The UV rectangle’s left and right edges (u=0u=0 and u=2πu=2\pi) are the same line in 3D.
When a split curve crosses the seam, it wraps around. Phase 2 handles this. For perpendicular cuts like drilling holes, the intersection is a complete circle that doesn’t cross the seam, so we’re fine.
what’s next
Cylinder booleans unlocked:
- Drilling vertical holes through horizontal plates (done)
- Drilling angled holes (elliptical intersections)
- Cylinder-cylinder intersections (pipe joints)
- General curved surface booleans
Same pattern every time: map to UV, solve in 2D, map back.
Once you see surfaces as 2D domains, everything clicks.
Related: