partforge 0.132.1 → 0.133.1

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 (34) hide show
  1. package/bin/cli.js +12 -2
  2. package/docs/AUTHORING-PARTS.md +311 -6
  3. package/docs/KERNEL-CONTRACT.md +41 -11
  4. package/package.json +1 -1
  5. package/src/framework/geometry/arc-fit.js +169 -36
  6. package/src/framework/geometry/arc-math.js +15 -7
  7. package/src/framework/geometry/contour-offset.js +132 -5
  8. package/src/framework/geometry/kernel.js +1 -1
  9. package/src/framework/geometry/occt-backend.js +6 -2
  10. package/src/framework/geometry/occt-step.js +70 -0
  11. package/src/framework/geometry/polygon.js +7 -0
  12. package/src/framework/jobs.js +1 -1
  13. package/src/framework/lint/index.js +2 -1
  14. package/src/framework/lint/rules-schema.js +2 -1
  15. package/src/framework/lint/rules-shape.js +10 -3
  16. package/src/framework/lint/rules-sheet.js +172 -0
  17. package/src/framework/lint/rules-verify.js +10 -0
  18. package/src/framework/oracle/gates.js +13 -0
  19. package/src/framework/oracle/measure.js +129 -5
  20. package/src/framework/oracle/verify.js +113 -5
  21. package/src/framework/process/laser/descriptor.js +1089 -0
  22. package/src/framework/process/registry.js +24 -0
  23. package/src/framework/sheet/constants.js +104 -0
  24. package/src/framework/sheet/joinery.js +356 -0
  25. package/src/framework/sheet/part.js +98 -0
  26. package/src/framework/sheet/pose.js +114 -0
  27. package/src/framework/sheet/resolve.js +133 -0
  28. package/src/framework/verify-metrics.js +8 -1
  29. package/src/parts/laser-box.js +108 -0
  30. package/types/geometry.d.ts +115 -0
  31. package/types/lint.d.ts +4 -1
  32. package/types/oracle.d.ts +1 -1
  33. package/types/part.d.ts +57 -1
  34. package/types/testing.d.ts +81 -1
