@code3d/core 0.0.1-alpha.11 → 0.0.1-alpha.12

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.
Files changed (36) hide show
  1. package/README.md +18 -13
  2. package/bld/chunks/{chunk-JBVIAMJ6.js → chunk-CQKOD54C.js} +552 -25
  3. package/bld/chunks/chunk-CQKOD54C.js.map +7 -0
  4. package/bld/chunks/{chunk-CL3E2DE4.js → chunk-JF6QRICU.js} +2 -2
  5. package/bld/chunks/{chunk-HZRQUHM2.js → chunk-L4V6X7RH.js} +2 -2
  6. package/bld/chunks/{chunk-QK6ZET47.js → chunk-QJVTVAYM.js} +3 -3
  7. package/bld/library/extrude.d.ts +5 -0
  8. package/bld/library/extrude.d.ts.map +1 -1
  9. package/bld/library/index.d.ts +2 -2
  10. package/bld/library/index.d.ts.map +1 -1
  11. package/bld/library/index.js +11 -1
  12. package/bld/library/inspect.d.ts +3 -1
  13. package/bld/library/inspect.d.ts.map +1 -1
  14. package/bld/library/loft.d.ts +7 -1
  15. package/bld/library/loft.d.ts.map +1 -1
  16. package/bld/library/replicad.js +2 -2
  17. package/bld/library/runtime.d.ts +68 -7
  18. package/bld/library/runtime.d.ts.map +1 -1
  19. package/bld/node/index.js +13 -3
  20. package/bld/node/replicad.js +4 -4
  21. package/bld/tooling/index.js +2 -2
  22. package/docs/api.md +134 -13
  23. package/docs/local-coordinates.md +2 -0
  24. package/docs/runtime.md +42 -2
  25. package/docs/topology.md +6 -0
  26. package/docs/values.md +9 -0
  27. package/package.json +1 -1
  28. package/src/library/extrude.ts +129 -2
  29. package/src/library/index.ts +6 -0
  30. package/src/library/inspect.ts +4 -2
  31. package/src/library/loft.ts +67 -2
  32. package/src/library/runtime.ts +599 -7
  33. package/bld/chunks/chunk-JBVIAMJ6.js.map +0 -7
  34. /package/bld/chunks/{chunk-CL3E2DE4.js.map → chunk-JF6QRICU.js.map} +0 -0
  35. /package/bld/chunks/{chunk-HZRQUHM2.js.map → chunk-L4V6X7RH.js.map} +0 -0
  36. /package/bld/chunks/{chunk-QK6ZET47.js.map → chunk-QJVTVAYM.js.map} +0 -0
@@ -1115,10 +1115,10 @@ function sketchCurveClosestParameter(curve, position2) {
1115
1115
  position2[0] - curve.center[0]
1116
1116
  );
1117
1117
  if (curve.kind === "circle") return sketchPositiveAngle(angle) / tau;
1118
- const sign3 = Math.sign(curve.sweep), sweep = Math.abs(curve.sweep);
1118
+ const sign3 = Math.sign(curve.sweep), sweep2 = Math.abs(curve.sweep);
1119
1119
  const distance4 = sketchPositiveAngle(sign3 * (angle - curve.start));
1120
- if (distance4 <= sweep) return sweep ? distance4 / sweep : 0;
1121
- return distance4 - sweep < tau - distance4 ? 1 : 0;
1120
+ if (distance4 <= sweep2) return sweep2 ? distance4 / sweep2 : 0;
1121
+ return distance4 - sweep2 < tau - distance4 ? 1 : 0;
1122
1122
  }
1123
1123
  __name(sketchCurveClosestParameter, "sketchCurveClosestParameter");
