File size: 7,701 Bytes
7c72eb2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# Free Function API

## Overview

The Free Function API provides an alternative to the fluent Workplane API.
It has no hidden state - every operation takes explicit inputs and returns explicit outputs.
Selectors still work as methods on Shape objects, but all other operations are free functions.

```python
from cadquery.func import *
```

Use this API when:
- Building shapes face-by-face or edge-by-edge
- Lofting between non-planar edges or constructing organic surfaces
- Avoiding booleans via `addHole()` / `replace()` for performance
- Working in parametric surface space (`trim()`, `edgeOn()`, `wireOn()`)
- The explicit, stateless style is clearer for the task at hand

---

## Primitives

All primitives return Shape objects that can be immediately operated on.

```python
from cadquery.func import *

e = segment((0, 0), (0, 1))     # line edge
c = circle(1)                    # circular edge
r = rect(2, 1)                   # rectangular wire
f = plane(1, 1.5)                # flat face
b = box(1, 1, 1)                 # solid box
cy = cylinder(1, 2)              # solid cylinder (radius, height)
sp = sphere(1)                   # solid sphere
co = cone(1, 1.5)                # solid cone (r1, r2)
```

Combine unrelated shapes into a compound for display or export:

```python
result = compound(e, c.moved(x=2), f.moved(x=4), b.moved(x=6))
```

---

## Shape Construction

Build higher-level shapes from lower-level ones.

```python
e1 = segment((0, 0), (1, 0))
e2 = segment((1, 0), (1, 1))

w = wire(e1, e2)           # edges β†’ wire
f = face(circle(1))        # closed wire β†’ face
s = solid(f1, f2, f3)      # faces β†’ solid
sh = shell(f1, f2)         # faces β†’ shell (open solid β€” use before solid() when sewing)
cp = compound(s1, s2)      # shapes β†’ compound
```

**`solid()` vs `shell()`:** Use `solid()` when all faces are already properly connected.
Use `shell()` first to sew faces together when the topology needs explicit stitching
(e.g., when adding protrusions or working with trimmed surfaces).

---

## Operations

### Extrude

Accepts a wire or a face. Direction is a 3-tuple vector.

```python
r = rect(1, 0.5)
f = face(r)

s1 = extrude(r, (0, 0, 2))      # wire β†’ solid with open ends
s2 = extrude(f, (0, 0, 1))      # face β†’ closed solid
```

### Loft

Lofts through a sequence of edges or wires. `cap=True` closes the ends automatically.

```python
s = loft(circle(1), circle(1.5).moved(z=5), circle(1).moved(z=10))
s_capped = loft(rect(2, 1), circle(1).moved(z=5), cap=True)
```

For curvature-continuous end caps, use `cap()` instead of `fill()` after lofting:

```python
side = loft(circle(1), circle(1.3).moved(z=5), circle(1).moved(z=10))
base = fill(side.edges("<Z"))                  # flat cap β€” no curvature continuity
top  = cap(side.edges(">Z"), side)             # smooth cap β€” continuous with side
result = solid(side, base, top)
```

### Sweep

```python
profile = rect(0.5, 0.3)
path = segment((0, 0, 0), (0, 0, 10))   # straight path

result = sweep(profile, path)
```

Spline paths are supported - see the CadQuery docs and tests for the correct
`spline()` argument form, as dispatch is sensitive to argument types.

### Revolve

```python
# revolve(face, axis_point, axis_direction, angle_degrees)
f = face(rect(1, 0.5)).moved(x=2)
result = revolve(f, (0, 0, 0), (0, 1, 0), 90)
```

---

## Placement

The Free Function API has no workplane. Position shapes with `.moved()` and `.move()`.

```python
b = box(1, 1, 1)

b.moved(x=2)                    # translate
b.moved(rx=90)                  # rotate 90Β° around X (degrees)
b.moved(x=2, rz=45)             # translate and rotate
b.move(z=5)                     # in-place variant (modifies and returns self)
```

### Patterns - multiple locations in one call

Passing multiple position tuples to `.moved()` creates a **compound** of copies:

```python
peg = cylinder(1, 5)

result = peg.moved(
    (-5, -5, 0),
    ( 5, -5, 0),
    (-5,  5, 0),
    ( 5,  5, 0),
)   # compound of 4 pegs
```

