forgecad 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -12
- package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
- package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
- package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
- package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
- package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
- package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
- package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
- package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
- package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
- package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
- package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
- package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
- package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
- package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
- package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
- package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
- package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
- package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
- package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/CLI.md +341 -718
- package/dist/docs-raw/generated/assembly.md +699 -112
- package/dist/docs-raw/generated/concepts.md +1834 -1346
- package/dist/docs-raw/generated/core.md +1012 -1059
- package/dist/docs-raw/generated/curves.md +759 -116
- package/dist/docs-raw/generated/lib.md +43 -748
- package/dist/docs-raw/generated/output.md +139 -245
- package/dist/docs-raw/generated/sdf.md +208 -0
- package/dist/docs-raw/generated/sheet-metal.md +473 -21
- package/dist/docs-raw/generated/sketch.md +1518 -362
- package/dist/docs-raw/generated/viewport.md +368 -299
- package/dist/docs-raw/generated/wood.md +104 -0
- package/dist/index.html +2 -2
- package/dist/landing/proof-ams-adapter.png +0 -0
- package/dist/landing/proof-bolt-and-nut.png +0 -0
- package/dist/landing/proof-fillet-enclosure.png +0 -0
- package/dist/landing/proof-glasses.png +0 -0
- package/dist/landing/proof-gyroid.png +0 -0
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +12321 -5700
- package/dist-cli/forgecad.js.map +1 -0
- package/dist-cli/solver-46FFSK2U.js +363 -0
- package/dist-cli/solver-46FFSK2U.js.map +1 -0
- package/dist-skill/CONTEXT.md +4890 -6302
- package/dist-skill/SKILL-dev.md +22 -66
- package/dist-skill/SKILL.md +20 -59
- package/dist-skill/docs/API/core/concepts.md +37 -92
- package/dist-skill/docs/CLI.md +341 -718
- package/dist-skill/docs/generated/assembly.md +699 -112
- package/dist-skill/docs/generated/core.md +1012 -1059
- package/dist-skill/docs/generated/curves.md +759 -116
- package/dist-skill/docs/generated/lib.md +43 -748
- package/dist-skill/docs/generated/output.md +139 -245
- package/dist-skill/docs/generated/sdf.md +208 -0
- package/dist-skill/docs/generated/sheet-metal.md +473 -21
- package/dist-skill/docs/generated/sketch.md +1518 -362
- package/dist-skill/docs/generated/viewport.md +368 -299
- package/dist-skill/docs/generated/wood.md +104 -0
- package/dist-skill/docs/guides/coordinate-system.md +11 -17
- package/dist-skill/docs/guides/geometry-conventions.md +13 -70
- package/dist-skill/docs/guides/joint-design.md +78 -0
- package/dist-skill/docs/guides/modeling-recipes.md +22 -195
- package/dist-skill/docs/guides/positioning.md +88 -147
- package/dist-skill/docs-dev/API/core/concepts.md +78 -0
- package/dist-skill/docs-dev/CLI.md +488 -0
- package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
- package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
- package/dist-skill/{docs → docs-dev}/coding.md +2 -4
- package/dist-skill/docs-dev/component-model.md +164 -0
- package/dist-skill/docs-dev/generated/assembly.md +779 -0
- package/dist-skill/docs-dev/generated/core.md +1676 -0
- package/dist-skill/docs-dev/generated/curves.md +855 -0
- package/dist-skill/docs-dev/generated/lib.md +55 -0
- package/dist-skill/docs-dev/generated/output.md +234 -0
- package/dist-skill/docs-dev/generated/sdf.md +208 -0
- package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
- package/dist-skill/docs-dev/generated/sketch.md +1753 -0
- package/dist-skill/docs-dev/generated/viewport.md +513 -0
- package/dist-skill/docs-dev/generated/wood.md +104 -0
- package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
- package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
- package/dist-skill/docs-dev/guides/joint-design.md +78 -0
- package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
- package/dist-skill/docs-dev/guides/positioning.md +151 -0
- package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
- package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
- package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
- package/examples/api/attachTo-basics.forge.js +8 -8
- package/examples/api/bill-of-materials.forge.js +9 -9
- package/examples/api/bolt-pattern.forge.js +5 -5
- package/examples/api/boolean-operations.forge.js +5 -5
- package/examples/api/bounding-box-visualizer.forge.js +3 -3
- package/examples/api/clone-duplicate.forge.js +2 -2
- package/examples/api/colors-union-vs-array.forge.js +6 -6
- package/examples/api/connector-assembly.forge.js +8 -6
- package/examples/api/connector-basics.forge.js +7 -7
- package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
- package/examples/api/elbow-test.forge.js +3 -3
- package/examples/api/extrude-options.forge.js +8 -14
- package/examples/api/feature-created-faces.forge.js +6 -10
- package/examples/api/fillet-showcase.forge.js +2 -2
- package/examples/api/folded-service-panel-cover.forge.js +2 -2
- package/examples/api/gears-tier1.forge.js +5 -5
- package/examples/api/group-test.forge.js +3 -3
- package/examples/api/group-vs-union.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +4 -0
- package/examples/api/js-module-pillars.js +1 -1
- package/examples/api/js-module-scene.js +2 -2
- package/examples/api/mesh-import-slats.forge.js +4 -4
- package/examples/api/patterns.forge.js +3 -3
- package/examples/api/pointAlong-orientation.forge.js +3 -3
- package/examples/api/profile-2020-b-slot6.forge.js +4 -5
- package/examples/api/route-perimeter-flange.forge.js +1 -1
- package/examples/api/sdf-rover-demo.forge.js +10 -10
- package/examples/api/sketch-on-face-demo.forge.js +2 -2
- package/examples/api/sketch-regions.forge.js +4 -4
- package/examples/api/sketch-rounding-strategies.forge.js +1 -1
- package/examples/api/smooth-curve-connections.forge.js +1 -1
- package/examples/api/transition-curves.forge.js +4 -4
- package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
- package/examples/api/variable-sweep-test.forge.js +2 -2
- package/examples/api/wood-joinery.forge.js +60 -0
- package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
- package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
- package/examples/constraints/01-fully-constrained-rect.forge.js +2 -2
- package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
- package/examples/constraints/03-redundant-constraints.forge.js +2 -2
- package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
- package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
- package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
- package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
- package/examples/constraints/09-stress-spiral.forge.js +1 -1
- package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
- package/examples/constraints/11-surface-grid.forge.js +2 -2
- package/examples/constraints/12-surface-nested.forge.js +4 -4
- package/examples/constraints/13-surface-complex.forge.js +1 -1
- package/examples/exact-arc-housing.forge.js +12 -0
- package/examples/experiments/drone-arm.forge.js +53 -0
- package/examples/furniture/adjustable-table.forge.js +15 -15
- package/examples/furniture/bathroom.forge.js +26 -26
- package/examples/furniture/chair.forge.js +13 -13
- package/examples/furniture/picture-frame.forge.js +6 -6
- package/examples/furniture/shoe-rack-doors.forge.js +8 -8
- package/examples/furniture/shoe-rack.forge.js +7 -7
- package/examples/furniture/table-lamp.forge.js +8 -8
- package/examples/gcode/lissajous-vase.forge.js +4 -4
- package/examples/gcode/math-surface.forge.js +3 -3
- package/examples/gcode/parametric-vase.forge.js +4 -4
- package/examples/gcode/spiral-tower.forge.js +4 -4
- package/examples/generative/crystal-growth.forge.js +9 -9
- package/examples/generative/frost-spires.forge.js +9 -9
- package/examples/generative/golden-spiral-tower.forge.js +11 -11
- package/examples/generative/molten-forge.forge.js +6 -6
- package/examples/generative/neon-coral.forge.js +7 -7
- package/examples/mechanical/3d-printer.forge.js +37 -37
- package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
- package/examples/mechanical/airplane-propeller.forge.js +9 -9
- package/examples/mechanical/bolt-and-nut.forge.js +10 -10
- package/examples/mechanical/door-with-hinges.forge.js +7 -7
- package/examples/mechanical/fillet-enclosure.forge.js +15 -11
- package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
- package/examples/mechanical/robot_hand.forge.js +24 -24
- package/examples/mechanical/robot_hand_2.forge.js +26 -26
- package/examples/nurbs-surface.forge.js +8 -0
- package/examples/nurbs-tube.forge.js +7 -0
- package/examples/products/bottle.forge.js +8 -8
- package/examples/products/chess-set.forge.js +25 -25
- package/examples/products/classical-piano.forge.js +20 -20
- package/examples/products/clock.forge.js +33 -33
- package/examples/products/cup.forge.js +5 -5
- package/examples/products/iphone.forge.js +20 -20
- package/examples/products/laptop.forge.js +24 -24
- package/examples/products/laser-cut-box.forge.js +6 -6
- package/examples/products/laser-cut-tray.forge.js +6 -6
- package/examples/products/liquid-soap-dispenser.forge.js +23 -23
- package/examples/products/origami-fish.forge.js +14 -12
- package/examples/products/spiderman-cake.forge.js +6 -6
- package/examples/shelf/container.forge.js +5 -5
- package/examples/shelf/shelf-unit.forge.js +6 -6
- package/examples/toolbox/bolted-joint.forge.js +7 -7
- package/package.json +9 -4
- package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
- package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
- package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
- package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
- package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
- package/dist/assets/index-1CYp3zUp.js +0 -1455
- package/dist-skill/docs/API/API.md +0 -1666
- package/dist-skill/docs/API/README.md +0 -37
- package/dist-skill/docs/API/assembly/assembly.md +0 -617
- package/dist-skill/docs/API/core/edge-queries.md +0 -130
- package/dist-skill/docs/API/core/parameters.md +0 -122
- package/dist-skill/docs/API/core/reserved-terms.md +0 -137
- package/dist-skill/docs/API/core/sdf.md +0 -326
- package/dist-skill/docs/API/core/skill-cli.md +0 -194
- package/dist-skill/docs/API/core/skill-guide.md +0 -205
- package/dist-skill/docs/API/core/specs.md +0 -186
- package/dist-skill/docs/API/core/topology.md +0 -372
- package/dist-skill/docs/API/entities.md +0 -268
- package/dist-skill/docs/API/output/bom.md +0 -58
- package/dist-skill/docs/API/output/brep-export.md +0 -87
- package/dist-skill/docs/API/output/dimensions.md +0 -67
- package/dist-skill/docs/API/output/export.md +0 -110
- package/dist-skill/docs/API/output/gcode.md +0 -195
- package/dist-skill/docs/API/runtime/viewport.md +0 -420
- package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
- package/dist-skill/docs/API/sketch/anchor.md +0 -37
- package/dist-skill/docs/API/sketch/booleans.md +0 -91
- package/dist-skill/docs/API/sketch/core.md +0 -73
- package/dist-skill/docs/API/sketch/extrude.md +0 -62
- package/dist-skill/docs/API/sketch/on-face.md +0 -104
- package/dist-skill/docs/API/sketch/operations.md +0 -78
- package/dist-skill/docs/API/sketch/path.md +0 -75
- package/dist-skill/docs/API/sketch/primitives.md +0 -146
- package/dist-skill/docs/API/sketch/regions.md +0 -80
- package/dist-skill/docs/API/sketch/text.md +0 -108
- package/dist-skill/docs/API/sketch/transforms.md +0 -65
- package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
- package/dist-skill/docs/INDEX.md +0 -94
- package/dist-skill/docs/RELEASING.md +0 -55
- package/dist-skill/docs/cli-monetization.md +0 -111
- package/dist-skill/docs/deployment.md +0 -281
- package/dist-skill/docs/generated/concepts.md +0 -2112
- package/dist-skill/docs/internals/shape-from-slices.md +0 -152
- package/dist-skill/docs/platform/admin.md +0 -45
- package/dist-skill/docs/platform/architecture.md +0 -79
- package/dist-skill/docs/platform/auth.md +0 -110
- package/dist-skill/docs/platform/email.md +0 -67
- package/dist-skill/docs/platform/projects.md +0 -111
- package/dist-skill/docs/platform/sharing.md +0 -90
- package/dist-skill/docs/runbook.md +0 -345
|
@@ -5,368 +5,547 @@ skill-order: 100
|
|
|
5
5
|
|
|
6
6
|
# Sketch API
|
|
7
7
|
|
|
8
|
-
> **Auto-generated** from `src/forge/forge-public-api.ts`. Do not edit by hand — run `npm run gen:docs` to regenerate.
|
|
9
|
-
|
|
10
8
|
2D geometry creation, transforms, booleans, constrained sketches, and extrusion.
|
|
11
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [2D Sketch Primitives](#2d-sketch-primitives) — `path`, `stroke`, `rect`, `circle2d`, `roundedRect`, `polygon`, `ngon`, `ellipse`, `slot`, `arcSlot`, `star`
|
|
13
|
+
- [2D Sketch Booleans](#2d-sketch-booleans) — `union2d`, `difference2d`, `intersection2d`
|
|
14
|
+
- [2D Sketch Features](#2d-sketch-features) — `fillet2d`, `chamfer2d`
|
|
15
|
+
- [2D Text](#2d-text) — `loadFont`, `text2d`, `textWidth`
|
|
16
|
+
- [Constrained Sketches](#constrained-sketches) — `constrainedSketch`, `addRect`, `addPolygon`, `addRegularPolygon`
|
|
17
|
+
- [2D Geometry Helpers](#2d-geometry-helpers) — `point`, `line`, `circle`, `degrees`, `radians`
|
|
18
|
+
- [Sketch](#sketch) — Transforms, Booleans, Features, Promotion, Placement, Labels, Measurement
|
|
19
|
+
- [ConstrainedSketchBuilder](#constrainedsketchbuilder) — Drawing, Entities, Geometric Constraints, Dimensional Constraints, Coincidence & Equality, Tangent Transitions, Shape Constraints, Positioning, Solving
|
|
20
|
+
- [ConstraintSketch](#constraintsketch)
|
|
21
|
+
- [SketchGroupBuilder](#sketchgroupbuilder)
|
|
22
|
+
- [Point2D](#point2d)
|
|
23
|
+
- [Line2D](#line2d)
|
|
24
|
+
- [Circle2D](#circle2d)
|
|
25
|
+
- [Rectangle2D](#rectangle2d)
|
|
26
|
+
|
|
12
27
|
## Functions
|
|
13
28
|
|
|
14
29
|
### 2D Sketch Primitives
|
|
15
30
|
|
|
16
|
-
Create
|
|
31
|
+
#### `path()` — Create a new [`PathBuilder`](/docs/curves#pathbuilder) for tracing a 2D outline point by point.
|
|
17
32
|
|
|
18
|
-
|
|
33
|
+
[`PathBuilder`](/docs/curves#pathbuilder) is a fluent API for constructing 2D profiles using a mix of line segments, arcs, bezier curves, and splines. Always start with `.moveTo(x, y)` to set the starting point. Call `.close()` to get a filled `Sketch`, or `.stroke(width)` to thicken an open polyline into a solid profile.
|
|
34
|
+
|
|
35
|
+
Edge labels can be assigned with `.label('name')` after any segment — they propagate through extrusion, revolve, loft, and sweep into named faces on the resulting [`Shape`](/docs/core#shape).
|
|
19
36
|
|
|
20
37
|
```ts
|
|
21
|
-
|
|
38
|
+
// Closed triangle
|
|
39
|
+
const triangle = path().moveTo(0, 0).lineH(50).lineV(30).close();
|
|
40
|
+
|
|
41
|
+
// L-shaped bracket as a stroke
|
|
42
|
+
const bracket = path().moveTo(0, 0).lineH(50).lineV(-70).lineAngled(20, 235).stroke(4);
|
|
43
|
+
|
|
44
|
+
// Labeled edges for downstream face references
|
|
45
|
+
const slot = path()
|
|
46
|
+
.moveTo(0, 0)
|
|
47
|
+
.lineTo(30, 0).label('bottom')
|
|
48
|
+
.lineTo(30, 10)
|
|
49
|
+
.lineTo(0, 10).label('top')
|
|
50
|
+
.close();
|
|
22
51
|
```
|
|
23
52
|
|
|
24
|
-
|
|
53
|
+
```ts
|
|
54
|
+
path(): PathBuilder
|
|
55
|
+
```
|
|
25
56
|
|
|
26
|
-
#### `stroke()`
|
|
57
|
+
#### `stroke()` — Create a stroked polyline sketch from an array of 2D points.
|
|
27
58
|
|
|
28
59
|
```ts
|
|
29
60
|
stroke(points: [ number, number ][], width: number, join?: "Round" | "Square"): Sketch
|
|
30
61
|
```
|
|
31
62
|
|
|
32
|
-
|
|
63
|
+
#### `rect()` — Create a 2D rectangle centered at the origin.
|
|
33
64
|
|
|
34
|
-
|
|
65
|
+
```ts
|
|
66
|
+
rect(40, 20).extrude(5);
|
|
67
|
+
```
|
|
35
68
|
|
|
36
69
|
```ts
|
|
37
|
-
rect(width: number, height: number
|
|
70
|
+
rect(width: number, height: number): Sketch
|
|
38
71
|
```
|
|
39
72
|
|
|
40
|
-
Create a 2D
|
|
73
|
+
#### `circle2d()` — Create a 2D circle centered at the origin.
|
|
74
|
+
|
|
75
|
+
Omit `segments` for a smooth (auto-tessellated) circle. Pass an integer to get a regular polygon approximation — e.g. `6` for a hexagon, `8` for an octagon.
|
|
41
76
|
|
|
42
|
-
|
|
77
|
+
```ts
|
|
78
|
+
circle2d(25).extrude(10); // smooth cylinder
|
|
79
|
+
circle2d(25, 6).extrude(10); // hexagonal prism
|
|
80
|
+
```
|
|
43
81
|
|
|
44
82
|
```ts
|
|
45
83
|
circle2d(radius: number, segments?: number): Sketch
|
|
46
84
|
```
|
|
47
85
|
|
|
48
|
-
Create a 2D
|
|
86
|
+
#### `roundedRect()` — Create a 2D rectangle with rounded corners, centered at the origin.
|
|
49
87
|
|
|
50
|
-
|
|
88
|
+
The corner radius is automatically clamped to `min(width/2, height/2)` so it can never exceed the shape dimensions.
|
|
51
89
|
|
|
52
90
|
```ts
|
|
53
|
-
roundedRect(
|
|
91
|
+
roundedRect(60, 30, 5).extrude(3);
|
|
54
92
|
```
|
|
55
93
|
|
|
56
|
-
|
|
94
|
+
```ts
|
|
95
|
+
roundedRect(width: number, height: number, radius: number): Sketch
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### `polygon()` — Create a 2D polygon from an array of `[x, y]` points or `Point2D` objects.
|
|
99
|
+
|
|
100
|
+
Winding order is normalized automatically — clockwise (CW) input is silently reversed to CCW before being passed to the geometry kernel.
|
|
57
101
|
|
|
58
|
-
|
|
102
|
+
```ts
|
|
103
|
+
polygon([[0, 0], [50, 0], [25, 40]]).extrude(5); // triangle
|
|
104
|
+
```
|
|
59
105
|
|
|
60
106
|
```ts
|
|
61
107
|
polygon(points: ([ number, number ] | Point2D)[]): Sketch
|
|
62
108
|
```
|
|
63
109
|
|
|
64
|
-
Create a
|
|
110
|
+
#### `ngon()` — Create a regular polygon inscribed in a circle of the given radius.
|
|
65
111
|
|
|
66
|
-
|
|
112
|
+
`radius` is the center-to-vertex (circumradius) distance. Use `sides` of `3` for a triangle, `6` for a hexagon, etc. The first vertex is at the top (−90° from +X).
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
ngon(6, 20).extrude(10); // hexagonal prism, circumradius 20
|
|
116
|
+
```
|
|
67
117
|
|
|
68
118
|
```ts
|
|
69
119
|
ngon(sides: number, radius: number): Sketch
|
|
70
120
|
```
|
|
71
121
|
|
|
72
|
-
|
|
122
|
+
#### `ellipse()` — Create a 2D ellipse centered at the origin.
|
|
73
123
|
|
|
74
|
-
|
|
124
|
+
```ts
|
|
125
|
+
ellipse(30, 15).extrude(5);
|
|
126
|
+
ellipse(30, 15, 32).extrude(5); // lower-resolution approximation
|
|
127
|
+
```
|
|
75
128
|
|
|
76
129
|
```ts
|
|
77
130
|
ellipse(rx: number, ry: number, segments?: number): Sketch
|
|
78
131
|
```
|
|
79
132
|
|
|
80
|
-
Create a
|
|
133
|
+
#### `slot()` — Create a slot (oblong / stadium shape) — a rectangle with semicircular ends, centered at the origin.
|
|
81
134
|
|
|
82
|
-
|
|
135
|
+
```ts
|
|
136
|
+
slot(40, 10).extrude(3); // 40mm long, 10mm wide slot
|
|
137
|
+
```
|
|
83
138
|
|
|
84
139
|
```ts
|
|
85
140
|
slot(length: number, width: number): Sketch
|
|
86
141
|
```
|
|
87
142
|
|
|
88
|
-
|
|
143
|
+
#### `arcSlot()` — Create an arc-shaped slot (banana / annular sector) centered at the origin.
|
|
89
144
|
|
|
90
|
-
|
|
145
|
+
The slot is symmetric about the +X axis. The two ends are closed with semicircular caps. `pitchRadius` is the distance from the origin to the centerline of the slot, and `thickness` is the radial width of the slot.
|
|
91
146
|
|
|
92
147
|
```ts
|
|
93
|
-
|
|
148
|
+
arcSlot(135, 74, 40).extrude(5); // pitch R135, 74° sweep, 40mm wide
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
arcSlot(pitchRadius: number, sweepDeg: number, thickness: number): Sketch
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### `star()` — Create a star shape with alternating outer and inner radii.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
star(5, 30, 12).extrude(4); // five-pointed star
|
|
94
159
|
```
|
|
95
160
|
|
|
96
|
-
|
|
161
|
+
```ts
|
|
162
|
+
star(points: number, outerR: number, innerR: number): Sketch
|
|
163
|
+
```
|
|
97
164
|
|
|
98
165
|
### 2D Sketch Booleans
|
|
99
166
|
|
|
100
|
-
Combine 2D sketches.
|
|
167
|
+
#### `union2d()` — Combine 2D sketches into a single profile using an additive boolean union.
|
|
101
168
|
|
|
102
|
-
|
|
169
|
+
Accepts individual sketches or arrays: `union2d(a, b, c)` or `union2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.add()` one by one when combining many sketches.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const cross = union2d(rect(60, 10), rect(10, 60));
|
|
173
|
+
```
|
|
103
174
|
|
|
104
175
|
```ts
|
|
105
176
|
union2d(...inputs: SketchOperandInput[]): Sketch
|
|
106
177
|
```
|
|
107
178
|
|
|
108
|
-
|
|
179
|
+
#### `difference2d()` — Subtract one or more 2D sketches from a base sketch.
|
|
180
|
+
|
|
181
|
+
The first sketch is the base; all subsequent sketches are subtracted from it. Accepts individual sketches or arrays: `difference2d(base, c1, c2)` or `difference2d([base, c1, c2])`. Uses Manifold's batch operation — faster than chaining `.subtract()` one by one.
|
|
109
182
|
|
|
110
|
-
|
|
183
|
+
```ts
|
|
184
|
+
const donut = difference2d(circle2d(50), circle2d(30));
|
|
185
|
+
```
|
|
111
186
|
|
|
112
187
|
```ts
|
|
113
188
|
difference2d(...inputs: SketchOperandInput[]): Sketch
|
|
114
189
|
```
|
|
115
190
|
|
|
116
|
-
|
|
191
|
+
#### `intersection2d()` — Keep only the area where all input sketches overlap (intersection boolean).
|
|
117
192
|
|
|
118
|
-
|
|
193
|
+
Accepts individual sketches or arrays: `intersection2d(a, b)` or `intersection2d([a, b, c])`. Uses Manifold's batch operation — faster than chaining `.intersect()` one by one.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const lens = intersection2d(circle2d(30).translate(-10, 0), circle2d(30).translate(10, 0));
|
|
197
|
+
```
|
|
119
198
|
|
|
120
199
|
```ts
|
|
121
200
|
intersection2d(...inputs: SketchOperandInput[]): Sketch
|
|
122
201
|
```
|
|
123
202
|
|
|
124
|
-
|
|
203
|
+
### 2D Sketch Features
|
|
125
204
|
|
|
126
|
-
|
|
205
|
+
#### `fillet2d()` — Round a named vertical edge of a shape with a circular fillet.
|
|
127
206
|
|
|
128
|
-
|
|
207
|
+
Compiler-owned fillet for tracked vertical edges. Requires a compile-plan-covered target (shapes from `box()`, `rectangle().extrude()`, or rigid transforms of those).
|
|
129
208
|
|
|
130
|
-
|
|
209
|
+
**Supported edges:**
|
|
131
210
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
211
|
+
- Tracked vertical edges from `box()` or `rectangle().extrude()`
|
|
212
|
+
- Rigid transforms between tracked source and target
|
|
213
|
+
- Untouched sibling tracked vertical edges after earlier `fillet2d`/`chamfer2d`
|
|
135
214
|
|
|
136
|
-
|
|
215
|
+
**Not supported:** edges after shell, hole, cut, trim, difference, intersection, generic sketch extrudes, or tapered extrudes. Use [`fillet()`](/docs/core#fillet) with an `EdgeQuery` for those cases.
|
|
137
216
|
|
|
138
|
-
|
|
217
|
+
Canonical quadrants: `vert-bl → [1,-1]`, `vert-br → [-1,-1]`, `vert-tr → [-1,1]`, `vert-tl → [1,1]`
|
|
139
218
|
|
|
140
219
|
```ts
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
size?: number;
|
|
144
|
-
/** Extra space between characters in model units. Negative values tighten the tracking. */
|
|
145
|
-
letterSpacing?: number;
|
|
146
|
-
/** Horizontal alignment relative to x = 0. - `'left'` — left edge at x = 0 (default) - `'center'` — centred on x = 0 - `'right'` — right edge at x = 0 */
|
|
147
|
-
align?: "left" | "center" | "right";
|
|
148
|
-
/** Vertical alignment relative to y = 0. - `'baseline'` — y = 0 is the text baseline (bottom of capital letters) - `'center'` — y = 0 is the vertical midpoint of the cap height - `'top'` — y = 0 is the top of capital letters */
|
|
149
|
-
baseline?: "baseline" | "center" | "top";
|
|
150
|
-
/** Font to use for text rendering. - `'sans-serif'` or `'inter'` — bundled Inter font (works everywhere, including browser) - **file path** — path to a TTF, OTF, or WOFF font file (CLI/Node only) - **Font object** — a previously loaded opentype.js Font (from `loadFont()`) - **omitted** — uses the bundled Inter font (same as `'sans-serif'`) text2d('Hello World', { size: 10 }) // default Inter text2d('Custom Font', { size: 10, font: '/path/to/font.ttf' }) */
|
|
151
|
-
font?: string | opentype$1.Font;
|
|
152
|
-
/** Bezier flattening tolerance in model units. Smaller = more polygon segments = smoother curves. */
|
|
153
|
-
flattenTolerance?: number;
|
|
154
|
-
}
|
|
220
|
+
const b = rectangle(0, 0, 50, 50).extrude(20);
|
|
221
|
+
const filleted = fillet2d(b.toShape(), b.edge('vert-br'), 5, [-1, -1]);
|
|
155
222
|
```
|
|
156
223
|
|
|
157
|
-
</details>
|
|
158
|
-
|
|
159
|
-
#### `textWidth()`
|
|
160
|
-
|
|
161
224
|
```ts
|
|
162
|
-
|
|
225
|
+
fillet2d(shape: Shape, edge: EdgeRef, radius: number, quadrant?: [ number, number ], segments?: number): Shape
|
|
163
226
|
```
|
|
164
227
|
|
|
165
|
-
|
|
228
|
+
**`EdgeRef`**
|
|
229
|
+
- `query?: EdgeQueryRef` — Compiler-owned edge query when available.
|
|
230
|
+
- Also: `name: EdgeName`
|
|
166
231
|
|
|
167
|
-
|
|
232
|
+
#### `chamfer2d()` — Bevel a named vertical edge of a shape with a 45° chamfer.
|
|
168
233
|
|
|
169
|
-
|
|
234
|
+
Compiler-owned chamfer for tracked vertical edges. Requires a compile-plan-covered target. Supported subset and quadrant semantics are the same as `fillet2d()` — see that function for details.
|
|
170
235
|
|
|
171
|
-
|
|
236
|
+
```ts
|
|
237
|
+
const b = rectangle(0, 0, 50, 50).extrude(20);
|
|
238
|
+
const chamfered = chamfer2d(b.toShape(), b.edge('vert-br'), 3, [-1, -1]);
|
|
239
|
+
```
|
|
172
240
|
|
|
173
241
|
```ts
|
|
174
|
-
|
|
242
|
+
chamfer2d(shape: Shape, edge: EdgeRef, size: number, quadrant?: [ number, number ]): Shape
|
|
175
243
|
```
|
|
176
244
|
|
|
177
|
-
|
|
245
|
+
### 2D Text
|
|
178
246
|
|
|
179
|
-
|
|
247
|
+
#### `loadFont()` — Pre-load and cache a font for use with `text2d()`.
|
|
180
248
|
|
|
181
|
-
|
|
182
|
-
interface ConstrainedSketchOptions {
|
|
183
|
-
/** When true, adding a constraint that cannot be satisfied throws instead of silently discarding it. */
|
|
184
|
-
strict?: boolean;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
249
|
+
Fonts are cached by their source string (or `cacheKey` for `ArrayBuffer` sources), so repeated calls with the same path are free. Pre-loading is useful when you call `text2d()` many times with the same font — it avoids repeated disk reads.
|
|
187
250
|
|
|
188
|
-
|
|
251
|
+
Built-in font names that work everywhere (browser + CLI):
|
|
189
252
|
|
|
190
|
-
|
|
253
|
+
- `'sans-serif'` or `'inter'` — bundled Inter Regular
|
|
191
254
|
|
|
192
255
|
```ts
|
|
193
|
-
|
|
256
|
+
const font = loadFont('/path/to/Arial Bold.ttf');
|
|
257
|
+
text2d('Title', { size: 12, font }).extrude(1.5);
|
|
258
|
+
text2d('Subtitle', { size: 8, font }).extrude(1);
|
|
194
259
|
```
|
|
195
260
|
|
|
196
|
-
|
|
261
|
+
```ts
|
|
262
|
+
loadFont(source: string | ArrayBuffer, cacheKey?: string): opentype.Font
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### `text2d()` — Build a filled 2D Sketch from a text string.
|
|
266
|
+
|
|
267
|
+
The Sketch origin is at the left end of the text baseline by default. Use `align` and `baseline` options to adjust placement. Text is rendered using the bundled Inter font by default, or any TTF/OTF/WOFF font you provide.
|
|
197
268
|
|
|
198
|
-
|
|
269
|
+
Alignment reference table:
|
|
270
|
+
|
|
271
|
+
| `align` | `baseline` | Origin | |------------|--------------|-------------------------------------| | `'left'` | `'baseline'` | Bottom-left of first char (default) | | `'center'` | `'center'` | Dead center of text block | | `'right'` | `'top'` | Top-right corner |
|
|
199
272
|
|
|
200
273
|
```ts
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
/** Prevent 180° rotation (ensures bottom edge points rightward). Default: false. */
|
|
211
|
-
blockRotation?: boolean;
|
|
212
|
-
}
|
|
213
|
-
```
|
|
274
|
+
// Extruded nameplate
|
|
275
|
+
text2d('FORGE CAD', { size: 8 }).extrude(1.2);
|
|
276
|
+
|
|
277
|
+
// Centered label on the XY plane
|
|
278
|
+
text2d('V 2.0', { size: 6, align: 'center', baseline: 'center' });
|
|
279
|
+
|
|
280
|
+
// Engraved text cut into the top face of a box
|
|
281
|
+
const label = text2d('REV A', { size: 5, align: 'center', baseline: 'center' });
|
|
282
|
+
plate.subtract(label.onFace(plate, 'top', { protrude: -0.5 }).extrude(1));
|
|
214
283
|
|
|
215
|
-
|
|
284
|
+
// Custom TTF font
|
|
285
|
+
text2d('Hello', { size: 10, font: '/path/to/Arial.ttf' }).extrude(1);
|
|
216
286
|
|
|
217
|
-
|
|
287
|
+
// Pre-loaded font for reuse
|
|
288
|
+
const font = loadFont('/path/to/Arial Bold.ttf');
|
|
289
|
+
text2d('Title', { size: 12, font }).extrude(1.5);
|
|
290
|
+
```
|
|
218
291
|
|
|
219
292
|
```ts
|
|
220
|
-
|
|
221
|
-
bottomLeft: PointId;
|
|
222
|
-
bottomRight: PointId;
|
|
223
|
-
topRight: PointId;
|
|
224
|
-
topLeft: PointId;
|
|
225
|
-
/** bottom-left → bottom-right */
|
|
226
|
-
bottom: LineId;
|
|
227
|
-
/** bottom-right → top-right */
|
|
228
|
-
right: LineId;
|
|
229
|
-
/** top-right → top-left */
|
|
230
|
-
top: LineId;
|
|
231
|
-
/** top-left → bottom-left */
|
|
232
|
-
left: LineId;
|
|
233
|
-
/** Center point constrained to the geometric center via `midpoint` on the diagonal. Can be used in further constraints: `sk.fix(rect.center, 0, 0)`, `sk.coincident(rect.center, other)`. */
|
|
234
|
-
center: PointId;
|
|
235
|
-
/** ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`. */
|
|
236
|
-
shape: ShapeId;
|
|
237
|
-
}
|
|
293
|
+
text2d(content: string, options?: TextOptions): Sketch
|
|
238
294
|
```
|
|
239
295
|
|
|
240
|
-
|
|
296
|
+
**`TextOptions`**
|
|
297
|
+
|
|
298
|
+
| Option | Type | Description |
|
|
299
|
+
|--------|------|-------------|
|
|
300
|
+
| `size?` | `number` | Cap height of the text in model units. All other dimensions (stroke weight, spacing) scale proportionally. |
|
|
301
|
+
| `letterSpacing?` | `number` | Extra space between characters in model units. Negative values tighten the tracking. |
|
|
302
|
+
| `align?` | `"left" | "center" | "right"` | Horizontal alignment relative to x = 0. - `'left'` — left edge at x = 0 (default) - `'center'` — centred on x = 0 - `'right'` — right edge at x = 0 |
|
|
303
|
+
| `baseline?` | `"baseline" | "center" | "top"` | Vertical alignment relative to y = 0. - `'baseline'` — y = 0 is the text baseline (bottom of capital letters) - `'center'` — y = 0 is the vertical midpoint of the cap height - `'top'` — y = 0 is the top of capital letters |
|
|
304
|
+
| `font?` | `string | opentype.Font` | Font to use for text rendering. - `'sans-serif'` or `'inter'` — bundled Inter font (works everywhere, including browser) - **file path** — path to a TTF, OTF, or WOFF font file (CLI/Node only) - **Font object** — a previously loaded opentype.js Font (from `loadFont()`) - **omitted** — uses the bundled Inter font (same as `'sans-serif'`) text2d('Hello World', { size: 10 }) // default Inter text2d('Custom Font', { size: 10, font: '/path/to/font.ttf' }) |
|
|
305
|
+
| `flattenTolerance?` | `number` | Bezier flattening tolerance in model units. Smaller = more polygon segments = smoother curves. |
|
|
306
|
+
|
|
307
|
+
#### `textWidth()` — Measure the rendered advance width of a string without creating any geometry.
|
|
241
308
|
|
|
242
|
-
|
|
309
|
+
Uses the same font metrics as `text2d()`. Useful for computing layout dimensions before building the actual sketch — e.g. sizing a plate to fit a label.
|
|
243
310
|
|
|
244
311
|
```ts
|
|
245
|
-
|
|
312
|
+
const w = textWidth('SERIAL: 001', { size: 6 });
|
|
313
|
+
const plate = box(w + 10, 12, 2);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
textWidth(content: string, options?: Pick<TextOptions, "size" | "letterSpacing" | "font">): number
|
|
246
318
|
```
|
|
247
319
|
|
|
248
|
-
|
|
320
|
+
### Constrained Sketches
|
|
321
|
+
|
|
322
|
+
#### `constrainedSketch()` — Create a parametric 2D sketch driven by geometric constraints and a nonlinear solver.
|
|
323
|
+
|
|
324
|
+
**Workflow**
|
|
249
325
|
|
|
250
|
-
|
|
326
|
+
1. Create a builder with `constrainedSketch()`.
|
|
327
|
+
2. Add geometry — points, lines, circles, arcs — using the builder methods.
|
|
328
|
+
3. Add constraints (`horizontal`, `length`, `fix`, etc.) to drive the geometry.
|
|
329
|
+
4. Call `.solve()` to run the solver and get a `ConstraintSketch` (which extends `Sketch`).
|
|
251
330
|
|
|
252
331
|
```ts
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
332
|
+
const sk = constrainedSketch();
|
|
333
|
+
const p1 = sk.point(0, 0);
|
|
334
|
+
const p2 = sk.point(50, 0);
|
|
335
|
+
const l1 = sk.line(p1, p2);
|
|
336
|
+
sk.fix(p1, 0, 0);
|
|
337
|
+
sk.horizontal(l1);
|
|
338
|
+
sk.length(l1, 50);
|
|
339
|
+
return sk.solve().extrude(10);
|
|
259
340
|
```
|
|
260
341
|
|
|
261
|
-
|
|
342
|
+
**Solver status**
|
|
262
343
|
|
|
263
|
-
|
|
344
|
+
```ts
|
|
345
|
+
const result = sk.solve();
|
|
346
|
+
result.constraintMeta.status; // 'fully' | 'under' | 'over' | 'over-redundant'
|
|
347
|
+
result.constraintMeta.dof; // 0 = fully constrained
|
|
348
|
+
result.constraintMeta.maxError; // residual — should be < 1e-6
|
|
349
|
+
result.inspect(); // human-readable summary
|
|
350
|
+
result.withUpdatedConstraint('cst-5', 120); // update a dimension without rebuilding
|
|
351
|
+
```
|
|
264
352
|
|
|
265
353
|
```ts
|
|
266
|
-
|
|
267
|
-
/** CCW-ordered PointIds. */
|
|
268
|
-
vertices: PointId[];
|
|
269
|
-
/** CCW-ordered LineIds. `sides[i]` runs from `vertices[i]` → `vertices[(i+1) % n]`. */
|
|
270
|
-
sides: LineId[];
|
|
271
|
-
/** ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`. */
|
|
272
|
-
shape: ShapeId;
|
|
273
|
-
}
|
|
354
|
+
constrainedSketch(options?: ConstrainedSketchOptions): ConstrainedSketchBuilder
|
|
274
355
|
```
|
|
275
356
|
|
|
276
|
-
|
|
357
|
+
**`ConstrainedSketchOptions`**
|
|
358
|
+
- `strict?: boolean` — When true, adding a constraint that cannot be satisfied throws instead of silently discarding it.
|
|
359
|
+
|
|
360
|
+
#### `addRect()` — Add an axis-aligned rectangle concept to the builder.
|
|
277
361
|
|
|
278
|
-
|
|
362
|
+
Creates 4 vertices (CCW: bl→br→tr→tl), 4 sides, 4 structural constraints (`horizontal`/`vertical` on each side), CCW winding, a center point, a loop, and a shape. Returns a `ConstrainedRect` handle with 4 DOF (x, y, width, height).
|
|
363
|
+
|
|
364
|
+
Use `sk.rect()` as the shorthand builder method.
|
|
279
365
|
|
|
280
366
|
```ts
|
|
281
|
-
|
|
367
|
+
const sk = constrainedSketch();
|
|
368
|
+
const r = sk.rect({ x: 0, y: 0, width: 100, height: 50 });
|
|
369
|
+
sk.fix(r.bottomLeft, 0, 0);
|
|
370
|
+
sk.length(r.bottom, 120); // override initial width
|
|
371
|
+
return sk.solve().extrude(10);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
addRect(sk: ConstrainedSketchBuilder, options?: RectOptions): ConstrainedRect
|
|
282
376
|
```
|
|
283
377
|
|
|
284
|
-
|
|
378
|
+
**`RectOptions`**
|
|
379
|
+
|
|
380
|
+
| Option | Type | Description |
|
|
381
|
+
|--------|------|-------------|
|
|
382
|
+
| `x?` | `number` | Bottom-left x coordinate. Default: 0. |
|
|
383
|
+
| `y?` | `number` | Bottom-left y coordinate. Default: 0. |
|
|
384
|
+
| `width?` | `number` | Width (along x). Default: 10. |
|
|
385
|
+
| `height?` | `number` | Height (along y). Default: 10. |
|
|
386
|
+
| `blockRotation?` | `boolean` | Prevent 180° rotation (ensures bottom edge points rightward). Default: false. |
|
|
387
|
+
|
|
388
|
+
**`ConstrainedRect`**
|
|
389
|
+
|
|
390
|
+
| Option | Type | Description |
|
|
391
|
+
|--------|------|-------------|
|
|
392
|
+
| `bottom` | `LineId` | bottom-left → bottom-right |
|
|
393
|
+
| `right` | `LineId` | bottom-right → top-right |
|
|
394
|
+
| `top` | `LineId` | top-right → top-left |
|
|
395
|
+
| `left` | `LineId` | top-left → bottom-left |
|
|
396
|
+
| `center` | `PointId` | Center point constrained to the geometric center via `midpoint` on the diagonal. Can be used in further constraints: `sk.fix(rect.center, 0, 0)`, `sk.coincident(rect.center, other)`. |
|
|
397
|
+
| `shape` | `ShapeId` | ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`. |
|
|
398
|
+
| `bottomLeft`, `bottomRight`, `topRight`, `topLeft` | | — |
|
|
399
|
+
|
|
400
|
+
#### `addPolygon()` — Add a general polygon concept to the builder.
|
|
401
|
+
|
|
402
|
+
Creates n vertices and n sides (CCW: `sides[i]` from `vertices[i]` → `vertices[(i+1) % n]`). Applies a `ccw` constraint to enforce winding. All dimensional constraints (lengths, angles, position) are left to the caller.
|
|
403
|
+
|
|
404
|
+
Use `sk.addPolygon()` as the shorthand builder method.
|
|
285
405
|
|
|
286
|
-
|
|
406
|
+
```ts
|
|
407
|
+
const sk = constrainedSketch();
|
|
408
|
+
const tri = sk.addPolygon({ points: [[0,0],[100,0],[50,80]] });
|
|
409
|
+
sk.fix(tri.vertex(0), 0, 0);
|
|
410
|
+
sk.length(tri.side(0), 100);
|
|
411
|
+
return sk.solve().extrude(5);
|
|
412
|
+
```
|
|
287
413
|
|
|
288
414
|
```ts
|
|
289
|
-
|
|
290
|
-
/** Number of sides (minimum 3). */
|
|
291
|
-
sides: number;
|
|
292
|
-
/** Circumradius — distance from center to vertex. Default: 10. */
|
|
293
|
-
radius?: number;
|
|
294
|
-
/** Center x coordinate. Default: 0. */
|
|
295
|
-
cx?: number;
|
|
296
|
-
/** Center y coordinate. Default: 0. */
|
|
297
|
-
cy?: number;
|
|
298
|
-
/** Angle (in degrees) of vertex[0] measured from the +X axis (CCW positive). Default: 0 (rightmost vertex). */
|
|
299
|
-
startAngle?: number;
|
|
300
|
-
/** Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false. */
|
|
301
|
-
blockRotation?: boolean;
|
|
302
|
-
}
|
|
415
|
+
addPolygon(sk: ConstrainedSketchBuilder, options: PolygonOptions): ConstrainedPolygon
|
|
303
416
|
```
|
|
304
417
|
|
|
305
|
-
|
|
418
|
+
**`PolygonOptions`**
|
|
419
|
+
- `addLoop?: boolean` — Whether to register a closed loop for sketch generation. Default: true.
|
|
420
|
+
- `blockRotation?: boolean` — Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false.
|
|
421
|
+
|
|
422
|
+
**`ConstrainedPolygon`**
|
|
423
|
+
- `vertices: PointId[]` — CCW-ordered PointIds.
|
|
424
|
+
- `sides: LineId[]` — CCW-ordered LineIds. `sides[i]` runs from `vertices[i]` → `vertices[(i+1) % n]`.
|
|
425
|
+
- `shape: ShapeId` — ShapeId for `shapeWidth`, `shapeHeight`, `shapeArea`, `shapeCentroidX/Y`.
|
|
306
426
|
|
|
427
|
+
#### `addRegularPolygon()` — Add a regular n-gon concept to the builder.
|
|
307
428
|
|
|
308
|
-
|
|
429
|
+
Vertices are placed at `(cx + r·cos(startAngle + i·2π/n), cy + r·sin(...))`. Equal-radius and equal-side constraints enforce regularity (4 DOF: center x/y, radius, rotation). The center point is tracked by the solver and exposed via the returned handle.
|
|
430
|
+
|
|
431
|
+
Use `sk.regularPolygon()` as the shorthand builder method.
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
const sk = constrainedSketch();
|
|
435
|
+
const hex = sk.regularPolygon({ sides: 6, radius: 25 });
|
|
436
|
+
sk.fix(hex.center, 0, 0);
|
|
437
|
+
sk.length(hex.side(0), 30); // all sides change (equal constraint)
|
|
438
|
+
return sk.solve().extrude(5);
|
|
439
|
+
```
|
|
309
440
|
|
|
310
441
|
```ts
|
|
311
|
-
|
|
312
|
-
/** Center point. Use `sk.fix(poly.center, x, y)` to pin location, or `sk.coincident(poly.center, other)` to align with other geometry. */
|
|
313
|
-
center: PointId;
|
|
314
|
-
}
|
|
442
|
+
addRegularPolygon(sk: ConstrainedSketchBuilder, options: RegularPolygonOptions): ConstrainedRegularPolygon
|
|
315
443
|
```
|
|
316
444
|
|
|
317
|
-
|
|
445
|
+
**`RegularPolygonOptions`**
|
|
446
|
+
|
|
447
|
+
| Option | Type | Description |
|
|
448
|
+
|--------|------|-------------|
|
|
449
|
+
| `sides` | `number` | Number of sides (minimum 3). |
|
|
450
|
+
| `radius?` | `number` | Circumradius — distance from center to vertex. Default: 10. |
|
|
451
|
+
| `cx?` | `number` | Center x coordinate. Default: 0. |
|
|
452
|
+
| `cy?` | `number` | Center y coordinate. Default: 0. |
|
|
453
|
+
| `startAngle?` | `number` | Angle (in degrees) of vertex[0] measured from the +X axis (CCW positive). Default: 0 (rightmost vertex). |
|
|
454
|
+
| `blockRotation?` | `boolean` | Prevent 180° rotation (ensures first edge maintains its initial direction). Default: false. |
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
**`ConstrainedRegularPolygon`** extends ConstrainedPolygon
|
|
458
|
+
- `center: PointId` — Center point. Use `sk.fix(poly.center, x, y)` to pin location, or `sk.coincident(poly.center, other)` to align with other geometry.
|
|
318
459
|
|
|
319
460
|
### 2D Geometry Helpers
|
|
320
461
|
|
|
321
|
-
|
|
462
|
+
#### `point()` — Create an analytic 2D point for measurement and construction geometry.
|
|
322
463
|
|
|
323
|
-
|
|
464
|
+
```ts
|
|
465
|
+
const p = point(10, 20);
|
|
466
|
+
p.distanceTo(point(30, 40)); // Euclidean distance
|
|
467
|
+
p.midpointTo(point(30, 40)); // midpoint
|
|
468
|
+
p.translate(5, 5); // new shifted point
|
|
469
|
+
p.toTuple(); // [10, 20]
|
|
470
|
+
```
|
|
324
471
|
|
|
325
472
|
```ts
|
|
326
473
|
point(x: number, y: number): Point2D
|
|
327
474
|
```
|
|
328
475
|
|
|
329
|
-
Create an analytic 2D
|
|
476
|
+
#### `line()` — Create an analytic 2D line segment between two points.
|
|
330
477
|
|
|
331
|
-
|
|
478
|
+
```ts
|
|
479
|
+
const l = line(0, 0, 50, 0);
|
|
480
|
+
l.length; l.midpoint; l.angle; l.direction;
|
|
481
|
+
l.parallel(10); // parallel line offset 10 (positive = left)
|
|
482
|
+
l.intersect(l2); // Point2D — treats lines as infinite
|
|
483
|
+
l.intersectSegment(l2); // Point2D or null — segments only
|
|
484
|
+
|
|
485
|
+
Line2D.fromPointAndAngle(point(0, 0), 45, 100);
|
|
486
|
+
Line2D.fromPointAndDirection(point(0, 0), [1, 1], 50);
|
|
487
|
+
```
|
|
332
488
|
|
|
333
489
|
```ts
|
|
334
490
|
line(x1: number, y1: number, x2: number, y2: number): Line2D
|
|
335
491
|
```
|
|
336
492
|
|
|
337
|
-
Create an analytic 2D
|
|
493
|
+
#### `circle()` — Create an analytic 2D circle for measurement, construction, and extrusion.
|
|
338
494
|
|
|
339
|
-
|
|
495
|
+
```ts
|
|
496
|
+
const c = circle(0, 0, 25);
|
|
497
|
+
c.diameter; c.circumference; c.area;
|
|
498
|
+
c.pointAtAngle(90); // Point2D at top (90° CCW from +X)
|
|
499
|
+
|
|
500
|
+
// Extrude to cylinder with named faces
|
|
501
|
+
const cyl = c.extrude(30);
|
|
502
|
+
cyl.face('top'); // FaceRef (planar)
|
|
503
|
+
cyl.face('side'); // FaceRef (curved)
|
|
504
|
+
|
|
505
|
+
Circle2D.fromDiameter(point(0, 0), 50);
|
|
506
|
+
```
|
|
340
507
|
|
|
341
508
|
```ts
|
|
342
509
|
circle(cx: number, cy: number, radius: number): Circle2D
|
|
343
510
|
```
|
|
344
511
|
|
|
345
|
-
|
|
512
|
+
#### `degrees()` — Identity function that returns degrees unchanged.
|
|
346
513
|
|
|
347
|
-
|
|
514
|
+
Use for clarity when the unit of an angle value would otherwise be ambiguous — e.g. `param("Angle", degrees(45))`.
|
|
348
515
|
|
|
349
516
|
```ts
|
|
350
517
|
degrees(deg: number): number
|
|
351
518
|
```
|
|
352
519
|
|
|
353
|
-
|
|
520
|
+
#### `radians()` — Convert radians to degrees.
|
|
354
521
|
|
|
355
|
-
|
|
522
|
+
ForgeCAD's public API uses degrees throughout. Use this when you have a radian value (e.g. from `Math.atan2`) that you want to express in degrees.
|
|
356
523
|
|
|
357
524
|
```ts
|
|
358
525
|
radians(rad: number): number
|
|
359
526
|
```
|
|
360
527
|
|
|
361
|
-
Convert radians to degrees
|
|
362
|
-
|
|
363
528
|
---
|
|
364
529
|
|
|
365
530
|
## Classes
|
|
366
531
|
|
|
367
532
|
### `Sketch`
|
|
368
533
|
|
|
369
|
-
2D profile for extrusion, revolve, and other operations.
|
|
534
|
+
Immutable 2D profile for extrusion, revolve, and other operations.
|
|
535
|
+
|
|
536
|
+
`Sketch` wraps Manifold's `CrossSection` with a chainable 2D API. Every method returns a new `Sketch` — the original is never mutated. Colors, edge labels, and placement data are preserved through all transforms and boolean operations.
|
|
537
|
+
|
|
538
|
+
Supported operations:
|
|
539
|
+
|
|
540
|
+
- **Transforms** — `translate`, `rotate`, `rotateAround`, `scale`, `mirror`
|
|
541
|
+
- **Booleans** — `add` (union), `subtract` (difference), `intersect`
|
|
542
|
+
- **Operations** — `offset`, `simplify`
|
|
543
|
+
- **Queries** — `area`, `bounds`, `isEmpty`, `numVert`
|
|
544
|
+
- **3D operations** — `extrude`, `revolve`, `onFace`
|
|
545
|
+
- **Regions** — `regions`, `region`
|
|
546
|
+
- **Placement** — `attachTo`
|
|
547
|
+
|
|
548
|
+
Named anchor positions used by `attachTo()`: `'center'` | `'top-left'` | `'top-right'` | `'bottom-left'` | `'bottom-right'` | `'top'` | `'bottom'` | `'left'` | `'right'`
|
|
370
549
|
|
|
371
550
|
**Properties:**
|
|
372
551
|
|
|
@@ -374,224 +553,1201 @@ Convert radians to degrees
|
|
|
374
553
|
|----------|------|-------------|
|
|
375
554
|
| `cross` | `ProfileBackend` | — |
|
|
376
555
|
|
|
377
|
-
**
|
|
556
|
+
**Transforms**
|
|
378
557
|
|
|
379
|
-
|
|
380
|
-
- `clone()` — Return a new Sketch wrapper for explicit duplication in scripts.
|
|
381
|
-
- `duplicate()` — Alias for clone()
|
|
382
|
-
- `area()` — Area in mm squared.
|
|
383
|
-
- `bounds()` — Bounding box as { min: [x,y], max: [x,y] }.
|
|
384
|
-
- `isEmpty()` — True if the sketch contains no area.
|
|
385
|
-
- `numVert()` — Vertex count of the polygon representation.
|
|
386
|
-
- `toPolygons()` — toPolygons(): number[][][]
|
|
387
|
-
- `translate()` — translate(_x: number, _y?: number): Sketch
|
|
388
|
-
- `rotate()` — rotate(_degrees: number): Sketch
|
|
389
|
-
- `rotateAround()` — rotateAround(_degrees: number, _pivot: [ number, number ]): Sketch
|
|
390
|
-
- `scale()` — scale(_v: number | [ number, number ]): Sketch
|
|
391
|
-
- `mirror()` — mirror(_ax: [ number, number ]): Sketch
|
|
392
|
-
- `scaleAround()` — scaleAround(_pivot: [ number, number ], _v: number | [ number, number ]): Sketch
|
|
393
|
-
- `mirrorThrough()` — mirrorThrough(_point: [ number, number ], _ax: [ number, number ]): Sketch
|
|
394
|
-
- `add()` — add(..._others: SketchOperandInput[]): Sketch
|
|
395
|
-
- `subtract()` — subtract(..._others: SketchOperandInput[]): Sketch
|
|
396
|
-
- `intersect()` — intersect(..._others: SketchOperandInput[]): Sketch
|
|
397
|
-
- `union()` — Alias for add() — matches the free-function union() naming.
|
|
398
|
-
- `difference()` — Alias for subtract() — matches the free-function difference() naming.
|
|
399
|
-
- `intersection()` — Alias for intersect() — matches the free-function intersection() naming.
|
|
400
|
-
- `offset()` — offset(_delta: number, _join?: "Square" | "Round" | "Miter"): Sketch
|
|
401
|
-
- `regions()` — Decompose this sketch into its distinct filled regions. See `sketchRegions()`. Regions are returned largest-first by area.
|
|
402
|
-
- `region()` — Select the single filled region that contains the given 2D seed point. Throws if the seed is outside all regions. See `sketchRegion()`.
|
|
403
|
-
- `extrude()` — Extrude this 2D sketch along Z to create a 3D solid. Supports twist, scale tapering, and centering.
|
|
404
|
-
- `revolve()` — Revolve this 2D sketch around the Y axis to create a 3D solid of revolution.
|
|
405
|
-
- `attachTo()` — attachTo(_target: Sketch, _targetAnchor: Anchor, _selfAnchor?: Anchor, _offset?:
|
|
406
|
-
- `onFace()` — onFace(_parentOrFace: Shape | { toShape(): Shape; } | { _bbox(): { min: number[]
|
|
558
|
+
#### `translate()` — Move the sketch by the given X and Y offset.
|
|
407
559
|
|
|
408
|
-
|
|
560
|
+
```ts
|
|
561
|
+
translate(x: number, y?: number): Sketch
|
|
562
|
+
```
|
|
409
563
|
|
|
410
|
-
|
|
564
|
+
#### `rotate()` — Rotate the sketch around its bounding-box center.
|
|
565
|
+
|
|
566
|
+
```ts
|
|
567
|
+
rotate(degrees: number): Sketch
|
|
568
|
+
```
|
|
411
569
|
|
|
412
|
-
|
|
413
|
-
- `lineTo()` — lineTo(x: number, y: number): this
|
|
414
|
-
- `lineH()` — lineH(dx: number): this
|
|
415
|
-
- `lineV()` — lineV(dy: number): this
|
|
416
|
-
- `lineAngled()` — lineAngled(length: number, degrees: number): this
|
|
417
|
-
- `arcTo()` — arcTo(x: number, y: number, radius: number, clockwise?: boolean): this
|
|
418
|
-
- `arcByCenter()` — arcByCenter(centerId: PointId, startId: PointId, endId: PointId, clockwise?: boo
|
|
419
|
-
- `bezier()` — bezier(p0: any, p1: any, p2: any, p3: any, name?: string): BezierId
|
|
420
|
-
- `bezierTo()` — bezierTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number)
|
|
421
|
-
- `blendTo()` — blendTo(x: number, y: number, weight?: number): this
|
|
422
|
-
- `close()` — close(): this
|
|
423
|
-
- `addLoopCircle()` — addLoopCircle(center: PointId, radius: number, segments?: number): this
|
|
424
|
-
- `addLoop()` — addLoop(points: any[]): this
|
|
425
|
-
- `addProfileLoop()` — addProfileLoop(segments: Array<{ kind: "line"; line: any; } | { kind: "arc"; arc
|
|
426
|
-
- `horizontal()` — horizontal(line: any): this
|
|
427
|
-
- `vertical()` — vertical(line: any): this
|
|
428
|
-
- `parallel()` — parallel(a: any, b: any): this
|
|
429
|
-
- `sameDirection()` — sameDirection(a: any, b: any): this
|
|
430
|
-
- `oppositeDirection()` — oppositeDirection(a: any, b: any): this
|
|
431
|
-
- `blockRotation()` — blockRotation(points: any[], axis?: "x" | "y"): this
|
|
432
|
-
- `perpendicular()` — perpendicular(a: any, b: any): this
|
|
433
|
-
- `tangent()` — tangent(a: any, b: any): this
|
|
434
|
-
- `equal()` — equal(a: any, b: any): this
|
|
435
|
-
- `coincident()` — coincident(a: any, b: any): this
|
|
436
|
-
- `concentric()` — concentric(a: any, b: any): this
|
|
437
|
-
- `collinear()` — collinear(point: any, line: any): this
|
|
438
|
-
- `symmetric()` — symmetric(a: any, b: any, axis: any): this
|
|
439
|
-
- `fix()` — fix(point: any, x?: number, y?: number): this
|
|
440
|
-
- `midpoint()` — midpoint(point: any, line: any): this
|
|
441
|
-
- `pointOnCircle()` — pointOnCircle(point: any, circle: any): this
|
|
442
|
-
- `pointOnLine()` — pointOnLine(point: any, line: any): this
|
|
443
|
-
- `distance()` — distance(a: any, b: any, value: number): this
|
|
444
|
-
- `length()` — length(line: any, value: number): this
|
|
445
|
-
- `angle()` — angle(a: any, b: any, value: number): this
|
|
446
|
-
- `radius()` — radius(circle: any, value: number): this
|
|
447
|
-
- `diameter()` — diameter(circle: any, value: number): this
|
|
448
|
-
- `hDistance()` — hDistance(a: any, b: any, value: number): this
|
|
449
|
-
- `vDistance()` — vDistance(a: any, b: any, value: number): this
|
|
450
|
-
- `pointLineDistance()` — pointLineDistance(point: any, line: any, value: number): this
|
|
451
|
-
- `lineDistance()` — lineDistance(a: any, b: any, value: number): this
|
|
452
|
-
- `absoluteAngle()` — absoluteAngle(line: any, value: number): this
|
|
453
|
-
- `equalRadius()` — equalRadius(a: any, b: any): this
|
|
454
|
-
- `arcLength()` — arcLength(arc: any, value: number): this
|
|
455
|
-
- `lineTangentArc()` — lineTangentArc(line: any, arc: any, atStart: boolean): this
|
|
456
|
-
- `arcTangentArc()` — arcTangentArc(arcA: any, arcB: any, aAtStart?: boolean, bAtStart?: boolean): thi
|
|
457
|
-
- `bezierTangentArc()` — bezierTangentArc(bezier: any, arc: any, atBezierStart: boolean, atArcStart: bool
|
|
458
|
-
- `smoothBlend()` — smoothBlend(arc1: any, arc2: any, options?: { weight?: number; arc1End?: "start"
|
|
459
|
-
- `shapeWidth()` — shapeWidth(shape: any, value: number): this
|
|
460
|
-
- `shapeHeight()` — shapeHeight(shape: any, value: number): this
|
|
461
|
-
- `shapeCentroidX()` — shapeCentroidX(shape: any, value: number): this
|
|
462
|
-
- `shapeCentroidY()` — shapeCentroidY(shape: any, value: number): this
|
|
463
|
-
- `shapeArea()` — shapeArea(shape: any, value: number): this
|
|
464
|
-
- `shapeEqualCentroid()` — shapeEqualCentroid(a: any, b: any): this
|
|
465
|
-
- `angleBetween()` — angleBetween(a: any, b: any, value: number): this
|
|
466
|
-
- `ccw()` — ccw(...points: any[]): this
|
|
467
|
-
- `offsetX()` — Constrain the horizontal (X-axis) offset between two lines. Uses the start-point of each line to measure horizontal distance. `value` is the signed distance: b.startPt.x − a.startPt.x = value.
|
|
468
|
-
- `offsetY()` — Constrain the vertical (Y-axis) offset between two lines. Uses the start-point of each line to measure vertical distance. `value` is the signed distance: b.startPt.y − a.startPt.y = value.
|
|
469
|
-
- `importPoint()` — importPoint(pt: { x: number; y: number; }, fixed?: boolean): PointId
|
|
470
|
-
- `importLine()` — importLine(l: { start: { x: number; y: number; }; end: { x: number; y: number; }
|
|
471
|
-
- `importRectangle()` — importRectangle(r: { vertices: [ { x: number; y: number; }, { x: number; y: numb
|
|
472
|
-
- `referencePoint()` — referencePoint(x: number, y: number): PointId
|
|
473
|
-
- `referenceLine()` — referenceLine(x1: number, y1: number, x2: number, y2: number): LineId
|
|
474
|
-
- `referenceFrom()` — referenceFrom(source: ConstraintSketch, entityId: string): PointId | LineId | nu
|
|
475
|
-
- `referenceAllFrom()` — referenceAllFrom(source: ConstraintSketch): { points: Map<string, PointId>; line
|
|
476
|
-
- `point()` — point(x?: number, y?: number, fixed?: boolean): PointId
|
|
477
|
-
- `pointAt()` — pointAt(index: number): PointId
|
|
478
|
-
- `line()` — line(a: PointId, b: PointId, construction?: boolean, name?: string): LineId
|
|
479
|
-
- `lineAt()` — lineAt(index: number): LineId
|
|
480
|
-
- `circle()` — circle(center: PointId, radius: number, construction?: boolean, segments?: numbe
|
|
481
|
-
- `circleAt()` — circleAt(index: number): CircleId
|
|
482
|
-
- `shape()` — Register a named shape (closed polygon) from an ordered list of line IDs. Returns the ShapeId for use in shape constraints (shapeWidth, shapeCentroidX, etc.).
|
|
483
|
-
- `group()` — Create a rigid-body group with a local coordinate frame. Points/lines added to the group move together as a unit — the solver sees 3 DOF (x, y, θ) instead of 2N per point. ```ts const g = sk.group({ x: 50, y: 30 }); const p0 = g.point(0, 0); // local origin → world (50, 30) const p1 = g.point(100, 0); // local (100,0) → world (150, 30) const l = g.line(p0, p1); g.fixRotation(); // p0, p1 work in constraints like any other PointId: sk.coincident(p0, someExternalPoint); ```
|
|
484
|
-
- `constrain()` — constrain(constraint: Omit<SketchConstraint, "id">): this
|
|
485
|
-
- `solve()` — solve(options?: SolveOptions): ConstraintSketch | Sketch
|
|
486
|
-
- `solveConstraintsOnly()` — Run the solver without building a full `ConstraintSketch`. Useful for lightweight constraint validation or progress monitoring. Returns the final maxError, the number of rejected constraints, and the solved `ConstraintDefinition` with updated point positions.
|
|
487
|
-
- `route()` — Route a profile through a sequence of geometric elements (legacy API). The solver computes all tangent points and intersections automatically. Steps can include: - `{ point: [x, y] }` — route through a point - `{ axis: 'x'|'y', offset: n }` — follow a construction line - `{ line: {...}, until: n }` — follow a line clipped to a coordinate - `{ tangent: { center, radius } }` — tangent arc onto a construction circle - `{ fillet: radius }` — fillet between adjacent elements - `{ tangentArc: radius }` — free tangent arc (solver finds center) Returns `this` for chaining. Call `.solve()` after to get the Sketch.
|
|
488
|
-
- `rect()` — Add an axis-aligned rectangle concept. Returns a `ConstrainedRect` handle with named vertices, sides, and center.
|
|
489
|
-
- `addPolygon()` — Add a general polygon concept (CCW winding enforced). Returns a `ConstrainedPolygon` handle.
|
|
490
|
-
- `regularPolygon()` — Add a regular n-gon concept (equal sides, CCW winding). Returns a `ConstrainedRegularPolygon` handle with a center point.
|
|
491
|
-
- `groupRect()` — Add a rigid rectangle as a group concept. Returns a `ConstrainedGroupRect` handle with named vertices and sides. The rectangle is fixed in shape — only position (and optionally rotation) varies.
|
|
570
|
+
#### `rotateAround()` — Rotate the sketch around a specific pivot point.
|
|
492
571
|
|
|
493
|
-
|
|
572
|
+
```ts
|
|
573
|
+
rect(20, 20).rotateAround(45, [0, 0]);
|
|
574
|
+
```
|
|
494
575
|
|
|
495
|
-
|
|
576
|
+
```ts
|
|
577
|
+
rotateAround(degrees: number, pivot: [ number, number ]): Sketch
|
|
578
|
+
```
|
|
496
579
|
|
|
497
|
-
|
|
498
|
-
|----------|------|-------------|
|
|
499
|
-
| `constraintMeta` | `SketchConstraintMeta` | — |
|
|
500
|
-
| `definition` | `ConstraintDefinition` | — |
|
|
580
|
+
#### `scale()` — Scale the sketch relative to its bounding-box center.
|
|
501
581
|
|
|
502
|
-
|
|
582
|
+
Pass a single number for uniform scaling, or `[sx, sy]` for per-axis scaling.
|
|
503
583
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
- `inspect()` — Return a human-readable diagnostic string of the solved state.
|
|
584
|
+
```ts
|
|
585
|
+
scale(v: number | [ number, number ]): Sketch
|
|
586
|
+
```
|
|
508
587
|
|
|
509
|
-
|
|
588
|
+
#### `scaleAround()` — Scale the sketch relative to an arbitrary pivot point.
|
|
510
589
|
|
|
511
|
-
|
|
590
|
+
```ts
|
|
591
|
+
scaleAround(pivot: [ number, number ], v: number | [ number, number ]): Sketch
|
|
592
|
+
```
|
|
512
593
|
|
|
513
|
-
|
|
514
|
-
- `line()` — Connect two group points with a line. Both must be PointIds from this group.
|
|
515
|
-
- `fixRotation()` — Freeze rotation (θ). Group can still translate — 2 DOF remain.
|
|
516
|
-
- `fix()` — Freeze all 3 DOF — group is completely fixed.
|
|
517
|
-
- `done()` — Finalize and register the group with the builder. Returns a handle for referencing group points/lines in constraints.
|
|
594
|
+
#### `mirror()` — Mirror the sketch across a line through its bounding-box center.
|
|
518
595
|
|
|
519
|
-
|
|
596
|
+
`normal` is the normal vector of the mirror line (not the line direction). For example, `[1, 0]` mirrors across a vertical line (Y axis direction), and `[0, 1]` mirrors across a horizontal line.
|
|
520
597
|
|
|
521
|
-
|
|
598
|
+
```ts
|
|
599
|
+
mirror(normal: [ number, number ]): Sketch
|
|
600
|
+
```
|
|
522
601
|
|
|
523
|
-
|
|
524
|
-
|----------|------|-------------|
|
|
525
|
-
| `x` | `number` | — |
|
|
526
|
-
| `y` | `number` | — |
|
|
602
|
+
#### `mirrorThrough()` — Mirror the sketch across a line defined by a point and a normal direction.
|
|
527
603
|
|
|
528
|
-
|
|
604
|
+
```ts
|
|
605
|
+
mirrorThrough(point: [ number, number ], normal: [ number, number ]): Sketch
|
|
606
|
+
```
|
|
529
607
|
|
|
530
|
-
|
|
531
|
-
- `midpointTo()` — midpointTo(other: Point2D): Point2D
|
|
532
|
-
- `translate()` — translate(dx: number, dy: number): Point2D
|
|
533
|
-
- `toTuple()` — toTuple(): [ number, number ]
|
|
608
|
+
**Booleans**
|
|
534
609
|
|
|
535
|
-
|
|
610
|
+
#### `add()` — Add (union) one or more sketches to this sketch.
|
|
536
611
|
|
|
537
|
-
|
|
612
|
+
Accepts individual sketches or arrays: `sketch.add(a, b)` or `sketch.add([a, b])`. For combining many sketches at once, prefer the free function `union2d()` which uses Manifold's batch operation and is faster than chaining.
|
|
538
613
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
| `end` | `Point2D` | — |
|
|
614
|
+
```ts
|
|
615
|
+
circle2d(20).add(rect(10, 30)).extrude(5);
|
|
616
|
+
```
|
|
543
617
|
|
|
544
|
-
|
|
618
|
+
```ts
|
|
619
|
+
add(...others: SketchOperandInput[]): Sketch
|
|
620
|
+
```
|
|
545
621
|
|
|
546
|
-
|
|
547
|
-
- `get midpoint()` — get midpoint(): Point2D
|
|
548
|
-
- `get angle()` — get angle(): number
|
|
549
|
-
- `get direction()` — get direction(): [ number, number ]
|
|
550
|
-
- `parallel()` — Create a line parallel to this one, offset by distance. positive = left of direction
|
|
551
|
-
- `intersect()` — Intersection point of two lines (treating them as infinite lines). Returns null if lines are parallel.
|
|
552
|
-
- `intersectSegment()` — Intersection point within both line segments only. Returns null if segments don't cross.
|
|
553
|
-
- `static fromCoordinates()` — static fromCoordinates(x1: number, y1: number, x2: number, y2: number): Line2D
|
|
554
|
-
- `static fromPointAndAngle()` — static fromPointAndAngle(origin: Point2D, angleDeg: number, length: number): Lin
|
|
555
|
-
- `static fromPointAndDirection()` — static fromPointAndDirection(origin: Point2D, dir: [ number, number ], length: n
|
|
622
|
+
#### `subtract()` — Subtract one or more sketches from this sketch.
|
|
556
623
|
|
|
557
|
-
|
|
624
|
+
Accepts individual sketches or arrays: `sketch.subtract(a, b)` or `sketch.subtract([a, b])`. For subtracting many cutters at once, prefer the free function `difference2d()`.
|
|
558
625
|
|
|
559
|
-
|
|
626
|
+
```ts
|
|
627
|
+
rect(40, 40).subtract(circle2d(10)).extrude(5);
|
|
628
|
+
```
|
|
560
629
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
| `radius` | `number` | — |
|
|
630
|
+
```ts
|
|
631
|
+
subtract(...others: SketchOperandInput[]): Sketch
|
|
632
|
+
```
|
|
565
633
|
|
|
566
|
-
|
|
634
|
+
#### `intersect()` — Intersect this sketch with one or more others (keep overlapping area only).
|
|
567
635
|
|
|
568
|
-
|
|
569
|
-
- `get circumference()` — get circumference(): number
|
|
570
|
-
- `get area()` — get area(): number
|
|
571
|
-
- `pointAtAngle()` — Point on the circle at given angle (degrees, 0=right, CCW)
|
|
572
|
-
- `translate()` — translate(dx: number, dy: number): Circle2D
|
|
573
|
-
- `toSketch()` — toSketch(segments?: number): Sketch
|
|
574
|
-
- `extrude()` — Extrude to Shape with top/bottom/side faces via topology WeakMap
|
|
575
|
-
- `static fromCenterAndRadius()` — static fromCenterAndRadius(center: Point2D, radius: number): Circle2D
|
|
576
|
-
- `static fromDiameter()` — static fromDiameter(center: Point2D, diameter: number): Circle2D
|
|
636
|
+
Accepts individual sketches or arrays: `sketch.intersect(a, b)` or `sketch.intersect([a, b])`. For intersecting many sketches, prefer the free function `intersection2d()`.
|
|
577
637
|
|
|
578
|
-
|
|
638
|
+
```ts
|
|
639
|
+
intersect(...others: SketchOperandInput[]): Sketch
|
|
640
|
+
```
|
|
579
641
|
|
|
580
|
-
|
|
642
|
+
**Features**
|
|
581
643
|
|
|
582
|
-
|
|
644
|
+
#### `offset()` — Inflate (positive delta) or deflate (negative delta) the sketch contour.
|
|
645
|
+
|
|
646
|
+
Use `offset(-r).offset(+r)` to round every convex corner of a closed sketch.
|
|
647
|
+
|
|
648
|
+
- `'Round'` — smooth arc at each corner (default)
|
|
649
|
+
- `'Square'` — flat mitered extension
|
|
650
|
+
- `'Miter'` — sharp pointed extension
|
|
651
|
+
|
|
652
|
+
```ts
|
|
653
|
+
rect(40, 20).offset(3); // expand by 3
|
|
654
|
+
rect(40, 20).offset(-2).offset(2); // round all convex corners
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
offset(delta: number, join?: "Square" | "Round" | "Miter"): Sketch
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
#### `regions()` — Decompose this sketch into its distinct filled regions, sorted largest-first by area.
|
|
583
662
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
663
|
+
A single sketch can contain several disconnected filled areas (e.g., two separate rectangles, or a ring shape with a hole). This method enumerates all top-level connected regions as independent `Sketch` objects, each with its own outer boundary and associated holes.
|
|
664
|
+
|
|
665
|
+
```ts
|
|
666
|
+
const pair = union2d(rect(40, 40), rect(40, 40).translate(60, 0));
|
|
667
|
+
const [left, right] = pair.regions(); // largest first
|
|
668
|
+
left.extrude(5);
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
```ts
|
|
672
|
+
regions(): Sketch[]
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
#### `region()` — Select the single filled region that contains the given 2D seed point.
|
|
676
|
+
|
|
677
|
+
The seed must lie strictly inside the filled area — not on a boundary edge and not inside a hole. Throws a descriptive error if the seed is outside all regions. If unsure where regions are, use `.regions()` first — each result has `.bounds()`.
|
|
678
|
+
|
|
679
|
+
```ts
|
|
680
|
+
const donut = circle2d(50).subtract(circle2d(30));
|
|
681
|
+
donut.region([40, 0]).extrude(10); // seed at radius 40, inside the ring
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
```ts
|
|
685
|
+
region(seed: [ number, number ]): Sketch
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Promotion**
|
|
689
|
+
|
|
690
|
+
#### `extrude()` — Extrude this 2D sketch along Z to create a 3D solid. Supports twist and scale tapering.
|
|
691
|
+
|
|
692
|
+
```ts
|
|
693
|
+
extrude(height: number, opts?: { twist?: number; divisions?: number; scaleTop?: number | [ number, number ]; }): Shape
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
#### `revolve()` — Revolve this 2D sketch around the Y axis to create a 3D solid of revolution.
|
|
697
|
+
|
|
698
|
+
```ts
|
|
699
|
+
revolve(degrees?: number, segments?: number): Shape
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
**Placement**
|
|
703
|
+
|
|
704
|
+
#### `attachTo()` — Position this sketch relative to another using named anchor points.
|
|
705
|
+
|
|
706
|
+
Computes the translation needed to align `selfAnchor` on this sketch with `targetAnchor` on the target sketch, then applies an optional pixel-exact offset.
|
|
707
|
+
|
|
708
|
+
Anchor positions: `'center'` | `'top-left'` | `'top-right'` | `'bottom-left'` | `'bottom-right'` | `'top'` | `'bottom'` | `'left'` | `'right'`
|
|
709
|
+
|
|
710
|
+
```ts
|
|
711
|
+
const arm = rect(4, 70).attachTo(plate, 'bottom-left', 'top-left');
|
|
712
|
+
const shifted = rect(4, 70).attachTo(plate, 'bottom-left', 'top-left', [5, 0]);
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
attachTo(target: Sketch, targetAnchor: Anchor, selfAnchor?: Anchor, offset?: [ number, number ]): Sketch
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
#### `onFace()` — Place this sketch on a face or planar target in 3D space.
|
|
720
|
+
|
|
721
|
+
Use this when a 2D profile should be oriented onto a 3D face before extrusion or other downstream operations.
|
|
722
|
+
|
|
723
|
+
```ts
|
|
724
|
+
onFace(parentOrFace: Shape | { toShape(): Shape; } | { _bbox(): { min: number[]; max: number[]; }; } | FaceRef, faceOrOpts?: "front" | "back" | "left" | "right" | "top" | "bottom" | string | FaceRef | { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }, opts?: { u?: number; v?: number; protrude?: number; selfAnchor?: Anchor; }): Sketch
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
**Labels**
|
|
728
|
+
|
|
729
|
+
#### `labelEdge()` — Label the single boundary edge (for circles, single-loop profiles).
|
|
730
|
+
|
|
731
|
+
```ts
|
|
732
|
+
labelEdge(name: string): Sketch
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
#### `labelEdges()` — Label edges in winding order, or by named map for rect.
|
|
736
|
+
|
|
737
|
+
Positional: `labelEdges('bottom', 'right', 'top', 'left')` — one per edge, `null` to skip. Named (rect only): `labelEdges({ bottom: 'floor', top: 'ceiling' })`.
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
labelEdges(...args: (string | null)[] | [ Record<string, string> ]): Sketch
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### `edgeLabels()` — List current edge label names.
|
|
744
|
+
|
|
745
|
+
```ts
|
|
746
|
+
edgeLabels(): string[]
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
#### `prefixLabels()` — Prefix all edge labels. Returns this sketch (mutates labels in place).
|
|
750
|
+
|
|
751
|
+
```ts
|
|
752
|
+
prefixLabels(prefix: string): Sketch
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
#### `renameLabel()` — Rename a single edge label.
|
|
756
|
+
|
|
757
|
+
```ts
|
|
758
|
+
renameLabel(from: string, to: string): Sketch
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### `dropLabels()` — Remove specific labels.
|
|
762
|
+
|
|
763
|
+
```ts
|
|
764
|
+
dropLabels(...names: string[]): Sketch
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### `dropAllLabels()` — Remove all labels.
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
dropAllLabels(): Sketch
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
**Measurement**
|
|
774
|
+
|
|
775
|
+
#### `area()` — Return the total filled area of the sketch.
|
|
776
|
+
|
|
777
|
+
```ts
|
|
778
|
+
area(): number
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
#### `bounds()` — Return the axis-aligned bounding box of the sketch.
|
|
782
|
+
|
|
783
|
+
```ts
|
|
784
|
+
bounds(): ProfileBounds
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
#### `isEmpty()` — Return `true` if the sketch contains no filled area.
|
|
788
|
+
|
|
789
|
+
```ts
|
|
790
|
+
isEmpty(): boolean
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
#### `numVert()` — Return the number of vertices in the polygon representation of the sketch contours.
|
|
794
|
+
|
|
795
|
+
```ts
|
|
796
|
+
numVert(): number
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
#### `toPolygons()` — Return the sketch as a list of polygons matching its contour topology.
|
|
800
|
+
|
|
801
|
+
Useful when you need raw polygon data for inspection or custom export.
|
|
802
|
+
|
|
803
|
+
```ts
|
|
804
|
+
toPolygons(): number[][][]
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
**Other**
|
|
808
|
+
|
|
809
|
+
#### `color()` — Set the display color of this sketch.
|
|
810
|
+
|
|
811
|
+
Color is preserved through all transforms and boolean operations. Pass `undefined` to clear the color.
|
|
812
|
+
|
|
813
|
+
```ts
|
|
814
|
+
circle2d(20).color('#ff0000').extrude(5);
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
```ts
|
|
818
|
+
color(value: string | undefined): Sketch
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
#### `clone()` — Create an explicit copy of this sketch for branching variants.
|
|
822
|
+
|
|
823
|
+
Because all Sketch operations are immutable, `clone()` is rarely needed. Use it when you want to assign the same sketch to multiple names and continue modifying each independently without confusion.
|
|
824
|
+
|
|
825
|
+
```ts
|
|
826
|
+
clone(): Sketch
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### `ConstrainedSketchBuilder`
|
|
830
|
+
|
|
831
|
+
**Drawing**
|
|
832
|
+
|
|
833
|
+
#### `moveTo()` — Move the cursor to `(x, y)` and start a new profile loop.
|
|
834
|
+
|
|
835
|
+
```ts
|
|
836
|
+
moveTo(x: number, y: number): this
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
#### `lineTo()` — Draw a line from the current cursor to `(x, y)`.
|
|
840
|
+
|
|
841
|
+
```ts
|
|
842
|
+
lineTo(x: number, y: number): this
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
#### `lineH()` — Draw a horizontal line of length `dx` from the current cursor.
|
|
846
|
+
|
|
847
|
+
```ts
|
|
848
|
+
lineH(dx: number): this
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
#### `lineV()` — Draw a vertical line of length `dy` from the current cursor.
|
|
852
|
+
|
|
853
|
+
```ts
|
|
854
|
+
lineV(dy: number): this
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
#### `lineAngled()` — Draw a line of the given `length` at `degrees` from +X.
|
|
858
|
+
|
|
859
|
+
```ts
|
|
860
|
+
lineAngled(length: number, degrees: number): this
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
#### `arcTo()` — Draw a circular arc from the current cursor to `(x, y)` with the given radius.
|
|
864
|
+
|
|
865
|
+
```ts
|
|
866
|
+
arcTo(x: number, y: number, radius: number, clockwise?: boolean): this
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
#### `arcByCenter()` — Create an arc from an explicit center point and endpoint IDs.
|
|
870
|
+
|
|
871
|
+
```ts
|
|
872
|
+
arcByCenter(centerId: PointId, startId: PointId, endId: PointId, clockwise?: boolean, name?: string, fixedRadius?: boolean): ArcId
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
#### `bezier()` — Create a cubic Bezier curve from four control points.
|
|
876
|
+
|
|
877
|
+
```ts
|
|
878
|
+
bezier(p0: any, p1: any, p2: any, p3: any, name?: string): BezierId
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
#### `bezierTo()` — Draw a cubic Bezier from the current cursor to `(x3, y3)`.
|
|
882
|
+
|
|
883
|
+
```ts
|
|
884
|
+
bezierTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): this
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
#### `blendTo()` — Draw a smooth Bezier tangent to the previous arc.
|
|
888
|
+
|
|
889
|
+
```ts
|
|
890
|
+
blendTo(x: number, y: number, weight?: number): this
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
#### `label()` — Label the current path segment.
|
|
894
|
+
|
|
895
|
+
```ts
|
|
896
|
+
label(name: string): this
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
#### `close()` — Close the current path and register the loop.
|
|
900
|
+
|
|
901
|
+
```ts
|
|
902
|
+
close(): this
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
#### `addLoopCircle()` — Add a circle loop to the path.
|
|
906
|
+
|
|
907
|
+
```ts
|
|
908
|
+
addLoopCircle(center: PointId, radius: number, segments?: number): this
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
#### `addLoop()` — Add a closed polygon loop from point IDs.
|
|
912
|
+
|
|
913
|
+
```ts
|
|
914
|
+
addLoop(points: any[]): this
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
#### `addProfileLoop()` — Add a profile loop from prebuilt line/arc/bezier segments.
|
|
918
|
+
|
|
919
|
+
```ts
|
|
920
|
+
addProfileLoop(segments: Array<{ kind: "line"; line: any; } | { kind: "arc"; arc: any; } | { kind: "bezier"; bezier: any; }>): this
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
**Entities**
|
|
924
|
+
|
|
925
|
+
#### `point()` — Add a free point to the sketch at `(x, y)`.
|
|
926
|
+
|
|
927
|
+
If `x` or `y` are omitted, the point is placed at the bounding-box center of existing geometry so it starts near other entities rather than at the origin. Throws if either coordinate is `NaN` or `Infinity`.
|
|
928
|
+
|
|
929
|
+
```ts
|
|
930
|
+
point(x?: number, y?: number, fixed?: boolean): PointId
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
#### `pointAt()` — Return the `PointId` of the point created at the given insertion index.
|
|
934
|
+
|
|
935
|
+
```ts
|
|
936
|
+
pointAt(index: number): PointId
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
#### `line()` — Connect two existing points with a line segment.
|
|
940
|
+
|
|
941
|
+
Pass `construction = true` for a helper line that participates in constraints but is excluded from the solved sketch output (not part of any profile loop).
|
|
942
|
+
|
|
943
|
+
```ts
|
|
944
|
+
const axis = sk.line(sk.point(0, -50), sk.point(0, 50), true);
|
|
945
|
+
sk.symmetric(p1, p2, axis);
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
```ts
|
|
949
|
+
line(a: PointId, b: PointId, construction?: boolean, name?: string): LineId
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
#### `lineAt()` — Return the `LineId` of the line created at the given insertion index.
|
|
953
|
+
|
|
954
|
+
```ts
|
|
955
|
+
lineAt(index: number): LineId
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
#### `circle()` — Add a circle to the sketch with the given center point and initial radius.
|
|
959
|
+
|
|
960
|
+
The radius is a starting value — if you add a `radius()` or `diameter()` constraint, the solver will adjust it. Non-construction circles automatically register a loop.
|
|
961
|
+
|
|
962
|
+
```ts
|
|
963
|
+
circle(center: PointId, radius: number, construction?: boolean, segments?: number, name?: string): CircleId
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
#### `circleAt()` — Return the `CircleId` of the circle created at the given insertion index.
|
|
967
|
+
|
|
968
|
+
```ts
|
|
969
|
+
circleAt(index: number): CircleId
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
#### `shape()` — Register a named shape (closed polygon) from an ordered list of line IDs.
|
|
973
|
+
|
|
974
|
+
The `ShapeId` can be passed to `shapeWidth()`, `shapeHeight()`, `shapeArea()`, `shapeCentroidX()`, `shapeCentroidY()`, and `shapeEqualCentroid()` constraints. Shape registration is done automatically by concept factories like `rect()` and `addPolygon()`.
|
|
975
|
+
|
|
976
|
+
```ts
|
|
977
|
+
shape(lines: LineId[]): ShapeId
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
#### [`group()`](/docs/core#group) — Create a rigid-body group with a local coordinate frame.
|
|
981
|
+
|
|
982
|
+
Points and lines added to the group move together as a unit — the solver sees 3 DOF (x, y, θ) instead of 2N per point. After configuring the group, call `.done()` to register it and receive a `SketchGroupHandle`.
|
|
983
|
+
|
|
984
|
+
Group points are addressable by their `PointId` in all sketch constraints (e.g. `sk.coincident`, `sk.distance`) just like any other points.
|
|
985
|
+
|
|
986
|
+
```ts
|
|
987
|
+
const g = sk.group({ x: 50, y: 30 });
|
|
988
|
+
const p0 = g.point(0, 0); // local origin → world (50, 30)
|
|
989
|
+
const p1 = g.point(100, 0); // local (100,0) → world (150, 30)
|
|
990
|
+
const l = g.line(p0, p1);
|
|
991
|
+
g.fixRotation();
|
|
992
|
+
const handle = g.done();
|
|
993
|
+
// p0, p1 work in constraints like any other PointId:
|
|
994
|
+
sk.coincident(p0, someExternalPoint);
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
```ts
|
|
998
|
+
group(opts?: { x?: number; y?: number; theta?: number; id?: string; }): SketchGroupBuilder
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
#### `rect()` — Add an axis-aligned rectangle concept. Returns a `ConstrainedRect` handle with named vertices, sides, and center.
|
|
1002
|
+
|
|
1003
|
+
```ts
|
|
1004
|
+
rect(options?: RectOptions): ConstrainedRect
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
#### `addPolygon()` — Add a general polygon concept (CCW winding enforced). Returns a `ConstrainedPolygon` handle.
|
|
1008
|
+
|
|
1009
|
+
```ts
|
|
1010
|
+
addPolygon(options: PolygonOptions): ConstrainedPolygon
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
#### `regularPolygon()` — Add a regular n-gon concept (equal sides, CCW winding). Returns a `ConstrainedRegularPolygon` handle with a center point.
|
|
1014
|
+
|
|
1015
|
+
```ts
|
|
1016
|
+
regularPolygon(options: RegularPolygonOptions): ConstrainedRegularPolygon
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
#### `groupRect()` — Add a rigid rectangle as a group concept. Returns a `ConstrainedGroupRect` handle with named vertices and sides. The rectangle is fixed in shape — only position (and optionally rotation) varies.
|
|
1020
|
+
|
|
1021
|
+
```ts
|
|
1022
|
+
groupRect(options: GroupRectOptions): ConstrainedGroupRect
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
**Geometric Constraints**
|
|
1026
|
+
|
|
1027
|
+
#### `horizontal()` — Constrain a line to be horizontal (parallel to the X axis).
|
|
1028
|
+
|
|
1029
|
+
```ts
|
|
1030
|
+
horizontal(line: any): this
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
#### `vertical()` — Constrain a line to be vertical (parallel to the Y axis).
|
|
1034
|
+
|
|
1035
|
+
```ts
|
|
1036
|
+
vertical(line: any): this
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
#### `parallel()` — Constrain two lines to be parallel.
|
|
1040
|
+
|
|
1041
|
+
```ts
|
|
1042
|
+
parallel(a: any, b: any): this
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
#### `sameDirection()` — Constrain two lines to point in the same direction.
|
|
1046
|
+
|
|
1047
|
+
```ts
|
|
1048
|
+
sameDirection(a: any, b: any): this
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
#### `oppositeDirection()` — Constrain two lines to point in opposite directions.
|
|
1052
|
+
|
|
1053
|
+
```ts
|
|
1054
|
+
oppositeDirection(a: any, b: any): this
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
#### `perpendicular()` — Constrain two lines to be perpendicular.
|
|
1058
|
+
|
|
1059
|
+
```ts
|
|
1060
|
+
perpendicular(a: any, b: any): this
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
#### `tangent()` — Constrain a line/circle or circle/circle tangency relationship.
|
|
1064
|
+
|
|
1065
|
+
```ts
|
|
1066
|
+
tangent(a: any, b: any): this
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
#### `collinear()` — Constrain a point to lie on the infinite extension of a line.
|
|
1070
|
+
|
|
1071
|
+
```ts
|
|
1072
|
+
collinear(point: any, line: any): this
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
#### `symmetric()` — Constrain two points to be symmetric about an axis line.
|
|
1076
|
+
|
|
1077
|
+
```ts
|
|
1078
|
+
symmetric(a: any, b: any, axis: any): this
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
#### `blockRotation()` — Prevent 180° rotation of a polygon by anchoring its first edge.
|
|
1082
|
+
|
|
1083
|
+
```ts
|
|
1084
|
+
blockRotation(points: any[], axis?: "x" | "y"): this
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
**Dimensional Constraints**
|
|
1088
|
+
|
|
1089
|
+
#### `distance()` — Constrain the Euclidean distance between two points.
|
|
1090
|
+
|
|
1091
|
+
```ts
|
|
1092
|
+
distance(a: any, b: any, value: number): this
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
#### `length()` — Constrain the length of a line segment.
|
|
1096
|
+
|
|
1097
|
+
```ts
|
|
1098
|
+
length(line: any, value: number): this
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
#### `angle()` — Constrain the signed angle from line `a` to line `b`.
|
|
1102
|
+
|
|
1103
|
+
```ts
|
|
1104
|
+
angle(a: any, b: any, value: number): this
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
#### `radius()` — Constrain the radius of a circle.
|
|
1108
|
+
|
|
1109
|
+
```ts
|
|
1110
|
+
radius(circle: any, value: number): this
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
#### `diameter()` — Constrain the diameter of a circle.
|
|
1114
|
+
|
|
1115
|
+
```ts
|
|
1116
|
+
diameter(circle: any, value: number): this
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
#### `hDistance()` — Constrain the horizontal distance between two points.
|
|
1120
|
+
|
|
1121
|
+
```ts
|
|
1122
|
+
hDistance(a: any, b: any, value: number): this
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
#### `vDistance()` — Constrain the vertical distance between two points.
|
|
1126
|
+
|
|
1127
|
+
```ts
|
|
1128
|
+
vDistance(a: any, b: any, value: number): this
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
#### `pointLineDistance()` — Constrain the signed perpendicular distance from a point to a line.
|
|
1132
|
+
|
|
1133
|
+
```ts
|
|
1134
|
+
pointLineDistance(point: any, line: any, value: number): this
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
#### `lineDistance()` — Constrain the perpendicular offset distance between two lines.
|
|
1138
|
+
|
|
1139
|
+
```ts
|
|
1140
|
+
lineDistance(a: any, b: any, value: number): this
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
#### `absoluteAngle()` — Constrain the absolute angle of a line measured from +X.
|
|
1144
|
+
|
|
1145
|
+
```ts
|
|
1146
|
+
absoluteAngle(line: any, value: number): this
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
#### `arcLength()` — Constrain the arc length of an arc.
|
|
1150
|
+
|
|
1151
|
+
```ts
|
|
1152
|
+
arcLength(arc: any, value: number): this
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
#### `equalRadius()` — Constrain two circles to have equal radii.
|
|
1156
|
+
|
|
1157
|
+
```ts
|
|
1158
|
+
equalRadius(a: any, b: any): this
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
#### `angleBetween()` — Constrain the unsigned angle between two lines.
|
|
1162
|
+
|
|
1163
|
+
```ts
|
|
1164
|
+
angleBetween(a: any, b: any, value: number): this
|
|
1165
|
+
```
|
|
1166
|
+
|
|
1167
|
+
**Coincidence & Equality**
|
|
1168
|
+
|
|
1169
|
+
#### `equal()` — Constrain two lines to have equal length.
|
|
1170
|
+
|
|
1171
|
+
```ts
|
|
1172
|
+
equal(a: any, b: any): this
|
|
1173
|
+
```
|
|
1174
|
+
|
|
1175
|
+
#### `coincident()` — Constrain two points to coincide.
|
|
1176
|
+
|
|
1177
|
+
```ts
|
|
1178
|
+
coincident(a: any, b: any): this
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
#### `concentric()` — Constrain two circles to share a center.
|
|
1182
|
+
|
|
1183
|
+
```ts
|
|
1184
|
+
concentric(a: any, b: any): this
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
#### `fix()` — Pin a point at a specific world location.
|
|
1188
|
+
|
|
1189
|
+
```ts
|
|
1190
|
+
fix(point: any, x?: number, y?: number): this
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
#### `midpoint()` — Constrain a point to lie at the midpoint of a line.
|
|
1194
|
+
|
|
1195
|
+
```ts
|
|
1196
|
+
midpoint(point: any, line: any): this
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
#### `pointOnCircle()` — Constrain a point to lie on the perimeter of a circle.
|
|
1200
|
+
|
|
1201
|
+
```ts
|
|
1202
|
+
pointOnCircle(point: any, circle: any): this
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
#### `pointOnLine()` — Constrain a point to lie on the bounded segment of a line.
|
|
1206
|
+
|
|
1207
|
+
```ts
|
|
1208
|
+
pointOnLine(point: any, line: any): this
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
#### `ccw()` — Constrain all given points to be in counter-clockwise order.
|
|
1212
|
+
|
|
1213
|
+
```ts
|
|
1214
|
+
ccw(...points: any[]): this
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
**Tangent Transitions**
|
|
1218
|
+
|
|
1219
|
+
#### `lineTangentArc()` — Constrain a line to be tangent to an arc at its start or end point.
|
|
1220
|
+
|
|
1221
|
+
```ts
|
|
1222
|
+
lineTangentArc(line: any, arc: any, atStart: boolean): this
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
#### `arcTangentArc()` — Constrain two arcs to be tangent at their shared junction point.
|
|
1226
|
+
|
|
1227
|
+
```ts
|
|
1228
|
+
arcTangentArc(arcA: any, arcB: any, aAtStart?: boolean, bAtStart?: boolean): this
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
#### `bezierTangentArc()` — Constrain a Bezier to be tangent to an arc at one endpoint.
|
|
1232
|
+
|
|
1233
|
+
```ts
|
|
1234
|
+
bezierTangentArc(bezier: any, arc: any, atBezierStart: boolean, atArcStart: boolean): this
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
#### `smoothBlend()` — Create a Bezier blend between two arcs.
|
|
1238
|
+
|
|
1239
|
+
```ts
|
|
1240
|
+
smoothBlend(arc1: any, arc2: any, options?: { weight?: number; arc1End?: "start" | "end"; arc2End?: "start" | "end"; }): BezierId
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
**Shape Constraints**
|
|
1244
|
+
|
|
1245
|
+
#### `shapeWidth()` — Constrain a shape's width.
|
|
1246
|
+
|
|
1247
|
+
```ts
|
|
1248
|
+
shapeWidth(shape: any, value: number): this
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
#### `shapeHeight()` — Constrain a shape's height.
|
|
1252
|
+
|
|
1253
|
+
```ts
|
|
1254
|
+
shapeHeight(shape: any, value: number): this
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
#### `shapeCentroidX()` — Constrain a shape's centroid X position.
|
|
1258
|
+
|
|
1259
|
+
```ts
|
|
1260
|
+
shapeCentroidX(shape: any, value: number): this
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
#### `shapeCentroidY()` — Constrain a shape's centroid Y position.
|
|
1264
|
+
|
|
1265
|
+
```ts
|
|
1266
|
+
shapeCentroidY(shape: any, value: number): this
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
#### `shapeArea()` — Constrain a shape's area.
|
|
1270
|
+
|
|
1271
|
+
```ts
|
|
1272
|
+
shapeArea(shape: any, value: number): this
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
#### `shapeEqualCentroid()` — Constrain two shapes to have the same centroid.
|
|
1276
|
+
|
|
1277
|
+
```ts
|
|
1278
|
+
shapeEqualCentroid(a: any, b: any): this
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
**Positioning**
|
|
1282
|
+
|
|
1283
|
+
#### `offsetX()` — Constrain the horizontal (X-axis) offset between two lines. Uses the start-point of each line to measure horizontal distance. `value` is the signed distance: b.startPt.x − a.startPt.x = value.
|
|
1284
|
+
|
|
1285
|
+
```ts
|
|
1286
|
+
offsetX(a: any, b: any, value: number): this
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
#### `offsetY()` — Constrain the vertical (Y-axis) offset between two lines. Uses the start-point of each line to measure vertical distance. `value` is the signed distance: b.startPt.y − a.startPt.y = value.
|
|
1290
|
+
|
|
1291
|
+
```ts
|
|
1292
|
+
offsetY(a: any, b: any, value: number): this
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
#### `importPoint()` — Import a `Point2D` object into the sketch.
|
|
1296
|
+
|
|
1297
|
+
```ts
|
|
1298
|
+
importPoint(pt: { x: number; y: number; }, fixed?: boolean): PointId
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
#### `importLine()` — Import a `Line2D` object into the sketch.
|
|
1302
|
+
|
|
1303
|
+
```ts
|
|
1304
|
+
importLine(l: { start: { x: number; y: number; }; end: { x: number; y: number; }; }, fixed?: boolean): LineId
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
#### `importRectangle()` — Import a `Rectangle2D` as four points and four lines.
|
|
1308
|
+
|
|
1309
|
+
```ts
|
|
1310
|
+
importRectangle(r: { vertices: [ { x: number; y: number; }, { x: number; y: number; }, { x: number; y: number; }, { x: number; y: number; } ]; }, fixed?: boolean): { ... }
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
#### `referencePoint()` — Add a fixed reference point at `(x, y)`.
|
|
1314
|
+
|
|
1315
|
+
```ts
|
|
1316
|
+
referencePoint(x: number, y: number): PointId
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
#### `referenceLine()` — Add a fixed reference line from `(x1, y1)` to `(x2, y2)`.
|
|
1320
|
+
|
|
1321
|
+
```ts
|
|
1322
|
+
referenceLine(x1: number, y1: number, x2: number, y2: number): LineId
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
#### `referenceFrom()` — Import a single named entity from a solved sketch as fixed reference geometry.
|
|
1326
|
+
|
|
1327
|
+
```ts
|
|
1328
|
+
referenceFrom(source: ConstraintSketch, entityId: string): PointId | LineId | null
|
|
1329
|
+
```
|
|
1330
|
+
|
|
1331
|
+
#### `referenceAllFrom()` — Import all non-construction entities from a solved sketch as fixed references.
|
|
1332
|
+
|
|
1333
|
+
```ts
|
|
1334
|
+
referenceAllFrom(source: ConstraintSketch): { points: Map<string, PointId>; lines: Map<string, LineId>; }
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
**Solving**
|
|
1338
|
+
|
|
1339
|
+
#### `constrain()` — Add a raw constraint object to the builder.
|
|
1340
|
+
|
|
1341
|
+
```ts
|
|
1342
|
+
constrain(constraint: Omit<SketchConstraint, "id">): this
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
#### `solve()` — Run the constraint solver and return a solved sketch.
|
|
1346
|
+
|
|
1347
|
+
The returned `ConstraintSketch` extends `Sketch` and can be used directly in all 3D operations (`extrude`, `revolve`, etc.). It also exposes `constraintMeta` with the solver status:
|
|
1348
|
+
|
|
1349
|
+
```ts
|
|
1350
|
+
const result = sk.solve();
|
|
1351
|
+
result.constraintMeta.status; // 'fully' | 'under' | 'over' | 'over-redundant'
|
|
1352
|
+
result.constraintMeta.dof; // 0 = fully constrained
|
|
1353
|
+
result.constraintMeta.maxError; // residual — should be < 1e-6
|
|
1354
|
+
result.inspect(); // human-readable summary
|
|
1355
|
+
result.withUpdatedConstraint('cst-5', 120); // update a dimension without rebuilding
|
|
1356
|
+
```
|
|
1357
|
+
|
|
1358
|
+
**Troubleshooting**
|
|
1359
|
+
|
|
1360
|
+
- **Under-constrained (dof > 0)** — add `fix()`, `length()`, or other dimensional constraints.
|
|
1361
|
+
- **Over-constrained** — conflicting constraints are auto-rejected. Check `result.constraintMeta.constraints` and `result.inspect()`.
|
|
1362
|
+
- **maxError > 1e-6** — solver did not converge; check for contradictory constraints.
|
|
1363
|
+
|
|
1364
|
+
```ts
|
|
1365
|
+
solve(options?: SolveOptions): ConstraintSketch | Sketch
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
#### `solveConstraintsOnly()` — Run the solver without building a full `ConstraintSketch`.
|
|
1369
|
+
|
|
1370
|
+
Lighter than `solve()` — skips profile and DOF analysis. Useful for lightweight constraint validation or progress monitoring mid-construction.
|
|
1371
|
+
|
|
1372
|
+
```ts
|
|
1373
|
+
solveConstraintsOnly(options?: SolveOptions): { maxError: number; rejectedCount: number; definition: ConstraintDefinition; }
|
|
1374
|
+
```
|
|
1375
|
+
|
|
1376
|
+
#### `route()` — Start a directional route from coordinates.
|
|
1377
|
+
|
|
1378
|
+
Returns a [`RouteBuilder`](/docs/viewport#routebuilder) - describe the path with up/down/left/right/arcLeft/arcRight. Each method returns the entity ID (`LineId` or `ArcId`) for use in `sk.*` constraints.
|
|
1379
|
+
|
|
1380
|
+
```js
|
|
1381
|
+
```ts
|
|
1382
|
+
|
|
1383
|
+
const r = sk.route(0, 0); const stem = r.up(18); r.arcLeft(8.9); const neck = r.down(); r.done(); sk.offsetX(stem, neck, 10.8);
|
|
1384
|
+
|
|
1385
|
+
```
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
```ts
|
|
1389
|
+
route(x: number, y: number): RouteBuilder
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
### `ConstraintSketch`
|
|
1393
|
+
|
|
1394
|
+
**Properties:**
|
|
1395
|
+
|
|
1396
|
+
| Property | Type | Description |
|
|
1397
|
+
|----------|------|-------------|
|
|
1398
|
+
| `constraintMeta` | `SketchConstraintMeta` | — |
|
|
1399
|
+
| `definition` | `ConstraintDefinition` | — |
|
|
1400
|
+
|
|
1401
|
+
**Methods:**
|
|
1402
|
+
|
|
1403
|
+
#### `detectArrangement()` — Enumerate all bounded regions formed by the line arrangement of this sketch. Construction lines are excluded. Regions are returned largest-first by area.
|
|
1404
|
+
|
|
1405
|
+
```ts
|
|
1406
|
+
detectArrangement(): Sketch[]
|
|
1407
|
+
```
|
|
1408
|
+
|
|
1409
|
+
#### `detectArrangementRegion()` — Select the single arrangement region that contains the given seed point. Throws if no region contains the seed.
|
|
1410
|
+
|
|
1411
|
+
```ts
|
|
1412
|
+
detectArrangementRegion(seed: [ number, number ]): Sketch
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
#### `withUpdatedConstraint()` — Re-solve the sketch after changing the value of one existing constraint.
|
|
1416
|
+
|
|
1417
|
+
Use this for interactive dimension edits without rebuilding the whole sketch graph. It attempts a warm-started solve first, then falls back to a full solve if needed.
|
|
1418
|
+
|
|
1419
|
+
```ts
|
|
1420
|
+
withUpdatedConstraint(constraintId: string, value: number): ConstraintSketch
|
|
1421
|
+
```
|
|
1422
|
+
|
|
1423
|
+
#### `inspect()` — Return a human-readable diagnostic string of the solved state.
|
|
1424
|
+
|
|
1425
|
+
```ts
|
|
1426
|
+
inspect(): string
|
|
1427
|
+
```
|
|
1428
|
+
|
|
1429
|
+
### `SketchGroupBuilder`
|
|
1430
|
+
|
|
1431
|
+
#### `point()` — Add a point in local coordinates. Returns its globally-addressable PointId.
|
|
1432
|
+
|
|
1433
|
+
```ts
|
|
1434
|
+
point(lx: number, ly: number): PointId
|
|
1435
|
+
```
|
|
1436
|
+
|
|
1437
|
+
#### `line()` — Connect two group points with a line. Both must be PointIds from this group.
|
|
1438
|
+
|
|
1439
|
+
```ts
|
|
1440
|
+
line(a: PointId, b: PointId, name?: string): LineId
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
#### `fixRotation()` — Freeze rotation (theta). Group can still translate - 2 DOF remain.
|
|
1444
|
+
|
|
1445
|
+
```ts
|
|
1446
|
+
fixRotation(): this
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
#### `fix()` — Freeze all 3 DOF - group is completely fixed.
|
|
1450
|
+
|
|
1451
|
+
```ts
|
|
1452
|
+
fix(): this
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
#### `done()` — Finalize and register the group with the builder.
|
|
1456
|
+
|
|
1457
|
+
```ts
|
|
1458
|
+
done(): SketchGroupHandle
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
### `Point2D`
|
|
1462
|
+
|
|
1463
|
+
An immutable 2D point with measurement and construction helpers.
|
|
1464
|
+
|
|
1465
|
+
Used as construction geometry in sketches, constraints, and analytic measurements. All methods return new instances — `Point2D` is immutable.
|
|
1466
|
+
|
|
1467
|
+
**Properties:**
|
|
1468
|
+
|
|
1469
|
+
| Property | Type | Description |
|
|
1470
|
+
|----------|------|-------------|
|
|
1471
|
+
| `x` | `number` | — |
|
|
1472
|
+
| `y` | `number` | — |
|
|
1473
|
+
|
|
1474
|
+
**Methods:**
|
|
1475
|
+
|
|
1476
|
+
#### `distanceTo()` — Measure straight-line distance to another point.
|
|
1477
|
+
|
|
1478
|
+
```ts
|
|
1479
|
+
distanceTo(other: Point2D): number
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1482
|
+
#### `midpointTo()` — Compute the midpoint between this point and another point.
|
|
1483
|
+
|
|
1484
|
+
```ts
|
|
1485
|
+
midpointTo(other: Point2D): Point2D
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
#### `translate()` — Return a point shifted by the given delta.
|
|
1489
|
+
|
|
1490
|
+
```ts
|
|
1491
|
+
translate(dx: number, dy: number): Point2D
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
#### `toTuple()` — Convert this point to a plain `[x, y]` tuple.
|
|
1495
|
+
|
|
1496
|
+
```ts
|
|
1497
|
+
toTuple(): [ number, number ]
|
|
1498
|
+
```
|
|
1499
|
+
|
|
1500
|
+
### `Line2D`
|
|
1501
|
+
|
|
1502
|
+
An immutable 2D line segment with length, angle, intersection, and parallel helpers.
|
|
1503
|
+
|
|
1504
|
+
Provides both segment-only (`intersectSegment`) and infinite-line (`intersect`) intersection queries. All methods return new instances.
|
|
1505
|
+
|
|
1506
|
+
**Properties:**
|
|
1507
|
+
|
|
1508
|
+
| Property | Type | Description |
|
|
1509
|
+
|----------|------|-------------|
|
|
1510
|
+
| `start` | `Point2D` | — |
|
|
1511
|
+
| `end` | `Point2D` | — |
|
|
1512
|
+
|
|
1513
|
+
**Methods:**
|
|
1514
|
+
|
|
1515
|
+
#### `length()` — Length of the line segment.
|
|
1516
|
+
|
|
1517
|
+
```ts
|
|
1518
|
+
get length(): number
|
|
1519
|
+
```
|
|
1520
|
+
|
|
1521
|
+
#### `midpoint()` — Midpoint of the line segment.
|
|
1522
|
+
|
|
1523
|
+
```ts
|
|
1524
|
+
get midpoint(): Point2D
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1527
|
+
#### `angle()` — Direction angle in degrees, measured CCW from +X.
|
|
1528
|
+
|
|
1529
|
+
```ts
|
|
1530
|
+
get angle(): number
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
#### `direction()` — Unit direction vector from start to end.
|
|
1534
|
+
|
|
1535
|
+
```ts
|
|
1536
|
+
get direction(): [ number, number ]
|
|
1537
|
+
```
|
|
1538
|
+
|
|
1539
|
+
#### `parallel()` — Create a parallel line offset by the given distance.
|
|
1540
|
+
|
|
1541
|
+
Positive distance shifts to the left of the line direction.
|
|
1542
|
+
|
|
1543
|
+
```ts
|
|
1544
|
+
parallel(distance: number): Line2D
|
|
1545
|
+
```
|
|
1546
|
+
|
|
1547
|
+
#### `intersect()` — Intersect this line with another infinite line.
|
|
1548
|
+
|
|
1549
|
+
```ts
|
|
1550
|
+
intersect(other: Line2D): Point2D | null
|
|
1551
|
+
```
|
|
1552
|
+
|
|
1553
|
+
#### `intersectSegment()` — Intersect this line with another as bounded segments.
|
|
1554
|
+
|
|
1555
|
+
```ts
|
|
1556
|
+
intersectSegment(other: Line2D): Point2D | null
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
#### `fromCoordinates()` — Create a line from raw coordinates.
|
|
1560
|
+
|
|
1561
|
+
```ts
|
|
1562
|
+
static fromCoordinates(x1: number, y1: number, x2: number, y2: number): Line2D
|
|
1563
|
+
```
|
|
1564
|
+
|
|
1565
|
+
#### `fromPointAndAngle()` — Create a line from a start point, angle, and length.
|
|
1566
|
+
|
|
1567
|
+
```ts
|
|
1568
|
+
static fromPointAndAngle(origin: Point2D, angleDeg: number, length: number): Line2D
|
|
1569
|
+
```
|
|
1570
|
+
|
|
1571
|
+
#### `fromPointAndDirection()` — Create a line from a start point, direction vector, and length.
|
|
1572
|
+
|
|
1573
|
+
```ts
|
|
1574
|
+
static fromPointAndDirection(origin: Point2D, dir: [ number, number ], length: number): Line2D
|
|
1575
|
+
```
|
|
1576
|
+
|
|
1577
|
+
### `Circle2D`
|
|
1578
|
+
|
|
1579
|
+
An immutable 2D circle with area, circumference, and extrusion support.
|
|
1580
|
+
|
|
1581
|
+
Extruding a `Circle2D` produces a cylinder with named `top`, `bottom`, and `side` faces accessible via the topology API.
|
|
1582
|
+
|
|
1583
|
+
**Properties:**
|
|
1584
|
+
|
|
1585
|
+
| Property | Type | Description |
|
|
1586
|
+
|----------|------|-------------|
|
|
1587
|
+
| `center` | `Point2D` | — |
|
|
1588
|
+
| `radius` | `number` | — |
|
|
1589
|
+
|
|
1590
|
+
**Methods:**
|
|
1591
|
+
|
|
1592
|
+
#### `diameter()` — Diameter of the circle.
|
|
1593
|
+
|
|
1594
|
+
```ts
|
|
1595
|
+
get diameter(): number
|
|
1596
|
+
```
|
|
1597
|
+
|
|
1598
|
+
#### `circumference()` — Circumference of the circle.
|
|
1599
|
+
|
|
1600
|
+
```ts
|
|
1601
|
+
get circumference(): number
|
|
1602
|
+
```
|
|
1603
|
+
|
|
1604
|
+
#### `area()` — Area of the circle.
|
|
1605
|
+
|
|
1606
|
+
```ts
|
|
1607
|
+
get area(): number
|
|
1608
|
+
```
|
|
1609
|
+
|
|
1610
|
+
#### `pointAtAngle()` — Return a point on the circle at the given angle.
|
|
1611
|
+
|
|
1612
|
+
```ts
|
|
1613
|
+
pointAtAngle(angleDeg: number): Point2D
|
|
1614
|
+
```
|
|
1615
|
+
|
|
1616
|
+
#### `translate()` — Return a translated circle.
|
|
1617
|
+
|
|
1618
|
+
```ts
|
|
1619
|
+
translate(dx: number, dy: number): Circle2D
|
|
1620
|
+
```
|
|
1621
|
+
|
|
1622
|
+
#### `toSketch()` — Convert this circle to a sketch profile.
|
|
1623
|
+
|
|
1624
|
+
```ts
|
|
1625
|
+
toSketch(segments?: number): Sketch
|
|
1626
|
+
```
|
|
1627
|
+
|
|
1628
|
+
#### `extrude()` — Extrude the circle into a solid cylinder.
|
|
1629
|
+
|
|
1630
|
+
```ts
|
|
1631
|
+
extrude(height: number, segments?: number): Shape
|
|
1632
|
+
```
|
|
1633
|
+
|
|
1634
|
+
#### `fromCenterAndRadius()` — Create a circle from its center and radius.
|
|
1635
|
+
|
|
1636
|
+
```ts
|
|
1637
|
+
static fromCenterAndRadius(center: Point2D, radius: number): Circle2D
|
|
1638
|
+
```
|
|
1639
|
+
|
|
1640
|
+
#### `fromDiameter()` — Create a circle from its center and diameter.
|
|
1641
|
+
|
|
1642
|
+
```ts
|
|
1643
|
+
static fromDiameter(center: Point2D, diameter: number): Circle2D
|
|
1644
|
+
```
|
|
1645
|
+
|
|
1646
|
+
### `Rectangle2D`
|
|
1647
|
+
|
|
1648
|
+
A rectangle with named sides, vertices, and extrusion support.
|
|
1649
|
+
|
|
1650
|
+
Sides are named based on the rectangle's local orientation at construction time. Vertices go: bottom-left, bottom-right, top-right, top-left (CCW).
|
|
1651
|
+
|
|
1652
|
+
Extruding a `Rectangle2D` produces a [`Shape`](/docs/core#shape) with named faces: `top`, `bottom`, `side-left`, `side-right`, `side-top`, `side-bottom`. These are accessible via the topology API (`.face()`, `.edge()`).
|
|
1653
|
+
|
|
1654
|
+
```ts
|
|
1655
|
+
const r = rectangle(0, 0, 100, 60);
|
|
1656
|
+
r.side('top'); r.side('left'); // Line2D
|
|
1657
|
+
r.vertex('top-left'); // Point2D
|
|
1658
|
+
r.width; r.height; r.center;
|
|
1659
|
+
const [d1, d2] = r.diagonals(); // [bl-tr, br-tl]
|
|
1660
|
+
|
|
1661
|
+
r.toSketch(); // Sketch (for 2D operations)
|
|
1662
|
+
r.extrude(20); // Shape with named faces
|
|
1663
|
+
|
|
1664
|
+
Rectangle2D.fromCenterAndDimensions(point(50, 30), 100, 60);
|
|
1665
|
+
Rectangle2D.from2Corners(point(0, 0), point(100, 60));
|
|
1666
|
+
Rectangle2D.from3Points(p1, p2, p3); // free-angle rectangle
|
|
1667
|
+
```
|
|
1668
|
+
|
|
1669
|
+
#### `width()` — Width of the rectangle.
|
|
1670
|
+
|
|
1671
|
+
```ts
|
|
1672
|
+
get width(): number
|
|
1673
|
+
```
|
|
1674
|
+
|
|
1675
|
+
#### `height()` — Height of the rectangle.
|
|
1676
|
+
|
|
1677
|
+
```ts
|
|
1678
|
+
get height(): number
|
|
1679
|
+
```
|
|
1680
|
+
|
|
1681
|
+
#### `center()` — Geometric center of the rectangle.
|
|
1682
|
+
|
|
1683
|
+
```ts
|
|
1684
|
+
get center(): Point2D
|
|
1685
|
+
```
|
|
1686
|
+
|
|
1687
|
+
#### `side()` — Return a named side of the rectangle.
|
|
1688
|
+
|
|
1689
|
+
```ts
|
|
1690
|
+
side(name: RectSide): Line2D
|
|
1691
|
+
```
|
|
1692
|
+
|
|
1693
|
+
#### `sideAt()` — Return a side by index.
|
|
1694
|
+
|
|
1695
|
+
```ts
|
|
1696
|
+
sideAt(index: number): Line2D
|
|
1697
|
+
```
|
|
1698
|
+
|
|
1699
|
+
#### `vertex()` — Return a named vertex of the rectangle.
|
|
1700
|
+
|
|
1701
|
+
```ts
|
|
1702
|
+
vertex(name: RectVertex): Point2D
|
|
1703
|
+
```
|
|
1704
|
+
|
|
1705
|
+
#### `diagonals()` — Return the two diagonals of the rectangle.
|
|
1706
|
+
|
|
1707
|
+
```ts
|
|
1708
|
+
diagonals(): [ Line2D, Line2D ]
|
|
1709
|
+
```
|
|
1710
|
+
|
|
1711
|
+
#### `toSketch()` — Convert the rectangle to a sketch profile.
|
|
1712
|
+
|
|
1713
|
+
```ts
|
|
1714
|
+
toSketch(): Sketch
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
#### `translate()` — Return a translated rectangle.
|
|
1718
|
+
|
|
1719
|
+
```ts
|
|
1720
|
+
translate(dx: number, dy: number): Rectangle2D
|
|
1721
|
+
```
|
|
1722
|
+
|
|
1723
|
+
#### `fromDimensions()` — Create an axis-aligned rectangle from origin corner plus width and height.
|
|
1724
|
+
|
|
1725
|
+
```ts
|
|
1726
|
+
static fromDimensions(x: number, y: number, width: number, height: number): Rectangle2D
|
|
1727
|
+
```
|
|
1728
|
+
|
|
1729
|
+
#### `fromCenterAndDimensions()` — Create a rectangle centered on a point.
|
|
1730
|
+
|
|
1731
|
+
```ts
|
|
1732
|
+
static fromCenterAndDimensions(center: Point2D, width: number, height: number): Rectangle2D
|
|
1733
|
+
```
|
|
1734
|
+
|
|
1735
|
+
#### `from2Corners()` — Create an axis-aligned rectangle from two opposite corners.
|
|
1736
|
+
|
|
1737
|
+
```ts
|
|
1738
|
+
static from2Corners(p1: Point2D, p2: Point2D): Rectangle2D
|
|
1739
|
+
```
|
|
1740
|
+
|
|
1741
|
+
#### `from3Points()` — Create a free-angle rectangle from three points.
|
|
1742
|
+
|
|
1743
|
+
`p1` and `p2` define one edge, and `p3` chooses the perpendicular side.
|
|
1744
|
+
|
|
1745
|
+
```ts
|
|
1746
|
+
static from3Points(p1: Point2D, p2: Point2D, p3: Point2D): Rectangle2D
|
|
1747
|
+
```
|
|
1748
|
+
|
|
1749
|
+
#### `extrude()` — Extrude the rectangle into a solid prism with named topology.
|
|
1750
|
+
|
|
1751
|
+
```ts
|
|
1752
|
+
extrude(height: number, up?: boolean): Shape
|
|
1753
|
+
```
|