brepjs 18.123.0 → 18.124.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.
Files changed (81) hide show
  1. package/dist/2d.cjs +6 -6
  2. package/dist/2d.js +6 -6
  3. package/dist/{adjacencyFns-YdbeJQOQ.cjs → adjacencyFns-BJ6jcQ-N.cjs} +2 -2
  4. package/dist/{adjacencyFns-BjQlu_ta.js → adjacencyFns-CnehwLNj.js} +2 -2
  5. package/dist/{blueprint-D15K1m3D.js → blueprint-BGWbpQ-w.js} +5 -5
  6. package/dist/{blueprint-DRdJngbT.cjs → blueprint-BSfG0Uik.cjs} +5 -5
  7. package/dist/{blueprintFns-BYBj5nAC.js → blueprintFns-Bt1hKlL7.js} +2 -2
  8. package/dist/{blueprintFns-DjhpKV3P.cjs → blueprintFns-C0-nGqlW.cjs} +2 -2
  9. package/dist/{blueprintSketcher-BrqUJtEJ.js → blueprintSketcher-BTGRoQ_G.js} +9 -5
  10. package/dist/{blueprintSketcher-BwrJrjxs.cjs → blueprintSketcher-Bd5ZS9p6.cjs} +9 -5
  11. package/dist/{boolean2D-DzfMpynm.cjs → boolean2D-Cr6oLsbf.cjs} +4 -4
  12. package/dist/{boolean2D-D68EbJPa.js → boolean2D-zZ9-qR5a.js} +4 -4
  13. package/dist/brepjs.cjs +27 -27
  14. package/dist/brepjs.js +27 -27
  15. package/dist/{cameraFns-BcMH4Nmd.js → cameraFns-CGMawqfi.js} +3 -3
  16. package/dist/{cameraFns-BoJrdghV.cjs → cameraFns-j2I9G3L_.cjs} +3 -3
  17. package/dist/core.cjs +2 -2
  18. package/dist/core.js +2 -2
  19. package/dist/{cornerFinder-Cbx8rGjg.cjs → cornerFinder-CPwSLgpM.cjs} +1 -1
  20. package/dist/{cornerFinder-DG-lilYY.js → cornerFinder-CaXBdZz9.js} +1 -1
  21. package/dist/{curveFns-BuqWKNvF.cjs → curveFns-BBLaLG1U.cjs} +1 -1
  22. package/dist/{curveFns-o05jCVtr.js → curveFns-BoHbhtqX.js} +1 -1
  23. package/dist/{drawFns-q-Ooe6d4.js → drawFns-BrRbAeYB.js} +12 -12
  24. package/dist/{drawFns-BiOerjkt.cjs → drawFns-DOkSdo8E.cjs} +12 -12
  25. package/dist/{faceFns-Dgiv4Jhb.js → faceFns-Ce7Fq6j5.js} +2 -2
  26. package/dist/{faceFns-DeTAgvu_.cjs → faceFns-UozswcwP.cjs} +2 -2
  27. package/dist/{healingFns-BDfz7tDU.js → healingFns-Dn0EFSHm.js} +4 -4
  28. package/dist/{healingFns-BvB2hVj5.cjs → healingFns-mKogaVOk.cjs} +4 -4
  29. package/dist/{helpers-DEN_M6k_.js → helpers-CZsK8STz.js} +6 -6
  30. package/dist/{helpers-B6br6W9E.cjs → helpers-DuTAcGVX.cjs} +6 -6
  31. package/dist/{importFns--rKvxKFm.js → importFns-CE4byS-8.js} +2 -2
  32. package/dist/{importFns-3RGNUkR-.cjs → importFns-Ch2YwieP.cjs} +2 -2
  33. package/dist/io.cjs +2 -2
  34. package/dist/io.js +2 -2
  35. package/dist/{loftFns-Cufcyuqt.cjs → loftFns-BYiUcAxk.cjs} +1 -1
  36. package/dist/{loftFns-BVkAi4-a.js → loftFns-DQVg8qxM.js} +1 -1
  37. package/dist/{measureFns-DcgzCTfb.js → measureFns-BbLLBg5q.js} +3 -3
  38. package/dist/{measureFns-CG3O8Mzp.cjs → measureFns-Cao9gY1L.cjs} +3 -3
  39. package/dist/measurement.cjs +1 -1
  40. package/dist/measurement.js +1 -1
  41. package/dist/{meshFns-DhFraVIQ.js → meshFns-B6NveFwc.js} +3 -3
  42. package/dist/{meshFns-BLqWnKyU.cjs → meshFns-CnYIUU9b.cjs} +3 -3
  43. package/dist/operations.cjs +2 -2
  44. package/dist/operations.js +2 -2
  45. package/dist/{originTrackingFns-4c8Sw44l.js → originTrackingFns-DXcggmgf.js} +2 -2
  46. package/dist/{originTrackingFns-7tC4igk0.cjs → originTrackingFns-uz38yuMp.cjs} +2 -2
  47. package/dist/{primitiveFns-D695dXsj.js → primitiveFns-CmmTWOkO.js} +4 -4
  48. package/dist/{primitiveFns-CFibG_KT.cjs → primitiveFns-DmEPf6av.cjs} +4 -4
  49. package/dist/projection.cjs +1 -1
  50. package/dist/projection.js +1 -1
  51. package/dist/query.cjs +2 -2
  52. package/dist/query.js +2 -2
  53. package/dist/{refResolveFns-u-3Okd3D.cjs → refResolveFns-CnPEaqHw.cjs} +6 -6
  54. package/dist/{refResolveFns-BwEBGVGr.js → refResolveFns-DqY7Cd00.js} +6 -6
  55. package/dist/{shapeFns-BqmsBoBy.cjs → shapeFns-BLZ1dDSz.cjs} +2 -2
  56. package/dist/{shapeFns-BvPYFFCd.js → shapeFns-mYczuWOy.js} +2 -2
  57. package/dist/shapeRef.cjs +1 -1
  58. package/dist/shapeRef.js +1 -1
  59. package/dist/{shapeTypes-D9TjxkdO.cjs → shapeTypes-DZKuRt24.cjs} +384 -13
  60. package/dist/{shapeTypes-u60nsijI.js → shapeTypes-bHlssytH.js} +384 -13
  61. package/dist/sketching.cjs +3 -3
  62. package/dist/sketching.js +3 -3
  63. package/dist/{solidBuilders-BRrbDIpu.cjs → solidBuilders-5tA9O1SM.cjs} +5 -5
  64. package/dist/{solidBuilders-DOafY0bO.js → solidBuilders-9s-j-ZiW.js} +5 -5
  65. package/dist/{surfaceBuilders-B4Yn-xOW.cjs → surfaceBuilders-0x7j0ibk.cjs} +3 -3
  66. package/dist/{surfaceBuilders-BnkTJeD4.js → surfaceBuilders-B7UnwkQz.js} +3 -3
  67. package/dist/text.cjs +2 -2
  68. package/dist/text.js +2 -2
  69. package/dist/{textBlueprints-DPldA7fV.cjs → textBlueprints-BPbIpA4-.cjs} +7 -7
  70. package/dist/{textBlueprints-B1JdMBb0.js → textBlueprints-DE3M-E9o.js} +7 -7
  71. package/dist/{textMetrics-YfWZZTIk.js → textMetrics-D3Bly1w4.js} +1 -1
  72. package/dist/{textMetrics-19pWWvqT.cjs → textMetrics-rRuWxQG_.cjs} +1 -1
  73. package/dist/{threadFns-B2YuXmV6.js → threadFns-BAjFNk2_.js} +7 -7
  74. package/dist/{threadFns-BDMSW3Od.cjs → threadFns-BMT6ziG_.cjs} +7 -7
  75. package/dist/topology.cjs +9 -9
  76. package/dist/topology.js +9 -9
  77. package/dist/{topologyQueryFns-DiuoNPqI.js → topologyQueryFns-DVhWxBwT.js} +1 -1
  78. package/dist/{topologyQueryFns-CUbx6oRW.cjs → topologyQueryFns-DZUpJz2p.cjs} +1 -1
  79. package/dist/{validityTypes-phPr-BRp.js → validityTypes-19mfqWVv.js} +1 -1
  80. package/dist/{validityTypes-DuiGeQhe.cjs → validityTypes-CCnRq3A9.cjs} +1 -1
  81. package/package.json +1 -1
