@faicad/faijs 0.18.3 → 0.19.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 (129) hide show
  1. package/dist/api/api-namespace.d.ts.map +1 -1
  2. package/dist/api/api-namespace.js +4 -1
  3. package/dist/api/api-namespace.js.map +1 -1
  4. package/dist/api/brep-mirror/joinery-brep.d.ts +1 -1
  5. package/dist/api/brep-mirror/joinery-brep.d.ts.map +1 -1
  6. package/dist/api/brep-mirror/joinery-brep.js +19 -19
  7. package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
  8. package/dist/api/index.d.ts +4 -0
  9. package/dist/api/index.d.ts.map +1 -1
  10. package/dist/api/index.js +3 -0
  11. package/dist/api/index.js.map +1 -1
  12. package/dist/api/profile.d.ts.map +1 -1
  13. package/dist/api/profile.js +113 -182
  14. package/dist/api/profile.js.map +1 -1
  15. package/dist/api/punch-hole.d.ts +74 -0
  16. package/dist/api/punch-hole.d.ts.map +1 -0
  17. package/dist/api/punch-hole.js +207 -0
  18. package/dist/api/punch-hole.js.map +1 -0
  19. package/dist/api/sketch-on-face.d.ts +85 -0
  20. package/dist/api/sketch-on-face.d.ts.map +1 -0
  21. package/dist/api/sketch-on-face.js +136 -0
  22. package/dist/api/sketch-on-face.js.map +1 -0
  23. package/dist/api/sketch-on-plane.d.ts +81 -0
  24. package/dist/api/sketch-on-plane.d.ts.map +1 -0
  25. package/dist/api/sketch-on-plane.js +103 -0
  26. package/dist/api/sketch-on-plane.js.map +1 -0
  27. package/dist/boolean/csg-backend.d.ts +6 -6
  28. package/dist/boolean/csg-backend.d.ts.map +1 -1
  29. package/dist/boolean/csg-backend.js +9 -9
  30. package/dist/boolean/csg-backend.js.map +1 -1
  31. package/dist/boolean/csg-core.d.ts +10 -10
  32. package/dist/boolean/csg-core.d.ts.map +1 -1
  33. package/dist/boolean/csg-core.js +24 -24
  34. package/dist/boolean/csg-core.js.map +1 -1
  35. package/dist/boolean/extrude-helpers.d.ts +8 -8
  36. package/dist/boolean/extrude-helpers.d.ts.map +1 -1
  37. package/dist/boolean/extrude-helpers.js +13 -13
  38. package/dist/boolean/extrude-helpers.js.map +1 -1
  39. package/dist/brep/brep-ops.d.ts +20 -6
  40. package/dist/brep/brep-ops.d.ts.map +1 -1
  41. package/dist/brep/brep-ops.js +38 -12
  42. package/dist/brep/brep-ops.js.map +1 -1
  43. package/dist/browser-host/csg-worker-protocol.d.ts +3 -3
  44. package/dist/browser-host/csg-worker-protocol.d.ts.map +1 -1
  45. package/dist/browser-host/csg-worker-protocol.js.map +1 -1
  46. package/dist/browser-host/csg-worker.js +3 -3
  47. package/dist/browser-host/csg-worker.js.map +1 -1
  48. package/dist/browser-host/inline-csg-backend.d.ts +3 -3
  49. package/dist/browser-host/inline-csg-backend.d.ts.map +1 -1
  50. package/dist/browser-host/inline-csg-backend.js +3 -3
  51. package/dist/browser-host/inline-csg-backend.js.map +1 -1
  52. package/dist/browser-host/worker-csg-backend.d.ts +3 -3
  53. package/dist/browser-host/worker-csg-backend.d.ts.map +1 -1
  54. package/dist/browser-host/worker-csg-backend.js.map +1 -1
  55. package/dist/cad-runtime/ports.d.ts +3 -3
  56. package/dist/cad-runtime/ports.d.ts.map +1 -1
  57. package/dist/cad-runtime/ports.js.map +1 -1
  58. package/dist/geometry2d/adapt.d.ts +46 -0
  59. package/dist/geometry2d/adapt.d.ts.map +1 -0
  60. package/dist/geometry2d/adapt.js +41 -0
  61. package/dist/geometry2d/adapt.js.map +1 -0
  62. package/dist/geometry2d/bbox2d.d.ts +82 -0
  63. package/dist/geometry2d/bbox2d.d.ts.map +1 -0
  64. package/dist/geometry2d/bbox2d.js +123 -0
  65. package/dist/geometry2d/bbox2d.js.map +1 -0
  66. package/dist/geometry2d/blueprint-sketcher.d.ts +27 -0
  67. package/dist/geometry2d/blueprint-sketcher.d.ts.map +1 -0
  68. package/dist/geometry2d/blueprint-sketcher.js +29 -0
  69. package/dist/geometry2d/blueprint-sketcher.js.map +1 -0
  70. package/dist/geometry2d/blueprint.d.ts +102 -0
  71. package/dist/geometry2d/blueprint.d.ts.map +1 -0
  72. package/dist/geometry2d/blueprint.js +225 -0
  73. package/dist/geometry2d/blueprint.js.map +1 -0
  74. package/dist/geometry2d/blueprints.d.ts +58 -0
  75. package/dist/geometry2d/blueprints.d.ts.map +1 -0
  76. package/dist/geometry2d/blueprints.js +72 -0
  77. package/dist/geometry2d/blueprints.js.map +1 -0
  78. package/dist/geometry2d/bridge/lift-on-plane.d.ts +50 -0
  79. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -0
  80. package/dist/geometry2d/bridge/lift-on-plane.js +72 -0
  81. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -0
  82. package/dist/geometry2d/bridge/on-surface.d.ts +98 -0
  83. package/dist/geometry2d/bridge/on-surface.d.ts.map +1 -0
  84. package/dist/geometry2d/bridge/on-surface.js +94 -0
  85. package/dist/geometry2d/bridge/on-surface.js.map +1 -0
  86. package/dist/geometry2d/bridge/plane.d.ts +69 -0
  87. package/dist/geometry2d/bridge/plane.d.ts.map +1 -0
  88. package/dist/geometry2d/bridge/plane.js +96 -0
  89. package/dist/geometry2d/bridge/plane.js.map +1 -0
  90. package/dist/geometry2d/canned-blueprints.d.ts +44 -0
  91. package/dist/geometry2d/canned-blueprints.d.ts.map +1 -0
  92. package/dist/geometry2d/canned-blueprints.js +94 -0
  93. package/dist/geometry2d/canned-blueprints.js.map +1 -0
  94. package/dist/geometry2d/compound-blueprint.d.ts +72 -0
  95. package/dist/geometry2d/compound-blueprint.d.ts.map +1 -0
  96. package/dist/geometry2d/compound-blueprint.js +95 -0
  97. package/dist/geometry2d/compound-blueprint.js.map +1 -0
  98. package/dist/geometry2d/curve2d.d.ts +298 -0
  99. package/dist/geometry2d/curve2d.d.ts.map +1 -0
  100. package/dist/geometry2d/curve2d.js +1110 -0
  101. package/dist/geometry2d/curve2d.js.map +1 -0
  102. package/dist/geometry2d/index.d.ts +22 -0
  103. package/dist/geometry2d/index.d.ts.map +1 -0
  104. package/dist/geometry2d/index.js +21 -0
  105. package/dist/geometry2d/index.js.map +1 -0
  106. package/dist/geometry2d/organise.d.ts +28 -0
  107. package/dist/geometry2d/organise.d.ts.map +1 -0
  108. package/dist/geometry2d/organise.js +108 -0
  109. package/dist/geometry2d/organise.js.map +1 -0
  110. package/dist/geometry2d/pen-sketcher.d.ts +340 -0
  111. package/dist/geometry2d/pen-sketcher.d.ts.map +1 -0
  112. package/dist/geometry2d/pen-sketcher.js +477 -0
  113. package/dist/geometry2d/pen-sketcher.js.map +1 -0
  114. package/dist/geometry2d/point.d.ts +44 -0
  115. package/dist/geometry2d/point.d.ts.map +1 -0
  116. package/dist/geometry2d/point.js +57 -0
  117. package/dist/geometry2d/point.js.map +1 -0
  118. package/dist/geometry2d/svg-ellipse.d.ts +74 -0
  119. package/dist/geometry2d/svg-ellipse.d.ts.map +1 -0
  120. package/dist/geometry2d/svg-ellipse.js +163 -0
  121. package/dist/geometry2d/svg-ellipse.js.map +1 -0
  122. package/dist/lang/symbol-table.generated.d.ts +3 -0
  123. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  124. package/dist/lang/symbol-table.generated.js +3 -0
  125. package/dist/lang/symbol-table.generated.js.map +1 -1
  126. package/dist/mesh/types.d.ts +1 -1
  127. package/dist/mesh/types.d.ts.map +1 -1
  128. package/dist/mesh/types.js.map +1 -1
  129. package/package.json +9 -1
