@hatiolab/figure-model 0.1.71 → 0.1.73

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.
@@ -394,6 +394,13 @@ export declare function copyV3PartJoint(asset: V3Asset, from: string, to: string
394
394
  * Before a part is taken away. What hangs from it, or follows its joint, is named and the removal refused -- a
395
395
  * silent cascade would take parts the author did not pick. A part nothing hangs from goes with its own joint.
396
396
  */
397
+ /**
398
+ * The declared room taken out of the graph, for a command that declares it again from the parts once it is done
399
+ * (a part deleted with 「지우고 공간 다시 맞추기」). What it stood on stays: placement and the mounting face.
400
+ */
401
+ export declare function releaseV3Room(asset: V3Asset): {
402
+ placement: 'floor' | 'ceiling' | 'center';
403
+ } | null;
397
404
  export declare function releaseV3PartJoints(asset: V3Asset, part: string): void;
398
405
  /**
399
406
  * The records are the canon: made again from them, the joints' nodes must be the nodes the asset holds. An asset
@@ -1 +1 @@
1
- {"version":3,"file":"v3-authoring-actions.d.ts","sourceRoot":"","sources":["../src/v3-authoring-actions.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,6EAA6E;AAC7E,eAAO,MAAM,QAAQ;;;;;;;CAAmF,CAAA;AACxG,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,QAAQ,CAAA;AAE1C;;;;GAIG;AACH,eAAO,MAAM,cAAc,6CAA8C,CAAA;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AACzD,gCAAgC;AAChC,MAAM,MAAM,WAAW,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AAEzC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,gBAAgB,CAAA;KAAE,CAAA;IACnE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,uGAAuG;IACvG,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;QACzB,GAAG,CAAC,EAAE,SAAS,CAAA;QACf,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAA;QAC9C,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACpC;;;;;WAKG;QACH,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD,oGAAoG;IACpG,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,wGAAwG;IACxG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,iBAAiB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,mHAAmH;IACnH,KAAK,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACvE,qHAAqH;IACrH,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACjE;AAID;;;GAGG;AACH,MAAM,MAAM,iBAAiB;AAC3B,gEAAgE;AAC9D;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE;AAChC,yGAAyG;GACvG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AAChC,2CAA2C;GACzC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAA;AAE5C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3F,2FAA2F;AAC3F,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG;IAAE,EAAE,EAAE,SAAS,CAAA;CAAE,CAAA;AAE1E,MAAM,MAAM,iBAAiB;AAC3B;;;;GAIG;AACD;IACE,IAAI,EAAE,gBAAgB,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,iBAAiB,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AACH,4FAA4F;GAC1F;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AACpE;;;;;;;;;;;;;;GAcG;GACD;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,6GAA6G;IAC7G,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,gBAAgB,CAAA;KAAE,CAAA;IAChE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACzB,GAAG,CAAC,EAAE,SAAS,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAA;IAC9C,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AACH,sGAAsG;GACpG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAClC;;;;GAIG;GACD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE;AACvC,kFAAkF;GAChF;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AACtC;;;;;GAKG;GACD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,QAAQ,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE;AAClJ;;;;;;;GAOG;GACD;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;AAC7I,yFAAyF;GACvF;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAC3D,qDAAqD;GACnD;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE;AACjC;;;;;GAKG;GACD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE;AACpD;;;;;;;;GAQG;GACD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE;AACtD;;;;;;GAMG;GACD;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE;AAC7B;;;;;;GAMG;GACD;IAAE,IAAI,EAAE,2BAA2B,CAAA;CAAE;AACvC,uHAAuH;GACrH;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAA;CAAE;AAC7D;;;;;;GAMG;GACD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACrD;;;;GAIG;GACD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE;AAC5F,kEAAkE;GAChE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACzC;;;;;;;;GAQG;GACD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE;AACtJ;;;;;;;GAOG;GACD;IACE,IAAI,EAAE,aAAa,CAAA;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AACH,uCAAuC;GACrC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AACxC;;;GAGG;GACD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAkrBpC,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAgGpF;AA+FD,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAK7E;AAyaD,gKAAgK;AAChK,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAgCnF;AAiCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAiB9E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAYtE;AAyED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAalD;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,YAAY,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE;QAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAA;KAAE,CAAA;IAC9E,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7H,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,iBAAiB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;IACpI,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AA4GD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,+GAA+G;IAC/G,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,2CAA2C;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,0FAA0F;IAC1F,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAChD;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;CACd;AA6WD,6GAA6G;AAC7G,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAO,GAAG,mBAAmB,CAgBjH;AA2JD,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;CACpC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,EAAE,CAmB7D;AA+KD,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B,wGAAwG;IACxG,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9D,mGAAmG;IACnG,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF;;;OAGG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC,CAAA;CACjE;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAEpE"}
1
+ {"version":3,"file":"v3-authoring-actions.d.ts","sourceRoot":"","sources":["../src/v3-authoring-actions.ts"],"names":[],"mappings":"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"}
@@ -404,7 +404,8 @@ function dropIfUnused(asset, ref, ownedInput) {
404
404
  }
405
405
  /** Which part each part is fastened to, read from the frames rather than from a second record of it. */
406
406
  function parentOf(m, id) {
407
- if (!nodeById(m, `${id}.chain`))
407
+ /* A row's template has no chain of its own -- its copies are composed by the row -- but it is fastened all the same. */
408
+ if (!nodeById(m, `${id}.chain`) && !nodeById(m, `${id}.repeat`))
408
409
  return null;
409
410
  // The seat rigid carries the part into the frame it is fastened to, moving or not (an old asset may have only a motion).
410
411
  const above = nodeById(m, `${id}.seat.rigid`) ?? nodeById(m, `${id}.motion`);
@@ -1512,6 +1513,23 @@ export function copyV3PartJoint(asset, from, to) {
1512
1513
  * Before a part is taken away. What hangs from it, or follows its joint, is named and the removal refused -- a
1513
1514
  * silent cascade would take parts the author did not pick. A part nothing hangs from goes with its own joint.
1514
1515
  */
1516
+ /**
1517
+ * The declared room taken out of the graph, for a command that declares it again from the parts once it is done
1518
+ * (a part deleted with 「지우고 공간 다시 맞추기」). What it stood on stays: placement and the mounting face.
1519
+ */
1520
+ export function releaseV3Room(asset) {
1521
+ const a = asset;
1522
+ if (!a.occupancy?.bounds)
1523
+ return null;
1524
+ const was = stringsIn(a.occupancy.bounds);
1525
+ const placement = a.occupancy.placement;
1526
+ a.occupancy = a.occupancy.contact ? { contact: a.occupancy.contact, placement } : undefined;
1527
+ if (!a.occupancy)
1528
+ delete a.occupancy;
1529
+ for (const ref of was)
1530
+ dropIfUnused(a, ref);
1531
+ return { placement };
1532
+ }
1515
1533
  export function releaseV3PartJoints(asset, part) {
1516
1534
  refuseIfRead(asset, part);
1517
1535
  const joints = (asset.joints ?? []);
@@ -1837,6 +1855,10 @@ function travelAt(m, asset, motion, bound) {
1837
1855
  return out;
1838
1856
  }
1839
1857
  if (w?.op === 'mul@1' && w.args.length === 2) {
1858
+ /* A ratio times a length (the one ratio's size, u × x₀) is kept whole: the sum's terms stay lengths. */
1859
+ const known = (arg) => m.constants.find((c) => c.id === arg);
1860
+ if (!w.args.every(known) && w.args.some(arg => known(arg) && known(arg).unit !== 'ratio'))
1861
+ return still(ref) ? { terms: [{ ref, k: 1 }], c: 0 } : null;
1840
1862
  const [a, b] = w.args.map(arg => read(arg, depth + 1));
1841
1863
  if (!a || !b)
1842
1864
  return null;
@@ -1851,40 +1873,91 @@ function travelAt(m, asset, motion, bound) {
1851
1873
  };
1852
1874
  return read(motion.args[3]);
1853
1875
  }
1854
- /** Where a part's centre is on one axis, as a sum, following whatever it is fastened to. */
1855
- function centreLin(m, asset, id, axis, bound) {
1856
- const i = AXES.indexOf(axis);
1857
- let out = { terms: [], c: 0 };
1876
+ const zeroVec = () => ({ x: { terms: [], c: 0 }, y: { terms: [], c: 0 }, z: { terms: [], c: 0 } });
1877
+ /** A vector of sums turned by a quarter turn (a signed axis permutation). */
1878
+ const turnVec = (r, v) => Object.fromEntries(AXES.map((a, i) => [a, AXES.reduce((sum, b, j) => (r[i][j] ? linAdd(sum, v[b], r[i][j]) : sum), { terms: [], c: 0 })]));
1879
+ const isQuarter = (t) => t !== null && Number.isFinite(t) && Math.abs(t / 90 - Math.round(t / 90)) < 1e-9;
1880
+ /** A part's own turn: none, a quarter turn, or one this command cannot add up (any other angle, or not a number). */
1881
+ function poseTurnOf(m, asset, part) {
1882
+ const pose = nodeById(m, `${part}.pose`);
1883
+ const turn = (pose?.args.slice(3, 6) ?? []).map((ref) => angleOf(m, asset, ref));
1884
+ if (turn.every((t) => t === 0))
1885
+ return null;
1886
+ return turn.every(isQuarter) ? turnMatrix(turn) : 'other';
1887
+ }
1888
+ /** Whether a part, or anything carrying it, turns on a joint or stands turned by other than quarter turns. */
1889
+ function carriedByATurn(m, asset, id) {
1890
+ for (let part = id; part; part = parentOf(m, part)) {
1891
+ if (nodeById(m, `${part}.motion`)?.op === 'axis-turn@1')
1892
+ return true;
1893
+ if (poseTurnOf(m, asset, part) === 'other')
1894
+ return true;
1895
+ }
1896
+ return false;
1897
+ }
1898
+ /** How a part's own axes lie in the figure's: the quarter turns of it and everything carrying it, composed. */
1899
+ function worldTurnOf(m, asset, id) {
1900
+ let c = IDENTITY;
1901
+ for (let part = id; part; part = parentOf(m, part)) {
1902
+ const r = poseTurnOf(m, asset, part);
1903
+ if (r === 'other')
1904
+ return null;
1905
+ if (r)
1906
+ c = mul3(r, c);
1907
+ }
1908
+ return c;
1909
+ }
1910
+ /**
1911
+ * Where a point of a part lies in the figure, as sums, following whatever it is fastened to: its centre, or `from` in
1912
+ * its own frame. A part standing a quarter turned turns what it carries -- a valve body on a lying pipe, a hub on its
1913
+ * post -- and was refused, those figures left without a room (2026-09-25); another angle still is.
1914
+ */
1915
+ function centreVec(m, asset, id, bound, from) {
1916
+ let v = from ?? zeroVec();
1858
1917
  for (let part = id; part; part = parentOf(m, part)) {
1859
1918
  const pose = nodeById(m, `${part}.pose`);
1860
1919
  if (!pose)
1861
1920
  return `${part} has no pose this command can read`;
1862
- /* A part's own turn turns it about its centre; a turn above it would turn everything below. */
1863
- if (part !== id)
1864
- for (const ref of pose.args.slice(3, 6))
1865
- if (angleOf(m, asset, ref) !== 0)
1866
- return `${part} is turned, so its reach is not a box this command can add up`;
1867
- out = linAdd(out, linOf(m, pose.args[i]));
1868
- const seat = nodeById(m, `${part}.seat.rigid`);
1869
- if (seat)
1870
- out = linAdd(out, linOf(m, seat.args[i]));
1921
+ /* A part's own turn turns it about its centre: its centre does not move by it. */
1922
+ if (part !== id || from) {
1923
+ const r = poseTurnOf(m, asset, part);
1924
+ if (r === 'other')
1925
+ return `${part} is turned by other than quarter turns, so what it carries is not a box this command can add up`;
1926
+ if (r)
1927
+ v = turnVec(r, v);
1928
+ }
1929
+ for (const [i, a] of AXES.entries())
1930
+ v[a] = linAdd(v[a], linOf(m, pose.args[i]));
1871
1931
  const motion = nodeById(m, `${part}.motion`);
1872
1932
  if (motion) {
1873
1933
  if (motion.op !== 'axis-slide@1')
1874
1934
  return `${part} turns, so its reach is not a box this command can add up`;
1875
1935
  const unit = motion.args.slice(0, 3).map((ref) => m.constants.find((k) => k.id === ref)?.value ?? null);
1876
- if (unit.some((v) => v === null))
1936
+ if (unit.some((u) => u === null))
1877
1937
  return `${part}'s slide axis is not a constant`;
1878
- const along = unit[i];
1879
- if (along !== 0) {
1938
+ if (unit.some((u) => u !== 0)) {
1880
1939
  const travel = travelAt(m, asset, motion, bound);
1881
1940
  if (!travel)
1882
1941
  return `${part}'s travel is not a distance this command can read`;
1883
- out = linAdd(out, travel, along);
1942
+ for (const [i, a] of AXES.entries())
1943
+ if (unit[i])
1944
+ v[a] = linAdd(v[a], travel, unit[i]);
1884
1945
  }
1885
1946
  }
1947
+ const seat = nodeById(m, `${part}.seat.rigid`);
1948
+ if (seat) {
1949
+ if (seat.args.slice(3, 6).some((ref) => angleOf(m, asset, ref) !== 0))
1950
+ return `${part} is seated turned, which this command does not add up`;
1951
+ for (const [i, a] of AXES.entries())
1952
+ v[a] = linAdd(v[a], linOf(m, seat.args[i]));
1953
+ }
1886
1954
  }
1887
- return out;
1955
+ return v;
1956
+ }
1957
+ /** Where a part's centre is on one axis, as a sum, following whatever it is fastened to. */
1958
+ function centreLin(m, asset, id, axis, bound) {
1959
+ const v = centreVec(m, asset, id, bound);
1960
+ return typeof v === 'string' ? v : v[axis];
1888
1961
  }
1889
1962
  /** A value written as a sum of design inputs times constants, or null where it is anything else. */
1890
1963
  function affineOf(m, ref, seen = 0) {
@@ -1908,7 +1981,8 @@ function affineOf(m, ref, seen = 0) {
1908
1981
  }
1909
1982
  if (writer?.op === 'mul@1' && writer.args.length === 2) {
1910
1983
  /* A ratio times a length is kept whole: its terms must stay lengths (the one ratio's size, u × x₀). */
1911
- const ratioTimesLength = writer.args.some((arg) => m.constants.some((c) => c.id === arg && c.unit !== 'ratio'));
1984
+ const constant = (arg) => m.constants.find((c) => c.id === arg);
1985
+ const ratioTimesLength = !writer.args.every(constant) && writer.args.some((arg) => constant(arg) && constant(arg).unit !== 'ratio');
1912
1986
  if (ratioTimesLength)
1913
1987
  return sizeValue(m, ref) ? { terms: [{ ref, k: 1 }], c: 0 } : null;
1914
1988
  const [a, b] = writer.args.map((arg) => affineOf(m, arg, seen + 1));
@@ -1976,7 +2050,8 @@ function reachOf(m, asset, id, ends, freezeless = true) {
1976
2050
  const chain = [];
1977
2051
  for (let part = id; part; part = parentOf(m, part))
1978
2052
  chain.push(part);
1979
- const top = chain.reduce((found, part, i) => (nodeById(m, `${part}.motion`)?.op === 'axis-turn@1' ? i : found), -1);
2053
+ /* The topmost part that turns on a joint, or stands turned by an angle a box cannot follow (a fan's blade at 120°). */
2054
+ const top = chain.reduce((found, part, i) => (nodeById(m, `${part}.motion`)?.op === 'axis-turn@1' || poseTurnOf(m, asset, part) === 'other' ? i : found), -1);
1980
2055
  if (top < 0)
1981
2056
  return `${id} is carried by no turn`;
1982
2057
  let radius = { terms: [], c: 0 };
@@ -1987,7 +2062,9 @@ function reachOf(m, asset, id, ends, freezeless = true) {
1987
2062
  radius = linAdd(radius, size);
1988
2063
  return null;
1989
2064
  };
1990
- const sizes = standingRefsOf(m, asset, id, id, !freezeless);
2065
+ /* Its half size on every axis of its own, whichever way it stands: the ball holds it at any angle. */
2066
+ const sizes = sizeRefsOf(m, id, id);
2067
+ void freezeless;
1991
2068
  for (const axis of AXES) {
1992
2069
  const bad = grow({ terms: [{ ref: sizes[axis].ref, k: 0.5 * sizes[axis].k }], c: 0 }, `${id}'s size`);
1993
2070
  if (bad)
@@ -2027,29 +2104,15 @@ function reachOf(m, asset, id, ends, freezeless = true) {
2027
2104
  */
2028
2105
  const pivotPart = chain[top];
2029
2106
  const parent = parentOf(m, pivotPart);
2030
- if (parent) {
2031
- const pose = nodeById(m, `${parent}.pose`);
2032
- if (!pose)
2033
- return `${parent} has no pose this command can read`;
2034
- for (const ref of pose.args.slice(3, 6))
2035
- if (angleOf(m, asset, ref) !== 0)
2036
- return `${parent} is turned, so where ${pivotPart} turns is not a point this command can add up`;
2037
- }
2038
2107
  const seat = nodeById(m, `${pivotPart}.seat.rigid`);
2108
+ const seatAt = Object.fromEntries(AXES.map((a, i) => [a, seat ? linOf(m, seat.args[i]) : { terms: [], c: 0 }]));
2039
2109
  const centres = [];
2040
2110
  for (const end of ends) {
2041
- const centre = {};
2042
- for (const axis of AXES) {
2043
- let at = seat ? linOf(m, seat.args[AXES.indexOf(axis)]) : { terms: [], c: 0 };
2044
- if (parent) {
2045
- const above = centreLin(m, asset, parent, axis, end);
2046
- if (typeof above === 'string')
2047
- return above;
2048
- at = linAdd(at, above);
2049
- }
2050
- centre[axis] = at;
2051
- }
2052
- centres.push(centre);
2111
+ /* The point it turns about, in the frame of what carries it, carried there -- turned with it if that stands turned. */
2112
+ const at = parent ? centreVec(m, asset, parent, end, structuredClone(seatAt)) : seatAt;
2113
+ if (typeof at === 'string')
2114
+ return at;
2115
+ centres.push(at);
2053
2116
  }
2054
2117
  return { centres, radius };
2055
2118
  }
@@ -2084,21 +2147,28 @@ function occupancyLins(asset, over) {
2084
2147
  const high = { x: [], y: [], z: [] };
2085
2148
  /* Parts carried by the same turn share one ball: its radius the larger of theirs, term by term. */
2086
2149
  const balls = new Map();
2087
- for (const place of m.nodes.filter((n) => n.op === 'place@1')) {
2088
- let sizes;
2150
+ /* A row's template stands for its copies (`repeatPart`): leaving it out left a conveyor's rollers out of its room. */
2151
+ const rowOf = (id) => nodeById(m, `${id}.repeat`);
2152
+ for (const place of m.nodes.filter((n) => n.op === 'place@1' || (n.op === 'member@1' && rowOf(n.id)))) {
2153
+ const turns = carriedByATurn(m, asset, place.id);
2154
+ let sizes = {};
2089
2155
  try {
2090
- sizes = standingRefsOf(m, asset, place.id, place.id, false);
2156
+ const own = sizeRefsOf(m, place.id, place.id);
2157
+ /* Its size along the figure's axes, whichever quarter turns it and what carries it stand in. */
2158
+ const c = turns ? IDENTITY : worldTurnOf(m, asset, place.id);
2159
+ if (!c)
2160
+ throw new V3ContractError('EDIT_TARGET', place.id, `${place.id} is turned by other than quarter turns`);
2161
+ AXES.forEach((axis, i) => (sizes[axis] = own[AXES[c[i].findIndex(v => v !== 0)]]));
2091
2162
  }
2092
2163
  catch (e) {
2093
2164
  skipped.push({ part: place.id, reason: e instanceof V3ContractError ? e.message : 'not a part whose size this command can read' });
2094
2165
  continue;
2095
2166
  }
2096
- const turns = (() => {
2097
- for (let part = place.id; part; part = parentOf(m, part))
2098
- if (nodeById(m, `${part}.motion`)?.op === 'axis-turn@1')
2099
- return true;
2100
- return false;
2101
- })();
2167
+ const row = place.op === 'member@1' ? rowOf(place.id) : undefined;
2168
+ if (turns && row) {
2169
+ skipped.push({ part: place.id, reason: `${place.id} is a row carried by a turn; where its copies reach is not added up` });
2170
+ continue;
2171
+ }
2102
2172
  if (turns) {
2103
2173
  const reach = reachOf(m, asset, place.id, over === 'rest' ? ['start'] : ['min', 'max']);
2104
2174
  if (typeof reach === 'string') {
@@ -2128,8 +2198,35 @@ function occupancyLins(asset, over) {
2128
2198
  skipped.push({ part: place.id, reason: String(bad) });
2129
2199
  continue;
2130
2200
  }
2201
+ /*
2202
+ A row runs from its parent's one edge to the other along its axis, every copy inside (fit-pitch and fixed-count
2203
+ lay them out within that length): along it the row takes the parent's room, across it the template's.
2204
+ */
2205
+ let rowAxis;
2206
+ if (row) {
2207
+ rowAxis = String(row.params?.axis ?? '').toLowerCase();
2208
+ const parent = parentOf(m, place.id);
2209
+ const straight = parent && worldTurnOf(m, asset, parent);
2210
+ if (!parent || !AXES.includes(rowAxis) || !straight || AXES.some((_, i) => straight[i][i] !== 1)) {
2211
+ skipped.push({ part: place.id, reason: `${place.id} is a row whose run this command cannot read` });
2212
+ continue;
2213
+ }
2214
+ const theirs = standingRefsOf(m, asset, parent, parent, false)[rowAxis];
2215
+ const half = { terms: [{ ref: theirs.ref, k: 0.5 * theirs.k }], c: 0 };
2216
+ const centres = ends.map(end => centreLin(m, asset, parent, rowAxis, end));
2217
+ if (centres.some(c => typeof c === 'string')) {
2218
+ skipped.push({ part: place.id, reason: String(centres.find(c => typeof c === 'string')) });
2219
+ continue;
2220
+ }
2221
+ for (const centre of centres) {
2222
+ low[rowAxis].push(linAdd(centre, half, -1));
2223
+ high[rowAxis].push(linAdd(centre, half, 1));
2224
+ }
2225
+ }
2131
2226
  parts.push(place.id);
2132
2227
  for (const r of readings) {
2228
+ if (r.axis === rowAxis)
2229
+ continue;
2133
2230
  const half = { terms: [{ ref: sizes[r.axis].ref, k: 0.5 * sizes[r.axis].k }], c: 0 };
2134
2231
  const seen = new Set();
2135
2232
  for (const centre of r.at) {