@@ -11770,7 +11770,7 @@ function meshVertices(shape) {
11770
11770
  function spinePath(spine, segments) {
11771
11771
  const shape = asShape$1(spine);
11772
11772
  const params = shape.node?.params;
11773
- const recorded = params?.["path"] ?? params?.["points"];
11773
+ const recorded = params?.["path"] ?? params?.["points"] ?? params?.["ring"];
11774
11774
  if (recorded && recorded.length >= 2) return recorded.map((p) => [
11775
11775
  p[0],
11776
11776
  p[1],
@@ -12117,12 +12117,21 @@ function makeSweepOps(module) {
12117
12117
  }),
12118
12118
  ...sweepFamilyEntries(module),
12119
12119
  draftPrism: (shape, face, _baseFace, height, angleDeg, fuse) => draftPrismOp(module, shape, face, height, angleDeg, fuse),
12120
- buildExtrusionLaw: (profile, length, endFactor) => ({
12121
- type: "extrusionLaw",
12122
- profile,
12123
- length,
12124
- endFactor
12125
- }),
12120
+ buildExtrusionLaw: (profile, length, endFactor) => {
12121
+ const law = {
12122
+ type: "extrusionLaw",
12123
+ profile,
12124
+ length,
12125
+ endFactor,
12126
+ Trim: (first, last, _tol) => ({
12127
+ ...law,
12128
+ trimFirst: first,
12129
+ trimLast: last
12130
+ }),
12131
+ delete: () => {}
12132
+ };
12133
+ return law;
12134
+ },
12126
12135
  loftBatch: () => notImplemented("loftBatch"),
12127
12136
  extrudeBatch: (entries) => entries.map((e) => extrudeOp(module, e.face, e.direction, e.length))
12128
12137
  };
@@ -14598,6 +14607,320 @@ function makeRepairOps(_module) {
14598
14607
  //#endregion
14599
14608
  //#region src/kernel/manifold/kernel2dNative.ts
14600
14609
  var CHORD_TOL = .004;
14610
+ /**
14611
+ * Closest parameter on a native curve to (x, y), in that curve's own
14612
+ * parametrization: signed distance for a line, angle for a conic, [0,1] for a
14613
+ * bezier. Exact where the geometry allows it, and a bounded golden-section
14614
+ * search where it does not (general ellipse, bezier) — both of which are
14615
+ * unimodal in distance over a single arc, so the search cannot land on a
14616
+ * spurious local minimum.
14617
+ */
14618
+ function closestParamOn(c, x, y) {
14619
+ if (c.k === "line") {
14620
+ const dx = c.p2[0] - c.p1[0];
14621
+ const dy = c.p2[1] - c.p1[1];
14622
+ const len = Math.hypot(dx, dy);
14623
+ if (len === 0) return 0;
14624
+ const t = ((x - c.p1[0]) * dx + (y - c.p1[1]) * dy) / len;
14625
+ return Math.min(Math.max(t, 0), len);
14626
+ }
14627
+ if (c.k === "conic") {
14628
+ const ru = Math.hypot(c.u[0], c.u[1]);
14629
+ const rv = Math.hypot(c.v[0], c.v[1]);
14630
+ if (Math.abs(ru - rv) < 1e-12 && Math.abs(c.u[0] * c.v[0] + c.u[1] * c.v[1]) < 1e-12) {
14631
+ const px = x - c.c[0];
14632
+ const py = y - c.c[1];
14633
+ return clampToArc(Math.atan2((px * c.v[0] + py * c.v[1]) / (rv * rv || 1), (px * c.u[0] + py * c.u[1]) / (ru * ru || 1)), c.a0, c.a1);
14634
+ }
14635
+ return bracketedMin(c.a0, c.a1, (t) => distSqAt(c, t, x, y), stepsFor(c, CHORD_TOL));
14636
+ }
14637
+ return bracketedMin(0, 1, (t) => distSqAt(c, t, x, y), stepsFor(c, CHORD_TOL));
14638
+ }
14639
+ /**
14640
+ * Global minimum of f over [lo, hi].
14641
+ *
14642
+ * Distance to an eccentric ellipse or a cubic-or-higher bezier is NOT unimodal
14643
+ * — a point inside a flat ellipse has one minimum per end, and a self-nearing
14644
+ * bezier can have several. So scan coarsely for the best sample, then refine
14645
+ * only inside the bracket around it, which is unimodal by construction.
14646
+ */
14647
+ function bracketedMin(lo, hi, f, steps) {
14648
+ const N = Math.max(8, steps);
14649
+ let bestI = 0;
14650
+ let best = Infinity;
14651
+ for (let i = 0; i <= N; i++) {
14652
+ const v = f(lo + (hi - lo) * i / N);
14653
+ if (v < best) {
14654
+ best = v;
14655
+ bestI = i;
14656
+ }
14657
+ }
14658
+ return goldenMin(lo + (hi - lo) * Math.max(0, bestI - 1) / N, lo + (hi - lo) * Math.min(N, bestI + 1) / N, f);
14659
+ }
14660
+ /** Wrap an angle into [a0, a1] where possible, else clamp to the nearer end. */
14661
+ function clampToArc(a, a0, a1) {
14662
+ if (a1 - a0 >= 2 * Math.PI - 1e-12) return a;
14663
+ let t = a;
14664
+ while (t < a0) t += 2 * Math.PI;
14665
+ while (t > a0 + 2 * Math.PI) t -= 2 * Math.PI;
14666
+ if (t <= a1) return t;
14667
+ return t - a1 < a0 + 2 * Math.PI - t ? a1 : a0;
14668
+ }
14669
+ function distSqAt(c, t, x, y) {
14670
+ const p = nativeAt(c, t);
14671
+ const dx = p[0] - x;
14672
+ const dy = p[1] - y;
14673
+ return dx * dx + dy * dy;
14674
+ }
14675
+ function nativeAt(c, t) {
14676
+ if (c.k === "line") {
14677
+ const dx = c.p2[0] - c.p1[0];
14678
+ const dy = c.p2[1] - c.p1[1];
14679
+ const len = Math.hypot(dx, dy) || 1;
14680
+ return [c.p1[0] + dx * t / len, c.p1[1] + dy * t / len];
14681
+ }
14682
+ if (c.k === "bezier") return bezierAt(c.pts, t);
14683
+ return [c.c[0] + c.u[0] * Math.cos(t) + c.v[0] * Math.sin(t), c.c[1] + c.u[1] * Math.cos(t) + c.v[1] * Math.sin(t)];
14684
+ }
14685
+ /** Golden-section minimum of a unimodal f over [lo, hi]. */
14686
+ function goldenMin(lo, hi, f) {
14687
+ const phi = (Math.sqrt(5) - 1) / 2;
14688
+ let a = lo;
14689
+ let b = hi;
14690
+ let c1 = b - phi * (b - a);
14691
+ let d1 = a + phi * (b - a);
14692
+ for (let i = 0; i < 80 && b - a > 1e-12; i++) if (f(c1) < f(d1)) {
14693
+ b = d1;
14694
+ d1 = c1;
14695
+ c1 = b - phi * (b - a);
14696
+ } else {
14697
+ a = c1;
14698
+ c1 = d1;
14699
+ d1 = a + phi * (b - a);
14700
+ }
14701
+ return (a + b) / 2;
14702
+ }
14703
+ /**
14704
+ * Curve-curve intersection over the shim's own polyline discretization.
14705
+ *
14706
+ * Manifold has no exact curve algebra, so candidate crossings come from
14707
+ * segment pairs and are then refined by alternating projection: each point is
14708
+ * projected onto the other curve until it stops moving. That converges to a
14709
+ * genuine crossing when the segments really cross, and to the closest approach
14710
+ * when they only nearly touch — which the tolerance check then rejects.
14711
+ */
14712
+ function intersectNative(a, b, tol) {
14713
+ const pa = sample(a);
14714
+ const pb = sample(b);
14715
+ const points = [];
14716
+ const params = [];
14717
+ for (let i = 0; i + 1 < pa.length; i++) for (let j = 0; j + 1 < pb.length; j++) {
14718
+ const hit = segSeg(pa[i], pa[i + 1], pb[j], pb[j + 1]);
14719
+ if (!hit) continue;
14720
+ let p = hit;
14721
+ for (let k = 0; k < 24; k++) {
14722
+ const qa = nativeAt(a, closestParamOn(a, p[0], p[1]));
14723
+ const qb = nativeAt(b, closestParamOn(b, qa[0], qa[1]));
14724
+ const moved = Math.hypot(qb[0] - p[0], qb[1] - p[1]);
14725
+ p = [(qa[0] + qb[0]) / 2, (qa[1] + qb[1]) / 2];
14726
+ if (moved < 1e-12) break;
14727
+ }
14728
+ const ta = closestParamOn(a, p[0], p[1]);
14729
+ const tb = closestParamOn(b, p[0], p[1]);
14730
+ const d = sub2(nativeAt(a, ta), nativeAt(b, tb));
14731
+ if (Math.hypot(d[0], d[1]) > Math.max(tol, 1e-7)) continue;
14732
+ if (points.some((q) => Math.hypot(q[0] - p[0], q[1] - p[1]) <= Math.max(tol, 1e-9))) continue;
14733
+ points.push(p);
14734
+ params.push(ta);
14735
+ }
14736
+ return dropOverlapPoints(points, params, contactRuns(a, b, tol, points, params), tol);
14737
+ }
14738
+ /**
14739
+ * Spans of `a` that lie on `b` within tolerance.
14740
+ *
14741
+ * Coincident spans and tangential touches never register as segment crossings —
14742
+ * collinear chords are parallel, and a tangency grazes without passing through.
14743
+ * Walking a's parameter range finds both: a run with length is a common
14744
+ * segment, an isolated dip is a tangential point (appended to `points`).
14745
+ */
14746
+ function contactRuns(a, b, tol, points, params) {
14747
+ const { first, last } = nativeBounds(a);
14748
+ const M = 192;
14749
+ const on = [];
14750
+ for (let i = 0; i <= M; i++) {
14751
+ const p = nativeAt(a, first + (last - first) * i / M);
14752
+ const tb = closestParamOn(b, p[0], p[1]);
14753
+ on.push(Math.sqrt(distSqAt(b, tb, p[0], p[1])) <= Math.max(tol, 1e-9));
14754
+ }
14755
+ const segments = [];
14756
+ let runStart = -1;
14757
+ for (let i = 0; i <= 193; i++) {
14758
+ const inside = i <= M && on[i] === true;
14759
+ if (inside && runStart < 0) runStart = i;
14760
+ if (inside || runStart < 0) continue;
14761
+ const t0 = first + (last - first) * runStart / M;
14762
+ const t1 = first + (last - first) * (i - 1) / M;
14763
+ let physical = 0;
14764
+ for (let k = runStart; k < i - 1; k++) {
14765
+ const q0 = nativeAt(a, first + (last - first) * k / M);
14766
+ const q1 = nativeAt(a, first + (last - first) * (k + 1) / M);
14767
+ physical += Math.hypot(q1[0] - q0[0], q1[1] - q0[1]);
14768
+ }
14769
+ if (physical > Math.max(tol, CHORD_TOL)) segments.push(trimNative(a, t0, t1));
14770
+ else {
14771
+ const p = nativeAt(a, t0);
14772
+ if (!points.some((q) => Math.hypot(q[0] - p[0], q[1] - p[1]) <= Math.max(tol, 1e-9))) {
14773
+ points.push(p);
14774
+ params.push(t0);
14775
+ }
14776
+ }
14777
+ runStart = -1;
14778
+ }
14779
+ return segments;
14780
+ }
14781
+ /**
14782
+ * A coincident span makes the crossing search fire at every sampled chord pair
14783
+ * along it — 79 "intersections" for two identical circles. Those points are the
14784
+ * overlap, not isolated crossings, so drop any that land on a reported segment.
14785
+ */
14786
+ function dropOverlapPoints(points, params, segments, tol) {
14787
+ if (segments.length === 0) return {
14788
+ points,
14789
+ params,
14790
+ segments
14791
+ };
14792
+ const keep = [];
14793
+ for (let i = 0; i < points.length; i++) {
14794
+ const p = points[i];
14795
+ if (!segments.some((seg) => {
14796
+ const t = closestParamOn(seg, p[0], p[1]);
14797
+ return Math.sqrt(distSqAt(seg, t, p[0], p[1])) <= Math.max(tol, CHORD_TOL);
14798
+ })) keep.push(i);
14799
+ }
14800
+ return {
14801
+ points: keep.map((i) => points[i]),
14802
+ params: keep.map((i) => params[i]),
14803
+ segments
14804
+ };
14805
+ }
14806
+ function sub2(a, b) {
14807
+ return [a[0] - b[0], a[1] - b[1]];
14808
+ }
14809
+ /** Intersection point of two segments, or null when they do not cross. */
14810
+ function segSeg(p1, p2, p3, p4) {
14811
+ const d1x = p2[0] - p1[0];
14812
+ const d1y = p2[1] - p1[1];
14813
+ const d2x = p4[0] - p3[0];
14814
+ const d2y = p4[1] - p3[1];
14815
+ const den = d1x * d2y - d1y * d2x;
14816
+ if (Math.abs(den) < 1e-15) return null;
14817
+ const t = ((p3[0] - p1[0]) * d2y - (p3[1] - p1[1]) * d2x) / den;
14818
+ const u = ((p3[0] - p1[0]) * d1y - (p3[1] - p1[1]) * d1x) / den;
14819
+ if (t < -1e-9 || t > 1.000000001 || u < -1e-9 || u > 1.000000001) return null;
14820
+ return [p1[0] + d1x * t, p1[1] + d1y * t];
14821
+ }
14822
+ /**
14823
+ * How many parameter steps resolve `c` to within `tol`.
14824
+ *
14825
+ * A fixed step count is wrong at both ends: wasteful on a short line and blind
14826
+ * to a feature narrower than one interval on a long or wiggly curve. Deriving
14827
+ * it from the curve's own extent — control-polygon length for a bezier, arc
14828
+ * length for a conic — ties the resolution to the geometry and the caller's
14829
+ * tolerance, the same way conicSegments already does for discretization.
14830
+ *
14831
+ * This bounds the miss, it does not remove it: any sampling scheme can still
14832
+ * step over a feature narrower than its own interval. Exactly resolving that
14833
+ * needs polynomial root-finding on the distance function, which is a different
14834
+ * and much larger piece of machinery than this shim carries.
14835
+ */
14836
+ function stepsFor(c, tol) {
14837
+ const t = Math.max(tol, 1e-9);
14838
+ if (c.k === "line") return 2;
14839
+ let extent;
14840
+ if (c.k === "conic") {
14841
+ const r = Math.max(Math.hypot(c.u[0], c.u[1]), Math.hypot(c.v[0], c.v[1]));
14842
+ extent = Math.abs(c.a1 - c.a0) * r;
14843
+ } else {
14844
+ extent = 0;
14845
+ for (let i = 0; i + 1 < c.pts.length; i++) {
14846
+ const a = c.pts[i];
14847
+ const b = c.pts[i + 1];
14848
+ extent += Math.hypot(b[0] - a[0], b[1] - a[1]);
14849
+ }
14850
+ }
14851
+ return Math.min(2e4, Math.max(64, Math.ceil(2 * extent / t)));
14852
+ }
14853
+ /** Parameter range of a native curve, matching getCurve2dBounds. */
14854
+ function nativeBounds(c) {
14855
+ if (c.k === "conic") return {
14856
+ first: c.a0,
14857
+ last: c.a1
14858
+ };
14859
+ if (c.k === "line") return {
14860
+ first: 0,
14861
+ last: Math.hypot(c.p2[0] - c.p1[0], c.p2[1] - c.p1[1])
14862
+ };
14863
+ return {
14864
+ first: 0,
14865
+ last: 1
14866
+ };
14867
+ }
14868
+ /** Restrict a native curve to [from, to] in its own parametrization. */
14869
+ function trimNative(c, from, to) {
14870
+ if (c.k === "conic") return {
14871
+ ...c,
14872
+ a0: from,
14873
+ a1: to
14874
+ };
14875
+ if (c.k === "line") {
14876
+ const p1 = nativeAt(c, from);
14877
+ const p2 = nativeAt(c, to);
14878
+ return {
14879
+ ...c,
14880
+ p1,
14881
+ p2
14882
+ };
14883
+ }
14884
+ const right = deCasteljauRight(c.pts, from);
14885
+ const span = 1 - from;
14886
+ const t2 = span <= 1e-15 ? 1 : (to - from) / span;
14887
+ return {
14888
+ ...c,
14889
+ pts: deCasteljauLeft(right, t2)
14890
+ };
14891
+ }
14892
+ function deCasteljauLeft(pts, t) {
14893
+ const out = [];
14894
+ let cur = pts.map((p) => [p[0], p[1]]);
14895
+ out.push(cur[0]);
14896
+ while (cur.length > 1) {
14897
+ const next = [];
14898
+ for (let i = 0; i + 1 < cur.length; i++) {
14899
+ const a = cur[i];
14900
+ const b = cur[i + 1];
14901
+ next.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
14902
+ }
14903
+ cur = next;
14904
+ out.push(cur[0]);
14905
+ }
14906
+ return out;
14907
+ }
14908
+ function deCasteljauRight(pts, t) {
14909
+ const out = [];
14910
+ let cur = pts.map((p) => [p[0], p[1]]);
14911
+ out.push(cur[cur.length - 1]);
14912
+ while (cur.length > 1) {
14913
+ const next = [];
14914
+ for (let i = 0; i + 1 < cur.length; i++) {
14915
+ const a = cur[i];
14916
+ const b = cur[i + 1];
14917
+ next.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
14918
+ }
14919
+ cur = next;
14920
+ out.push(cur[cur.length - 1]);
14921
+ }
14922
+ return out.reverse();
14923
+ }
14601
14924
  function isNative(x) {
14602
14925
  return !!x && typeof x === "object" && x.__nativeC2d === true;
14603
14926
  }
@@ -15159,14 +15482,62 @@ function makeNativeKernel2DOps(module, occt) {
15159
15482
  },
15160
15483
  makeBSpline2d: (points, options) => occtOr("makeBSpline2d").makeBSpline2d(points, options),
15161
15484
  offsetCurve2d: (c, offset) => occtOr("offsetCurve2d").offsetCurve2d(toOcct(c), offset),
15162
- intersectCurves2d: (c1, c2, tol) => occtOr("intersectCurves2d").intersectCurves2d(toOcct(c1), toOcct(c2), tol),
15163
- projectPointOnCurve2d: (c, x, y) => occtOr("projectPointOnCurve2d").projectPointOnCurve2d(toOcct(c), x, y),
15164
- distanceBetweenCurves2d: (c1, c2, s1, e1, s2, e2) => occtOr("distanceBetweenCurves2d").distanceBetweenCurves2d(toOcct(c1), toOcct(c2), s1, e1, s2, e2),
15485
+ intersectCurves2d: (c1, c2, tol) => {
15486
+ if (!isNative(c1) || !isNative(c2)) return occtOr("intersectCurves2d").intersectCurves2d(toOcct(c1), toOcct(c2), tol);
15487
+ const { points, segments } = intersectNative(asC(c1), asC(c2), tol);
15488
+ return {
15489
+ points: points.map((p) => [p[0], p[1]]),
15490
+ segments
15491
+ };
15492
+ },
15493
+ projectPointOnCurve2d: (c, x, y) => {
15494
+ if (!isNative(c)) return occtOr("projectPointOnCurve2d").projectPointOnCurve2d(toOcct(c), x, y);
15495
+ const n = asC(c);
15496
+ const param = closestParamOn(n, x, y);
15497
+ return {
15498
+ param,
15499
+ distance: Math.sqrt(distSqAt(n, param, x, y))
15500
+ };
15501
+ },
15502
+ distanceBetweenCurves2d: (c1, c2, s1, e1, s2, e2) => {
15503
+ if (!isNative(c1) || !isNative(c2)) return occtOr("distanceBetweenCurves2d").distanceBetweenCurves2d(toOcct(c1), toOcct(c2), s1, e1, s2, e2);
15504
+ const a = asC(c1);
15505
+ const b = asC(c2);
15506
+ const N = 256;
15507
+ let best = Infinity;
15508
+ for (let i = 0; i <= N; i++) {
15509
+ const p = nativeAt(a, s1 + (e1 - s1) * i / N);
15510
+ const q = closestParamOn(b, p[0], p[1]);
15511
+ best = Math.min(best, Math.sqrt(distSqAt(b, Math.min(Math.max(q, Math.min(s2, e2)), Math.max(s2, e2)), p[0], p[1])));
15512
+ }
15513
+ return best;
15514
+ },
15165
15515
  approximateCurve2dAsBSpline: (c, tol, cont, maxSeg) => occtOr("approximateCurve2dAsBSpline").approximateCurve2dAsBSpline(toOcct(c), tol, cont, maxSeg),
15166
15516
  decomposeBSpline2dToBeziers: (c) => occtOr("decomposeBSpline2dToBeziers").decomposeBSpline2dToBeziers(toOcct(c)),
15167
- serializeCurve2d: (c) => occtOr("serializeCurve2d").serializeCurve2d(toOcct(c)),
15168
- deserializeCurve2d: (data) => occtOr("deserializeCurve2d").deserializeCurve2d(data),
15169
- splitCurve2d: (c, params) => occtOr("splitCurve2d").splitCurve2d(toOcct(c), params),
15517
+ serializeCurve2d: (c) => isNative(c) ? JSON.stringify({
15518
+ __nativeC2d: 1,
15519
+ c: asC(c)
15520
+ }) : occtOr("serializeCurve2d").serializeCurve2d(toOcct(c)),
15521
+ deserializeCurve2d: (data) => {
15522
+ if (data.startsWith("{\"__nativeC2d\"")) return {
15523
+ __nativeC2d: true,
15524
+ ...JSON.parse(data).c
15525
+ };
15526
+ return occtOr("deserializeCurve2d").deserializeCurve2d(data);
15527
+ },
15528
+ splitCurve2d: (c, params) => {
15529
+ if (!isNative(c)) return occtOr("splitCurve2d").splitCurve2d(toOcct(c), params);
15530
+ const n = asC(c);
15531
+ const { first, last } = nativeBounds(n);
15532
+ const cuts = [
15533
+ first,
15534
+ ...params.filter((t) => t > first && t < last).sort((a, b) => a - b),
15535
+ last
15536
+ ];
15537
+ const out = [];
15538
+ for (let i = 0; i + 1 < cuts.length; i++) out.push(trimNative(n, cuts[i] ?? 0, cuts[i + 1] ?? 0));
15539
+ return out;
15540
+ },
15170
15541
  getCurve2dEllipseData: (c) => occtOr("getCurve2dEllipseData").getCurve2dEllipseData(toOcct(c)),
15171
15542
  getCurve2dBezierPoles: (c) => occtOr("getCurve2dBezierPoles").getCurve2dBezierPoles(toOcct(c)),
15172
15543
  getCurve2dBezierDegree: (c) => occtOr("getCurve2dBezierDegree").getCurve2dBezierDegree(toOcct(c)),