@@ -1 +1 @@
1
- {"version":3,"file":"worker-csg-backend.js","sourceRoot":"","sources":["../../src/browser-host/worker-csg-backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WorkerCsgBackend — 经 Web Worker 跑 CSG 后端(csg-worker)\n *\n * 与 InlineCsgBackend 的行为一致(共用 csg-core 同一套纯函数),\n * 区别是 manifold WASM 计算在独立 Worker 线程执行,不阻塞 UI。\n *\n * 构造时即向 worker 发送 init 握手(携带 wasm 地址,取自 manifold-loader 的\n * setManifoldWasmUrl 配置),后续每个 op 自动等待握手完成。\n */\n\nimport type { CsgBackend, MeshData, PlaneParams, SplitResult } from '../cad-runtime/ports'\nimport type {\n CsgWorkerRequest,\n CsgWorkerResponse,\n} from './csg-worker-protocol'\nimport { getManifoldWasmUrl } from '../mesh/manifold-loader'\n\ninterface Pending {\n resolve: (result: unknown) => void\n reject: (err: Error) => void\n}\n\n/**\n * WorkerCsgBackend is a CSG backend that runs manifold-3d in a Web Worker.\n *\n * It behaves identically to the InlineCsgBackend (both share the same pure\n * functions from csg-core), except that the manifold WASM computation happens\n * on a dedicated worker thread so the UI is not blocked. The constructor sends\n * the init handshake carrying the worker's wasm URL immediately (read from the\n * manifold-loader configuration); every subsequent operation awaits that\n * handshake.\n */\nexport class WorkerCsgBackend implements CsgBackend {\n private worker: Worker\n private nextId = 1\n private pending = new Map<number, Pending>()\n private initPromise: Promise<void>\n\n constructor() {\n this.worker = new Worker(new URL('./csg-worker.ts', import.meta.url), { type: 'module' })\n this.worker.onmessage = (ev: MessageEvent<CsgWorkerResponse>) => {\n this.handleMessage(ev.data)\n }\n this.worker.onerror = (ev) => {\n const err = new Error(`CSG worker 错误:${ev.message || '未知错误'}`)\n this.rejectAll(err)\n }\n this.initPromise = this.post({ id: 0, kind: 'init', wasmUrl: getManifoldWasmUrl() })\n .then(() => undefined)\n }\n\n private handleMessage(res: CsgWorkerResponse): void {\n const pending = this.pending.get(res.id)\n if (!pending) return\n this.pending.delete(res.id)\n if (res.ok) {\n pending.resolve(res)\n } else {\n pending.reject(new Error(res.error))\n }\n }\n\n private rejectAll(err: Error): void {\n for (const [, pending] of this.pending) pending.reject(err)\n this.pending.clear()\n }\n\n private post(req: CsgWorkerRequest): Promise<CsgWorkerResponse> {\n return new Promise<CsgWorkerResponse>((resolve, reject) => {\n this.pending.set(req.id, { resolve: resolve as Pending['resolve'], reject })\n this.worker.postMessage(req)\n })\n }\n\n private async call<T extends CsgWorkerResponse>(\n makeReq: (id: number) => CsgWorkerRequest,\n ): Promise<T> {\n await this.initPromise\n const res = (await this.post(makeReq(this.nextId++))) as T\n return res\n }\n\n async boolean(op: 'union' | 'subtract' | 'intersect', meshes: MeshData[]): Promise<MeshData> {\n const res = await this.call<Extract<CsgWorkerResponse, { kind: 'boolean'; ok: true }>>(\n (id) => ({ id, kind: 'boolean', op, meshes }),\n )\n return res.result\n }\n\n async splitPlane(\n mesh: MeshData,\n plane: PlaneParams,\n ): Promise<{ front: MeshData; back: MeshData }> {\n const res = await this.call<Extract<CsgWorkerResponse, { kind: 'splitPlane'; ok: true }>>(\n (id) => ({ id, kind: 'splitPlane', mesh, plane }),\n )\n return res.result\n }\n\n async splitDovetail(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n bboxWidthOnWidthDir: number\n groove: import('../cad-runtime/ports').DovetailGrooveParams\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitDovetail', mesh, params }),\n )\n return res.result\n }\n\n async splitDowel(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n dowel: import('../cad-runtime/ports').DowelSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitDowel', mesh, params }),\n )\n return res.result\n }\n\n async splitStraightTenon(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n tenon: import('../cad-runtime/ports').StraightTenonSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitStraightTenon', mesh, params }),\n )\n return res.result\n }\n\n /** 终止 worker(宿主生命周期管理用;terminate 后本实例不可再用) */\n terminate(): void {\n this.rejectAll(new Error('CSG worker 已终止'))\n this.worker.terminate()\n }\n}\n"]}
1
+ {"version":3,"file":"worker-csg-backend.js","sourceRoot":"","sources":["../../src/browser-host/worker-csg-backend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WorkerCsgBackend — 经 Web Worker 跑 CSG 后端(csg-worker)\n *\n * 与 InlineCsgBackend 的行为一致(共用 csg-core 同一套纯函数),\n * 区别是 manifold WASM 计算在独立 Worker 线程执行,不阻塞 UI。\n *\n * 构造时即向 worker 发送 init 握手(携带 wasm 地址,取自 manifold-loader 的\n * setManifoldWasmUrl 配置),后续每个 op 自动等待握手完成。\n */\n\nimport type { CsgBackend, MeshData, PlaneParams, SplitResult } from '../cad-runtime/ports'\nimport type {\n CsgWorkerRequest,\n CsgWorkerResponse,\n} from './csg-worker-protocol'\nimport { getManifoldWasmUrl } from '../mesh/manifold-loader'\n\ninterface Pending {\n resolve: (result: unknown) => void\n reject: (err: Error) => void\n}\n\n/**\n * WorkerCsgBackend is a CSG backend that runs manifold-3d in a Web Worker.\n *\n * It behaves identically to the InlineCsgBackend (both share the same pure\n * functions from csg-core), except that the manifold WASM computation happens\n * on a dedicated worker thread so the UI is not blocked. The constructor sends\n * the init handshake carrying the worker's wasm URL immediately (read from the\n * manifold-loader configuration); every subsequent operation awaits that\n * handshake.\n */\nexport class WorkerCsgBackend implements CsgBackend {\n private worker: Worker\n private nextId = 1\n private pending = new Map<number, Pending>()\n private initPromise: Promise<void>\n\n constructor() {\n this.worker = new Worker(new URL('./csg-worker.ts', import.meta.url), { type: 'module' })\n this.worker.onmessage = (ev: MessageEvent<CsgWorkerResponse>) => {\n this.handleMessage(ev.data)\n }\n this.worker.onerror = (ev) => {\n const err = new Error(`CSG worker 错误:${ev.message || '未知错误'}`)\n this.rejectAll(err)\n }\n this.initPromise = this.post({ id: 0, kind: 'init', wasmUrl: getManifoldWasmUrl() })\n .then(() => undefined)\n }\n\n private handleMessage(res: CsgWorkerResponse): void {\n const pending = this.pending.get(res.id)\n if (!pending) return\n this.pending.delete(res.id)\n if (res.ok) {\n pending.resolve(res)\n } else {\n pending.reject(new Error(res.error))\n }\n }\n\n private rejectAll(err: Error): void {\n for (const [, pending] of this.pending) pending.reject(err)\n this.pending.clear()\n }\n\n private post(req: CsgWorkerRequest): Promise<CsgWorkerResponse> {\n return new Promise<CsgWorkerResponse>((resolve, reject) => {\n this.pending.set(req.id, { resolve: resolve as Pending['resolve'], reject })\n this.worker.postMessage(req)\n })\n }\n\n private async call<T extends CsgWorkerResponse>(\n makeReq: (id: number) => CsgWorkerRequest,\n ): Promise<T> {\n await this.initPromise\n const res = (await this.post(makeReq(this.nextId++))) as T\n return res\n }\n\n async boolean(op: 'union' | 'subtract' | 'intersect', meshes: MeshData[]): Promise<MeshData> {\n const res = await this.call<Extract<CsgWorkerResponse, { kind: 'boolean'; ok: true }>>(\n (id) => ({ id, kind: 'boolean', op, meshes }),\n )\n return res.result\n }\n\n async splitPlane(\n mesh: MeshData,\n plane: PlaneParams,\n ): Promise<{ front: MeshData; back: MeshData }> {\n const res = await this.call<Extract<CsgWorkerResponse, { kind: 'splitPlane'; ok: true }>>(\n (id) => ({ id, kind: 'splitPlane', mesh, plane }),\n )\n return res.result\n }\n\n async splitDovetail(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n bboxWidthOnWidthDir: number\n groove: import('../cad-runtime/ports').DovetailGrooveParams\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitDovetail', mesh, params }),\n )\n return res.result\n }\n\n async splitDowel(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n dowel: import('../cad-runtime/ports').DowelSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitDowel', mesh, params }),\n )\n return res.result\n }\n\n async splitStraightTenon(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n tenon: import('../cad-runtime/ports').StraightTenonSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult> {\n const res = await this.call<\n Extract<CsgWorkerResponse, { kind: 'splitDovetail' | 'splitDowel' | 'splitStraightTenon'; ok: true }>\n >(\n (id) => ({ id, kind: 'splitStraightTenon', mesh, params }),\n )\n return res.result\n }\n\n /** 终止 worker(宿主生命周期管理用;terminate 后本实例不可再用) */\n terminate(): void {\n this.rejectAll(new Error('CSG worker 已终止'))\n this.worker.terminate()\n }\n}\n"]}
@@ -43,7 +43,7 @@ export interface CsgBackend {
43
43
  }>;
