@bldrs-ai/conway 1.578.1546 → 1.579.1547
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.
- package/compiled/examples/browser-bundled.cjs +1 -1
- package/compiled/examples/cli-bundled.cjs +1 -1
- package/compiled/examples/cli-step-bundled.cjs +232 -70
- package/compiled/examples/validator-bundled.cjs +1 -1
- package/compiled/src/AP214E3_2010/ap214_demand_unit_slicing.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_demand_unit_slicing.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_demand_unit_slicing.test.js +170 -0
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts +40 -9
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.js +407 -82
- package/compiled/src/compat/web-ifc/ap214_pump_budget.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ap214_pump_budget.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ap214_pump_budget.test.js +77 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +19 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +66 -12
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
|
|
|
30
30
|
var readline = __toESM(require("node:readline"), 1);
|
|
31
31
|
|
|
32
32
|
// compiled/src/version/version.js
|
|
33
|
-
var versionString = "Conway v1.
|
|
33
|
+
var versionString = "Conway v1.579.1547";
|
|
34
34
|
|
|
35
35
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
36
36
|
var wasmType = "";
|
|
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
|
|
|
14965
14965
|
var import_process = require("process");
|
|
14966
14966
|
|
|
14967
14967
|
// compiled/src/version/version.js
|
|
14968
|
-
var versionString = "Conway v1.
|
|
14968
|
+
var versionString = "Conway v1.579.1547";
|
|
14969
14969
|
|
|
14970
14970
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14971
14971
|
function pThreadsAllowed() {
|
|
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
|
|
|
15943
15943
|
};
|
|
15944
15944
|
|
|
15945
15945
|
// compiled/src/version/version.js
|
|
15946
|
-
var versionString = "Conway v1.
|
|
15946
|
+
var versionString = "Conway v1.579.1547";
|
|
15947
15947
|
|
|
15948
15948
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
15949
15949
|
function pThreadsAllowed() {
|
|
@@ -82528,6 +82528,9 @@ var AP214SceneBuilder = class {
|
|
|
82528
82528
|
// compiled/src/AP214E3_2010/ap214_geometry_extraction.js
|
|
82529
82529
|
var MINIMUM_BOUND_POINTS = 3;
|
|
82530
82530
|
var MAXIMUM_PCURVE_SPAN_SAMPLES = 256;
|
|
82531
|
+
var AP214_ITEMS_PER_DEMAND_UNIT = 4;
|
|
82532
|
+
var AP214_MAX_ITEM_UNITS_PER_REPRESENTATION = 256;
|
|
82533
|
+
var AP214_MAX_REPLAYED_PLACEMENTS = 8;
|
|
82531
82534
|
function isWholeCurveEdge(basisCurve, edgeStart, edgeEnd) {
|
|
82532
82535
|
if (!(edgeStart instanceof vertex_point) || !(edgeEnd instanceof vertex_point)) {
|
|
82533
82536
|
return false;
|
|
@@ -82586,6 +82589,7 @@ var AP214GeometryExtraction = class _AP214GeometryExtraction {
|
|
|
82586
82589
|
this.csgDepth = 0;
|
|
82587
82590
|
this.freeVectorPolygonalFaces_ = [];
|
|
82588
82591
|
this.geometryTypeCounts = /* @__PURE__ */ new Map();
|
|
82592
|
+
this.demandItemsPerUnit = AP214_ITEMS_PER_DEMAND_UNIT;
|
|
82589
82593
|
this.demandCursor_ = 0;
|
|
82590
82594
|
this.csgMemoization = !this.lowMemoryMode;
|
|
82591
82595
|
this.quietRecoverableLogging = false;
|
|
@@ -84208,31 +84212,14 @@ var AP214GeometryExtraction = class _AP214GeometryExtraction {
|
|
|
84208
84212
|
this.scene.addTransform(from.localID, nativeTransform.getValues(), nativeTransform, true);
|
|
84209
84213
|
++pushedTransforms;
|
|
84210
84214
|
};
|
|
84211
|
-
|
|
84212
|
-
|
|
84213
|
-
|
|
84214
|
-
|
|
84215
|
-
if (originTransform !== void 0) {
|
|
84216
|
-
const from2 = originTransform.invert();
|
|
84217
|
-
const to = nativeCartesianTransform;
|
|
84218
|
-
const params = {
|
|
84219
|
-
useRelPlacement: true,
|
|
84220
|
-
axis2Placement: from2,
|
|
84221
|
-
relPlacement: to
|
|
84222
|
-
};
|
|
84223
|
-
combinedTransform = this.conwayModel.getLocalPlacement(params);
|
|
84224
|
-
} else {
|
|
84225
|
-
combinedTransform = nativeCartesianTransform;
|
|
84226
|
-
}
|
|
84227
|
-
pushTransform(combinedTransform);
|
|
84228
|
-
} else if (mappingTarget instanceof placement) {
|
|
84229
|
-
const targetTransform = this.extractRawPlacement(mappingTarget);
|
|
84230
|
-
const originTransform = mappingOrigin instanceof placement ? this.extractRawPlacement(mappingOrigin) : void 0;
|
|
84231
|
-
if (targetTransform !== void 0) {
|
|
84215
|
+
try {
|
|
84216
|
+
if (mappingTarget instanceof cartesian_transformation_operator_3d) {
|
|
84217
|
+
const nativeCartesianTransform = this.extractCartesianTransformOperator3D(mappingTarget);
|
|
84218
|
+
const originTransform = mappingOrigin instanceof placement ? this.extractRawPlacement(mappingOrigin) : void 0;
|
|
84232
84219
|
let combinedTransform;
|
|
84233
84220
|
if (originTransform !== void 0) {
|
|
84234
84221
|
const from2 = originTransform.invert();
|
|
84235
|
-
const to =
|
|
84222
|
+
const to = nativeCartesianTransform;
|
|
84236
84223
|
const params = {
|
|
84237
84224
|
useRelPlacement: true,
|
|
84238
84225
|
axis2Placement: from2,
|
|
@@ -84240,44 +84227,64 @@ var AP214GeometryExtraction = class _AP214GeometryExtraction {
|
|
|
84240
84227
|
};
|
|
84241
84228
|
combinedTransform = this.conwayModel.getLocalPlacement(params);
|
|
84242
84229
|
} else {
|
|
84243
|
-
combinedTransform =
|
|
84230
|
+
combinedTransform = nativeCartesianTransform;
|
|
84244
84231
|
}
|
|
84245
84232
|
pushTransform(combinedTransform);
|
|
84233
|
+
} else if (mappingTarget instanceof placement) {
|
|
84234
|
+
const targetTransform = this.extractRawPlacement(mappingTarget);
|
|
84235
|
+
const originTransform = mappingOrigin instanceof placement ? this.extractRawPlacement(mappingOrigin) : void 0;
|
|
84236
|
+
if (targetTransform !== void 0) {
|
|
84237
|
+
let combinedTransform;
|
|
84238
|
+
if (originTransform !== void 0) {
|
|
84239
|
+
const from2 = originTransform.invert();
|
|
84240
|
+
const to = targetTransform;
|
|
84241
|
+
const params = {
|
|
84242
|
+
useRelPlacement: true,
|
|
84243
|
+
axis2Placement: from2,
|
|
84244
|
+
relPlacement: to
|
|
84245
|
+
};
|
|
84246
|
+
combinedTransform = this.conwayModel.getLocalPlacement(params);
|
|
84247
|
+
} else {
|
|
84248
|
+
combinedTransform = targetTransform;
|
|
84249
|
+
}
|
|
84250
|
+
pushTransform(combinedTransform);
|
|
84251
|
+
}
|
|
84246
84252
|
}
|
|
84247
|
-
|
|
84248
|
-
|
|
84249
|
-
|
|
84250
|
-
this.extractMappedItem(representationItem, owningElementLocalID, parents !== void 0 ? [from, ...parents] : [from]);
|
|
84251
|
-
} else {
|
|
84252
|
-
this.extractRepresentationItem(representationItem, owningElementLocalID);
|
|
84253
|
-
const styledItemLocalID_ = this.materials.styledItemMap.get(representationItem.localID);
|
|
84254
|
-
let materialOverrideID = void 0;
|
|
84255
|
-
if (styledItemLocalID_ !== void 0) {
|
|
84256
|
-
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
84257
|
-
this.extractStyledItem(styledItem_);
|
|
84253
|
+
for (const representationItem of representationMap.mapped_representation.items) {
|
|
84254
|
+
if (representationItem instanceof mapped_item) {
|
|
84255
|
+
this.extractMappedItem(representationItem, owningElementLocalID, parents !== void 0 ? [from, ...parents] : [from]);
|
|
84258
84256
|
} else {
|
|
84259
|
-
|
|
84260
|
-
|
|
84261
|
-
|
|
84262
|
-
|
|
84263
|
-
|
|
84264
|
-
|
|
84257
|
+
this.extractRepresentationItem(representationItem, owningElementLocalID);
|
|
84258
|
+
const styledItemLocalID_ = this.materials.styledItemMap.get(representationItem.localID);
|
|
84259
|
+
let materialOverrideID = void 0;
|
|
84260
|
+
if (styledItemLocalID_ !== void 0) {
|
|
84261
|
+
const styledItem_ = this.model.getElementByLocalID(styledItemLocalID_);
|
|
84262
|
+
this.extractStyledItem(styledItem_);
|
|
84263
|
+
} else {
|
|
84264
|
+
let styledItemParentLocalID = this.materials.styledItemMap.get(from.localID);
|
|
84265
|
+
let styleParent = from;
|
|
84266
|
+
if (parents !== void 0) {
|
|
84267
|
+
for (const parent of parents) {
|
|
84268
|
+
if (styledItemParentLocalID !== void 0) {
|
|
84269
|
+
break;
|
|
84270
|
+
}
|
|
84271
|
+
styledItemParentLocalID = this.materials.styledItemMap.get(parent.localID);
|
|
84272
|
+
styleParent = parent;
|
|
84265
84273
|
}
|
|
84266
|
-
|
|
84267
|
-
|
|
84274
|
+
}
|
|
84275
|
+
if (styledItemParentLocalID !== void 0) {
|
|
84276
|
+
const styledItemParent = this.model.getElementByLocalID(styledItemParentLocalID);
|
|
84277
|
+
this.extractStyledItem(styledItemParent, representationItem);
|
|
84278
|
+
materialOverrideID = styleParent.localID;
|
|
84268
84279
|
}
|
|
84269
84280
|
}
|
|
84270
|
-
|
|
84271
|
-
const styledItemParent = this.model.getElementByLocalID(styledItemParentLocalID);
|
|
84272
|
-
this.extractStyledItem(styledItemParent, representationItem);
|
|
84273
|
-
materialOverrideID = styleParent.localID;
|
|
84274
|
-
}
|
|
84281
|
+
this.scene.addGeometry(representationItem.localID, owningElementLocalID, materialOverrideID);
|
|
84275
84282
|
}
|
|
84276
|
-
this.scene.addGeometry(representationItem.localID, owningElementLocalID, materialOverrideID);
|
|
84277
84283
|
}
|
|
84278
|
-
}
|
|
84279
|
-
|
|
84280
|
-
|
|
84284
|
+
} finally {
|
|
84285
|
+
for (; pushedTransforms > 0; --pushedTransforms) {
|
|
84286
|
+
this.scene.popTransform();
|
|
84287
|
+
}
|
|
84281
84288
|
}
|
|
84282
84289
|
}
|
|
84283
84290
|
/**
|
|
@@ -85430,14 +85437,18 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85430
85437
|
* Prepare per-unit demand extraction (STEP demand parity phase 2)
|
|
85431
85438
|
* without executing any geometry work: builds the assembly tree and
|
|
85432
85439
|
* thunks exactly like the whole-model walk, but the root executions
|
|
85433
|
-
* are captured as an ordered list of UNITS
|
|
85434
|
-
*
|
|
85435
|
-
*
|
|
85436
|
-
*
|
|
85437
|
-
*
|
|
85438
|
-
*
|
|
85439
|
-
*
|
|
85440
|
-
*
|
|
85440
|
+
* are captured as an ordered list of UNITS. The tree is flattened
|
|
85441
|
+
* DEPTH FIRST — one unit per child (descending into any child whose
|
|
85442
|
+
* subtree carries more than {@link AP214_ITEMS_PER_DEMAND_UNIT}
|
|
85443
|
+
* items), then one unit per range of a node's own representation
|
|
85444
|
+
* items — so a single-root assembly pumps progressively all the way
|
|
85445
|
+
* down to individual solids rather than per top-level part
|
|
85446
|
+
* (conway#579: Arty's silkscreen is 654 solids sitting two levels
|
|
85447
|
+
* under the only root, which used to make it one 22 s task).
|
|
85448
|
+
* Executing every unit in order then calling
|
|
85449
|
+
* {@link finishDemandExtraction} reproduces the whole-model walk
|
|
85450
|
+
* exactly — the classic {@link extractAP214GeometryData} runs through
|
|
85451
|
+
* this same path. Idempotent.
|
|
85441
85452
|
*/
|
|
85442
85453
|
// eslint-disable-next-line max-lines-per-function
|
|
85443
85454
|
prepareDemandExtraction() {
|
|
@@ -85471,7 +85482,8 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85471
85482
|
occurrenceExpressID ??= this.model.getExpressIDByLocalID(childOwningLocalID);
|
|
85472
85483
|
this.scene.pushOccurrence(occurrenceExpressID ?? childOwningLocalID);
|
|
85473
85484
|
try {
|
|
85474
|
-
mappedChild.thunk
|
|
85485
|
+
const runChild = slice?.childThunk ?? mappedChild.thunk;
|
|
85486
|
+
runChild(childOwningLocalID, childTransform);
|
|
85475
85487
|
} catch (ex) {
|
|
85476
85488
|
if (this.quietRecoverableLogging) {
|
|
85477
85489
|
} else if (ex instanceof Error) {
|
|
@@ -85493,7 +85505,22 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85493
85505
|
}
|
|
85494
85506
|
}
|
|
85495
85507
|
const includeItems = slice?.includeItems ?? true;
|
|
85496
|
-
|
|
85508
|
+
const items = includeItems ? representation2.items : [];
|
|
85509
|
+
const itemStart = slice?.itemStart ?? 0;
|
|
85510
|
+
const itemEnd = Math.min(slice?.itemEnd ?? items.length, items.length);
|
|
85511
|
+
for (const replayIndex of slice?.replayPlacements ?? []) {
|
|
85512
|
+
const replayItem = items[replayIndex];
|
|
85513
|
+
if (replayItem instanceof placement) {
|
|
85514
|
+
try {
|
|
85515
|
+
this.extractPlacement(replayItem, mappedItem);
|
|
85516
|
+
} catch {
|
|
85517
|
+
}
|
|
85518
|
+
}
|
|
85519
|
+
}
|
|
85520
|
+
const verifySliceNeutrality = slice?.itemStart !== void 0;
|
|
85521
|
+
for (let itemIndex = itemStart; itemIndex < itemEnd; ++itemIndex) {
|
|
85522
|
+
const item = items[itemIndex];
|
|
85523
|
+
const depthBeforeItem = verifySliceNeutrality ? this.scene.stackLength : 0;
|
|
85497
85524
|
try {
|
|
85498
85525
|
if (item instanceof placement) {
|
|
85499
85526
|
this.extractPlacement(item, mappedItem);
|
|
@@ -85523,6 +85550,10 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85523
85550
|
} else {
|
|
85524
85551
|
logger_default.error(`Unknown exception processing representation item (${ex}) expressID: #${item.expressID}`);
|
|
85525
85552
|
}
|
|
85553
|
+
} finally {
|
|
85554
|
+
if (verifySliceNeutrality && !(item instanceof placement) && this.scene.stackLength !== depthBeforeItem && !this.quietRecoverableLogging) {
|
|
85555
|
+
logger_default.error(`Representation item left transform state inside a sliced range expressID: #${item.expressID}`);
|
|
85556
|
+
}
|
|
85526
85557
|
}
|
|
85527
85558
|
}
|
|
85528
85559
|
while (this.scene.stackLength > entryTransformDepth) {
|
|
@@ -85533,6 +85564,51 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85533
85564
|
}
|
|
85534
85565
|
};
|
|
85535
85566
|
};
|
|
85567
|
+
const itemUnitRanges = (representation2) => {
|
|
85568
|
+
let items;
|
|
85569
|
+
try {
|
|
85570
|
+
items = representation2.items;
|
|
85571
|
+
} catch {
|
|
85572
|
+
return void 0;
|
|
85573
|
+
}
|
|
85574
|
+
const itemCount = items.length;
|
|
85575
|
+
if (itemCount <= this.demandItemsPerUnit) {
|
|
85576
|
+
return void 0;
|
|
85577
|
+
}
|
|
85578
|
+
const itemsPerUnit = Math.max(this.demandItemsPerUnit, Math.ceil(itemCount / AP214_MAX_ITEM_UNITS_PER_REPRESENTATION));
|
|
85579
|
+
const ranges = [];
|
|
85580
|
+
const replayed = [];
|
|
85581
|
+
const pending = [];
|
|
85582
|
+
let start = 0;
|
|
85583
|
+
for (let cursor = 0; cursor < itemCount; ++cursor) {
|
|
85584
|
+
if (items[cursor] instanceof placement) {
|
|
85585
|
+
pending.push(cursor);
|
|
85586
|
+
}
|
|
85587
|
+
if (cursor + 1 - start < itemsPerUnit || cursor + 1 >= itemCount) {
|
|
85588
|
+
continue;
|
|
85589
|
+
}
|
|
85590
|
+
if (replayed.length + pending.length > AP214_MAX_REPLAYED_PLACEMENTS) {
|
|
85591
|
+
break;
|
|
85592
|
+
}
|
|
85593
|
+
ranges.push({
|
|
85594
|
+
itemStart: start,
|
|
85595
|
+
itemEnd: cursor + 1,
|
|
85596
|
+
replayPlacements: replayed.length > 0 ? replayed.slice() : void 0
|
|
85597
|
+
});
|
|
85598
|
+
replayed.push(...pending);
|
|
85599
|
+
pending.length = 0;
|
|
85600
|
+
start = cursor + 1;
|
|
85601
|
+
}
|
|
85602
|
+
if (ranges.length === 0) {
|
|
85603
|
+
return void 0;
|
|
85604
|
+
}
|
|
85605
|
+
ranges.push({
|
|
85606
|
+
itemStart: start,
|
|
85607
|
+
itemEnd: itemCount,
|
|
85608
|
+
replayPlacements: replayed.length > 0 ? replayed.slice() : void 0
|
|
85609
|
+
});
|
|
85610
|
+
return ranges;
|
|
85611
|
+
};
|
|
85536
85612
|
const pendingRoots = [];
|
|
85537
85613
|
{
|
|
85538
85614
|
this.scene.clearParentStack();
|
|
@@ -85737,20 +85813,80 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85737
85813
|
}
|
|
85738
85814
|
}
|
|
85739
85815
|
const units = [];
|
|
85816
|
+
const subtreeItemCounts = /* @__PURE__ */ new Map();
|
|
85817
|
+
const ownItemCount = (node) => {
|
|
85818
|
+
if (node.rep === void 0) {
|
|
85819
|
+
return 0;
|
|
85820
|
+
}
|
|
85821
|
+
try {
|
|
85822
|
+
return node.rep.items.length;
|
|
85823
|
+
} catch {
|
|
85824
|
+
return 0;
|
|
85825
|
+
}
|
|
85826
|
+
};
|
|
85827
|
+
const subtreeItemCount = (node, path3) => {
|
|
85828
|
+
const memoized = subtreeItemCounts.get(node);
|
|
85829
|
+
if (memoized !== void 0) {
|
|
85830
|
+
return memoized;
|
|
85831
|
+
}
|
|
85832
|
+
if (path3.has(node)) {
|
|
85833
|
+
return 0;
|
|
85834
|
+
}
|
|
85835
|
+
path3.add(node);
|
|
85836
|
+
let count = ownItemCount(node);
|
|
85837
|
+
for (const [childLocalID] of node.children ?? []) {
|
|
85838
|
+
const child = treeMap.get(childLocalID);
|
|
85839
|
+
if (child !== void 0) {
|
|
85840
|
+
count += subtreeItemCount(child, path3);
|
|
85841
|
+
}
|
|
85842
|
+
}
|
|
85843
|
+
path3.delete(node);
|
|
85844
|
+
subtreeItemCounts.set(node, count);
|
|
85845
|
+
return count;
|
|
85846
|
+
};
|
|
85847
|
+
const expandUnits = (node, path3, wrap) => {
|
|
85848
|
+
const childCount = node.children?.length ?? 0;
|
|
85849
|
+
for (let child = 0; child < childCount; ++child) {
|
|
85850
|
+
const childNode = treeMap.get(node.children[child][0]);
|
|
85851
|
+
const descend = childNode !== void 0 && childNode.rep !== void 0 && childNode.thunk !== void 0 && !path3.has(childNode) && subtreeItemCount(childNode, /* @__PURE__ */ new Set()) > this.demandItemsPerUnit;
|
|
85852
|
+
if (!descend) {
|
|
85853
|
+
wrap({ childStart: child, childEnd: child + 1, includeItems: false });
|
|
85854
|
+
continue;
|
|
85855
|
+
}
|
|
85856
|
+
const descendant = childNode;
|
|
85857
|
+
path3.add(descendant);
|
|
85858
|
+
expandUnits(descendant, path3, (childSlice) => {
|
|
85859
|
+
const childThunk = makeThunk(descendant.rep, descendant.owningLocalID, descendant, childSlice);
|
|
85860
|
+
wrap({
|
|
85861
|
+
childStart: child,
|
|
85862
|
+
childEnd: child + 1,
|
|
85863
|
+
includeItems: false,
|
|
85864
|
+
childThunk
|
|
85865
|
+
});
|
|
85866
|
+
});
|
|
85867
|
+
path3.delete(descendant);
|
|
85868
|
+
}
|
|
85869
|
+
const itemRanges = node.rep !== void 0 ? itemUnitRanges(node.rep) : void 0;
|
|
85870
|
+
if (itemRanges === void 0) {
|
|
85871
|
+
wrap({ childStart: 0, childEnd: 0, includeItems: true });
|
|
85872
|
+
return;
|
|
85873
|
+
}
|
|
85874
|
+
for (const range of itemRanges) {
|
|
85875
|
+
wrap({ childStart: 0, childEnd: 0, includeItems: true, ...range });
|
|
85876
|
+
}
|
|
85877
|
+
};
|
|
85740
85878
|
for (const root of pendingRoots) {
|
|
85741
85879
|
const node = root.node;
|
|
85742
85880
|
const scaleTransform = root.scaleTransform;
|
|
85743
|
-
const
|
|
85744
|
-
if (
|
|
85881
|
+
const rep = node.rep;
|
|
85882
|
+
if (rep === void 0) {
|
|
85745
85883
|
units.push(() => node.thunk(void 0, scaleTransform));
|
|
85746
85884
|
continue;
|
|
85747
85885
|
}
|
|
85748
|
-
|
|
85749
|
-
const sliced = makeThunk(
|
|
85886
|
+
expandUnits(node, /* @__PURE__ */ new Set([node]), (slice) => {
|
|
85887
|
+
const sliced = makeThunk(rep, node.owningLocalID, node, slice);
|
|
85750
85888
|
units.push(() => sliced(void 0, scaleTransform));
|
|
85751
|
-
}
|
|
85752
|
-
const itemsOnly = makeThunk(node.rep, node.owningLocalID, node, { childStart: 0, childEnd: 0, includeItems: true });
|
|
85753
|
-
units.push(() => itemsOnly(void 0, scaleTransform));
|
|
85889
|
+
});
|
|
85754
85890
|
}
|
|
85755
85891
|
this.demandUnits_ = units;
|
|
85756
85892
|
}
|
|
@@ -85791,15 +85927,32 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85791
85927
|
* AP214 models. Staged face tessellation is finalized after every
|
|
85792
85928
|
* batch so captured geometry is complete and readable.
|
|
85793
85929
|
*
|
|
85930
|
+
* `budgetMs` is what keeps an interactive caller's thread responsive
|
|
85931
|
+
* now that a unit is a slice rather than a product. Unit cost is wildly
|
|
85932
|
+
* uneven both across models and inside one: Arty_Z7's 603 units average
|
|
85933
|
+
* 58 ms but run from under a millisecond to 600 ms (a single silkscreen
|
|
85934
|
+
* solid), while DSA2's average 32 ms. No fixed unit-count-per-call
|
|
85935
|
+
* serves that — it either overshoots the frame budget on the expensive
|
|
85936
|
+
* units or burns hundreds of calls on the cheap ones — so a caller with
|
|
85937
|
+
* a frame to hit passes a wall-clock budget and gets as many units as
|
|
85938
|
+
* fit. One unit always runs: a single unit that overruns the budget is
|
|
85939
|
+
* the floor this layer can offer, and shrinking it further is geometry
|
|
85940
|
+
* cost, not granularity (conway#564). Callers that want completion
|
|
85941
|
+
* rather than responsiveness (the whole-model walk, the deferred drain)
|
|
85942
|
+
* pass no budget and keep the pre-conway#579 behaviour exactly.
|
|
85943
|
+
*
|
|
85794
85944
|
* @param count Max units to execute this call (min 1).
|
|
85945
|
+
* @param budgetMs Wall-clock this call may spend before returning
|
|
85946
|
+
* early; unbounded when absent.
|
|
85795
85947
|
* @return {number} Units actually executed.
|
|
85796
85948
|
*/
|
|
85797
|
-
extractDemandUnitBatch(count) {
|
|
85949
|
+
extractDemandUnitBatch(count, budgetMs) {
|
|
85798
85950
|
const units = this.demandUnits_;
|
|
85799
85951
|
if (units === void 0) {
|
|
85800
85952
|
return 0;
|
|
85801
85953
|
}
|
|
85802
85954
|
const end = Math.min(this.demandCursor_ + Math.max(count, 1), units.length);
|
|
85955
|
+
const deadline = budgetMs !== void 0 ? Date.now() + budgetMs : void 0;
|
|
85803
85956
|
let executed = 0;
|
|
85804
85957
|
for (; this.demandCursor_ < end; ++this.demandCursor_) {
|
|
85805
85958
|
try {
|
|
@@ -85815,6 +85968,15 @@ ${error.stack} - expressID: #${face_.expressID}`);
|
|
|
85815
85968
|
logger_default.error(`Unknown exception processing demand unit (${ex})`);
|
|
85816
85969
|
}
|
|
85817
85970
|
}
|
|
85971
|
+
if (deadline !== void 0) {
|
|
85972
|
+
if (this.useStagedFaces) {
|
|
85973
|
+
this.finalizeStagedFaces();
|
|
85974
|
+
}
|
|
85975
|
+
if (Date.now() >= deadline) {
|
|
85976
|
+
++this.demandCursor_;
|
|
85977
|
+
break;
|
|
85978
|
+
}
|
|
85979
|
+
}
|
|
85818
85980
|
}
|
|
85819
85981
|
this.finalizeStagedFaces();
|
|
85820
85982
|
return executed;
|
|
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
|
|
|
944
944
|
var entity_types_ifc_gen_default = EntityTypesIfc;
|
|
945
945
|
|
|
946
946
|
// compiled/src/version/version.js
|
|
947
|
-
var versionString = "Conway v1.
|
|
947
|
+
var versionString = "Conway v1.579.1547";
|
|
948
948
|
|
|
949
949
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
950
950
|
var wasmType = "";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ap214_demand_unit_slicing.test.d.ts","sourceRoot":"","sources":["../../../src/AP214E3_2010/ap214_demand_unit_slicing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { describe, expect, test, beforeAll } from "@jest/globals";
|
|
3
|
+
import { AP214GeometryExtraction } from "./ap214_geometry_extraction.js";
|
|
4
|
+
import { ParseResult } from "../step/parsing/step_parser.js";
|
|
5
|
+
import AP214StepParser from "./ap214_step_parser.js";
|
|
6
|
+
import ParsingBuffer from "../parsing/parsing_buffer.js";
|
|
7
|
+
import { ConwayGeometry } from "../../dependencies/conway-geom/index.js";
|
|
8
|
+
import { ExtractResult } from "../core/shared_constants.js";
|
|
9
|
+
/**
|
|
10
|
+
* conway#579: a demand unit used to be a whole product, so one item-heavy
|
|
11
|
+
* representation (Arty_Z7's silkscreen: 654 solids in one
|
|
12
|
+
* ADVANCED_BREP_SHAPE_REPRESENTATION, two levels under the only root) ran
|
|
13
|
+
* as a single 22 s uninterruptible task. prepareDemandExtraction now
|
|
14
|
+
* flattens depth first and cuts a representation's `items` into index
|
|
15
|
+
* ranges, which is only sound if the cut walk visits the same items in the
|
|
16
|
+
* same order with the same transform state — the claim these tests pin.
|
|
17
|
+
*
|
|
18
|
+
* `demandItemsPerUnit` is the granularity knob: `Infinity` reproduces the
|
|
19
|
+
* pre-change flattening (one unit per immediate child of a root, plus one
|
|
20
|
+
* for the root's own items), and small values cut both deeper and finer.
|
|
21
|
+
* Every setting has to emit byte-identical placed geometry.
|
|
22
|
+
*/
|
|
23
|
+
/** Assembly with a 13-NAUO occurrence tree and real BREP leaves. */
|
|
24
|
+
const ASSEMBLY_FIXTURE = "data/as1-oc-214.stp";
|
|
25
|
+
/**
|
|
26
|
+
* Single-root assembly whose #14069 ADVANCED_BREP_SHAPE_REPRESENTATION
|
|
27
|
+
* carries ten solids in one `items` array — the multi-item representation
|
|
28
|
+
* the issue is about, at a size the default granularity actually cuts.
|
|
29
|
+
*/
|
|
30
|
+
const MULTI_ITEM_FIXTURE = "data/nema-23-76mm.step";
|
|
31
|
+
/**
|
|
32
|
+
* Derived from `create-a-tube.step`: one
|
|
33
|
+
* ADVANCED_BREP_SHAPE_REPRESENTATION holding a NON-IDENTITY
|
|
34
|
+
* AXIS2_PLACEMENT_3D followed by three copies of the tube solid. That
|
|
35
|
+
* leading placement is the state the item loop carries — it pushes onto
|
|
36
|
+
* the scene transform stack and places every item after it — so a range
|
|
37
|
+
* that starts past it lands its solids at the wrong place unless the
|
|
38
|
+
* range replays it. It is also the shape of the worst real case:
|
|
39
|
+
* DSA2.step's single root is one placement followed by 28,674 solids.
|
|
40
|
+
*/
|
|
41
|
+
const LEADING_PLACEMENT_FIXTURE = "data/ap214-sliced-item-ranges.step";
|
|
42
|
+
/**
|
|
43
|
+
* Six items, the first of which is a MAPPED_ITEM that pushes its mapping
|
|
44
|
+
* transform and then throws (its REPRESENTATION_MAP's
|
|
45
|
+
* `mapped_representation` points at a CARTESIAN_POINT, so the dereference
|
|
46
|
+
* fails after the push).
|
|
47
|
+
*
|
|
48
|
+
* That failure path is the one way a NON-placement item can leave
|
|
49
|
+
* transform state behind: extractMappedItem's pop loop is unreachable once
|
|
50
|
+
* the walk between the pushes throws. Unsliced, the leak displaces every
|
|
51
|
+
* later item in the representation; sliced, only the ones sharing its
|
|
52
|
+
* range — so the geometry depended on where the cut fell until
|
|
53
|
+
* extractMappedItem was made to pop in a `finally`. No model in the
|
|
54
|
+
* regression corpus contains a MAPPED_ITEM at all, so this fixture is the
|
|
55
|
+
* only thing standing between that fix and a silent regression.
|
|
56
|
+
*/
|
|
57
|
+
const MAPPED_ITEM_FAILURE_FIXTURE = "data/ap214-mapped-item-failure.step";
|
|
58
|
+
/* Wasm init, and the per-test budgets: these extractions run real BREPs. */
|
|
59
|
+
const WASM_INIT_TIMEOUT_MS = 60000;
|
|
60
|
+
const EXTRACT_TIMEOUT_MS = 120000;
|
|
61
|
+
const MULTI_EXTRACT_TIMEOUT_MS = 300000;
|
|
62
|
+
// Column-major 4x4: the translation column sits at 12, 13, 14.
|
|
63
|
+
const TRANSLATION_START = 12;
|
|
64
|
+
const TRANSLATION_END = 15;
|
|
65
|
+
let conwayGeometry;
|
|
66
|
+
beforeAll(async () => {
|
|
67
|
+
conwayGeometry = new ConwayGeometry();
|
|
68
|
+
expect(await conwayGeometry.initialize()).toBe(true);
|
|
69
|
+
}, WASM_INIT_TIMEOUT_MS);
|
|
70
|
+
/**
|
|
71
|
+
* Extract the fixture at one granularity and reduce the resulting scene to
|
|
72
|
+
* a comparable digest of every placed geometry instance, in walk order.
|
|
73
|
+
*
|
|
74
|
+
* The model is re-parsed per call because extraction memoizes geometry into
|
|
75
|
+
* it — two granularities have to start from equally cold models or the
|
|
76
|
+
* second one measures the first one's cache.
|
|
77
|
+
*
|
|
78
|
+
* @param fixture Path to the STEP file.
|
|
79
|
+
* @param itemsPerUnit Value for `demandItemsPerUnit`.
|
|
80
|
+
* @return {[PlacedDigest[], number]} The digest and the unit count.
|
|
81
|
+
*/
|
|
82
|
+
function extractAt(fixture, itemsPerUnit) {
|
|
83
|
+
const parser = AP214StepParser.Instance;
|
|
84
|
+
const buffer = new ParsingBuffer(fs.readFileSync(fixture));
|
|
85
|
+
expect(parser.parseHeader(buffer)[1]).toBe(ParseResult.COMPLETE);
|
|
86
|
+
const [, model] = parser.parseDataToModel(buffer);
|
|
87
|
+
expect(model).not.toBe(void 0);
|
|
88
|
+
const extraction = new AP214GeometryExtraction(conwayGeometry, model);
|
|
89
|
+
extraction.demandItemsPerUnit = itemsPerUnit;
|
|
90
|
+
extraction.prepareDemandExtraction();
|
|
91
|
+
const unitCount = extraction.demandUnitCount;
|
|
92
|
+
const [result, scene] = extraction.extractAP214GeometryData();
|
|
93
|
+
expect(result).toBe(ExtractResult.COMPLETE);
|
|
94
|
+
return [placedDigest(scene), unitCount];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Reduce a scene to one row per placed geometry instance: what it is, where
|
|
98
|
+
* the walk put it, and the contents of its vertex and index buffers.
|
|
99
|
+
*
|
|
100
|
+
* @param scene The extracted scene.
|
|
101
|
+
* @return {PlacedDigest[]} One row per instance, in walk order.
|
|
102
|
+
*/
|
|
103
|
+
function placedDigest(scene) {
|
|
104
|
+
const wasm = conwayGeometry.wasmModule;
|
|
105
|
+
const rows = [];
|
|
106
|
+
for (const [transform, , mesh, , entity, occurrencePath] of scene.walkWithOccurrence()) {
|
|
107
|
+
const geometry = mesh.geometry;
|
|
108
|
+
if (geometry === void 0 || typeof geometry.GetVertexDataSize !== "function") {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Read into copies immediately — HEAPF32/HEAPU32 views detach on wasm
|
|
112
|
+
// memory growth and a held view silently reads zeroes.
|
|
113
|
+
const floatCount = geometry.GetVertexDataSize();
|
|
114
|
+
const vertexData = wasm.HEAPF32.slice(geometry.GetVertexData() / 4, (geometry.GetVertexData() / 4) + floatCount);
|
|
115
|
+
const indexCount = geometry.GetIndexDataSize();
|
|
116
|
+
const indexData = wasm.HEAPU32.slice(geometry.GetIndexData() / 4, (geometry.GetIndexData() / 4) + indexCount);
|
|
117
|
+
rows.push({
|
|
118
|
+
expressID: entity?.expressID,
|
|
119
|
+
occurrencePath: occurrencePath.join("/"),
|
|
120
|
+
transform: (transform ?? []).join(","),
|
|
121
|
+
vertices: `${floatCount}:${vertexData.join(",")}`,
|
|
122
|
+
indices: `${indexCount}:${indexData.join(",")}`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return rows;
|
|
126
|
+
}
|
|
127
|
+
describe("AP214 demand unit granularity (conway#579)", () => {
|
|
128
|
+
test("an assembly extracts identically sliced and unsliced", () => {
|
|
129
|
+
const [unsliced, unslicedUnits] = extractAt(ASSEMBLY_FIXTURE, Infinity);
|
|
130
|
+
const [sliced, slicedUnits] = extractAt(ASSEMBLY_FIXTURE, 1);
|
|
131
|
+
// Without this the equality below would hold trivially.
|
|
132
|
+
expect(slicedUnits).toBeGreaterThan(unslicedUnits);
|
|
133
|
+
expect(unsliced.length).toBeGreaterThan(0);
|
|
134
|
+
expect(sliced).toStrictEqual(unsliced);
|
|
135
|
+
}, EXTRACT_TIMEOUT_MS);
|
|
136
|
+
test("a ten-solid representation extracts identically at every granularity", () => {
|
|
137
|
+
const [unsliced, unslicedUnits] = extractAt(MULTI_ITEM_FIXTURE, Infinity);
|
|
138
|
+
const [atDefault, defaultUnits] = extractAt(MULTI_ITEM_FIXTURE, 4);
|
|
139
|
+
const [perItem, perItemUnits] = extractAt(MULTI_ITEM_FIXTURE, 1);
|
|
140
|
+
expect(defaultUnits).toBeGreaterThan(unslicedUnits);
|
|
141
|
+
expect(perItemUnits).toBeGreaterThan(defaultUnits);
|
|
142
|
+
expect(unsliced.length).toBeGreaterThan(0);
|
|
143
|
+
expect(atDefault).toStrictEqual(unsliced);
|
|
144
|
+
expect(perItem).toStrictEqual(unsliced);
|
|
145
|
+
}, MULTI_EXTRACT_TIMEOUT_MS);
|
|
146
|
+
test("ranges after a leading placement are still placed by it", () => {
|
|
147
|
+
const [unsliced, unslicedUnits] = extractAt(LEADING_PLACEMENT_FIXTURE, Infinity);
|
|
148
|
+
const [sliced, slicedUnits] = extractAt(LEADING_PLACEMENT_FIXTURE, 1);
|
|
149
|
+
expect(slicedUnits).toBeGreaterThan(unslicedUnits);
|
|
150
|
+
// Three solids, and the placement they inherit is not the identity —
|
|
151
|
+
// both of which have to hold or the equality below proves nothing.
|
|
152
|
+
expect(unsliced.length).toBe(3);
|
|
153
|
+
expect(unsliced[0].transform).not.toBe("");
|
|
154
|
+
expect(unsliced[0].transform.split(",").slice(TRANSLATION_START, TRANSLATION_END))
|
|
155
|
+
.not.toStrictEqual(["0", "0", "0"]);
|
|
156
|
+
expect(sliced).toStrictEqual(unsliced);
|
|
157
|
+
}, EXTRACT_TIMEOUT_MS);
|
|
158
|
+
test("a mapped item that throws after pushing does not shift later items", () => {
|
|
159
|
+
const [unsliced, unslicedUnits] = extractAt(MAPPED_ITEM_FAILURE_FIXTURE, Infinity);
|
|
160
|
+
const [atDefault, defaultUnits] = extractAt(MAPPED_ITEM_FAILURE_FIXTURE, 4);
|
|
161
|
+
const [perItem, perItemUnits] = extractAt(MAPPED_ITEM_FAILURE_FIXTURE, 1);
|
|
162
|
+
expect(defaultUnits).toBeGreaterThan(unslicedUnits);
|
|
163
|
+
expect(perItemUnits).toBeGreaterThan(defaultUnits);
|
|
164
|
+
// Five solids follow the failing mapped item; if the fixture ever stops
|
|
165
|
+
// producing them the equalities below stop meaning anything.
|
|
166
|
+
expect(unsliced.length).toBe(5);
|
|
167
|
+
expect(atDefault).toStrictEqual(unsliced);
|
|
168
|
+
expect(perItem).toStrictEqual(unsliced);
|
|
169
|
+
}, EXTRACT_TIMEOUT_MS);
|
|
170
|
+
});
|