# Booleans, slots and parts

[Start here](https://pegmatite.dev/guide/start.md). Fetch this topic when a script cuts, intersects or reserves space, or divides a model into exported parts.

## Signs

| Sign | Operation            | Keeps                                  |
| ---- | -------------------- | -------------------------------------- |
| none | union                | both, joined                           |
| `-`  | difference           | what the operand does not cover        |
| `&`  | intersection         | only what the operand covers           |
| `^`  | symmetric difference | what belongs to exactly one of the two |

The sign may touch the solid or stand apart: `-cylinder 4 10` and `- cylinder 4 10` are the same. A sign against a value, `-$a`, negates the value. A compound or a macro call takes a sign too, so one operation handles several shapes:

```pegm
def %hole $diameter {
  cylinder $diameter 10
}

block 10 10 10
on #top -%hole 4
```

A signed volume cannot be the first volume of its context: braces, a part or the script.

### `-`

**Syntax:** **`-`** _solid_

Removes the operand. A `-` that misses every earlier volume or only touches one warns; the script still builds.

```pegm
/* Expected warning: This negative volume removes no material */
block 30 30 20
x 40 -cylinder 14 20
```

### `&`

**Syntax:** **`&`** _solid_

Keeps only what the operand covers, and discards every volume of the context it never reaches. With no overlap the model is empty. `-` and `^` also empty it when the operand covers or equals all material.

```pegm
cube 80
&cylinder 40 100
```

That leaves the cube's cylindrical core, full height.

### `^`

**Syntax:** **`^`** _solid_

Removes the overlap and adds the part of the operand that reaches past the model. An operand entirely inside the model acts as `-`.

```pegm
block 30 30 20
^block 44 20 20
```

The overhanging ends stay; the middle cancels.

## Placement of a signed volume

A signed volume uses the same context, anchor and alignment as a plain one, except on the anchor's axis: **a plain volume starts where its reference ends, a signed one reaches back across it** and bites into the material. Explicit alignments and offsets can still move it out of the material.

Default directions: `-` drills in from the top. `&` and `^` default to `@bottom`, so their bases are flush with the reference:

```pegm
block 30 30 20
&cylinder 24 20
```

A written direction overrides the default: `@top &cube 10` reaches down from the top. With `on`, the plane is the named face; with an anchor, the anchored face: `@top -cube 10` cuts a pocket where `@top cube 10` would rest a pin.

Only placement changes, not shape: a signed volume is not reflected, so a tapered solid keeps its taper. Use `flip` ([modifiers](https://pegmatite.dev/guide/modifiers.md)) for the reflected shape, `mirror` ([patterns](https://pegmatite.dev/guide/patterns.md)) for a reflected copy.

### Which end meets

Which end of the volume lands on the reference follows from the two signs. For an explicit `@top`:

| previous | this one | `@top` stands for | result                          |
| -------- | -------- | ----------------- | ------------------------------- |
| plain    | plain    | `z 100%:0%`       | they touch, end to end          |
| plain    | `-`      | `z 100%:100%`     | the cutter reaches back into it |
| `-`      | `-`      | `z 0%:0%`         | the cutter bases align          |
| `-`      | plain    | `z 0%:0%`         | the plug fills the hole's slot  |

Default directions are resolved separately; without a written direction, successive `-` volumes continue down into the model.

### The slot is the next reference

Every volume, whatever its sign, is the reference for the next. A signed volume leaves its operand's slot, marked as subtractive; the next placement uses it, not the bounds of the remaining material. A row of pockets lays out like a row of pins:

```pegm
cube 80
@top -cube 10
@right 10
-cube 10
```

With `cube` for `-cube` this gives two pins at the same X and Y. A pattern over a signed volume steps the same way:

```pegm
block 120 30 16
on #top
!@right 6
repeat 5 -cylinder 8 8
```

## Boolean scope

A signed volume combines with every earlier volume of its context, as though they were unioned first. A list does not isolate them:

```pegm
!@right 5
cube 20
cube 20
on #top -block 70 4 10
```

The groove crosses both cubes. Braces have their own context, so an operation inside never reaches out:

```pegm
cube 20
{
  block 30 30 10
  on #top -cube 12
}
```

The outer cube is untouched. A part is a context too. Scope `&` with braces: it discards everything of its context that it misses.

`-` and `&` distribute over the union, so the model keeps its separate volumes and colors. `^` does not: the piece of the operand no volume covered is added once, as a volume of its own.

## Slots

A volume has a **slot**, its box used for placement, and **material**. A sphere's slot is its bounding box, empty corners included. An ordinary prism's slot is the box around its faces, not its base's circumcircle.

- A compound's slot encloses the slots of its adding volumes, empty slots and partial sweep bounds included. `-` and `&` volumes lead the next volume inside the body but claim no room.
- Circular patterns, partial revolutions and helices under one turn use bounds mirrored about their sweep axis, so a partial ring keeps its axis; `shrink` uses the material's bounds instead.

### `slot`

**Syntax:** **`slot`** _solid_

Builds and places a solid with its whole pipeline, keeping its bounds and faces but no material. It becomes the next reference.

```pegm
slot block 40 40 60
on #front block 60 40 5
```

It takes any solid, compound or macro call. The shape's own faces come with it, numbered sides included:

```pegm
slot prism 6 100 20
on #f2 cube 10
```

A modifier shapes the room: `slot block 10 20 30 | rotate 90 about x` is the turned block's room. Labels, anchors, alignment and `on` work as with a solid:

```pegm
gap: slot block 60 40 20
block 60 40 5
on gap #back block 60 20 5
```

A plate 20 above the ground on a wall at the back of the space beneath. `-slot` and the other signs are refused: a slot has no volume to combine. For a plain gap in a row, `@top 20` says the same as a 20 tall `slot block`; use `slot` when the space must be named, aligned against or built on.

### Zero-sized volumes

A solid with a zero size, including an extrude's height or wall thickness, builds no material but is placed, passed through its pipeline and keeps its room like a slot:

```pegm
set $lid 0
block 40 40 20
@top block 40 40 $lid
@top cylinder 10 5
```

The cylinder stands where it would on a lid of any thickness. The room of `cube 0` is a point, of `block 40 40 0` a flat rectangle; `cube 0 @right cube 5` puts the cube's left face on the point.

- A sign treats it as empty: `cube 5 -cube 0` leaves the cube whole, `cube 5 &cube 0` leaves nothing, `cube 0 -cube 5` removes nothing. It still leaves its slot.
- A transform such as `rotate` turns its room: `cylinder 10 0 | rotate 90 about x` stands as tall as it is wide. Other modifiers only remove material and are skipped.
- It offers the six box faces and no numbered sides.
- An `extrude` of height zero keeps the flat room of its outline, its wall or its `to` shape; `apex` has no height to close. A zero wall keeps the room of its outline, rising or tapering as the wall would.
- A size within rounding of zero, `0.1 + 0.2 - 0.3`, counts as zero. A negative size is an error.
- A literal zero, `cube 0`, warns. A zero computed from a variable or a macro argument does not.

## Parts

**Syntax:** **`part`** _name_

Begins a part: the material built up to the next `part` belongs to it.

```pegm
part "Box"
box: block 60 40 30 | shell 2
part "Lid"
on box #top block 60 40 3
on #bottom block 55 35 3
```

- Placement, labels, persistent settings and variables carry on across parts; that is how the lid sits on the box.
- A part is its own boolean context: a signed volume reaches only its own part, and a part cannot begin with one.
- The name is a string, spaces allowed, `part "Left hinge"`. It names the export object and the report heading and is no reference: `on` cannot reach a part, use a label. Two parts may share a name and stay two parts.
- Material before the first `part` is a part named `Unnamed`. A script without `part` is one part, and each separate body is its own export object.
- `part` stands among the root statements, never inside braces, a list, an `if` branch or a macro body.

```pegm
part "Box"
block 40 40 10
part "Lid"
on #top block 40 40 4
-cylinder 6 30
```

The hole goes through the lid only. To cut both parts, cut in each, or call one macro in each.

```pegm
/* Expected error: A negative volume needs a volume to combine with */
part "Box"
block 40 40 10
part "Hole"
on #top -cylinder 6 30
```

A part that builds no material warns and is left out of the export:

```pegm
/* Expected warning: part "Spacer" builds no material and is not exported */
part "Box"
cube 20
part "Spacer"
slot cube 10
```

### Report and export

`--check` groups rows and diagnostics by part: a heading row with the part's name, material size, spans and line, then its labelled volumes.

- 3MF: one object per part, named after it, so a slicer lists touching parts apart. Within a part, touching material fuses; separate bodies are one object of several pieces.
- STEP: bodies named after their part, numbered when it has several. A model without parts names its bodies after the model.
- STL drops part names. See [CLI](https://pegmatite.dev/guide/cli.md).