44
44
  splitDovetail(mesh: MeshData, params: {
45
45
  planeNormal: [number, number, number];
46
- planeOriginOffset: number;
46
+ planeDistance: number;
47
47
  planeCenter: [number, number, number];
48
48
  widthDir: [number, number, number];
49
49
  bboxWidthOnWidthDir: number;
@@ -51,7 +51,7 @@ export interface CsgBackend {
51
51
  }): Promise<SplitResult>;
52
52
  splitDowel(mesh: MeshData, params: {
53
53
  planeNormal: [number, number, number];
54
- planeOriginOffset: number;
54
+ planeDistance: number;
55
55
  planeCenter: [number, number, number];
56
56
  widthDir: [number, number, number];
57
57
  dowel: DowelSplitParams;
@@ -59,7 +59,7 @@ export interface CsgBackend {
59
59
  }): Promise<SplitResult>;
60
60
  splitStraightTenon(mesh: MeshData, params: {
61
61
  planeNormal: [number, number, number];
62
- planeOriginOffset: number;
62
+ planeDistance: number;
63
63
  planeCenter: [number, number, number];
64
64
  widthDir: [number, number, number];
65
65
  tenon: StraightTenonSplitParams;
@@ -1 +1 @@
1
- {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/cad-runtime/ports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/cad-runtime/ports.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/cad-runtime/ports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * Ports 接口定义 — Host 注入的环境能力\n *\n *\n * L2 CadRuntime 通过这些接口获取所有环境能力(CSG 计算、SDF 求值、字体、纹理、资产、事件)。\n * 不直接 import 任何 ?worker、window、document、zustand store——这些由 Host 实现。\n *\n * 两个宿主各自实现:\n * - browser host: WorkerCsgBackend / WorkerSdfBackend / BrowserFontProvider / ...\n * - node host (P3): InlineCsgBackend / InlineSdfBackend / NodeFontProvider / ...\n */\n\nimport type { PartName } from '../identity'\nimport type { StdlibNamespace } from '../runtime-state'\n\n// ── 共享类型 ──\n\n/** 网格数据(与 csg.ts ManifoldMeshData 同构) */\nexport interface MeshData {\n positions: Float32Array\n indices: Uint32Array\n}\n\n/** 平面参数 */\nexport interface PlaneParams {\n normal: [number, number, number]\n offset: number\n}\n\n// Re-export joinery param types from boolean/geo-convert to ensure\n// structural identity across CsgBackend interface and implementations.\nexport type {\n DovetailGrooveParams,\n DowelSplitParams,\n StraightTenonSplitParams,\n} from '../boolean/geo-convert'\nimport type {\n DovetailGrooveParams,\n DowelSplitParams,\n StraightTenonSplitParams,\n} from '../boolean/geo-convert'\n\n/** 分割结果 */\nexport interface SplitResult {\n front: MeshData\n back: MeshData\n wedge: MeshData | null\n}\n\n// ── CsgBackend ──\n\n/**\n * CSG 后端接口 — mesh 路径的布尔/分割操作。\n *\n * browser 实现:WorkerCsgBackend(经 csg-worker postMessage)\n * node 实现 (P3):InlineCsgBackend(主线程直跑 manifold-3d)\n */\nexport interface CsgBackend {\n boolean(op: 'union' | 'subtract' | 'intersect', meshes: MeshData[]): Promise<MeshData>\n splitPlane(mesh: MeshData, plane: PlaneParams): Promise<{ front: MeshData; back: MeshData }>\n splitDovetail(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n bboxWidthOnWidthDir: number\n groove: DovetailGrooveParams\n },\n ): Promise<SplitResult>\n splitDowel(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n dowel: DowelSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult>\n splitStraightTenon(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeOriginOffset: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n tenon: StraightTenonSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult>\n}\n\n// ── SdfBackend ──\n\n/**\n * SDF 后端接口 — SDF 求值。\n *\n * browser 实现:WorkerSdfBackend(经 sdf-worker postMessage)\n * node 实现 (P3):InlineSdfBackend(主线程直跑)\n */\nexport interface SdfBackend {\n runSdf(\n code: string,\n params: Record<string, number>,\n bounds: [number, number, number, number, number, number],\n edgeLength: number,\n level?: number,\n tolerance?: number,\n ): Promise<MeshData>\n}\n\n// ── FontProvider ──\n\n/**\n * 字体提供者接口。\n *\n * browser 实现:BrowserFontProvider(?url + fetch + fontRegistry DI)\n * node 实现 (P3):NodeFontProvider(fs 字体加载)\n */\nexport interface FontProvider {\n /** 加载字体字节(按 key/path),返回 ArrayBuffer */\n loadFont(key: string): Promise<ArrayBuffer>\n /** 列出可用字体 key(node 端为资产目录,browser 端为注册表) */\n listFonts(): string[]\n}\n\n// ── TextureSampler ──\n\n/**\n * 纹理采样接口 — knurl 纹理。\n *\n * browser 实现:CanvasTextureSampler(Image + canvas)\n * node 实现 (P3):纯数据解码\n */\nexport interface TextureSampler {\n /** 采样纹理在 (u, v) 处的值 [0,1] */\n sample(u: number, v: number): number\n /** 纹理尺寸 */\n readonly width: number\n readonly height: number\n}\n\n// ── AssetResolver ──\n\n/**\n * 资产解析接口 — load* 操作的字节来源。\n *\n * browser 实现:FaicadAssetResolver(faicad 会话缓存)\n * node 实现 (P3):FsAssetResolver(--assets 目录/manifest)\n */\nexport interface AssetResolver {\n /** loadByKey 的 headless 等价物 */\n resolveByKey(key: string): Promise<{ bytes: ArrayBuffer; format?: string }>\n /** 本地文件路径(browser 下抛错) */\n resolveFile(path: string): Promise<ArrayBuffer>\n /** 网络 URL(两环境通用) */\n resolveUrl(url: string): Promise<ArrayBuffer>\n}\n\n// ── EventSink ──\n\n/**\n * 事件通知接口 — BREP 丢失等事件。\n *\n * browser 实现:BrowserEventSink(window.dispatchEvent → toast)\n * node 实现 (P3):CliEventSink(写入 stderr + 收集到 events 数组)\n */\nexport interface EventSink {\n emit(event: 'part-brep-lost', detail: { partName: PartName; callee: string; reason: string }): void\n}\n\n// ── LibLoader ──\n\n/**\n * 库加载器接口 — 按 packageName 自动装载未注册的第三方库。\n *\n * 宿主实现:\n * - node CLI(createNodePorts):白名单 + Node 原生 `import(name)`(monorepo\n * workspace symlink 直接把裸包解析到包源码)。\n * - browser / demo:静态 `LIB_MODULES` 映射表(value 必须是静态字面量\n * specifier,Vite/Rollup 才能静态分析打包;禁止变量传参的 import(name))。\n * - vitest:复用浏览器映射表写法 + `await import('@faicad/…')`(alias 落位活源码)。\n */\nexport interface LibLoader {\n /** 按 packageName 加载库模块,返回其导出命名空间对象(与 registerLib 的 ns 同形)。 */\n loadLib(packageName: string): Promise<StdlibNamespace>\n /** 列出当前可加载的 packageName(check 阶段同步校验 import specifier 用)。 */\n listLibs(): string[]\n /** 自动装载的注册选项;缺省由推断式决定(有 dual-op 的库不提升,全裸函数库自动提升,与手动注入一致)。 */\n options?: {\n autoLift?: boolean\n /**\n * 按 packageName 的逐库 `autoLift` 覆盖(优先于 `options.autoLift`)。\n * 返回 `undefined` 时回落到全局选项 / 推断式。用于别名库:如 cq-compat 在\n * 浏览器 host 被全局 autoLift 提升后,compat 边界的 borrowDeep 会把实参里的\n * faijs Shape 替换成 brepjs 借用视图,破坏其内部「以 Shape 受众」的借面逻辑\n * (原 CLI 即按 autoLift=false 运行)。逐库关掉提升恢复 CLI 等价行为。\n */\n autoLiftFor?: (packageName: string) => boolean | undefined\n }\n /**\n * 可选源码扫描钩子(§6.2 ②):宿主返回库源码时走同一 SecurityScanner(A4,固定 strict);\n * 不提供或返回 undefined 则跳过。不改 loadLib 返回值——返回 StdlibNamespace,\n * 往里挂 source 会被 admitCompatLib 当成导出值并污染命名空间。\n * @param packageName - the npm package name.\n * @returns the library source text if available, otherwise undefined.\n */\n loadSource?(packageName: string): Promise<string | undefined>\n}\n\n// ── ProjectLoader ──\n\n/**\n * 项目文件加载器(多文件,§4.5)——按 moduleKey 读取/枚举项目内 .fai.js 模块源码。\n *\n * moduleKey 约定:host 决定字符串形态(项目根相对路径等);引擎只做最小归一\n * (POSIX 斜杠、去掉 `./`/`../`/前导 `/` 前缀),随后按 `listModules()` 精确匹配。\n *\n * host 实现:\n * - 3d_editor / browser:项目文件表 + session 内缓存;\n * - node / vitest:内存映射表或 fs 读取(fixture 目录)。\n */\nexport interface ProjectLoader {\n /** 列出当前可加载的 moduleKey(装载前预检 / 错误提示用)。 */\n listModules(): string[]\n /** 按 moduleKey 读取模块源码(.fai.js 文本)。 */\n readSource(moduleKey: string): Promise<string>\n /** 模块内容指纹(增量缓存用;不提供则每次全量重读重执行)。 */\n fingerprint?(moduleKey: string): Promise<string>\n}\n\n// ── HostPorts 汇总 ──\n\n/**\n * Host 在 createRuntime 时注入的全部环境能力。\n *\n * 所有字段可选——node 测试环境可只提供 occt kernel(不注入 csg/sdf),\n * BREP-path ops 不依赖这些 Port。\n */\nexport interface HostPorts {\n csg?: CsgBackend\n sdf?: SdfBackend\n fonts?: FontProvider\n texture?: TextureSampler\n assets?: AssetResolver\n events: EventSink // events 必填——断链通知是基础能力\n /** 库加载器(execute 自动装载未注册库;check 用它做 specifier 预检)。可选——无则仅手工 registerLib。 */\n libLoader?: LibLoader\n /** 项目文件加载器(相对 specifier 的多文件模块,§4.5)。可选——不提供则单文件行为不变。 */\n projectLoader?: ProjectLoader\n}\n\n// ── 执行模式 ──\n\n/**\n * 执行模式(设计文档 §4.4)。\n *\n * - `auto`(默认):优先 BREP,断链后自动切 mesh + EventSink 通知\n * - `brep`:强制 BREP,断链即报错 E_BREP_UNSUPPORTED,不自动切换\n * - `mesh`:全部走 mesh 路径\n */\nexport type ExecutionMode = 'auto' | 'brep' | 'mesh'\n"]}
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/cad-runtime/ports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG","sourcesContent":["/**\n * Ports 接口定义 — Host 注入的环境能力\n *\n *\n * L2 CadRuntime 通过这些接口获取所有环境能力(CSG 计算、SDF 求值、字体、纹理、资产、事件)。\n * 不直接 import 任何 ?worker、window、document、zustand store——这些由 Host 实现。\n *\n * 两个宿主各自实现:\n * - browser host: WorkerCsgBackend / WorkerSdfBackend / BrowserFontProvider / ...\n * - node host (P3): InlineCsgBackend / InlineSdfBackend / NodeFontProvider / ...\n */\n\nimport type { PartName } from '../identity'\nimport type { StdlibNamespace } from '../runtime-state'\n\n// ── 共享类型 ──\n\n/** 网格数据(与 csg.ts ManifoldMeshData 同构) */\nexport interface MeshData {\n positions: Float32Array\n indices: Uint32Array\n}\n\n/** 平面参数 */\nexport interface PlaneParams {\n normal: [number, number, number]\n offset: number\n}\n\n// Re-export joinery param types from boolean/geo-convert to ensure\n// structural identity across CsgBackend interface and implementations.\nexport type {\n DovetailGrooveParams,\n DowelSplitParams,\n StraightTenonSplitParams,\n} from '../boolean/geo-convert'\nimport type {\n DovetailGrooveParams,\n DowelSplitParams,\n StraightTenonSplitParams,\n} from '../boolean/geo-convert'\n\n/** 分割结果 */\nexport interface SplitResult {\n front: MeshData\n back: MeshData\n wedge: MeshData | null\n}\n\n// ── CsgBackend ──\n\n/**\n * CSG 后端接口 — mesh 路径的布尔/分割操作。\n *\n * browser 实现:WorkerCsgBackend(经 csg-worker postMessage)\n * node 实现 (P3):InlineCsgBackend(主线程直跑 manifold-3d)\n */\nexport interface CsgBackend {\n boolean(op: 'union' | 'subtract' | 'intersect', meshes: MeshData[]): Promise<MeshData>\n splitPlane(mesh: MeshData, plane: PlaneParams): Promise<{ front: MeshData; back: MeshData }>\n splitDovetail(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n bboxWidthOnWidthDir: number\n groove: DovetailGrooveParams\n },\n ): Promise<SplitResult>\n splitDowel(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n dowel: DowelSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult>\n splitStraightTenon(\n mesh: MeshData,\n params: {\n planeNormal: [number, number, number]\n planeDistance: number\n planeCenter: [number, number, number]\n widthDir: [number, number, number]\n tenon: StraightTenonSplitParams\n selectedSections?: number[] | null\n },\n ): Promise<SplitResult>\n}\n\n// ── SdfBackend ──\n\n/**\n * SDF 后端接口 — SDF 求值。\n *\n * browser 实现:WorkerSdfBackend(经 sdf-worker postMessage)\n * node 实现 (P3):InlineSdfBackend(主线程直跑)\n */\nexport interface SdfBackend {\n runSdf(\n code: string,\n params: Record<string, number>,\n bounds: [number, number, number, number, number, number],\n edgeLength: number,\n level?: number,\n tolerance?: number,\n ): Promise<MeshData>\n}\n\n// ── FontProvider ──\n\n/**\n * 字体提供者接口。\n *\n * browser 实现:BrowserFontProvider(?url + fetch + fontRegistry DI)\n * node 实现 (P3):NodeFontProvider(fs 字体加载)\n */\nexport interface FontProvider {\n /** 加载字体字节(按 key/path),返回 ArrayBuffer */\n loadFont(key: string): Promise<ArrayBuffer>\n /** 列出可用字体 key(node 端为资产目录,browser 端为注册表) */\n listFonts(): string[]\n}\n\n// ── TextureSampler ──\n\n/**\n * 纹理采样接口 — knurl 纹理。\n *\n * browser 实现:CanvasTextureSampler(Image + canvas)\n * node 实现 (P3):纯数据解码\n */\nexport interface TextureSampler {\n /** 采样纹理在 (u, v) 处的值 [0,1] */\n sample(u: number, v: number): number\n /** 纹理尺寸 */\n readonly width: number\n readonly height: number\n}\n\n// ── AssetResolver ──\n\n/**\n * 资产解析接口 — load* 操作的字节来源。\n *\n * browser 实现:FaicadAssetResolver(faicad 会话缓存)\n * node 实现 (P3):FsAssetResolver(--assets 目录/manifest)\n */\nexport interface AssetResolver {\n /** loadByKey 的 headless 等价物 */\n resolveByKey(key: string): Promise<{ bytes: ArrayBuffer; format?: string }>\n /** 本地文件路径(browser 下抛错) */\n resolveFile(path: string): Promise<ArrayBuffer>\n /** 网络 URL(两环境通用) */\n resolveUrl(url: string): Promise<ArrayBuffer>\n}\n\n// ── EventSink ──\n\n/**\n * 事件通知接口 — BREP 丢失等事件。\n *\n * browser 实现:BrowserEventSink(window.dispatchEvent → toast)\n * node 实现 (P3):CliEventSink(写入 stderr + 收集到 events 数组)\n */\nexport interface EventSink {\n emit(event: 'part-brep-lost', detail: { partName: PartName; callee: string; reason: string }): void\n}\n\n// ── LibLoader ──\n\n/**\n * 库加载器接口 — 按 packageName 自动装载未注册的第三方库。\n *\n * 宿主实现:\n * - node CLI(createNodePorts):白名单 + Node 原生 `import(name)`(monorepo\n * workspace symlink 直接把裸包解析到包源码)。\n * - browser / demo:静态 `LIB_MODULES` 映射表(value 必须是静态字面量\n * specifier,Vite/Rollup 才能静态分析打包;禁止变量传参的 import(name))。\n * - vitest:复用浏览器映射表写法 + `await import('@faicad/…')`(alias 落位活源码)。\n */\nexport interface LibLoader {\n /** 按 packageName 加载库模块,返回其导出命名空间对象(与 registerLib 的 ns 同形)。 */\n loadLib(packageName: string): Promise<StdlibNamespace>\n /** 列出当前可加载的 packageName(check 阶段同步校验 import specifier 用)。 */\n listLibs(): string[]\n /** 自动装载的注册选项;缺省由推断式决定(有 dual-op 的库不提升,全裸函数库自动提升,与手动注入一致)。 */\n options?: {\n autoLift?: boolean\n /**\n * 按 packageName 的逐库 `autoLift` 覆盖(优先于 `options.autoLift`)。\n * 返回 `undefined` 时回落到全局选项 / 推断式。用于别名库:如 cq-compat 在\n * 浏览器 host 被全局 autoLift 提升后,compat 边界的 borrowDeep 会把实参里的\n * faijs Shape 替换成 brepjs 借用视图,破坏其内部「以 Shape 受众」的借面逻辑\n * (原 CLI 即按 autoLift=false 运行)。逐库关掉提升恢复 CLI 等价行为。\n */\n autoLiftFor?: (packageName: string) => boolean | undefined\n }\n /**\n * 可选源码扫描钩子(§6.2 ②):宿主返回库源码时走同一 SecurityScanner(A4,固定 strict);\n * 不提供或返回 undefined 则跳过。不改 loadLib 返回值——返回 StdlibNamespace,\n * 往里挂 source 会被 admitCompatLib 当成导出值并污染命名空间。\n * @param packageName - the npm package name.\n * @returns the library source text if available, otherwise undefined.\n */\n loadSource?(packageName: string): Promise<string | undefined>\n}\n\n// ── ProjectLoader ──\n\n/**\n * 项目文件加载器(多文件,§4.5)——按 moduleKey 读取/枚举项目内 .fai.js 模块源码。\n *\n * moduleKey 约定:host 决定字符串形态(项目根相对路径等);引擎只做最小归一\n * (POSIX 斜杠、去掉 `./`/`../`/前导 `/` 前缀),随后按 `listModules()` 精确匹配。\n *\n * host 实现:\n * - 3d_editor / browser:项目文件表 + session 内缓存;\n * - node / vitest:内存映射表或 fs 读取(fixture 目录)。\n */\nexport interface ProjectLoader {\n /** 列出当前可加载的 moduleKey(装载前预检 / 错误提示用)。 */\n listModules(): string[]\n /** 按 moduleKey 读取模块源码(.fai.js 文本)。 */\n readSource(moduleKey: string): Promise<string>\n /** 模块内容指纹(增量缓存用;不提供则每次全量重读重执行)。 */\n fingerprint?(moduleKey: string): Promise<string>\n}\n\n// ── HostPorts 汇总 ──\n\n/**\n * Host 在 createRuntime 时注入的全部环境能力。\n *\n * 所有字段可选——node 测试环境可只提供 occt kernel(不注入 csg/sdf),\n * BREP-path ops 不依赖这些 Port。\n */\nexport interface HostPorts {\n csg?: CsgBackend\n sdf?: SdfBackend\n fonts?: FontProvider\n texture?: TextureSampler\n assets?: AssetResolver\n events: EventSink // events 必填——断链通知是基础能力\n /** 库加载器(execute 自动装载未注册库;check 用它做 specifier 预检)。可选——无则仅手工 registerLib。 */\n libLoader?: LibLoader\n /** 项目文件加载器(相对 specifier 的多文件模块,§4.5)。可选——不提供则单文件行为不变。 */\n projectLoader?: ProjectLoader\n}\n\n// ── 执行模式 ──\n\n/**\n * 执行模式(设计文档 §4.4)。\n *\n * - `auto`(默认):优先 BREP,断链后自动切 mesh + EventSink 通知\n * - `brep`:强制 BREP,断链即报错 E_BREP_UNSUPPORTED,不自动切换\n * - `mesh`:全部走 mesh 路径\n */\nexport type ExecutionMode = 'auto' | 'brep' | 'mesh'\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Adaptors from legacy profile-segment shapes to `Curve2dObj` (pure-data).
3
+ *
4
+ * faijs `cad.profile` historically fed its own `ProfileLineSeg`/`ProfileArcSeg`
5
+ * segment model directly into OCCT edge construction. To unify every 2D input on
6
+ * the pure-2D `Geometry2dObj` base (plan F2), this module converts those segment
7
+ * shapes into `Curve2dObj` without importing `api/` (the input types are declared
8
+ * structurally here; `api/profile.ts`'s `ProfileSeg` is structurally compatible).
9
+ *
10
+ * @module
11
+ */
12
+ import type { Curve2dObj } from './curve2d.js';
13
+ /** Line segment in profile form (2D, z=0). */
14
+ export interface ProfileLineSegLike {
15
+ kind: 'line';
16
+ x1: number;
17
+ y1: number;
18
+ x2: number;
19
+ y2: number;
20
+ }
21
+ /** Arc segment in profile form (2D, z=0). `x1/y1/x2/y2` are the sampled arc
22
+ * endpoints, but many inputs omit them (e.g. FCBL corpus), so endpoints are
23
+ * always re-derived from `(cx, cy, radius, startAngle, endAngle)` — matching
24
+ * the original kernel construction. */
25
+ export interface ProfileArcSegLike {
26
+ kind: 'arc';
27
+ cx: number;
28
+ cy: number;
29
+ radius: number;
30
+ startAngle: number;
31
+ endAngle: number;
32
+ ccw: boolean;
33
+ x1?: number;
34
+ y1?: number;
35
+ x2?: number;
36
+ y2?: number;
37
+ }
38
+ /** A profile segment: either a profile line or a profile arc. */
39
+ export type ProfileSegLike = ProfileLineSegLike | ProfileArcSegLike;
40
+ /**
41
+ * Convert a single profile segment to the equivalent 2D curve.
42
+ * @param seg - the profile line or arc segment.
43
+ * @returns the equivalent `Curve2dObj` (line, trimmed arc, or full circle).
44
+ */
45
+ export declare function profileSegToCurve(seg: ProfileSegLike): Curve2dObj;
46
+ //# sourceMappingURL=adapt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapt.d.ts","sourceRoot":"","sources":["../../src/geometry2d/adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAG3C,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX;AAED;;;uCAGuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,OAAO,CAAA;IACZ,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,iEAAiE;AACjE,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,CAAA;AAEnE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,UAAU,CA4BjE"}
@@ -0,0 +1,41 @@
1
+ import { makeLine2d, makeArc2dThreePoints, makeCircle2d } from './curve2d.js';
2
+ /**
3
+ * Convert a single profile segment to the equivalent 2D curve.
4
+ * @param seg - the profile line or arc segment.
5
+ * @returns the equivalent `Curve2dObj` (line, trimmed arc, or full circle).
6
+ */
7
+ export function profileSegToCurve(seg) {
8
+ if (seg.kind === 'line')
9
+ return makeLine2d(seg.x1, seg.y1, seg.x2, seg.y2);
10
+ // GOTCHA(2026-09-25, A3 FCBL_tree_entourage):`ccw` 决定几何方向,非元数据。
11
+ // CW 弧的正向扫角是 startAngle→endAngle **递减**:不能沿用 `endAngle−startAngle`
12
+ // 再归一化到 (0,2π],那样会把短 CW 弧(如 65°)算成 CCW 的补角长弧
13
+ // (294°),使 makeArcEdge 收到穿过旋转轴的补角弧 → revolve 退化 → BRepMesh 挂死
14
+ // (进程无声死亡,正被 sketch-arc-ccw-gotcha.test.ts 护栏锁定)。
15
+ // 归一化沿用 brepjs/旧 `arcToHandles`:`while` 平移而非 `%`(`%` 会把
16
+ // 恰为 2π 的整圆扫角消成 0——fp 上 `x % x === 0`——把整圆误判成退化线段)。
17
+ let sweep = seg.ccw ? seg.endAngle - seg.startAngle : seg.startAngle - seg.endAngle;
18
+ while (sweep <= 0)
19
+ sweep += 2 * Math.PI;
20
+ while (sweep > 2 * Math.PI)
21
+ sweep -= 2 * Math.PI;
22
+ // 极小扫角(退化弧)→ 退化为线段。
23
+ if (sweep < 1e-9)
24
+ return makeLine2d(seg.cx + seg.radius * Math.cos(seg.startAngle), seg.cy + seg.radius * Math.sin(seg.startAngle), seg.cx + seg.radius * Math.cos(seg.endAngle), seg.cy + seg.radius * Math.sin(seg.endAngle));
25
+ // 整圆(扫 ≈ 2π,起点≈终点)须保留为真圆:三点构造过奇异点退化(→line)。
26
+ if (sweep >= 2 * Math.PI - 1e-9)
27
+ return makeCircle2d(seg.cx, seg.cy, seg.radius, seg.ccw);
28
+ // 端点/中点一律由 (cx, cy, radius, angle) 解析(缺失 x1/y1/x2/y2 时仍精确),
29
+ // 与旧 `arcToHandles` 一致:这样相邻线段的接缝点完全重合,wire 闭合。
30
+ const sx = seg.cx + seg.radius * Math.cos(seg.startAngle);
31
+ const sy = seg.cy + seg.radius * Math.sin(seg.startAngle);
32
+ const ex = seg.cx + seg.radius * Math.cos(seg.endAngle);
33
+ const ey = seg.cy + seg.radius * Math.sin(seg.endAngle);
34
+ // 几何中点:CCW 从 startAngle 顺向 +sweep/2;CW 从 startAngle 反向 −sweep/2;
35
+ // 三点(起点/中点/终点)定唯一弧。
36
+ const midAngle = seg.ccw ? seg.startAngle + sweep / 2 : seg.startAngle - sweep / 2;
37
+ const mx = seg.cx + seg.radius * Math.cos(midAngle);
38
+ const my = seg.cy + seg.radius * Math.sin(midAngle);
39
+ return makeArc2dThreePoints(sx, sy, mx, my, ex, ey);
40
+ }
41
+ //# sourceMappingURL=adapt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapt.js","sourceRoot":"","sources":["../../src/geometry2d/adapt.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAgC1E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IAC1E,gEAAgE;IAChE,mEAAmE;IACnE,6CAA6C;IAC7C,8DAA8D;IAC9D,kDAAkD;IAClD,wDAAwD;IACxD,oDAAoD;IACpD,IAAI,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAA;IACnF,OAAO,KAAK,IAAI,CAAC;QAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAA;IACvC,OAAO,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE;QAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAA;IAChD,oBAAoB;IACpB,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC/N,4CAA4C;IAC5C,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI;QAAE,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IACzF,4DAA4D;IAC5D,+CAA+C;IAC/C,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACzD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACzD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACvD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACvD,iEAAiE;IACjE,oBAAoB;IACpB,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,KAAK,GAAG,CAAC,CAAA;IAClF,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnD,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnD,OAAO,oBAAoB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AACrD,CAAC","sourcesContent":["/**\n * Adaptors from legacy profile-segment shapes to `Curve2dObj` (pure-data).\n *\n * faijs `cad.profile` historically fed its own `ProfileLineSeg`/`ProfileArcSeg`\n * segment model directly into OCCT edge construction. To unify every 2D input on\n * the pure-2D `Geometry2dObj` base (plan F2), this module converts those segment\n * shapes into `Curve2dObj` without importing `api/` (the input types are declared\n * structurally here; `api/profile.ts`'s `ProfileSeg` is structurally compatible).\n *\n * @module\n */\nimport type { Curve2dObj } from './curve2d'\nimport { makeLine2d, makeArc2dThreePoints, makeCircle2d } from './curve2d'\n\n/** Line segment in profile form (2D, z=0). */\nexport interface ProfileLineSegLike {\n kind: 'line'\n x1: number\n y1: number\n x2: number\n y2: number\n}\n\n/** Arc segment in profile form (2D, z=0). `x1/y1/x2/y2` are the sampled arc\n * endpoints, but many inputs omit them (e.g. FCBL corpus), so endpoints are\n * always re-derived from `(cx, cy, radius, startAngle, endAngle)` — matching\n * the original kernel construction. */\nexport interface ProfileArcSegLike {\n kind: 'arc'\n cx: number\n cy: number\n radius: number\n startAngle: number\n endAngle: number\n ccw: boolean\n x1?: number\n y1?: number\n x2?: number\n y2?: number\n}\n\n/** A profile segment: either a profile line or a profile arc. */\nexport type ProfileSegLike = ProfileLineSegLike | ProfileArcSegLike\n\n/**\n * Convert a single profile segment to the equivalent 2D curve.\n * @param seg - the profile line or arc segment.\n * @returns the equivalent `Curve2dObj` (line, trimmed arc, or full circle).\n */\nexport function profileSegToCurve(seg: ProfileSegLike): Curve2dObj {\n if (seg.kind === 'line') return makeLine2d(seg.x1, seg.y1, seg.x2, seg.y2)\n // GOTCHA(2026-09-25, A3 FCBL_tree_entourage):`ccw` 决定几何方向,非元数据。\n // CW 弧的正向扫角是 startAngle→endAngle **递减**:不能沿用 `endAngle−startAngle`\n // 再归一化到 (0,2π],那样会把短 CW 弧(如 65°)算成 CCW 的补角长弧\n // (294°),使 makeArcEdge 收到穿过旋转轴的补角弧 → revolve 退化 → BRepMesh 挂死\n // (进程无声死亡,正被 sketch-arc-ccw-gotcha.test.ts 护栏锁定)。\n // 归一化沿用 brepjs/旧 `arcToHandles`:`while` 平移而非 `%`(`%` 会把\n // 恰为 2π 的整圆扫角消成 0——fp 上 `x % x === 0`——把整圆误判成退化线段)。\n let sweep = seg.ccw ? seg.endAngle - seg.startAngle : seg.startAngle - seg.endAngle\n while (sweep <= 0) sweep += 2 * Math.PI\n while (sweep > 2 * Math.PI) sweep -= 2 * Math.PI\n // 极小扫角(退化弧)→ 退化为线段。\n if (sweep < 1e-9) return makeLine2d(seg.cx + seg.radius * Math.cos(seg.startAngle), seg.cy + seg.radius * Math.sin(seg.startAngle), seg.cx + seg.radius * Math.cos(seg.endAngle), seg.cy + seg.radius * Math.sin(seg.endAngle))\n // 整圆(扫 ≈ 2π,起点≈终点)须保留为真圆:三点构造过奇异点退化(→line)。\n if (sweep >= 2 * Math.PI - 1e-9) return makeCircle2d(seg.cx, seg.cy, seg.radius, seg.ccw)\n // 端点/中点一律由 (cx, cy, radius, angle) 解析(缺失 x1/y1/x2/y2 时仍精确),\n // 与旧 `arcToHandles` 一致:这样相邻线段的接缝点完全重合,wire 闭合。\n const sx = seg.cx + seg.radius * Math.cos(seg.startAngle)\n const sy = seg.cy + seg.radius * Math.sin(seg.startAngle)\n const ex = seg.cx + seg.radius * Math.cos(seg.endAngle)\n const ey = seg.cy + seg.radius * Math.sin(seg.endAngle)\n // 几何中点:CCW 从 startAngle 顺向 +sweep/2;CW 从 startAngle 反向 −sweep/2;\n // 三点(起点/中点/终点)定唯一弧。\n const midAngle = seg.ccw ? seg.startAngle + sweep / 2 : seg.startAngle - sweep / 2\n const mx = seg.cx + seg.radius * Math.cos(midAngle)\n const my = seg.cy + seg.radius * Math.sin(midAngle)\n return makeArc2dThreePoints(sx, sy, mx, my, ex, ey)\n}"]}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Axis-aligned 2D bounding box (pure-data; faijs port of brepjs `BoundingBox2d`).
3
+ * brepjs backs this with a kernel `Bnd_Box2d`; here it's plain numbers.
4
+ *
5
+ * License: adapted from brepjs (Apache-2.0).
6
+ * @module
7
+ */
8
+ export interface BBox2d {
9
+ xMin: number;
10
+ yMin: number;
11
+ xMax: number;
12
+ yMax: number;
13
+ }
14
+ /**
15
+ * Create an empty (inverted) bounding box.
16
+ * @returns a fresh BBox2d whose mins are +Infinity and maxes are -Infinity.
17
+ */
18
+ export declare function createBBox2d(): BBox2d;
19
+ /**
20
+ * True when the box holds no finite extent yet.
21
+ * @param bb - the bounding box to test.
22
+ * @returns true when any corner is non-finite or the box is inverted.
23
+ */
24
+ export declare function isEmpty(bb: BBox2d): boolean;
25
+ /**
26
+ * Expand `bb` to include the given corner points.
27
+ * @param bb - the bounding box to expand in place.
28
+ * @param pts - the corner points to include.
29
+ */
30
+ export declare function addPoints(bb: BBox2d, pts: ReadonlyArray<readonly [number, number]>): void;
31
+ /**
32
+ * Expand `bb` to include all points of `other`.
33
+ * @param bb - the box to expand in place.
34
+ * @param other - the box whose extent is folded into `bb`.
35
+ */
36
+ export declare function mergeBBox(bb: BBox2d, other: BBox2d): void;
37
+ /**
38
+ * Return `[min, max]` corner points.
39
+ * @param bb - the bounding box to read from.
40
+ * @returns the lower-left and upper-right corners as `[[xMin,yMin],[xMax,yMax]]`.
41
+ */
42
+ export declare function boundsOf(bb: BBox2d): [[number, number], [number, number]];
43
+ /**
44
+ * Compute the center point of the box.
45
+ * @param bb - the bounding box to read from.
46
+ * @returns the midpoint `[x, y]` between the min and max corners.
47
+ */
48
+ export declare function centerOf(bb: BBox2d): [number, number];
49
+ /**
50
+ * Compute the width of the box.
51
+ * @param bb - the bounding box to read from.
52
+ * @returns the absolute horizontal extent.
53
+ */
54
+ export declare function widthOf(bb: BBox2d): number;
55
+ /**
56
+ * Compute the height of the box.
57
+ * @param bb - the bounding box to read from.
58
+ * @returns the absolute vertical extent.
59
+ */
60
+ export declare function heightOf(bb: BBox2d): number;
61
+ /**
62
+ * Point guaranteed outside (to the upper-right of) the box.
63
+ * @param bb - the bounding box to read from.
64
+ * @param paddingPercent - the padding as a percent of the box extent (default 1).
65
+ * @returns a point offset to the upper-right of `bb`.
66
+ */
67
+ export declare function outsidePointOf(bb: BBox2d, paddingPercent?: number): [number, number];
68
+ /**
69
+ * True if `bb` and `other` are completely disjoint.
70
+ * @param bb - the first bounding box.
71
+ * @param other - the second bounding box.
72
+ * @returns true when the two boxes do not overlap (empty boxes count as disjoint).
73
+ */
74
+ export declare function isBBoxOut(bb: BBox2d, other: BBox2d): boolean;
75
+ /**
76
+ * True if the point lies inside (or on the boundary of) the box.
77
+ * @param bb - the bounding box to test against.
78
+ * @param pt - the 2D point to test, `[x, y]`.
79
+ * @returns true when `pt` is within (or on) the box.
80
+ */
81
+ export declare function containsPoint(bb: BBox2d, pt: readonly [number, number]): boolean;
82
+ //# sourceMappingURL=bbox2d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bbox2d.d.ts","sourceRoot":"","sources":["../../src/geometry2d/bbox2d.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAK3C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAKzD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAKzE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAErD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,SAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAI/E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAI5D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAIhF"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Axis-aligned 2D bounding box (pure-data; faijs port of brepjs `BoundingBox2d`).
3
+ * brepjs backs this with a kernel `Bnd_Box2d`; here it's plain numbers.
4
+ *
5
+ * License: adapted from brepjs (Apache-2.0).
6
+ * @module
7
+ */
8
+ /**
9
+ * Create an empty (inverted) bounding box.
10
+ * @returns a fresh BBox2d whose mins are +Infinity and maxes are -Infinity.
11
+ */
12
+ export function createBBox2d() {
13
+ return { xMin: Infinity, yMin: Infinity, xMax: -Infinity, yMax: -Infinity };
14
+ }
15
+ /**
16
+ * True when the box holds no finite extent yet.
17
+ * @param bb - the bounding box to test.
18
+ * @returns true when any corner is non-finite or the box is inverted.
19
+ */
20
+ export function isEmpty(bb) {
21
+ return (!isFinite(bb.xMin) || !isFinite(bb.yMin) || !isFinite(bb.xMax) || !isFinite(bb.yMax) ||
22
+ bb.xMax < bb.xMin || bb.yMax < bb.yMin);
23
+ }
24
+ /**
25
+ * Expand `bb` to include the given corner points.
26
+ * @param bb - the bounding box to expand in place.
27
+ * @param pts - the corner points to include.
28
+ */
29
+ export function addPoints(bb, pts) {
30
+ for (const [x, y] of pts) {
31
+ if (x < bb.xMin)
32
+ bb.xMin = x;
33
+ if (y < bb.yMin)
34
+ bb.yMin = y;
35
+ if (x > bb.xMax)
36
+ bb.xMax = x;
37
+ if (y > bb.yMax)
38
+ bb.yMax = y;
39
+ }
40
+ }
41
+ /**
42
+ * Expand `bb` to include all points of `other`.
43
+ * @param bb - the box to expand in place.
44
+ * @param other - the box whose extent is folded into `bb`.
45
+ */
46
+ export function mergeBBox(bb, other) {
47
+ if (other.xMin < bb.xMin)
48
+ bb.xMin = other.xMin;
49
+ if (other.yMin < bb.yMin)
50
+ bb.yMin = other.yMin;
51
+ if (other.xMax > bb.xMax)
52
+ bb.xMax = other.xMax;
53
+ if (other.yMax > bb.yMax)
54
+ bb.yMax = other.yMax;
55
+ }
56
+ /**
57
+ * Return `[min, max]` corner points.
58
+ * @param bb - the bounding box to read from.
59
+ * @returns the lower-left and upper-right corners as `[[xMin,yMin],[xMax,yMax]]`.
60
+ */
61
+ export function boundsOf(bb) {
62
+ return [
63
+ [bb.xMin, bb.yMin],
64
+ [bb.xMax, bb.yMax],
65
+ ];
66
+ }
67
+ /**
68
+ * Compute the center point of the box.
69
+ * @param bb - the bounding box to read from.
70
+ * @returns the midpoint `[x, y]` between the min and max corners.
71
+ */
72
+ export function centerOf(bb) {
73
+ return [(bb.xMin + bb.xMax) / 2, (bb.yMin + bb.yMax) / 2];
74
+ }
75
+ /**
76
+ * Compute the width of the box.
77
+ * @param bb - the bounding box to read from.
78
+ * @returns the absolute horizontal extent.
79
+ */
80
+ export function widthOf(bb) {
81
+ return Math.abs(bb.xMax - bb.xMin);
82
+ }
83
+ /**
84
+ * Compute the height of the box.
85
+ * @param bb - the bounding box to read from.
86
+ * @returns the absolute vertical extent.
87
+ */
88
+ export function heightOf(bb) {
89
+ return Math.abs(bb.yMax - bb.yMin);
90
+ }
91
+ /**
92
+ * Point guaranteed outside (to the upper-right of) the box.
93
+ * @param bb - the bounding box to read from.
94
+ * @param paddingPercent - the padding as a percent of the box extent (default 1).
95
+ * @returns a point offset to the upper-right of `bb`.
96
+ */
97
+ export function outsidePointOf(bb, paddingPercent = 1) {
98
+ const width = bb.xMax - bb.xMin;
99
+ const height = bb.yMax - bb.yMin;
100
+ return [bb.xMax + (width / 100) * paddingPercent, bb.yMax + (height / 100) * paddingPercent * 0.9];
101
+ }
102
+ /**
103
+ * True if `bb` and `other` are completely disjoint.
104
+ * @param bb - the first bounding box.
105
+ * @param other - the second bounding box.
106
+ * @returns true when the two boxes do not overlap (empty boxes count as disjoint).
107
+ */
108
+ export function isBBoxOut(bb, other) {
109
+ // Handles degenerate (empty) boxes by treating them as disjoint.
110
+ if (isEmpty(bb) || isEmpty(other))
111
+ return true;
112
+ return other.xMax < bb.xMin || other.xMin > bb.xMax || other.yMax < bb.yMin || other.yMin > bb.yMax;
113
+ }
114
+ /**
115
+ * True if the point lies inside (or on the boundary of) the box.
116
+ * @param bb - the bounding box to test against.
117
+ * @param pt - the 2D point to test, `[x, y]`.
118
+ * @returns true when `pt` is within (or on) the box.
119
+ */
120
+ export function containsPoint(bb, pt) {
121
+ return (pt[0] >= bb.xMin && pt[0] <= bb.xMax && pt[1] >= bb.yMin && pt[1] <= bb.yMax);
122
+ }
123
+ //# sourceMappingURL=bbox2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bbox2d.js","sourceRoot":"","sources":["../../src/geometry2d/bbox2d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Axis-aligned 2D bounding box (pure-data; faijs port of brepjs `BoundingBox2d`).\n * brepjs backs this with a kernel `Bnd_Box2d`; here it's plain numbers.\n *\n * License: adapted from brepjs (Apache-2.0).\n * @module\n */\n\nexport interface BBox2d {\n xMin: number\n yMin: number\n xMax: number\n yMax: number\n}\n\n/**\n * Create an empty (inverted) bounding box.\n * @returns a fresh BBox2d whose mins are +Infinity and maxes are -Infinity.\n */\nexport function createBBox2d(): BBox2d {\n return { xMin: Infinity, yMin: Infinity, xMax: -Infinity, yMax: -Infinity }\n}\n\n/**\n * True when the box holds no finite extent yet.\n * @param bb - the bounding box to test.\n * @returns true when any corner is non-finite or the box is inverted.\n */\nexport function isEmpty(bb: BBox2d): boolean {\n return (\n !isFinite(bb.xMin) || !isFinite(bb.yMin) || !isFinite(bb.xMax) || !isFinite(bb.yMax) ||\n bb.xMax < bb.xMin || bb.yMax < bb.yMin\n )\n}\n\n/**\n * Expand `bb` to include the given corner points.\n * @param bb - the bounding box to expand in place.\n * @param pts - the corner points to include.\n */\nexport function addPoints(bb: BBox2d, pts: ReadonlyArray<readonly [number, number]>): void {\n for (const [x, y] of pts) {\n if (x < bb.xMin) bb.xMin = x\n if (y < bb.yMin) bb.yMin = y\n if (x > bb.xMax) bb.xMax = x\n if (y > bb.yMax) bb.yMax = y\n }\n}\n\n/**\n * Expand `bb` to include all points of `other`.\n * @param bb - the box to expand in place.\n * @param other - the box whose extent is folded into `bb`.\n */\nexport function mergeBBox(bb: BBox2d, other: BBox2d): void {\n if (other.xMin < bb.xMin) bb.xMin = other.xMin\n if (other.yMin < bb.yMin) bb.yMin = other.yMin\n if (other.xMax > bb.xMax) bb.xMax = other.xMax\n if (other.yMax > bb.yMax) bb.yMax = other.yMax\n}\n\n/**\n * Return `[min, max]` corner points.\n * @param bb - the bounding box to read from.\n * @returns the lower-left and upper-right corners as `[[xMin,yMin],[xMax,yMax]]`.\n */\nexport function boundsOf(bb: BBox2d): [[number, number], [number, number]] {\n return [\n [bb.xMin, bb.yMin],\n [bb.xMax, bb.yMax],\n ]\n}\n\n/**\n * Compute the center point of the box.\n * @param bb - the bounding box to read from.\n * @returns the midpoint `[x, y]` between the min and max corners.\n */\nexport function centerOf(bb: BBox2d): [number, number] {\n return [(bb.xMin + bb.xMax) / 2, (bb.yMin + bb.yMax) / 2]\n}\n\n/**\n * Compute the width of the box.\n * @param bb - the bounding box to read from.\n * @returns the absolute horizontal extent.\n */\nexport function widthOf(bb: BBox2d): number {\n return Math.abs(bb.xMax - bb.xMin)\n}\n\n/**\n * Compute the height of the box.\n * @param bb - the bounding box to read from.\n * @returns the absolute vertical extent.\n */\nexport function heightOf(bb: BBox2d): number {\n return Math.abs(bb.yMax - bb.yMin)\n}\n\n/**\n * Point guaranteed outside (to the upper-right of) the box.\n * @param bb - the bounding box to read from.\n * @param paddingPercent - the padding as a percent of the box extent (default 1).\n * @returns a point offset to the upper-right of `bb`.\n */\nexport function outsidePointOf(bb: BBox2d, paddingPercent = 1): [number, number] {\n const width = bb.xMax - bb.xMin\n const height = bb.yMax - bb.yMin\n return [bb.xMax + (width / 100) * paddingPercent, bb.yMax + (height / 100) * paddingPercent * 0.9]\n}\n\n/**\n * True if `bb` and `other` are completely disjoint.\n * @param bb - the first bounding box.\n * @param other - the second bounding box.\n * @returns true when the two boxes do not overlap (empty boxes count as disjoint).\n */\nexport function isBBoxOut(bb: BBox2d, other: BBox2d): boolean {\n // Handles degenerate (empty) boxes by treating them as disjoint.\n if (isEmpty(bb) || isEmpty(other)) return true\n return other.xMax < bb.xMin || other.xMin > bb.xMax || other.yMax < bb.yMin || other.yMin > bb.yMax\n}\n\n/**\n * True if the point lies inside (or on the boundary of) the box.\n * @param bb - the bounding box to test against.\n * @param pt - the 2D point to test, `[x, y]`.\n * @returns true when `pt` is within (or on) the box.\n */\nexport function containsPoint(bb: BBox2d, pt: readonly [number, number]): boolean {\n return (\n pt[0] >= bb.xMin && pt[0] <= bb.xMax && pt[1] >= bb.yMin && pt[1] <= bb.yMax\n )\n}"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * geometry2d — `BlueprintSketcher` (C2): a pen that packages its curves as a
3
+ * `Blueprint`.
4
+ *
5
+ * Ported from brepjs `2d/blueprints/blueprintSketcher.ts` (Apache-2.0). Built
6
+ * on the pure `BaseSketcher2d`. `done()` returns the still-open contour as a
7
+ * `Blueprint`; callers that want a closed contour draw the closing segment
8
+ * (the base `close()` does this) and wrap the result.
9
+ *
10
+ * @module
11
+ */
12
+ import { Blueprint } from './blueprint.js';
13
+ import { BaseSketcher2d } from './pen-sketcher.js';
14
+ /**
15
+ * A `BaseSketcher2d` that packages the drawn contour as a `Blueprint`.
16
+ *
17
+ * Extends the pen with a `done()` result owner; closes still go through:
18
+ * `new Blueprint(pen.close())` yields the closed contour as a `Blueprint`.
19
+ */
20
+ export declare class BlueprintSketcher extends BaseSketcher2d {
21
+ /**
22
+ * Package the accumulated curves as a `Blueprint` without closing.
23
+ * @returns the open Blueprint of the drawn contour.
24
+ */
25
+ done(): Blueprint;
26
+ }
27
+ //# sourceMappingURL=blueprint-sketcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint-sketcher.d.ts","sourceRoot":"","sources":["../../src/geometry2d/blueprint-sketcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;IACnD;;;OAGG;IACH,IAAI,IAAI,SAAS;CAGlB"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * geometry2d — `BlueprintSketcher` (C2): a pen that packages its curves as a
3
+ * `Blueprint`.
4
+ *
5
+ * Ported from brepjs `2d/blueprints/blueprintSketcher.ts` (Apache-2.0). Built
6
+ * on the pure `BaseSketcher2d`. `done()` returns the still-open contour as a
7
+ * `Blueprint`; callers that want a closed contour draw the closing segment
8
+ * (the base `close()` does this) and wrap the result.
9
+ *
10
+ * @module
11
+ */
12
+ import { Blueprint } from './blueprint.js';
13
+ import { BaseSketcher2d } from './pen-sketcher.js';
14
+ /**
15
+ * A `BaseSketcher2d` that packages the drawn contour as a `Blueprint`.
16
+ *
17
+ * Extends the pen with a `done()` result owner; closes still go through:
18
+ * `new Blueprint(pen.close())` yields the closed contour as a `Blueprint`.
19
+ */
20
+ export class BlueprintSketcher extends BaseSketcher2d {
21
+ /**
22
+ * Package the accumulated curves as a `Blueprint` without closing.
23
+ * @returns the open Blueprint of the drawn contour.
24
+ */
25
+ done() {
26
+ return new Blueprint([...this.pendingCurves]);
27
+ }
28
+ }
29
+ //# sourceMappingURL=blueprint-sketcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint-sketcher.js","sourceRoot":"","sources":["../../src/geometry2d/blueprint-sketcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C;;;;;GAKG;AACH,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACnD;;;OAGG;IACH,IAAI;QACF,OAAO,IAAI,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;IAC/C,CAAC;CACF","sourcesContent":["/**\n * geometry2d — `BlueprintSketcher` (C2): a pen that packages its curves as a\n * `Blueprint`.\n *\n * Ported from brepjs `2d/blueprints/blueprintSketcher.ts` (Apache-2.0). Built\n * on the pure `BaseSketcher2d`. `done()` returns the still-open contour as a\n * `Blueprint`; callers that want a closed contour draw the closing segment\n * (the base `close()` does this) and wrap the result.\n *\n * @module\n */\n\nimport { Blueprint } from './blueprint'\nimport { BaseSketcher2d } from './pen-sketcher'\n\n/**\n * A `BaseSketcher2d` that packages the drawn contour as a `Blueprint`.\n *\n * Extends the pen with a `done()` result owner; closes still go through:\n * `new Blueprint(pen.close())` yields the closed contour as a `Blueprint`.\n */\nexport class BlueprintSketcher extends BaseSketcher2d {\n /**\n * Package the accumulated curves as a `Blueprint` without closing.\n * @returns the open Blueprint of the drawn contour.\n */\n done(): Blueprint {\n return new Blueprint([...this.pendingCurves])\n }\n}"]}