@code3d/core 0.0.1-alpha.11 → 0.0.1-alpha.13
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 +55 -41
- package/bld/chunks/{chunk-HZRQUHM2.js → chunk-776Q5P2L.js} +2 -2
- package/bld/chunks/{chunk-QK6ZET47.js → chunk-N7JJWNVL.js} +3 -3
- package/bld/chunks/{chunk-CL3E2DE4.js → chunk-VFPWXSFD.js} +2 -2
- package/bld/chunks/{chunk-JBVIAMJ6.js → chunk-VINZNODV.js} +589 -26
- package/bld/chunks/chunk-VINZNODV.js.map +7 -0
- package/bld/library/extrude.d.ts +5 -0
- package/bld/library/extrude.d.ts.map +1 -1
- package/bld/library/index.d.ts +2 -2
- package/bld/library/index.d.ts.map +1 -1
- package/bld/library/index.js +17 -1
- package/bld/library/inspect.d.ts +3 -1
- package/bld/library/inspect.d.ts.map +1 -1
- package/bld/library/loft.d.ts +7 -1
- package/bld/library/loft.d.ts.map +1 -1
- package/bld/library/replicad.js +2 -2
- package/bld/library/runtime.d.ts +75 -8
- package/bld/library/runtime.d.ts.map +1 -1
- package/bld/node/index.js +19 -3
- package/bld/node/replicad.js +4 -4
- package/bld/tooling/index.js +2 -2
- package/docs/api.md +143 -13
- package/docs/local-coordinates.md +2 -0
- package/docs/runtime.md +52 -2
- package/docs/topology.md +6 -0
- package/docs/values.md +34 -31
- package/package.json +1 -1
- package/src/library/extrude.ts +129 -2
- package/src/library/index.ts +9 -0
- package/src/library/inspect.ts +4 -2
- package/src/library/loft.ts +67 -2
- package/src/library/runtime.ts +646 -8
- package/bld/chunks/chunk-JBVIAMJ6.js.map +0 -7
- /package/bld/chunks/{chunk-HZRQUHM2.js.map → chunk-776Q5P2L.js.map} +0 -0
- /package/bld/chunks/{chunk-QK6ZET47.js.map → chunk-N7JJWNVL.js.map} +0 -0
- /package/bld/chunks/{chunk-CL3E2DE4.js.map → chunk-VFPWXSFD.js.map} +0 -0
package/docs/api.md
CHANGED
|
@@ -5,6 +5,9 @@ sidebar:
|
|
|
5
5
|
order: 1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
Construct geometry, combine models and query the result with the public Core
|
|
9
|
+
API. For a first runnable model, see the [Core example](../README.md#example).
|
|
10
|
+
|
|
8
11
|
Import these functions from `@code3d/core`. The editor's TypeScript signatures
|
|
9
12
|
provide exact overloads and inferred model interfaces.
|
|
10
13
|
|
|
@@ -31,6 +34,7 @@ radius. For coils, `coilRadius` is measured to the wire centerline and
|
|
|
31
34
|
`pitch` is the advance per turn. Fractional turns are supported; the wire
|
|
32
35
|
must fit inside the coil radius and neighboring turns must remain separated.
|
|
33
36
|
Use [`@code3d/screws`](../../screws/docs/assembly.mdx) for standard fasteners and matching hole tools.
|
|
37
|
+
Use [`@code3d/gears`](../../gears/README.md) for nominal spur, helical and internal gear parts.
|
|
34
38
|
|
|
35
39
|
To build a solid beyond these primitives, import `definePrimitive` and
|
|
36
40
|
`replicad` from `@code3d/core/replicad`. See
|
|
@@ -40,19 +44,21 @@ To build a solid beyond these primitives, import `definePrimitive` and
|
|
|
40
44
|
|
|
41
45
|
Planar profiles lie in the local XZ plane with a +Y normal.
|
|
42
46
|
|
|
43
|
-
| Function | Meaning
|
|
44
|
-
| ------------------------------------------ |
|
|
45
|
-
| `circle(radius)` | Circular face
|
|
46
|
-
| `ellipse(xRadius, zRadius)` | Elliptical face
|
|
47
|
-
| `rectangle(x, z)` | Rectangular face
|
|
48
|
-
| `regularPolygon(radius, sides, rotation?)` | Regular polygonal face
|
|
49
|
-
| `point()` or `point([x, y, z])` | Vertex model
|
|
50
|
-
| `line([x, y, z])` or `line(start, end)` | Straight edge
|
|
51
|
-
| `arc(start, middle, end)` | Arc through three points
|
|
52
|
-
| `bezier(points)` | Bézier curve
|
|
53
|
-
| `spline(points)` | Interpolating spline
|
|
54
|
-
| `loft(sections, options?)` | Solid through sections; optional curve spine
|
|
55
|
-
| `extrude(faceOrFaces, distance)` | Solid extruded along one face's local normal
|
|
47
|
+
| Function | Meaning |
|
|
48
|
+
| ------------------------------------------ | ------------------------------------------------------------------------- |
|
|
49
|
+
| `circle(radius)` | Circular face |
|
|
50
|
+
| `ellipse(xRadius, zRadius)` | Elliptical face |
|
|
51
|
+
| `rectangle(x, z)` | Rectangular face |
|
|
52
|
+
| `regularPolygon(radius, sides, rotation?)` | Regular polygonal face |
|
|
53
|
+
| `point()` or `point([x, y, z])` | Vertex model |
|
|
54
|
+
| `line([x, y, z])` or `line(start, end)` | Straight edge |
|
|
55
|
+
| `arc(start, middle, end)` | Arc through three points |
|
|
56
|
+
| `bezier(points)` | Bézier curve |
|
|
57
|
+
| `spline(points)` | Interpolating spline |
|
|
58
|
+
| `loft(sections, options?)` | Solid through sections; optional curve spine |
|
|
59
|
+
| `extrude(faceOrFaces, distance)` | Solid extruded along one face's local normal |
|
|
60
|
+
| `revolve(profile, axis, config)` | Solid rotated about a straight directed axis, with optional axial advance |
|
|
61
|
+
| `sweep(profile, spine)` | Solid formed by carrying one face along an open curve |
|
|
56
62
|
|
|
57
63
|
See [local coordinates and placement](local-coordinates.md) for
|
|
58
64
|
the coordinate frame of a model, reference, or composition.
|
|
@@ -83,8 +89,126 @@ export const plate = rectangle(30, 20).extrude(3).fillet(0.5);
|
|
|
83
89
|
export const pin = extrude(circle(2), -10);
|
|
84
90
|
```
|
|
85
91
|
|
|
92
|
+
### Rotational solids
|
|
93
|
+
|
|
94
|
+
`revolve(profile, axis, config: RevolveConfig)` and
|
|
95
|
+
`profile.revolve(axis, config)` rotate one face about a straight directed axis.
|
|
96
|
+
`line(...)` can be passed directly; an existing straight edge or axis reference
|
|
97
|
+
also works.
|
|
98
|
+
`config.angle` is a required finite, non-zero angle in degrees. `config.advance`
|
|
99
|
+
is the signed total distance traveled along the directed axis during that angle;
|
|
100
|
+
it defaults to zero. A positive angle follows the axis's right-hand direction.
|
|
101
|
+
Reversing the axis reverses both the rotation sense and the direction of a positive
|
|
102
|
+
advance. With zero advance, the angle may cover at most one turn. With non-zero
|
|
103
|
+
advance, it may cover multiple turns to form a simple screw-motion solid.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import {circle, line, rectangle, revolve} from '@code3d/core';
|
|
107
|
+
|
|
108
|
+
const axis = line([0, -20, 0], [0, 20, 0]);
|
|
109
|
+
const ringSection = rectangle(4, 6).rotate(90, 0, 0).originOffset(-8, 0, 0);
|
|
110
|
+
export const ring = revolve(ringSection, axis, {angle: 360});
|
|
111
|
+
|
|
112
|
+
const wireSection = circle(1).rotate(90, 0, 0).originOffset(-8, 0, 0);
|
|
113
|
+
export const spring = wireSection.revolve(axis, {angle: 5 * 360, advance: 25});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The authoring signature requires `config`. While editing an incomplete call,
|
|
117
|
+
the App uses 360 degrees and zero advance so its parameter tool can add the
|
|
118
|
+
config object.
|
|
119
|
+
|
|
120
|
+
The result keeps the profile's local frame and is an ordinary `SolidModel`.
|
|
121
|
+
The axis participates in the same relation solve as the profile; its own model
|
|
122
|
+
placement is respected. A helical profile must have one outer boundary without
|
|
123
|
+
holes. Intersecting turns and profiles that cross the axis may fail to produce a
|
|
124
|
+
valid solid; leave clearance between turns and keep the profile off the axis.
|
|
125
|
+
For a multi-turn coil with round wire and automatic pitch clearance checks,
|
|
126
|
+
[`coil`](#solid-primitives) remains the shorter constructor.
|
|
127
|
+
|
|
128
|
+
### Path sweeps
|
|
129
|
+
|
|
130
|
+
`sweep(profile, spine)` and `profile.sweep(spine)` carry one planar face along a
|
|
131
|
+
continuous open `EdgeModel`, such as a line or Bézier curve. The face's local
|
|
132
|
+
origin must meet the path's start, and its normal must point along the starting
|
|
133
|
+
tangent. The operation respects the solved placement of both inputs and returns
|
|
134
|
+
a solid in the profile's local frame; it does not move or rotate the supplied
|
|
135
|
+
profile to fit the path.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import {bezier, circle, sweep} from '@code3d/core';
|
|
139
|
+
|
|
140
|
+
const profile = circle(2);
|
|
141
|
+
const spine = bezier([
|
|
142
|
+
[0, 0, 0],
|
|
143
|
+
[0, 8, 0],
|
|
144
|
+
[5, 16, 0],
|
|
145
|
+
[5, 24, 0],
|
|
146
|
+
]);
|
|
147
|
+
export const bentRod = sweep(profile, spine);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The path must be open with a non-zero starting tangent. The output is an ordinary
|
|
151
|
+
`SolidModel` that supports subsequent Boolean and finishing operations. Very
|
|
152
|
+
tight bends or self-intersections may prevent the kernel from producing a valid
|
|
153
|
+
solid. One through hole in the profile is supported; profiles with multiple
|
|
154
|
+
holes currently need explicit contour correspondence. Use the
|
|
155
|
+
[App example](../../app/examples/operations/sweep.ts) to inspect
|
|
156
|
+
the profile, path and result.
|
|
157
|
+
|
|
86
158
|
## Measurements
|
|
87
159
|
|
|
160
|
+
### Length and area
|
|
161
|
+
|
|
162
|
+
Read `edge.length` or `line(...).length` for a finite edge's actual arc length.
|
|
163
|
+
A straight edge uses its endpoint distance; a closed edge uses its circumference.
|
|
164
|
+
Read `surface.area` or `faceModel.area` for a finite face's area, including curved
|
|
165
|
+
surfaces and trimming holes. `solid.area` / `solidModel.area` includes every
|
|
166
|
+
boundary face, including inner walls and cavity faces.
|
|
167
|
+
|
|
168
|
+
These properties return ordinary numbers in model units (area in square model
|
|
169
|
+
units). They are read-only. Rotation, origin changes, placement and reversing an
|
|
170
|
+
edge or flipping a face preserve the result. `scaled(s)` multiplies lengths by
|
|
171
|
+
`s` and areas by `s²`; exposed references use the scale of their actual geometry.
|
|
172
|
+
`LineAnchor` and `FaceAnchor` can describe infinite references and have no length
|
|
173
|
+
or area. Groups have no aggregate area.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import {line, rectangle, box} from '@code3d/core';
|
|
177
|
+
const length = line([3, 4, 0]).length; // 5
|
|
178
|
+
const area = rectangle(4, 6).area; // 24
|
|
179
|
+
const surfaceArea = box(2, 3, 4).area; // 52
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Select `.length` or `.area` in App to inspect the measured geometry and value.
|
|
183
|
+
Straight lengths use a dimension line; curves highlight their actual path with an
|
|
184
|
+
arc-length label. Area highlights the finite face or whole solid with an area
|
|
185
|
+
label. The read-only display does not create editable size constraints.
|
|
186
|
+
Try the [length example](../../app/examples/operations/length.ts) and
|
|
187
|
+
[area example](../../app/examples/operations/area.ts).
|
|
188
|
+
|
|
189
|
+
### Volume
|
|
190
|
+
|
|
191
|
+
Read `solid.volume` or `solidModel.volume` for the space occupied by the solid's
|
|
192
|
+
material. Holes and enclosed cavities are excluded. The result is a read-only
|
|
193
|
+
number in cubic model units. Rotation, origin changes and placement preserve it;
|
|
194
|
+
`scaled(s)` multiplies it by `s³`. Exposed solid references include the scale of
|
|
195
|
+
their actual geometry. Faces, edges, infinite references and groups have no volume
|
|
196
|
+
property.
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import {box, tube} from '@code3d/core';
|
|
200
|
+
const blockVolume = box(2, 3, 4).volume; // 24
|
|
201
|
+
const pipeVolume = tube(5, 3, 7).volume; // 112 * Math.PI
|
|
202
|
+
const enlargedVolume = box(2, 3, 4).scaled(2).volume; // 192
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Select `.volume` in App to inspect the whole solid with a volume label at its
|
|
206
|
+
volume centroid. This read-only display uses the getter's recorded result and
|
|
207
|
+
does not create an editable size constraint.
|
|
208
|
+
Try the [volume example](../../app/examples/operations/volume.ts).
|
|
209
|
+
|
|
210
|
+
### Distance between references
|
|
211
|
+
|
|
88
212
|
`distance(a, b, axis?)` returns a non-negative `number` from the models and
|
|
89
213
|
relations available at the call. It accepts vertex, edge, face and solid models,
|
|
90
214
|
non-empty groups, finite topology references, directional bounds, and point
|
|
@@ -491,6 +615,12 @@ the vertex picker, origin arrows, and rotation rings, see
|
|
|
491
615
|
|
|
492
616
|
## Anchors and relations
|
|
493
617
|
|
|
618
|
+
Package authors can use `setModelData(model, key, value)` to associate
|
|
619
|
+
package-specific data with a newly built model, and `getModelData(model, key)`
|
|
620
|
+
to read it. Keys are symbols. Data is retained when `.relate()` or
|
|
621
|
+
`.material()` creates a new value; other model operations do not retain it.
|
|
622
|
+
This data stays in process and is not part of model geometry or snapshots.
|
|
623
|
+
|
|
494
624
|
Solid primitives expose `center` and `axis`; every model provides directional
|
|
495
625
|
bounds: `up` (+Y), `down` (−Y), `right` (+X), `left` (−X), `front` (+Z),
|
|
496
626
|
and `back` (−Z), in that model's local frame.
|
|
@@ -47,6 +47,8 @@ Only an explicit origin operation chooses a different local zero.
|
|
|
47
47
|
| `text` | All returned faces share the text layout's baseline origin, including its glyph advances and offsets. Individual letters are not centered. |
|
|
48
48
|
| `definePrimitive` | Retain the frame used by the returned geometry; no automatic recentering. |
|
|
49
49
|
| `extrude` | Inherit the input face's frame, without centering the extrusion. |
|
|
50
|
+
| `revolve` | Inherit the input profile's frame; the axis's solved placement is converted into that frame. |
|
|
51
|
+
| `sweep` | Inherit the input profile's frame; the spine's solved placement is converted into that frame. |
|
|
50
52
|
| `union`, `intersect` | Inherit the first operand's frame. |
|
|
51
53
|
| `cut` | Inherit the stock's frame. |
|
|
52
54
|
| `loft` | Inherit the first section's frame. |
|
package/docs/runtime.md
CHANGED
|
@@ -70,6 +70,16 @@ Returning `undefined` declines the scope; returning `{}` intentionally displays
|
|
|
70
70
|
an empty scene. Target values matching `context.focused.values` receive focus;
|
|
71
71
|
generated geometry does not inherit focus from its inputs.
|
|
72
72
|
|
|
73
|
+
For a function that returns related copies of input models,
|
|
74
|
+
`inspectGroupMembers(result, inputs)` from `@code3d/core` renders each result
|
|
75
|
+
in the solved group frame and keeps its corresponding input as the focus
|
|
76
|
+
identity. This gives array member selection the same positioned, per-member
|
|
77
|
+
highlighting as the `group()` parameter inspector. Use the input array when
|
|
78
|
+
`context.focused.parameter` identifies that argument; when inspecting the
|
|
79
|
+
returned collection itself, use `inspectGroupMembers(result, result)` so its
|
|
80
|
+
members keep their result identities. The viewport does not add the current
|
|
81
|
+
execution's original inputs to this scene.
|
|
82
|
+
|
|
73
83
|
Selecting an array member focuses that value while keeping the other inspection
|
|
74
84
|
targets visible at a weaker level; selecting the whole array focuses its members.
|
|
75
85
|
For cut tools and intersect operands, selected inputs are targets and other inputs
|
|
@@ -79,9 +89,9 @@ shows the selected inputs and ambient operands without inventing a result.
|
|
|
79
89
|
These region inspectors use ordinary unlit materials with depth testing disabled,
|
|
80
90
|
so their colors remain visible through the translucent inputs.
|
|
81
91
|
|
|
82
|
-
Core uses this mechanism for distance measurements, relate calls and their
|
|
92
|
+
Core uses this mechanism for length/area/volume properties, distance measurements, relate calls and their
|
|
83
93
|
closures, on/align references, relative transformation stages, group children,
|
|
84
|
-
expose sources, Boolean operands
|
|
94
|
+
expose sources, Boolean operands, loft sections/spines and sweep profiles/spines, plus box and extrusion
|
|
85
95
|
dimensions. Selecting a normal constructor or Boolean function name
|
|
86
96
|
still previews its return value. Inspectors retain the original operation frame,
|
|
87
97
|
so a later relation or a different consumer cannot move its inspection.
|
|
@@ -108,6 +118,46 @@ the owner as `ambient` when the call fails or the reference collection is empty.
|
|
|
108
118
|
The owner therefore has the same background appearance before and after a
|
|
109
119
|
selection; missing or invalid IDs still produce their normal modeling errors.
|
|
110
120
|
|
|
121
|
+
### Getter inspection
|
|
122
|
+
|
|
123
|
+
A getter can declare `@code3d.inspect callback` in its JSDoc. A package can put
|
|
124
|
+
the same annotation on its public `readonly` property declaration when the
|
|
125
|
+
implementation getter is not present in its declarations. The callback receives
|
|
126
|
+
`[]`, with the actual receiver in `context.receiver`, the recorded property value
|
|
127
|
+
in `context.return`, and any `captureInspectData` payload in `context.data`.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import {
|
|
131
|
+
captureInspectData,
|
|
132
|
+
type InspectContext,
|
|
133
|
+
type Model,
|
|
134
|
+
} from '@code3d/core';
|
|
135
|
+
|
|
136
|
+
function inspectSize(_args: readonly [], context: InspectContext<number>) {
|
|
137
|
+
return {target: [context.data as Model]};
|
|
138
|
+
}
|
|
139
|
+
class Part {
|
|
140
|
+
constructor(readonly body: Model) {}
|
|
141
|
+
/** @code3d.inspect inspectSize */
|
|
142
|
+
get size() {
|
|
143
|
+
captureInspectData(this.body);
|
|
144
|
+
return 42;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Read `part.size` normally to record it. Selecting the property runs only its
|
|
150
|
+
inspector; it never runs the getter again. Each reached read keeps its own
|
|
151
|
+
receiver, return and data, even if several reads return the same number. Local
|
|
152
|
+
getters retain their declaration's lexical inspector binding; published callbacks
|
|
153
|
+
must be runtime exports of the package. Optional reads that short-circuit do not
|
|
154
|
+
invoke an inspector. A failed getter can still inspect its captured data, with
|
|
155
|
+
`context.return` undefined. Merely enumerating an object never invokes its getters.
|
|
156
|
+
|
|
157
|
+
Core's `.length`, `.area` and `.volume` use this mechanism. Passive `dimension` annotations
|
|
158
|
+
accept either `start`/`end`, alternative `candidates`, or `at: [x, y, z]` to show
|
|
159
|
+
only a value at an owner's local position. Labels do not add CAD geometry.
|
|
160
|
+
|
|
111
161
|
### Call data
|
|
112
162
|
|
|
113
163
|
The App runs JSDoc inspection callbacks when the corresponding source is selected.
|
package/docs/topology.md
CHANGED
|
@@ -127,6 +127,12 @@ const corners = boundary[0].vertices();
|
|
|
127
127
|
const center = face.center;
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
Edges expose readonly `.length` for actual arc length; surfaces expose `.area`
|
|
131
|
+
for their trimmed finite area. Exposed solids provide total boundary `.area` and
|
|
132
|
+
material `.volume`, excluding holes and cavities. These measurements include the
|
|
133
|
+
scale of the selected geometry. See [length and area](api.md#length-and-area)
|
|
134
|
+
and [volume](api.md#volume).
|
|
135
|
+
|
|
130
136
|
Queries use the original model's IDs and stay within the selected element.
|
|
131
137
|
`face.edge(id)` reports an error if that edge is outside the face. The viewport
|
|
132
138
|
picker offers only the eligible edges or vertices, including when the geometry
|
package/docs/values.md
CHANGED
|
@@ -5,6 +5,10 @@ sidebar:
|
|
|
5
5
|
order: 2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
Build models from reusable values, then measure their geometry or relative
|
|
9
|
+
placement. Queries return ordinary numbers and vectors; modeling operations
|
|
10
|
+
return new model values.
|
|
11
|
+
|
|
8
12
|
## Model values and coordinates
|
|
9
13
|
|
|
10
14
|
Operations produce new model values. Building another result must not change an
|
|
@@ -22,27 +26,10 @@ angles use degrees. Read [local coordinates](local-coordinates.md)
|
|
|
22
26
|
and [relations](relations.mdx) before mixing
|
|
23
27
|
origin changes, alignment, and rotation.
|
|
24
28
|
|
|
25
|
-
Constraints express `on` and `align
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Choose a
|
|
31
|
-
center with `pivot([x,y,z])`, self topology with `pivotVertex(id)`/`axisEdge(id)`,
|
|
32
|
-
or references with `pivotPoint(pointRef)`/`axisLine(lineRef)`; finish each selector
|
|
33
|
-
with `rotate`. Point rotations retain self XYZ axes, including external centers. Consecutive constraints solve jointly; transformations
|
|
34
|
-
then act on that result in order. A later constraint starts a new segment using
|
|
35
|
-
the preceding pose. Independent offsets use fixed composition axes, and rotations
|
|
36
|
-
default to self's current origin. Each completed transformation is one array item,
|
|
37
|
-
for example `[offset(0, 8, 0), rotate(0, 25, 0)]`. Only pivot/axis selections
|
|
38
|
-
chain into `rotate`; completed transformations cannot chain into another operation.
|
|
39
|
-
Keep a selected reference while moving it with
|
|
40
|
-
`pivotVertex(id).pivotOffset(dx, dy, dz).rotate(x, y, z)` or
|
|
41
|
-
`axisLine(axis).axisOffset(dx, dy, dz).rotate(angle)`. Point offsets use self local
|
|
42
|
-
axes; axis offsets use the selected axis frame and preserve its direction.
|
|
43
|
-
Each selector accepts one matching offset, followed by `rotate`.
|
|
44
|
-
See the [transformation example](../../app/examples/constraints/transformations.ts)
|
|
45
|
-
and [placement guide](relations.mdx#transform-a-joint-result).
|
|
29
|
+
Constraints express `on` and `align`; relative `offset` and `rotate` operations
|
|
30
|
+
follow them as separate items in the `relate` array. For pivots, reference axes
|
|
31
|
+
and operation order, see the [placement guide](relations.mdx#transform-a-joint-result)
|
|
32
|
+
and [transformation example](../../app/examples/constraints/transformations.ts).
|
|
46
33
|
|
|
47
34
|
Build readable models from named intermediate values and public operations. A
|
|
48
35
|
profile followed by extrusion, or solids combined with Boolean operations,
|
|
@@ -63,6 +50,29 @@ finite geometry, nested occurrences, axis frames and source-order dependencies.
|
|
|
63
50
|
|
|
64
51
|
## Geometry measurements
|
|
65
52
|
|
|
53
|
+
Read a model's dimensions in its own frame, or query its bounds and position
|
|
54
|
+
relative to another model:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {box, group, offset} from '@code3d/core';
|
|
58
|
+
|
|
59
|
+
const base = box(20, 4, 20);
|
|
60
|
+
const part = box(8, 12, 4).relate(self => [self.on(base.up), offset(20, 0, 0)]);
|
|
61
|
+
const size = part.bounds().size; // [8, 12, 4]
|
|
62
|
+
const origin = part.position(base); // [20, 8, 0]
|
|
63
|
+
const minimum = part.bounds(base).minimum; // [16, 2, -2]
|
|
64
|
+
export default group([base, part]);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Finite edges and edge models provide readonly `.length`; finite surfaces and
|
|
68
|
+
face models provide `.area`. Solids provide `.area` for their total boundary
|
|
69
|
+
surface, including inner walls, and `.volume` for material volume, excluding holes
|
|
70
|
+
and cavities. These are plain numbers, follow geometry scaling, and retain the
|
|
71
|
+
original value when later operations create a new model. Infinite axes/planes
|
|
72
|
+
and groups do not have these measurements. See [length and area](api.md#length-and-area)
|
|
73
|
+
and [volume](api.md#volume), and select these properties in App for a read-only
|
|
74
|
+
visual measurement.
|
|
75
|
+
|
|
66
76
|
`model.bounds(relativeTo?)` returns readonly `minimum`, `maximum` and `size`
|
|
67
77
|
XYZ vectors for tight finite geometry bounds. By default it uses the model's
|
|
68
78
|
own local frame. An explicit reference includes solved placement and nested
|
|
@@ -76,16 +86,7 @@ changes the model or its placement. These methods are available on every model
|
|
|
76
86
|
kind, including groups. As model members, `bounds` and `position` are reserved
|
|
77
87
|
names and cannot be used as exposed element names.
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
import {box, group, offset} from '@code3d/core';
|
|
81
|
-
|
|
82
|
-
const base = box(20, 4, 20);
|
|
83
|
-
const part = box(8, 12, 4).relate(self => [self.on(base.up), offset(20, 0, 0)]);
|
|
84
|
-
const size = part.bounds().size; // [8, 12, 4]
|
|
85
|
-
const origin = part.position(base); // [20, 8, 0]
|
|
86
|
-
const minimum = part.bounds(base).minimum; // [16, 2, -2]
|
|
87
|
-
export default group([base, part]);
|
|
88
|
-
```
|
|
89
|
+
## Editing incomplete calls
|
|
89
90
|
|
|
90
91
|
Dimension-based primitives and numeric modeling methods retain required TypeScript
|
|
91
92
|
signatures while providing runtime defaults for omitted or `undefined` values.
|
|
@@ -102,6 +103,8 @@ edit and completion share one undo step. Use explicit dimensions in finished
|
|
|
102
103
|
models; the [reference](api.md#runtime-defaults-while-editing)
|
|
103
104
|
lists the actual defaults.
|
|
104
105
|
|
|
106
|
+
## Composition and topology
|
|
107
|
+
|
|
105
108
|
Topology capabilities follow dimension: vertices expose vertex selection, edges
|
|
106
109
|
add edge selection, and faces and solids add surface selection. Only solids
|
|
107
110
|
provide `fillet`, `chamfer`, and `shell`. Groups compose values and support
|
package/package.json
CHANGED
package/src/library/extrude.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
assembleWire,
|
|
3
|
+
getOC,
|
|
4
|
+
makeHelix,
|
|
5
|
+
makeLine,
|
|
6
|
+
measureVolume,
|
|
7
|
+
Vector,
|
|
8
|
+
type Face,
|
|
9
|
+
type Shape3D,
|
|
10
|
+
} from 'replicad';
|
|
11
|
+
import {castOwnedShape3D, shapeSubshapes} from './kernel-shapes.js';
|
|
3
12
|
import {
|
|
4
13
|
transferShapeTopology,
|
|
5
14
|
type TopologyInput,
|
|
@@ -36,3 +45,121 @@ export function extrudeWithTopology(
|
|
|
36
45
|
vector.delete();
|
|
37
46
|
}
|
|
38
47
|
}
|
|
48
|
+
|
|
49
|
+
/** Sweep a face around a directed axis, optionally advancing along it. */
|
|
50
|
+
export function revolveWithTopology(
|
|
51
|
+
source: TopologyInput,
|
|
52
|
+
center: Vec3,
|
|
53
|
+
direction: Vec3,
|
|
54
|
+
angle: number,
|
|
55
|
+
advance: number,
|
|
56
|
+
): {shape: Shape3D; topology?: ShapeTopology} {
|
|
57
|
+
const oc = getOC();
|
|
58
|
+
if (advance === 0) {
|
|
59
|
+
const point = new oc.gp_Pnt(...center);
|
|
60
|
+
let dir: InstanceType<typeof oc.gp_Dir> | undefined;
|
|
61
|
+
let axis: InstanceType<typeof oc.gp_Ax1> | undefined;
|
|
62
|
+
let shape: Shape3D | undefined;
|
|
63
|
+
try {
|
|
64
|
+
dir = new oc.gp_Dir(...direction);
|
|
65
|
+
axis = new oc.gp_Ax1(point, dir);
|
|
66
|
+
const builder = new oc.BRepPrimAPI_MakeRevol(
|
|
67
|
+
source.shape.wrapped,
|
|
68
|
+
axis,
|
|
69
|
+
angle * (Math.PI / 180),
|
|
70
|
+
false,
|
|
71
|
+
);
|
|
72
|
+
try {
|
|
73
|
+
if (!builder.IsDone()) throw new Error('Could not revolve the face.');
|
|
74
|
+
shape = castOwnedShape3D(builder.Shape());
|
|
75
|
+
requireRevolvedVolume(shape);
|
|
76
|
+
return {
|
|
77
|
+
shape,
|
|
78
|
+
topology: transferShapeTopology([source], shape, builder),
|
|
79
|
+
};
|
|
80
|
+
} finally {
|
|
81
|
+
builder.delete();
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
shape?.delete();
|
|
85
|
+
throw error;
|
|
86
|
+
} finally {
|
|
87
|
+
axis?.delete();
|
|
88
|
+
dir?.delete();
|
|
89
|
+
point.delete();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const boundaries = shapeSubshapes(source.shape, 'wire');
|
|
94
|
+
try {
|
|
95
|
+
if (boundaries.length !== 1)
|
|
96
|
+
throw new Error('Helical revolution requires a face without holes.');
|
|
97
|
+
} finally {
|
|
98
|
+
boundaries.forEach(boundary => boundary.delete());
|
|
99
|
+
}
|
|
100
|
+
const end: Vec3 = [
|
|
101
|
+
center[0] + direction[0] * advance,
|
|
102
|
+
center[1] + direction[1] * advance,
|
|
103
|
+
center[2] + direction[2] * advance,
|
|
104
|
+
];
|
|
105
|
+
let startVector: Vector | undefined;
|
|
106
|
+
let endVector: Vector | undefined;
|
|
107
|
+
let line: ReturnType<typeof makeLine> | undefined;
|
|
108
|
+
let spine: ReturnType<typeof assembleWire> | undefined;
|
|
109
|
+
let guide: ReturnType<typeof makeHelix> | undefined;
|
|
110
|
+
let wire: ReturnType<Face['outerWire']> | undefined;
|
|
111
|
+
let shape: Shape3D | undefined;
|
|
112
|
+
try {
|
|
113
|
+
startVector = new Vector([...center]);
|
|
114
|
+
endVector = new Vector([...end]);
|
|
115
|
+
line = makeLine(startVector, endVector);
|
|
116
|
+
spine = assembleWire([line]);
|
|
117
|
+
guide = makeHelix(
|
|
118
|
+
(advance * 360) / angle,
|
|
119
|
+
advance,
|
|
120
|
+
1,
|
|
121
|
+
[...center],
|
|
122
|
+
[...direction],
|
|
123
|
+
);
|
|
124
|
+
// Replicad's outerWire consumes its cloned Face wrapper.
|
|
125
|
+
wire = (source.shape as Face).clone().outerWire();
|
|
126
|
+
const builder = new oc.BRepOffsetAPI_MakePipeShell(spine.wrapped);
|
|
127
|
+
try {
|
|
128
|
+
builder.SetMode(
|
|
129
|
+
guide.wrapped,
|
|
130
|
+
false,
|
|
131
|
+
oc.BRepFill_TypeOfContact.BRepFill_NoContact,
|
|
132
|
+
);
|
|
133
|
+
builder.Add(wire.wrapped, false, false);
|
|
134
|
+
if (!builder.IsReady())
|
|
135
|
+
throw new Error(
|
|
136
|
+
'Could not associate the profile with the rotation axis.',
|
|
137
|
+
);
|
|
138
|
+
builder.Build();
|
|
139
|
+
if (!builder.IsDone() || !builder.MakeSolid())
|
|
140
|
+
throw new Error('Could not construct a solid helical revolution.');
|
|
141
|
+
shape = castOwnedShape3D(builder.Shape());
|
|
142
|
+
requireRevolvedVolume(shape);
|
|
143
|
+
// PipeShell does not expose face-cap history for an input face. Assign
|
|
144
|
+
// stable output IDs without guessing an inherited input correspondence.
|
|
145
|
+
return {shape};
|
|
146
|
+
} finally {
|
|
147
|
+
builder.delete();
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
shape?.delete();
|
|
151
|
+
throw error;
|
|
152
|
+
} finally {
|
|
153
|
+
wire?.delete();
|
|
154
|
+
guide?.delete();
|
|
155
|
+
spine?.delete();
|
|
156
|
+
line?.delete();
|
|
157
|
+
endVector?.delete();
|
|
158
|
+
startVector?.delete();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function requireRevolvedVolume(shape: Shape3D): void {
|
|
163
|
+
if (!(Math.abs(measureVolume(shape)) > 0))
|
|
164
|
+
throw new Error('Revolution did not produce a non-degenerate solid.');
|
|
165
|
+
}
|
package/src/library/index.ts
CHANGED
|
@@ -13,6 +13,9 @@ export {
|
|
|
13
13
|
align,
|
|
14
14
|
expose,
|
|
15
15
|
inspectTopologyReference,
|
|
16
|
+
inspectLength,
|
|
17
|
+
inspectArea,
|
|
18
|
+
inspectVolume,
|
|
16
19
|
} from './runtime.js';
|
|
17
20
|
export type {
|
|
18
21
|
Dimension,
|
|
@@ -44,8 +47,10 @@ export type {
|
|
|
44
47
|
} from './sketch.js';
|
|
45
48
|
|
|
46
49
|
export {
|
|
50
|
+
getModelData,
|
|
47
51
|
offset,
|
|
48
52
|
rotate,
|
|
53
|
+
setModelData,
|
|
49
54
|
pivot,
|
|
50
55
|
pivotVertex,
|
|
51
56
|
pivotPoint,
|
|
@@ -64,6 +69,7 @@ export {
|
|
|
64
69
|
text,
|
|
65
70
|
frustum,
|
|
66
71
|
group,
|
|
72
|
+
inspectGroupMembers,
|
|
67
73
|
intersect,
|
|
68
74
|
line,
|
|
69
75
|
loft,
|
|
@@ -71,7 +77,9 @@ export {
|
|
|
71
77
|
rectangle,
|
|
72
78
|
regularPolygon,
|
|
73
79
|
regularPrism,
|
|
80
|
+
revolve,
|
|
74
81
|
spline,
|
|
82
|
+
sweep,
|
|
75
83
|
sphere,
|
|
76
84
|
tube,
|
|
77
85
|
union,
|
|
@@ -117,6 +125,7 @@ export type {
|
|
|
117
125
|
NamedElements,
|
|
118
126
|
PlanarElements,
|
|
119
127
|
PointAnchor,
|
|
128
|
+
RevolveConfig,
|
|
120
129
|
Solid,
|
|
121
130
|
SolidModel,
|
|
122
131
|
SolidModificationCapabilities,
|
package/src/library/inspect.ts
CHANGED
|
@@ -49,14 +49,16 @@ export function recordInspectionCalls(
|
|
|
49
49
|
export type DimensionSegment = Readonly<{start: Vec3; end: Vec3}>;
|
|
50
50
|
|
|
51
51
|
type DimensionLines =
|
|
52
|
-
|
|
52
|
+
| DimensionSegment
|
|
53
|
+
| Readonly<{candidates: readonly DimensionSegment[]}>
|
|
54
|
+
| Readonly<{at: Vec3}>;
|
|
53
55
|
type DimensionOptions = Readonly<{
|
|
54
56
|
owner: Model;
|
|
55
57
|
value: number;
|
|
56
58
|
axisLabel?: string;
|
|
57
59
|
}>;
|
|
58
60
|
|
|
59
|
-
/** A passive
|
|
61
|
+
/** A passive measurement. `at` labels a point without a dimension line. */
|
|
60
62
|
export type Dimension = Readonly<{kind: 'dimension'}> &
|
|
61
63
|
DimensionOptions &
|
|
62
64
|
DimensionLines;
|