1124
1124
  function sketchCurveBounds(curve) {
@@ -3944,14 +3944,14 @@ function pointSession(context, policies) {
3944
3944
  );
3945
3945
  if (radius === 0) continue;
3946
3946
  radii.set(index, radius);
3947
- const sweep = reference.constraints.some(
3947
+ const sweep2 = reference.constraints.some(
3948
3948
  (c) => c.kind === "sweep" && c.index === index
3949
3949
  );
3950
3950
  const direction = target.position.every((v, axis) => v === center[axis]) ? current.points[target.point].position : target.position;
3951
3951
  const turn = Math.atan2(direction[1] - center[1], direction[0] - center[0]) - Math.atan2(from[1] - center[1], from[0] - center[0]);
3952
3952
  for (const point3 of arc2.points) {
3953
3953
  let position2 = point3 === target.point ? direction : reference.points[point3].position;
3954
- if (sweep && point3 !== target.point) {
3954
+ if (sweep2 && point3 !== target.point) {
3955
3955
  const [x, y] = [position2[0] - center[0], position2[1] - center[1]];
3956
3956
  position2 = [
3957
3957
  center[0] + x * Math.cos(turn) - y * Math.sin(turn),
@@ -4172,7 +4172,7 @@ __name(averagePosition, "averagePosition");
4172
4172
 
4173
4173
  // packages/core/src/library/runtime.ts
4174
4174
  import {
4175
- assembleWire,
4175
+ assembleWire as assembleWire3,
4176
4176
  basicFaceExtrusion,
4177
4177
  BoundingBox as BoundingBox2,
4178
4178
  genericSweep,
@@ -4182,11 +4182,14 @@ import {
4182
4182
  makeCircle as makeCircle2,
4183
4183
  makeCylinder,
4184
4184
  makeFace,
4185
- makeHelix,
4186
- makeLine as makeLine2,
4185
+ makeHelix as makeHelix2,
4186
+ makeLine as makeLine3,
4187
4187
  makeSphere,
4188
4188
  makeThreePointArc as makeThreePointArc2,
4189
4189
  makeVertex,
4190
+ measureShapeLinearProperties as measureShapeLinearProperties2,
4191
+ measureShapeSurfaceProperties as measureShapeSurfaceProperties2,
4192
+ measureShapeVolumeProperties,
4190
4193
  sketchCircle,
4191
4194
  sketchEllipse,
4192
4195
  sketchPolysides,
@@ -4538,7 +4541,14 @@ function nearestPoint(point3, geometry) {
4538
4541
  __name(nearestPoint, "nearestPoint");
4539
4542
 
4540
4543
  // packages/core/src/library/extrude.ts
4541
- import { getOC as getOC6, Vector } from "replicad";
4544
+ import {
4545
+ assembleWire,
4546
+ getOC as getOC6,
4547
+ makeHelix,
4548
+ makeLine,
4549
+ measureVolume,
4550
+ Vector
4551
+ } from "replicad";
4542
4552
 
4543
4553
  // packages/core/src/library/topology.ts
4544
4554
  import {
@@ -5102,12 +5112,169 @@ function extrudeWithTopology(source, direction) {
5102
5112
  }
5103
5113
  }
5104
5114
  __name(extrudeWithTopology, "extrudeWithTopology");
5115
+ function revolveWithTopology(source, center, direction, angle, advance) {
5116
+ const oc = getOC6();
5117
+ if (advance === 0) {
5118
+ const point3 = new oc.gp_Pnt(...center);
5119
+ let dir;
5120
+ let axis;
5121
+ let shape2;
5122
+ try {
5123
+ dir = new oc.gp_Dir(...direction);
5124
+ axis = new oc.gp_Ax1(point3, dir);
5125
+ const builder = new oc.BRepPrimAPI_MakeRevol(
5126
+ source.shape.wrapped,
5127
+ axis,
5128
+ angle * (Math.PI / 180),
5129
+ false
5130
+ );
5131
+ try {
5132
+ if (!builder.IsDone()) throw new Error("Could not revolve the face.");
5133
+ shape2 = castOwnedShape3D(builder.Shape());
5134
+ requireRevolvedVolume(shape2);
5135
+ return {
5136
+ shape: shape2,
5137
+ topology: transferShapeTopology([source], shape2, builder)
5138
+ };
5139
+ } finally {
5140
+ builder.delete();
5141
+ }
5142
+ } catch (error) {
5143
+ shape2?.delete();
5144
+ throw error;
5145
+ } finally {
5146
+ axis?.delete();
5147
+ dir?.delete();
5148
+ point3.delete();
5149
+ }
5150
+ }
5151
+ const boundaries = shapeSubshapes(source.shape, "wire");
5152
+ try {
5153
+ if (boundaries.length !== 1)
5154
+ throw new Error("Helical revolution requires a face without holes.");
5155
+ } finally {
5156
+ boundaries.forEach((boundary) => boundary.delete());
5157
+ }
5158
+ const end = [
5159
+ center[0] + direction[0] * advance,
5160
+ center[1] + direction[1] * advance,
5161
+ center[2] + direction[2] * advance
5162
+ ];
5163
+ let startVector;
5164
+ let endVector;
5165
+ let line2;
5166
+ let spine;
5167
+ let guide;
5168
+ let wire;
5169
+ let shape;
5170
+ try {
5171
+ startVector = new Vector([...center]);
5172
+ endVector = new Vector([...end]);
5173
+ line2 = makeLine(startVector, endVector);
5174
+ spine = assembleWire([line2]);
5175
+ guide = makeHelix(
5176
+ advance * 360 / angle,
5177
+ advance,
5178
+ 1,
5179
+ [...center],
5180
+ [...direction]
5181
+ );
5182
+ wire = source.shape.clone().outerWire();
5183
+ const builder = new oc.BRepOffsetAPI_MakePipeShell(spine.wrapped);
5184
+ try {
5185
+ builder.SetMode(
5186
+ guide.wrapped,
5187
+ false,
5188
+ oc.BRepFill_TypeOfContact.BRepFill_NoContact
5189
+ );
5190
+ builder.Add(wire.wrapped, false, false);
5191
+ if (!builder.IsReady())
5192
+ throw new Error(
5193
+ "Could not associate the profile with the rotation axis."
5194
+ );
5195
+ builder.Build();
5196
+ if (!builder.IsDone() || !builder.MakeSolid())
5197
+ throw new Error("Could not construct a solid helical revolution.");
5198
+ shape = castOwnedShape3D(builder.Shape());
5199
+ requireRevolvedVolume(shape);
5200
+ return { shape };
5201
+ } finally {
5202
+ builder.delete();
5203
+ }
5204
+ } catch (error) {
5205
+ shape?.delete();
5206
+ throw error;
5207
+ } finally {
5208
+ wire?.delete();
5209
+ guide?.delete();
5210
+ spine?.delete();
5211
+ line2?.delete();
5212
+ endVector?.delete();
5213
+ startVector?.delete();
5214
+ }
5215
+ }
5216
+ __name(revolveWithTopology, "revolveWithTopology");
5217
+ function requireRevolvedVolume(shape) {
5218
+ if (!(Math.abs(measureVolume(shape)) > 0))
5219
+ throw new Error("Revolution did not produce a non-degenerate solid.");
5220
+ }
5221
+ __name(requireRevolvedVolume, "requireRevolvedVolume");
5105
5222
 
5106
5223
  // packages/core/src/library/loft.ts
5107
5224
  import {
5225
+ assembleWire as assembleWire2,
5108
5226
  cast as cast2,
5109
- getOC as getOC7
5227
+ getOC as getOC7,
5228
+ measureVolume as measureVolume2
5110
5229
  } from "replicad";
5230
+ function sweepWithTopology(profile, path, normal) {
5231
+ if (path.isClosed || !(path.length > 1e-9))
5232
+ throw new Error("Sweep spine must be a non-degenerate open curve.");
5233
+ const start = path.pointAt(0);
5234
+ let tangent2;
5235
+ try {
5236
+ tangent2 = path.tangentAt(0);
5237
+ const position2 = start.toTuple();
5238
+ const direction = tangent2.toTuple();
5239
+ const magnitude = Math.hypot(...direction);
5240
+ if (!(magnitude > 1e-9))
5241
+ throw new Error("Sweep spine must have a non-zero starting tangent.");
5242
+ if (Math.hypot(...position2) > 1e-6)
5243
+ throw new Error(
5244
+ "Sweep profile origin must coincide with the spine start."
5245
+ );
5246
+ if ((normal[0] * direction[0] + normal[1] * direction[1] + normal[2] * direction[2]) / magnitude < 1 - 1e-6)
5247
+ throw new Error(
5248
+ "Sweep profile normal must point along the spine start tangent."
5249
+ );
5250
+ } finally {
5251
+ tangent2?.delete();
5252
+ start.delete();
5253
+ }
5254
+ const spine = assembleWire2([path]);
5255
+ let result;
5256
+ try {
5257
+ result = loftWithTopology([profile], spine, false);
5258
+ if (!(Math.abs(measureVolume2(result.shape)) > 0))
5259
+ throw new Error("Sweep did not produce a non-degenerate solid.");
5260
+ const validation = new (getOC7()).BRepCheck_Analyzer(result.shape.wrapped);
5261
+ try {
5262
+ if (!validation.IsValid())
5263
+ throw new Error(
5264
+ "Sweep produced an invalid solid. Adjust the profile or path to avoid tight bends and intersections."
5265
+ );
5266
+ } finally {
5267
+ validation.delete();
5268
+ }
5269
+ return result;
5270
+ } catch (error) {
5271
+ result?.shape.delete();
5272
+ throw error;
5273
+ } finally {
5274
+ spine.delete();
5275
+ }
5276
+ }
5277
+ __name(sweepWithTopology, "sweepWithTopology");
5111
5278
  function loftWithTopology(sections, spine, ruled) {
5112
5279
  const holes = [];
5113
5280
  let outer;
@@ -5132,7 +5299,7 @@ function loftWithTopology(sections, spine, ruled) {
5132
5299
  throw new Error("Loft sections must have matching hole counts.");
5133
5300
  if (holes[0].length > 1)
5134
5301
  throw new Error(
5135
- "Loft currently supports at most one hole per section; multiple holes need explicit correspondence."
5302
+ "A swept or lofted profile currently supports at most one hole; multiple holes need explicit correspondence."
5136
5303
  );
5137
5304
  outer = loftContoursWithTopology(sections, spine, ruled);
5138
5305
  if (!holes[0].length) {
@@ -5190,7 +5357,8 @@ function loftContoursWithTopology(sections, spine, ruled, holes) {
5190
5357
  }
5191
5358
  result = castOwnedShape3D(builder.Shape());
5192
5359
  caps[0] = castOwnedShape(builder.FirstShape());
5193
- caps[sections.length - 1] = castOwnedShape(builder.LastShape());
5360
+ if (sections.length > 1)
5361
+ caps[sections.length - 1] = castOwnedShape(builder.LastShape());
5194
5362
  const topology = transferShapeTopology(
5195
5363
  sections,
5196
5364
  result,
@@ -6284,13 +6452,13 @@ __name(validVolume, "validVolume");
6284
6452
  import {
6285
6453
  getOC as getOC9,
6286
6454
  makeCircle,
6287
- makeLine,
6455
+ makeLine as makeLine2,
6288
6456
  makeThreePointArc
6289
6457
  } from "replicad";
6290
6458
  var position = /* @__PURE__ */ __name((p) => [p[0], 0, -p[1]], "position");
6291
6459
  function boundaryEdge(curve) {
6292
6460
  if (curve.kind === "line")
6293
- return makeLine(position(curve.points[0]), position(curve.points[1]));
6461
+ return makeLine2(position(curve.points[0]), position(curve.points[1]));
6294
6462
  if (curve.kind === "circle" || Math.abs(curve.sweep) === 2 * Math.PI)
6295
6463
  return makeCircle(curve.radius, position(curve.center), [
6296
6464
  0,
@@ -20541,6 +20709,18 @@ var ModelTopologyElement = class extends ModelAnchor {
20541
20709
  topologyCenter(geometry, this.#topology.selection)
20542
20710
  );
20543
20711
  }
20712
+ /** @code3d.inspect inspectLength */
20713
+ get length() {
20714
+ return measureFiniteGeometry(this, "length");
20715
+ }
20716
+ /** @code3d.inspect inspectArea */
20717
+ get area() {
20718
+ return measureFiniteGeometry(this, "area");
20719
+ }
20720
+ /** @code3d.inspect inspectVolume */
20721
+ get volume() {
20722
+ return measureFiniteGeometry(this, "volume");
20723
+ }
20544
20724
  get start() {
20545
20725
  return this.#curvePoint("start", 0);
20546
20726
  }
@@ -21871,6 +22051,18 @@ var ModelObject = class _ModelObject extends RelationObject {
21871
22051
  static create(init) {
21872
22052
  return new _ModelObject(init);
21873
22053
  }
22054
+ /** @code3d.inspect inspectLength */
22055
+ get length() {
22056
+ return measureFiniteGeometry(this, "length");
22057
+ }
22058
+ /** @code3d.inspect inspectArea */
22059
+ get area() {
22060
+ return measureFiniteGeometry(this, "area");
22061
+ }
22062
+ /** @code3d.inspect inspectVolume */
22063
+ get volume() {
22064
+ return measureFiniteGeometry(this, "volume");
22065
+ }
21874
22066
  get origin() {
21875
22067
  return this.frame.origin;
21876
22068
  }
@@ -22318,6 +22510,134 @@ var ModelObject = class _ModelObject extends RelationObject {
22318
22510
  _ModelObject.recordExtrusions([this], [result]);
22319
22511
  return result;
22320
22512
  }
22513
+ revolve(axis, config = { angle: 360 }) {
22514
+ if (this.kind !== "face")
22515
+ throw new Error("revolve requires a single face model.");
22516
+ const { angle = 360, advance = 0 } = config;
22517
+ if (!Number.isFinite(angle) || angle === 0)
22518
+ throw new Error("Revolution angle must be finite and non-zero.");
22519
+ if (!Number.isFinite(advance))
22520
+ throw new Error("Revolution advance must be finite.");
22521
+ if (advance === 0 && Math.abs(angle) > 360)
22522
+ throw new Error("A revolution without advance cannot exceed one turn.");
22523
+ const axisReference = straightAxisReference(axis, "revolve() axis");
22524
+ const context = _ModelObject.createSolveContext([this, axisReference.model]);
22525
+ const facePose = this.solvePose(context);
22526
+ const axisFrame = relativeTransform(
22527
+ composeTransforms(
22528
+ axisReference.model.solvePose(context),
22529
+ axisReference.transform
22530
+ ),
22531
+ facePose
22532
+ );
22533
+ const direction = rotateVector(
22534
+ [0, axisReference.direction ?? 1, 0],
22535
+ axisFrame.quaternion
22536
+ );
22537
+ const source = this.requireGeometry();
22538
+ const axisModel = isModelObject(axisReference.model) ? axisReference.model : void 0;
22539
+ _ModelObject.recordCompositionInspection(context, []);
22540
+ const geometry = evaluateSolidGeometry(
22541
+ "revolve",
22542
+ [axisFrame.position, direction, angle, advance],
22543
+ [source],
22544
+ () => revolveWithTopology(
22545
+ {
22546
+ shape: source.value.shape,
22547
+ topology: source.value.topology,
22548
+ namespace: 1
22549
+ },
22550
+ axisFrame.position,
22551
+ direction,
22552
+ angle,
22553
+ advance
22554
+ )
22555
+ );
22556
+ const result = _ModelObject.create({
22557
+ kind: "solid",
22558
+ name: "Revolve",
22559
+ geometry,
22560
+ material: this.materialSnapshot,
22561
+ placements: this.placements,
22562
+ sourceRefs: [...this.sourceRefs, ...axisModel?.sourceRefs ?? []],
22563
+ parameters: uniqueParameters([
22564
+ ...this.allParameters(),
22565
+ ...axisModel?.allParameters() ?? []
22566
+ ]),
22567
+ meshTolerance: this.meshTolerance,
22568
+ operation: storedOperation("revolve", [
22569
+ { model: this, role: "receiver", index: 0 },
22570
+ ...axisModel ? [{ model: axisModel, role: "reference", index: 1 }] : []
22571
+ ])
22572
+ });
22573
+ _ModelObject.recordCompositionInspection(context, [[result, this]]);
22574
+ return result;
22575
+ }
22576
+ sweep(spine) {
22577
+ if (this.kind !== "face")
22578
+ throw new Error("sweep requires a single face model.");
22579
+ const path = requireModelKind(
22580
+ spine,
22581
+ "edge",
22582
+ "sweep requires an edge model as its spine."
22583
+ );
22584
+ const context = _ModelObject.createSolveContext([this, path]);
22585
+ const profilePose = this.solvePose(context);
22586
+ const pathTransform = relativeTransform(
22587
+ path.solvePose(context),
22588
+ profilePose
22589
+ );
22590
+ const source = this.requireGeometry();
22591
+ const pathGeometry = path.requireGeometry();
22592
+ const normal = rotateVector(
22593
+ [0, 1, 0],
22594
+ this.geometryAnchor.transform.quaternion
22595
+ );
22596
+ _ModelObject.recordCompositionInspection(context, []);
22597
+ const geometry = evaluateSolidGeometry(
22598
+ "sweep",
22599
+ [pathTransform.position, pathTransform.quaternion, normal],
22600
+ [source, pathGeometry],
22601
+ () => {
22602
+ const positionedPath = shapeWithTransform(
22603
+ pathGeometry.value.shape,
22604
+ pathTransform
22605
+ );
22606
+ try {
22607
+ return sweepWithTopology(
22608
+ {
22609
+ shape: source.value.shape,
22610
+ topology: source.value.topology,
22611
+ namespace: 1
22612
+ },
22613
+ positionedPath,
22614
+ normal
22615
+ );
22616
+ } finally {
22617
+ positionedPath.delete();
22618
+ }
22619
+ }
22620
+ );
22621
+ const result = _ModelObject.create({
22622
+ kind: "solid",
22623
+ name: "Sweep",
22624
+ geometry,
22625
+ material: this.materialSnapshot,
22626
+ placements: this.placements,
22627
+ sourceRefs: [...this.sourceRefs, ...path.sourceRefs],
22628
+ parameters: uniqueParameters([
22629
+ ...this.allParameters(),
22630
+ ...path.allParameters()
22631
+ ]),
22632
+ meshTolerance: Math.min(this.meshTolerance, path.meshTolerance),
22633
+ operation: storedOperation("sweep", [
22634
+ { model: this, role: "receiver", index: 0 },
22635
+ { model: path, role: "spine", index: 1 }
22636
+ ])
22637
+ });
22638
+ _ModelObject.recordCompositionInspection(context, [[result, this]]);
22639
+ return result;
22640
+ }
22321
22641
  cut(tools) {
22322
22642
  return cut(this, tools);
22323
22643
  }
@@ -23070,6 +23390,32 @@ var ModelObject = class _ModelObject extends RelationObject {
23070
23390
  target: target.map((value) => frame.positioned(value))
23071
23391
  };
23072
23392
  }
23393
+ /** @internal */
23394
+ static recordRevolve(profile, axis, result) {
23395
+ if (!isRecordingInspection()) return;
23396
+ const reference = straightAxisReference(axis, "revolve() axis");
23397
+ const context = this.createSolveContext([profile, reference.model]);
23398
+ this.recordCompositionInspection(
23399
+ context,
23400
+ result ? [[result, profile]] : []
23401
+ );
23402
+ }
23403
+ /** @internal */
23404
+ static inspectRevolve(profile, axis, result, data, focus) {
23405
+ const frame = this.inspectionFrame(data.poses);
23406
+ const shownProfile = frame.positioned(profile);
23407
+ const shownAxis = anchorAnnotation(frame.positioned(axis), {
23408
+ direction: "forward"
23409
+ });
23410
+ const shownResult = result ? frame.positioned(result) : void 0;
23411
+ return focus === "axis" ? {
23412
+ ambient: [shownProfile, ...shownResult ? [shownResult] : []],
23413
+ target: [shownAxis]
23414
+ } : {
23415
+ ambient: [shownAxis, ...shownResult ? [shownResult] : []],
23416
+ target: [shownProfile]
23417
+ };
23418
+ }
23073
23419
  /** @internal Derive the focused cut volume using the original solved operands. */
23074
23420
  static inspectCutTools(stock, tools, focused, data) {
23075
23421
  const selected = new Set(focused);
@@ -23542,7 +23888,7 @@ function line(startOrEnd, end) {
23542
23888
  "line",
23543
23889
  "Line",
23544
23890
  [start, end],
23545
- () => makeLine2(toPoint(start), toPoint(end))
23891
+ () => makeLine3(toPoint(start), toPoint(end))
23546
23892
  );
23547
23893
  }
23548
23894
  __name(line, "line");
@@ -23696,11 +24042,11 @@ function coil(coilRadius = 5, wireRadius = 1, pitch = 3, turns = 3) {
23696
24042
  [coilRadius, wireRadius, pitch, turns],
23697
24043
  [],
23698
24044
  () => {
23699
- const spine = makeHelix(pitch, y, coilRadius, [0, -y / 2, 0], [0, 1, 0]);
24045
+ const spine = makeHelix2(pitch, y, coilRadius, [0, -y / 2, 0], [0, 1, 0]);
23700
24046
  const start = spine.pointAt(0);
23701
24047
  const tangent2 = spine.tangentAt(0);
23702
24048
  const circle2 = makeCircle2(wireRadius, start, tangent2);
23703
- const section = assembleWire([circle2]);
24049
+ const section = assembleWire3([circle2]);
23704
24050
  try {
23705
24051
  return { shape: genericSweep(section, spine, { frenet: true }) };
23706
24052
  } finally {
@@ -24070,6 +24416,75 @@ var relate;
24070
24416
  relate3.inspectBody = inspectBody;
24071
24417
  __name(inspectBody, "inspectBody");
24072
24418
  })(relate || (relate = {}));
24419
+ function measureFiniteGeometry(value, measure) {
24420
+ const topology = value instanceof ModelTopologyElement ? value[anchorReferenceValue].topology : void 0;
24421
+ const owner = value instanceof ModelObject ? value : value[anchorReferenceValue].model;
24422
+ const geometry = (topology?.source ?? value)[modelGeometry]().value;
24423
+ const scale3 = topology?.scale ?? 1;
24424
+ const position2 = /* @__PURE__ */ __name((point3) => topology ? topologyTransform(topology, translation(point3)).position : point3, "position");
24425
+ const read = /* @__PURE__ */ __name((shape) => {
24426
+ const properties = measure === "length" ? measureShapeLinearProperties2(shape) : measure === "area" ? measureShapeSurfaceProperties2(shape) : measureShapeVolumeProperties(shape);
24427
+ try {
24428
+ const magnitude = "length" in properties ? properties.length : "area" in properties ? properties.area : properties.volume;
24429
+ const power = measure === "length" ? 1 : measure === "area" ? 2 : 3;
24430
+ const result = magnitude * scale3 ** power;
24431
+ if (isRecordingInspection()) {
24432
+ const edge = shape;
24433
+ const edgePoint = /* @__PURE__ */ __name((parameter) => {
24434
+ const point3 = edge.pointAt(parameter);
24435
+ try {
24436
+ return position2(point3.toTuple());
24437
+ } finally {
24438
+ point3.delete();
24439
+ }
24440
+ }, "edgePoint");
24441
+ const placement = measure === "length" && edge.geomType === "LINE" ? { start: edgePoint(0), end: edgePoint(1) } : {
24442
+ at: measure === "length" ? edgePoint(0.5) : position2(properties.centerOfMass)
24443
+ };
24444
+ const target = value instanceof ModelObject ? value.kind === "edge" ? value.edges()[0] : value.kind === "face" ? value.surfaces()[0] : value : value;
24445
+ captureInspectData({ owner, target, placement });
24446
+ }
24447
+ return result;
24448
+ } finally {
24449
+ properties.delete();
24450
+ }
24451
+ }, "read");
24452
+ return topology ? withTopologyShape(
24453
+ geometry.shape,
24454
+ geometry.topology,
24455
+ topology.selection,
24456
+ read
24457
+ ) : read(geometry.shape);
24458
+ }
24459
+ __name(measureFiniteGeometry, "measureFiniteGeometry");
24460
+ function inspectLength(_args, context) {
24461
+ return inspectMeasurement(context, "length");
24462
+ }
24463
+ __name(inspectLength, "inspectLength");
24464
+ function inspectArea(_args, context) {
24465
+ return inspectMeasurement(context, "area");
24466
+ }
24467
+ __name(inspectArea, "inspectArea");
24468
+ function inspectVolume(_args, context) {
24469
+ return inspectMeasurement(context, "volume");
24470
+ }
24471
+ __name(inspectVolume, "inspectVolume");
24472
+ function inspectMeasurement(context, kind) {
24473
+ if (context.return === void 0 || !context.data) return;
24474
+ const { owner, target, placement } = context.data;
24475
+ return {
24476
+ target: [
24477
+ target,
24478
+ dimension({
24479
+ owner,
24480
+ value: context.return,
24481
+ ...placement,
24482
+ axisLabel: kind === "length" ? "at" in placement ? "arc length" : void 0 : kind
24483
+ })
24484
+ ]
24485
+ };
24486
+ }
24487
+ __name(inspectMeasurement, "inspectMeasurement");
24073
24488
  function inspectTopologyReference(_args, context) {
24074
24489
  if (context.return !== void 0 && (!Array.isArray(context.return) || context.return.length > 0))
24075
24490
  return void 0;
@@ -24128,6 +24543,33 @@ function extrude(face, distance4 = 10) {
24128
24543
  }
24129
24544
  }
24130
24545
  __name(extrude, "extrude");
24546
+ function revolve(profile, axis, config = { angle: 360 }) {
24547
+ const runtimeProfile = requireModelKind(
24548
+ profile,
24549
+ "face",
24550
+ "revolve requires a face model."
24551
+ );
24552
+ let result;
24553
+ try {
24554
+ result = runtimeProfile.revolve(axis, config);
24555
+ return result;
24556
+ } finally {
24557
+ ModelObject.recordRevolve(
24558
+ runtimeProfile,
24559
+ axis,
24560
+ result
24561
+ );
24562
+ }
24563
+ }
24564
+ __name(revolve, "revolve");
24565
+ function sweep(profile, spine) {
24566
+ return requireModelKind(
24567
+ profile,
24568
+ "face",
24569
+ "sweep requires a face model."
24570
+ ).sweep(spine);
24571
+ }
24572
+ __name(sweep, "sweep");
24131
24573
  function text(content, font2, size, options) {
24132
24574
  return textGlyphs(content, font2, size, options).flatMap(
24133
24575
  ({ regions, x, y }) => regions.value.map((region, index) => {
@@ -24234,7 +24676,7 @@ function withDistanceShape(part, visit) {
24234
24676
  return withTransformedGeometry(part.geometry.value, part, visit);
24235
24677
  const points = part.points;
24236
24678
  if (points.length <= 2) {
24237
- const shape = points.length === 1 ? makeVertex(toPoint(points[0])) : makeLine2(toPoint(points[0]), toPoint(points[1]));
24679
+ const shape = points.length === 1 ? makeVertex(toPoint(points[0])) : makeLine3(toPoint(points[0]), toPoint(points[1]));
24238
24680
  try {
24239
24681
  return visit(shape);
24240
24682
  } finally {
@@ -24247,10 +24689,10 @@ function withDistanceShape(part, visit) {
24247
24689
  try {
24248
24690
  points.forEach(
24249
24691
  (point3, index) => edges.push(
24250
- makeLine2(toPoint(point3), toPoint(points[(index + 1) % points.length]))
24692
+ makeLine3(toPoint(point3), toPoint(points[(index + 1) % points.length]))
24251
24693
  )
24252
24694
  );
24253
- wire = assembleWire(edges);
24695
+ wire = assembleWire3(edges);
24254
24696
  face = makeFace(wire);
24255
24697
  return visit(face);
24256
24698
  } finally {
@@ -24523,6 +24965,8 @@ var authoringApi = Object.freeze({
24523
24965
  bezier,
24524
24966
  spline,
24525
24967
  loft,
24968
+ revolve,
24969
+ sweep,
24526
24970
  box,
24527
24971
  cylinder,
24528
24972
  tube,
@@ -24837,7 +25281,7 @@ function buildLoftGeometry(sections, spine, ruled) {
24837
25281
  spine.transform
24838
25282
  );
24839
25283
  try {
24840
- spineWire = assembleWire([edge]);
25284
+ spineWire = assembleWire3([edge]);
24841
25285
  } finally {
24842
25286
  edge.delete();
24843
25287
  }
@@ -25297,6 +25741,84 @@ __name(requireModelKind, "requireModelKind");
25297
25741
  extrude2.inspectMethod = inspectMethod;
25298
25742
  __name(inspectMethod, "inspectMethod");
25299
25743
  })(extrude || (extrude = {}));
25744
+ ((revolve2) => {
25745
+ function inspectProfile([profile, axis], context) {
25746
+ return context.data && ModelObject.inspectRevolve(
25747
+ profile,
25748
+ axis,
25749
+ context.return,
25750
+ context.data,
25751
+ "profile"
25752
+ );
25753
+ }
25754
+ revolve2.inspectProfile = inspectProfile;
25755
+ __name(inspectProfile, "inspectProfile");
25756
+ function inspectAxis([profile, axis], context) {
25757
+ return context.data && ModelObject.inspectRevolve(
25758
+ profile,
25759
+ axis,
25760
+ context.return,
25761
+ context.data,
25762
+ "axis"
25763
+ );
25764
+ }
25765
+ revolve2.inspectAxis = inspectAxis;
25766
+ __name(inspectAxis, "inspectAxis");
25767
+ function inspectMethodProfile([axis], context) {
25768
+ return context.data && ModelObject.inspectRevolve(
25769
+ context.receiver,
25770
+ axis,
25771
+ context.return,
25772
+ context.data,
25773
+ "profile"
25774
+ );
25775
+ }
25776
+ revolve2.inspectMethodProfile = inspectMethodProfile;
25777
+ __name(inspectMethodProfile, "inspectMethodProfile");
25778
+ function inspectMethodAxis([axis], context) {
25779
+ return context.data && ModelObject.inspectRevolve(
25780
+ context.receiver,
25781
+ axis,
25782
+ context.return,
25783
+ context.data,
25784
+ "axis"
25785
+ );
25786
+ }
25787
+ revolve2.inspectMethodAxis = inspectMethodAxis;
25788
+ __name(inspectMethodAxis, "inspectMethodAxis");
25789
+ })(revolve || (revolve = {}));
25790
+ ((sweep2) => {
25791
+ function inspectProfile([profile, spine], context) {
25792
+ if (!context.data) return void 0;
25793
+ return ModelObject.inspectComposition(
25794
+ context.data,
25795
+ [spine, ...context.return ? [context.return] : []],
25796
+ [profile]
25797
+ );
25798
+ }
25799
+ sweep2.inspectProfile = inspectProfile;
25800
+ __name(inspectProfile, "inspectProfile");
25801
+ function inspectSpine([profile, spine], context) {
25802
+ if (!context.data) return void 0;
25803
+ return ModelObject.inspectComposition(
25804
+ context.data,
25805
+ [profile, ...context.return ? [context.return] : []],
25806
+ [spine]
25807
+ );
25808
+ }
25809
+ sweep2.inspectSpine = inspectSpine;
25810
+ __name(inspectSpine, "inspectSpine");
25811
+ function inspectMethodProfile([spine], context) {
25812
+ return inspectProfile([context.receiver, spine], context);
25813
+ }
25814
+ sweep2.inspectMethodProfile = inspectMethodProfile;
25815
+ __name(inspectMethodProfile, "inspectMethodProfile");
25816
+ function inspectMethodSpine([spine], context) {
25817
+ return inspectSpine([context.receiver, spine], context);
25818
+ }
25819
+ sweep2.inspectMethodSpine = inspectMethodSpine;
25820
+ __name(inspectMethodSpine, "inspectMethodSpine");
25821
+ })(sweep || (sweep = {}));
25300
25822
  ((union2) => {
25301
25823
  function inspectOperands([operands], context) {
25302
25824
  if (!context.data) return void 0;
@@ -26323,19 +26845,19 @@ function contourContains(curves, point3) {
26323
26845
  continue;
26324
26846
  }
26325
26847
  const start = curve.kind === "circle" ? 0 : curve.start;
26326
- const sweep = curve.kind === "circle" ? tau2 : curve.sweep;
26848
+ const sweep2 = curve.kind === "circle" ? tau2 : curve.sweep;
26327
26849
  const cuts = [
26328
26850
  0,
26329
26851
  1,
26330
26852
  ...[Math.PI / 2, 3 * Math.PI / 2].map(
26331
- (a) => sketchPositiveAngle(Math.sign(sweep) * (a - start)) / Math.abs(sweep)
26853
+ (a) => sketchPositiveAngle(Math.sign(sweep2) * (a - start)) / Math.abs(sweep2)
26332
26854
  ).filter((t) => t > 0 && t < 1)
26333
26855
  ].sort((a, b) => a - b);
26334
26856
  for (let i = 1; i < cuts.length; i++) {
26335
26857
  const a = sketchCurvePosition(curve, cuts[i - 1]), b = sketchCurvePosition(curve, cuts[i]);
26336
26858
  if (a[1] > point3[1] === b[1] > point3[1]) continue;
26337
26859
  const dy = point3[1] - curve.center[1];
26338
- const x = curve.center[0] + Math.sign(Math.cos(start + sweep * (cuts[i - 1] + cuts[i]) / 2)) * Math.sqrt(Math.max(0, (curve.radius - dy) * (curve.radius + dy)));
26860
+ const x = curve.center[0] + Math.sign(Math.cos(start + sweep2 * (cuts[i - 1] + cuts[i]) / 2)) * Math.sqrt(Math.max(0, (curve.radius - dy) * (curve.radius + dy)));
26339
26861
  if (x > point3[0]) crossings++;
26340
26862
  }
26341
26863
  }
@@ -26443,12 +26965,17 @@ export {
26443
26965
  group,
26444
26966
  distance2 as distance,
26445
26967
  relate,
26968
+ inspectLength,
26969
+ inspectArea,
26970
+ inspectVolume,
26446
26971
  inspectTopologyReference,
26447
26972
  expose,
26448
26973
  on,
26449
26974
  align,
26450
26975
  union,
26451
26976
  extrude,
26977
+ revolve,
26978
+ sweep,
26452
26979
  text,
26453
26980
  cut,
26454
26981
  intersect,
@@ -26471,4 +26998,4 @@ export {
26471
26998
  retainModelGeometry,
26472
26999
  authoringApi
26473
27000
  };
26474
- //# sourceMappingURL=chunk-JBVIAMJ6.js.map
27001
+ //# sourceMappingURL=chunk-CQKOD54C.js.map