@@ -263,6 +263,47 @@ export function overhang(
263
263
 
264
264
  // --- measure ----------------------------------------------------------------
265
265
 
266
+ /**
267
+ * A sheet sub-part's 2-D facts (`sheetPart()`, partforge/geometry) — what its
268
+ * process's checks read. Lengths in mm, areas in mm². `bridge` and `gap` are
269
+ * bisected to 0.05 mm; `…Capped` says nothing narrower than twice the floor was
270
+ * found and the value is that ceiling. `at2d` is in the drawing frame; `at` is
271
+ * the same spot in the assembly at mid-thickness, `null` when the sub-part's
272
+ * pose could not be traced. `evaluated` false: the 2-D time budget ran out, or
273
+ * the profile was too complex to start the checks under it, and `bridge`, `gap`,
274
+ * `marksOutside` and `marksArea` are `null`.
275
+ */
276
+ export interface SheetFacts {
277
+ process: string;
278
+ /** `null` only on a sheet naming no registered process whose declaration does not resolve (`evaluated` false). */
279
+ material: string | null;
280
+ /** `null` as for `material`. */
281
+ thickness: number | null;
282
+ /** `"<material, trimmed and lowercased>|<thickness to 0.01 mm>"`, e.g. `"birch plywood|3.00"`; `null` as for `material`. */
283
+ group: string | null;
284
+ /** The cut layer's bounding-box size, nominal (no kerf). */
285
+ flat: [number, number];
286
+ area: number;
287
+ pieces: number;
288
+ customBuild: boolean;
289
+ marksArea: number | null;
290
+ bridge: number | null;
291
+ bridgeCapped: boolean;
292
+ gap: number | null;
293
+ gapCapped: boolean;
294
+ marksOutside: number | null;
295
+ /** Custom builds only: `100·|volume − (area·thickness − 0.2·marksArea)| / (area·thickness − 0.2·marksArea)`. */
296
+ solidMatchPct: number | null;
297
+ at2d: { bridge: [number, number] | null; gap: [number, number] | null; marks: [number, number] | null };
298
+ at: { bridge: number[] | null; gap: number[] | null; marks: number[] | null };
299
+ /**
300
+ * Why a reading is `null` although `evaluated` is true — the geometry engine refused
301
+ * the profile, or the reading threw — or `null` for each one that was taken.
302
+ */
303
+ readErrors: { bridge: string | null; gap: string | null; marks: string | null; marksArea: string | null };
304
+ evaluated: boolean;
305
+ }
306
+
266
307
  export interface SubPartFacts {
267
308
  name: string;
268
309
  /** Size only — `[dx, dy, dz]`. */
@@ -302,6 +343,17 @@ export interface SubPartFacts {
302
343
  overhangAngle: number | null;
303
344
  /** Centroid of the largest offending face; `null` when none. */
304
345
  overhangAt: number[] | null;
346
+ /** A sheet sub-part's 2-D facts, or `null` on every other sub-part. */
347
+ sheet: SheetFacts | null;
348
+ /**
349
+ * Present only in a view that holds a sheet part, when a process bed will read it
350
+ * (`measuredPrintBboxes`), on each printed (`exportable !== false`, non-sheet)
351
+ * sub-part: its size in the print (export) pose, which is what verify fits the
352
+ * process profile's bed to there.
353
+ */
354
+ printBbox?: number[];
355
+ /** Instead of `printBbox` when this sub-part's export pose did not build: why. */
356
+ printBboxError?: string;
305
357
  }
306
358
 
307
359
  export interface AggregateFacts {
@@ -372,6 +424,11 @@ export interface MeasureReport {
372
424
  measuredMinWall: boolean;
373
425
  /** The overhang angle every sub-part's `overhangArea` was measured against, `null` when the pass did not run. */
374
426
  measuredOverhang: number | null;
427
+ /**
428
+ * Present only in a view holding a sheet part: whether the printed sub-parts' print
429
+ * (export) poses were built for `printBbox`.
430
+ */
431
+ measuredPrintBboxes?: boolean;
375
432
  subparts: SubPartFacts[];
376
433
  aggregate: AggregateFacts;
377
434
  overlaps: Overlap[];
@@ -404,6 +461,20 @@ export function measure(
404
461
  */
405
462
  overhang?: number | null;
406
463
  gapThreshold?: number;
464
+ /**
465
+ * Milliseconds the 2-D sheet checks may spend across every sheet sub-part in
466
+ * this call (default 1500), charged for 2-D work alone. Past it the remaining
467
+ * readings are withheld — `sheet.evaluated` false — never the report.
468
+ */
469
+ sheetBudgetMs?: number;
470
+ /** The clock that budget runs on, in ms (default `Date.now`) — a test's seam. */
471
+ now?: () => number;
472
+ /**
473
+ * In a view holding a sheet part, build each printed sub-part in its print (export)
474
+ * pose for `printBbox`. Default: when the part's own `verify.process` has a bed —
475
+ * the only check that reads it.
476
+ */
477
+ printBboxes?: boolean;
407
478
  /**
408
479
  * A build of this view the caller already has, measured instead of building a
409
480
  * second time. It is trusted, not checked against `view`/`params` — hand in a
@@ -433,12 +504,21 @@ export interface VerifyCheck {
433
504
  message: string;
434
505
  /** One self-contained corrective sentence (part-authored `hint` wins). */
435
506
  hint?: string;
436
- /** A stable ERROR-PATTERNS.md entry id. */
507
+ /** A stable ERROR-PATTERNS.md entry id — or `"sheet-parts"`, the authoring guide's "Sheet parts" section, on a sheet check. */
437
508
  pattern?: string;
438
509
  /** A measurement caveat or companion reading — `minWall` (sampling) and `overhangArea` (the steepest angle) set one. */
439
510
  note?: string;
440
511
  /** `[x, y, z]` in mm, for the metrics that have one. */
441
512
  location?: number[] | null;
513
+ /**
514
+ * A check the part never declared, offered by the oracle — a sheet part's
515
+ * process checks, or the notice standing in for them past the 2-D budget. It
516
+ * warns when it fails and never counts toward `declared`/`evaluated`, so it
517
+ * never decides `ok`.
518
+ */
519
+ volunteered?: boolean;
520
+ /** True when the check could not be evaluated this run (a quick lap, or a declared sheet check past the 2-D budget). */
521
+ unevaluated?: boolean;
442
522
  }
443
523
 
444
524
  export interface VerifyCaseResult {