### Face-relative placement

Select the face and use its geometry to derive position:

```python
b = box(20, 20, 10)
top = b.faces(">Z")
z = top.Center().z

boss = cylinder(3, 8).moved(z=z)
result = b + boss
```

---

## Boolean Operations

Boolean ops are available as both operators and free functions.
**Avoid booleans in loops** - they recompute the full boundary each time.

```python
c1 = cylinder(1, 2)
c2 = cylinder(0.5, 3)

r1 = c1 + c2          # union  (also: fuse(c1, c2))
r2 = c1 - c2          # cut    (also: cut(c1, c2))
r3 = c1 * c2          # intersect (also: intersect(c1, c2))
r4 = c1 / plane()     # split  (also: split(c1, plane()))
```

Boolean ops work on 2D shapes (faces, wires) as well as solids:

```python
outer = plane(20, 20)
inner = plane(10, 10)
frame = outer - inner          # face with a hole
result = extrude(frame, (0, 0, 5))
```

When unioning many shapes, combine into a compound first to reduce operation count:

```python
pins = [cylinder(0.5, 5).moved(x=i*1.5) for i in range(8)]
result = box(20, 5, 5) - compound(pins)   # one boolean, not 8
```

---

## Adding Features Without Booleans

For complex shapes where boolean performance matters, use `addHole()` and `replace()`
to modify individual faces directly rather than recomputing the full solid boundary.

```python
from cadquery.func import *

w = 1
r = 0.9 * w / 2

b = box(w, w, w)
b_bot = b.faces("<Z")
b_top = b.faces(">Z")

inner = extrude(circle(r), (0, 0, w))

b_bot_hole = b_bot.addHole(inner.edges("<Z"))
b_top_hole = b_top.addHole(inner.edges(">Z"))

result = solid(
    b.remove(b_top, b_bot).faces(),
    b_bot_hole,
    inner,
    b_top_hole,
)
```

For protrusions (adding material rather than removing it), sew with `shell()` first
to give the kernel enough context to stitch the new faces correctly:

```python
b = box(1, 1, 1)
b_top = b.faces(">Z")

feat_side = extrude(circle(0.4).moved(b_top.Center()), (0, 0, 0.2))
feat_top  = face(feat_side.edges(">Z"))
feat      = shell(feat_side, feat_top)   # sew into a shell first

b_top_hole = b_top.addHole(feat.edges("<Z"))
b = b.replace(b_top, b_top_hole)

sh = shell(b_top_hole, feat.faces("<Z"), ctx=(b, feat))
result = solid(sh)
```

---

## Text

`text()` uses multimethod dispatch β€” **all arguments must be positional**.
Keyword arguments will raise a `DispatchError`.

```python
from cadquery.func import *

# Planar text along a line
spine = segment((0, 0, 0), (30, 0, 0))
result = text("CadQuery", 3, spine, planar=True)

# Normal (projected) text along a spine on a surface
# See the CadQuery docs for the full surface projection example
```

---

## Parametric Surface Mapping

Advanced: trim faces and edges in parametric (u, v) space.

```python
from cadquery.func import cylinder, edgeOn, wire

base = cylinder(1.5, 3).faces("%CYLINDER")

# Rectangular trim
r = base.trim(-1.5, 0, 0, 1)

# Construct an edge in parametric space and trim with it
from math import pi
pcurve = edgeOn(base, [(0, 0.5), (pi, 0.5), (pi, 1.5), (0, 1.5)], periodic=True)
trimmed = base.trim(wire(pcurve))
```

Use `wireOn()` to map a 3D wire onto a surface, and `faceOn()` to map a face:

```python
from cadquery.func import sphere, text, faceOn

base = sphere(5).faces()
result = faceOn(base, text("CadQuery", 1))
```

---

## Selectors in the Free Function API

Selectors work identically to the fluent API β€” as string methods on any Shape object.

```python
b = box(20, 20, 10)

top       = b.faces(">Z")
side_faces = b.faces("#Z")
circ_edges = b.faces(">Z").edges("%Circle")
```

No Workplane is needed. The same selector strings, combinators, and tag syntax all apply.
See `concepts/selectors.md` for the full reference.