8.3 Boolean Operations in 2D
SLO 3
Describe, design, implement, and test structured programs using currently accepted methodology.
Learning Objectives
By the end of this section, you will be able to:
- combine two or more shapes with
union,subtract, andintersect; - explain why the order of arguments matters in
subtract; - build a washer or ring shape with a two-step subtract;
- explain why the order of operations changes the result of nested booleans;
- combine many shapes at once with a variadic boolean call.
All three live in JSCAD → booleans. Each takes two or more geometries of the same type (all geom2, or all geom3) and returns a new geometry — inputs are left unmodified.
In programming, a boolean operation is one that combines things with a yes/no rule. Here the "things" are shapes, and the rules are add, remove, and overlap — the same ideas as set union, subtraction, and intersection in math.
union(…geometries) → geom2|geom3
The combined space covered by every input geometry.
Union works the same way on 2D shapes. Here a rectangle and a circle are joined into one outline:
Union joins every input into one shape. If two shapes overlap, the overlap is counted once — you get a single merged object, not two shapes sitting on top of each other.
Use union to combine two circles: one of radius 10 at the origin and one of radius 10 centered at (15, 0). Write the JSCAD call.
Solution
Step 1 — pick the operation. We want to join two shapes, so we use union.
Step 2 — build the two circles. The first is circle({ radius: 10 }) at the origin. The second is circle({ radius: 10, center: [15, 0] }).
Step 3 — pass both to union. union takes all the geometries as arguments.
Answer: union(circle({ radius: 10 }), circle({ radius: 10, center: [15, 0] })) — one merged shape covering both circles.
subtract(…geometries) → geom2|geom3
Space in the first geometry that is not in any of the following geometries. Order matters: subtract(A, B) and subtract(B, A) are different shapes.
Subtract also carves a hole that is not centered. Here a circle is bitten out of the corner of a rectangle:
Subtract carves the first shape away using the ones that follow. Swap the arguments and you carve the other way — the result is a different shape, so always think about which shape you are keeping.
subtract keeps the first shape and carves the rest out of it — so the argument you put first is the one that survives. Build a rectangle and cut a hole out of its middle; each comment below is one line for you to write. Press Run when you are done.
Solution
You should see a 20-by-10 rectangle with a radius-4 hole in its middle. The rectangle went first, so it is the shape kept. Now swap the arguments — subtract(hole, base) — and run it again: you get the circle with a rectangle bitten out of it instead. Same two shapes, different result, because the first argument is the survivor.
Use subtract to remove a radius-4 circle from a radius-10 circle, both centered at the origin. Write the JSCAD call.
Solution
Step 1 — pick the operation. We want to remove one shape from another, so we use subtract.
Step 2 — decide which shape to keep. We keep the radius-10 circle, so it goes first.
Step 3 — build the two circles and subtract. The first argument is circle({ radius: 10 }); the second is circle({ radius: 4 }).
Answer: subtract(circle({ radius: 10 }), circle({ radius: 4 })) — a ring with a radius-4 hole in the middle.
intersect(…geometries) → geom2|geom3
Only the space present in all input geometries — the overlap.
Intersect works the same way on 2D shapes. Here a rectangle and a circle overlap, and only the shared space survives:
Where union keeps everything and subtract keeps one minus the other, intersect keeps only the part that is in every input at once. If two shapes barely touch, intersect returns a sliver.
Use intersect to find the overlap of two circles: one of radius 10 at the origin and one of radius 10 centered at (15, 0). Write the JSCAD call.
Solution
Step 1 — pick the operation. We want only the shared space, so we use intersect.
Step 2 — build the two circles. The first is circle({ radius: 10 }) at the origin. The second is circle({ radius: 10, center: [15, 0] }).
Step 3 — pass both to intersect.
Answer: intersect(circle({ radius: 10 }), circle({ radius: 10, center: [15, 0] })) — the lens-shaped overlap where the two circles meet.
Combining booleans
A washer/ring is a canonical two-step subtract:
A washer is just a big circle with a smaller circle cut out of its middle. It is the simplest real part you can make with booleans, and it shows how subtract turns two shapes into one useful object.
You are not limited to one operation. Build a washer with subtract, then union it with other shapes, or subtract again to add more holes — the operations combine to make complex parts.
The washer is the classic first boolean part: a big circle with a smaller one cut out of its middle. This version is a full script — imports, a main, and an export — not just one line. Each comment below is one line for you to write. Press Run when you are done.
Solution
You should see a washer — a radius-20 circle with a radius-12 hole cut from its center. The outer circle is the first argument, so it is the shape that survives. Change the inner radius to 8 and run it again: the hole grows and the ring of material gets thinner.
Write a complete JSCAD script that builds a washer with an outer radius of 30 and an inner radius of 18.
Solution
Step 1 — import the functions. We need circle from primitives and subtract from booleans.
Step 2 — set the radii. The outer radius is 30 and the inner radius is 18.
Step 3 — subtract the inner circle from the outer circle. The outer circle goes first so it is the shape we keep.
Answer: The script above returns a washer — a radius-30 circle with a radius-18 hole cut from its center.
Order of operations
Booleans nest, and the order you nest them changes the result. subtract(union(a, b), c) first joins a and b, then carves c out of the whole. union(subtract(a, c), b) first carves c out of a alone, then joins the result with b. When c overlaps the join between a and b, the two orders carve different shapes.
In the first fence, c sits right on the seam where a and b meet, so carving it out of the union leaves a clean hole through the middle. In the second, c is carved out of a before b is added, so the hole is only in a — the seam stays solid. Same three shapes, different result, because the parentheses decide what happens first.
Using the shapes a = circle({ radius: 10 }), b = circle({ radius: 10, center: [15, 0] }), and c = circle({ radius: 4, center: [7.5, 0] }), write the JSCAD call that carves c out of a first, then joins the result with b.
Solution
Step 1 — decide the order. We carve c out of a first, so subtract(a, c) comes first.
Step 2 — join the result with b. The carved a is the first argument to union, and b is the second.
Answer: union(subtract(a, c), b) — the hole is carved into a alone, then b is joined on, so the seam stays solid.
Booleans on many shapes at once
All three operations take a variadic list — you can pass as many geometries as you like, and they are combined in one call. union(a, b, c, d) joins all four. You can also spread an array of shapes into the call with the ... operator.
A variadic function accepts a list of arguments of any length, so union can take two shapes or twenty. When your shapes already live in an array, spread them in: union(...shapes) is the same as listing them out by hand.
Write a JSCAD call that joins four circles of radius 8 centered at (0, 0), (12, 0), (0, 12), and (12, 12) using a single union call.
Solution
Step 1 — build the four circles. Each is circle({ radius: 8 }) with a different center.
Step 2 — pass all four to one union call. union is variadic, so it takes all four geometries as arguments.
Answer: union(circle({ radius: 8 }), circle({ radius: 8, center: [12, 0] }), circle({ radius: 8, center: [0, 12] }), circle({ radius: 8, center: [12, 12] })) — one merged shape covering all four circles.
Problem Set
Problem 1. In your own words, describe what each of union, subtract, and intersect does to a set of input shapes.
Problem 2. Explain why subtract(A, B) and subtract(B, A) produce different shapes. Give a concrete example.
Problem 3. Write a JSCAD call that uses union to join a rectangle of size [10, 20] and a circle of radius 5 centered at (10, 0).
Problem 4. Write a JSCAD call that uses subtract to remove a radius-3 circle from a radius-8 circle, both centered at the origin.
Problem 5. Write a JSCAD call that uses intersect to find the overlap of a rectangle of size [10, 10] and a circle of radius 8 centered at (5, 5).
Problem 6. Write a complete JSCAD script that builds a washer with an outer radius of 25 and an inner radius of 10.
Problem 7. Using the shapes a = circle({ radius: 10 }), b = circle({ radius: 10, center: [15, 0] }), and c = circle({ radius: 4, center: [7.5, 0] }), write the JSCAD call that joins a and b first, then carves c out of the result.
Problem 8. Write a JSCAD call that joins four circles of radius 8 centered at (0, 0), (12, 0), (0, 12), and (12, 12) using a single union call.
Key Terms
boolean operation — a way of combining shapes with a yes/no rule: union, subtract, or intersect.
union — the combined space covered by every input geometry.
subtract — the space in the first geometry that is not in any of the following geometries.
intersect — only the space present in all input geometries, the overlap.
geom2 / geom3 — the object types JSCAD uses for 2D and 3D geometry; boolean operations require inputs of the same type.
variadic — a function that accepts any number of arguments, so union(a, b, c, d) can take two shapes or twenty.
order of operations — the sequence in which nested boolean operations are evaluated, decided by the parentheses; changing it changes the result.