@ifc-lite/export 3.0.1 → 4.0.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.
- package/README.md +37 -1
- package/dist/anonymize-export.d.ts +60 -0
- package/dist/anonymize-export.d.ts.map +1 -0
- package/dist/anonymize-export.js +217 -0
- package/dist/anonymize-export.js.map +1 -0
- package/dist/anonymize-placement.d.ts +71 -0
- package/dist/anonymize-placement.d.ts.map +1 -0
- package/dist/anonymize-placement.js +266 -0
- package/dist/anonymize-placement.js.map +1 -0
- package/dist/anonymize-scrub.d.ts +64 -0
- package/dist/anonymize-scrub.d.ts.map +1 -0
- package/dist/anonymize-scrub.js +315 -0
- package/dist/anonymize-scrub.js.map +1 -0
- package/dist/anonymize-types.d.ts +235 -0
- package/dist/anonymize-types.d.ts.map +1 -0
- package/dist/anonymize-types.js +5 -0
- package/dist/anonymize-types.js.map +1 -0
- package/dist/declared-property-type.d.ts +15 -0
- package/dist/declared-property-type.d.ts.map +1 -1
- package/dist/declared-property-type.js +43 -0
- package/dist/declared-property-type.js.map +1 -1
- package/dist/entity-type-sets.d.ts +47 -0
- package/dist/entity-type-sets.d.ts.map +1 -0
- package/dist/entity-type-sets.js +91 -0
- package/dist/entity-type-sets.js.map +1 -0
- package/dist/georef-closure.d.ts +55 -0
- package/dist/georef-closure.d.ts.map +1 -0
- package/dist/georef-closure.js +95 -0
- package/dist/georef-closure.js.map +1 -0
- package/dist/glb.d.ts.map +1 -1
- package/dist/glb.js +26 -2
- package/dist/glb.js.map +1 -1
- package/dist/ifc5-classification.d.ts +36 -0
- package/dist/ifc5-classification.d.ts.map +1 -0
- package/dist/ifc5-classification.js +46 -0
- package/dist/ifc5-classification.js.map +1 -0
- package/dist/ifc5-export-helpers.d.ts +32 -0
- package/dist/ifc5-export-helpers.d.ts.map +1 -0
- package/dist/ifc5-export-helpers.js +84 -0
- package/dist/ifc5-export-helpers.js.map +1 -0
- package/dist/ifc5-exporter.d.ts.map +1 -1
- package/dist/ifc5-exporter.js +14 -86
- package/dist/ifc5-exporter.js.map +1 -1
- package/dist/ifc5-material.d.ts +38 -0
- package/dist/ifc5-material.d.ts.map +1 -0
- package/dist/ifc5-material.js +32 -0
- package/dist/ifc5-material.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/merged-context.d.ts +100 -0
- package/dist/merged-context.d.ts.map +1 -0
- package/dist/merged-context.js +211 -0
- package/dist/merged-context.js.map +1 -0
- package/dist/merged-empty-containers.d.ts +63 -0
- package/dist/merged-empty-containers.d.ts.map +1 -0
- package/dist/merged-empty-containers.js +354 -0
- package/dist/merged-empty-containers.js.map +1 -0
- package/dist/merged-exporter.d.ts +28 -67
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +134 -258
- package/dist/merged-exporter.js.map +1 -1
- package/dist/merged-guid.d.ts +48 -0
- package/dist/merged-guid.d.ts.map +1 -0
- package/dist/merged-guid.js +128 -0
- package/dist/merged-guid.js.map +1 -0
- package/dist/merged-rel-aggregates.d.ts +63 -0
- package/dist/merged-rel-aggregates.d.ts.map +1 -0
- package/dist/merged-rel-aggregates.js +122 -0
- package/dist/merged-rel-aggregates.js.map +1 -0
- package/dist/merged-remap.d.ts +18 -0
- package/dist/merged-remap.d.ts.map +1 -0
- package/dist/merged-remap.js +66 -0
- package/dist/merged-remap.js.map +1 -0
- package/dist/merged-subcontext.d.ts +41 -0
- package/dist/merged-subcontext.d.ts.map +1 -0
- package/dist/merged-subcontext.js +99 -0
- package/dist/merged-subcontext.js.map +1 -0
- package/dist/parquet-exporter-ondemand.d.ts +34 -0
- package/dist/parquet-exporter-ondemand.d.ts.map +1 -0
- package/dist/parquet-exporter-ondemand.js +89 -0
- package/dist/parquet-exporter-ondemand.js.map +1 -0
- package/dist/parquet-exporter.d.ts +1 -29
- package/dist/parquet-exporter.d.ts.map +1 -1
- package/dist/parquet-exporter.js +68 -90
- package/dist/parquet-exporter.js.map +1 -1
- package/dist/parquet-type-strings.d.ts +11 -0
- package/dist/parquet-type-strings.d.ts.map +1 -0
- package/dist/parquet-type-strings.js +40 -0
- package/dist/parquet-type-strings.js.map +1 -0
- package/dist/parquet-uint32-columns.d.ts +30 -0
- package/dist/parquet-uint32-columns.d.ts.map +1 -0
- package/dist/parquet-uint32-columns.js +38 -0
- package/dist/parquet-uint32-columns.js.map +1 -0
- package/dist/reference-collector.d.ts +47 -51
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +115 -171
- package/dist/reference-collector.js.map +1 -1
- package/dist/related-entities.d.ts +10 -0
- package/dist/related-entities.d.ts.map +1 -0
- package/dist/related-entities.js +274 -0
- package/dist/related-entities.js.map +1 -0
- package/dist/schema-converter-attr-remap.d.ts +53 -0
- package/dist/schema-converter-attr-remap.d.ts.map +1 -0
- package/dist/schema-converter-attr-remap.js +106 -0
- package/dist/schema-converter-attr-remap.js.map +1 -0
- package/dist/schema-converter.d.ts.map +1 -1
- package/dist/schema-converter.js +24 -1
- package/dist/schema-converter.js.map +1 -1
- package/dist/schema-untranslatable.d.ts +35 -0
- package/dist/schema-untranslatable.d.ts.map +1 -0
- package/dist/schema-untranslatable.js +60 -0
- package/dist/schema-untranslatable.js.map +1 -0
- package/dist/step-argument-parser.d.ts.map +1 -1
- package/dist/step-argument-parser.js +11 -1
- package/dist/step-argument-parser.js.map +1 -1
- package/dist/step-attribute-mutations.js +14 -11
- package/dist/step-attribute-mutations.js.map +1 -1
- package/dist/step-collection.d.ts.map +1 -1
- package/dist/step-collection.js +51 -8
- package/dist/step-collection.js.map +1 -1
- package/dist/step-export-types.d.ts +42 -0
- package/dist/step-export-types.d.ts.map +1 -1
- package/dist/step-export-types.js +10 -0
- package/dist/step-export-types.js.map +1 -1
- package/dist/step-exporter.d.ts.map +1 -1
- package/dist/step-exporter.js +9 -1
- package/dist/step-exporter.js.map +1 -1
- package/dist/step-header.d.ts +1 -1
- package/dist/step-header.d.ts.map +1 -1
- package/dist/step-header.js +2 -2
- package/dist/step-header.js.map +1 -1
- package/dist/step-map-unit.d.ts +2 -1
- package/dist/step-map-unit.d.ts.map +1 -1
- package/dist/step-map-unit.js.map +1 -1
- package/dist/step-serialization.d.ts +10 -30
- package/dist/step-serialization.d.ts.map +1 -1
- package/dist/step-serialization.js +10 -60
- package/dist/step-serialization.js.map +1 -1
- package/dist/step-source-iteration.d.ts.map +1 -1
- package/dist/step-source-iteration.js +21 -0
- package/dist/step-source-iteration.js.map +1 -1
- package/dist/style-closure.d.ts +91 -0
- package/dist/style-closure.d.ts.map +1 -0
- package/dist/style-closure.js +164 -0
- package/dist/style-closure.js.map +1 -0
- package/dist/subset-entity-reader.d.ts +104 -0
- package/dist/subset-entity-reader.d.ts.map +1 -0
- package/dist/subset-entity-reader.js +112 -0
- package/dist/subset-entity-reader.js.map +1 -0
- package/dist/subset-roots.d.ts +74 -0
- package/dist/subset-roots.d.ts.map +1 -0
- package/dist/subset-roots.js +168 -0
- package/dist/subset-roots.js.map +1 -0
- package/dist/type-owned-psets.d.ts +19 -0
- package/dist/type-owned-psets.d.ts.map +1 -1
- package/dist/type-owned-psets.js +31 -0
- package/dist/type-owned-psets.js.map +1 -1
- package/dist/unit-normalize.d.ts.map +1 -1
- package/dist/unit-normalize.js +10 -2
- package/dist/unit-normalize.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -61,6 +61,39 @@ const blob = new Blob([stepText], { type: 'application/x-step' });
|
|
|
61
61
|
|
|
62
62
|
`exportToStep` is the round-trip path for property edits. Edit via `@ifc-lite/mutations`, export with `applyMutations: true`, ship the resulting `.ifc` to whatever consumes IFC.
|
|
63
63
|
|
|
64
|
+
## Anonymized isolated export — for bug reports
|
|
65
|
+
|
|
66
|
+
`collectRelatedEntities` + `exportAnonymizedSubset` pick a seed selection,
|
|
67
|
+
expand it by relationship context (host, openings/fillers, type, materials,
|
|
68
|
+
spatial containment), and export exactly that subset with every
|
|
69
|
+
project-identifying signal removed — while local placement rotations and
|
|
70
|
+
non-orthogonal cuts survive, so a parsing/geometry bug reproduction still
|
|
71
|
+
reproduces:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { collectRelatedEntities, exportAnonymizedSubset } from '@ifc-lite/export';
|
|
75
|
+
|
|
76
|
+
const related = collectRelatedEntities(store, new Set([312])); // seed expressId(s)
|
|
77
|
+
const result = exportAnonymizedSubset(store, related.all);
|
|
78
|
+
await saveFile('anonymized.ifc', result.content);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Every `AnonymizeOptions` field defaults to the maximally-scrubbed direction
|
|
82
|
+
(names pseudonymized, `GlobalId`s regenerated, property sets dropped, owner
|
|
83
|
+
history and georeferencing scrubbed) — `ObjectType` and material/style names
|
|
84
|
+
are pseudonymized right along with everything else under the default
|
|
85
|
+
`pseudonymizeAllNames`, and the STEP header's `originating_system` is
|
|
86
|
+
blanked under the default `scrubOwnerHistory`. What stays in the file by
|
|
87
|
+
decision: geometry and local placement rotations/non-orthogonal cuts (only
|
|
88
|
+
the root placement's translation is zeroed), structural entity types,
|
|
89
|
+
material *assignments* (which material, just not its original name), and
|
|
90
|
+
the header's `preprocessor_version` (from `IfcApplication`, defaults to
|
|
91
|
+
`'ifc-lite'`) — that is what makes the file useful for a bug repro. See the
|
|
92
|
+
[Exporting
|
|
93
|
+
Guide](https://ifclite.dev/docs/guide/exporting/#anonymized-isolated-export)
|
|
94
|
+
for the full option list, including how to opt back into authored names via
|
|
95
|
+
`--keep-other-names`.
|
|
96
|
+
|
|
64
97
|
## Apache Parquet — for analytics
|
|
65
98
|
|
|
66
99
|
```typescript
|
|
@@ -84,6 +117,8 @@ argument to drop overlay-deleted entities (and every row that references one) fr
|
|
|
84
117
|
`Entities`, `Properties`, `Quantities` and `Relationships`:
|
|
85
118
|
|
|
86
119
|
```typescript
|
|
120
|
+
import { ParquetExporter } from '@ifc-lite/export';
|
|
121
|
+
|
|
87
122
|
const exporter = new ParquetExporter(store, geometryResult, mutationView);
|
|
88
123
|
```
|
|
89
124
|
|
|
@@ -125,7 +160,7 @@ const bytes = new Uint8Array(await file.arrayBuffer());
|
|
|
125
160
|
const lod0 = await generateLod0(bytes);
|
|
126
161
|
|
|
127
162
|
// LOD1 — meshes simplified to bounding boxes / convex hulls, returned as GLB
|
|
128
|
-
const lod1 = await generateLod1(bytes
|
|
163
|
+
const lod1 = await generateLod1(bytes);
|
|
129
164
|
// { glb: Uint8Array, meta: { failedElements, mapping, ... } }
|
|
130
165
|
|
|
131
166
|
// Falls back gracefully to box geometry if a complex element fails to mesh
|
|
@@ -134,6 +169,7 @@ const lod1 = await generateLod1(bytes, { quality: 'medium' });
|
|
|
134
169
|
## Also exported
|
|
135
170
|
|
|
136
171
|
- `MergedExporter` - merge several parsed models into one STEP export
|
|
172
|
+
- `collectRelatedEntities` / `exportAnonymizedSubset` - anonymized isolated export (see above)
|
|
137
173
|
- `convertEntityType` / `convertStepLine` / `needsConversion` - IFC2X3 / IFC4 / IFC4X3 schema conversion helpers
|
|
138
174
|
- `parseGLB` / `parseGLBToMeshData` / `extractGlbMapping` - GLB round-trip readers
|
|
139
175
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `exportAnonymizedSubset` (#2934, the "anonymized isolated export" feature,
|
|
3
|
+
* plan A2 "Orchestrator" row): given a caller-picked `includedIds` selection
|
|
4
|
+
* (typically `RelatedEntities.all` from `related-entities.ts`), produces a
|
|
5
|
+
* STEP file that contains ONLY that subset, with every project-identifying
|
|
6
|
+
* signal removed while the geometry-relevant local transformations
|
|
7
|
+
* (rotations, non-orthogonal cuts) survive — so a parsing bug reproduction
|
|
8
|
+
* keeps reproducing.
|
|
9
|
+
*
|
|
10
|
+
* Per the plan's "Key mechanism choice": anonymization is expressed as
|
|
11
|
+
* mutations on a PRIVATE `MutablePropertyView` + `StoreEditor` — never a text
|
|
12
|
+
* post-pass — fed to the same `StepExporter` every other export mode uses.
|
|
13
|
+
* The overlay is scoped to one call: nothing here writes into `store`, and
|
|
14
|
+
* the view is discarded once `export()` returns, so two calls against the
|
|
15
|
+
* same `store` never interact.
|
|
16
|
+
*
|
|
17
|
+
* Call order matters and is fixed:
|
|
18
|
+
* 1. `pruneUnresolvableRelationships` — ahead of everything else, so a
|
|
19
|
+
* relationship this export cannot legally emit (its own mandatory,
|
|
20
|
+
* single-valued reference — or every member of a SET/LIST reference —
|
|
21
|
+
* names an entity outside `includedIds`) is removed from the ROOT set
|
|
22
|
+
* BEFORE `StepExporter` ever sees it, rather than discovered mid-closure
|
|
23
|
+
* and withheld with the generic `relationshipWithheldWarning`
|
|
24
|
+
* (`step-export-types.ts`). Reported distinctly, as
|
|
25
|
+
* `stats.prunedRelationshipIds`, for exactly this reason: a caller
|
|
26
|
+
* should be able to tell "this association is gone because the anonymizer
|
|
27
|
+
* pruned it" from "this association is gone for some other export-time
|
|
28
|
+
* reason" without grepping warning text.
|
|
29
|
+
* 2. `applyPlacementAnonymization` (`anonymize-placement.ts`) — root
|
|
30
|
+
* placement zeroing and georeferencing/address blanking.
|
|
31
|
+
* 3. `applyScrub` (`anonymize-scrub.ts`) — pseudonyms, GlobalId
|
|
32
|
+
* regeneration, owner-history scrub, `HasPropertySets` clearing.
|
|
33
|
+
* 4. `StepExporter.export` with `subsetEntityIds` set to the PRUNED id set
|
|
34
|
+
* and the header scrubbed (`author`/`organization`/`authorization`
|
|
35
|
+
* blanked, per the decision doc — `originating_system` and
|
|
36
|
+
* `preprocessor_version` are deliberately left alone).
|
|
37
|
+
*
|
|
38
|
+
* 2 and 3 both read `store`/`index` and queue their edits onto the SAME
|
|
39
|
+
* `view`/`editor` pair, so `StepExporter`'s closure walk (which reads the
|
|
40
|
+
* overlay through `effective-index.ts`) sees every edit from both passes at
|
|
41
|
+
* once — never two overlays that could disagree about the same entity.
|
|
42
|
+
*/
|
|
43
|
+
import type { IfcDataStore } from '@ifc-lite/parser';
|
|
44
|
+
import type { AnonymizeOptions, AnonymizeResult } from './anonymize-types.js';
|
|
45
|
+
/**
|
|
46
|
+
* Export `includedIds` (plus infrastructure and their forward closure — see
|
|
47
|
+
* `subset-roots.ts`) as an anonymized STEP file. Every `AnonymizeOptions`
|
|
48
|
+
* field defaults to the maximally-scrubbed direction (see that interface's
|
|
49
|
+
* own doc), so calling this with no options at all is the intended common
|
|
50
|
+
* case, not a partial anonymization a caller must opt further into.
|
|
51
|
+
*
|
|
52
|
+
* Throws when `store` has no source bytes to read entity records from — a
|
|
53
|
+
* server-parsed or synthetic store with `source.byteLength === 0` has
|
|
54
|
+
* nothing for `readEntityArgs`/`StepExporter`'s source-iteration pass to
|
|
55
|
+
* read, and every module this orchestrator calls assumes source-backed
|
|
56
|
+
* records exist for at least the infrastructure/relationship entities it
|
|
57
|
+
* touches.
|
|
58
|
+
*/
|
|
59
|
+
export declare function exportAnonymizedSubset(store: IfcDataStore, includedIds: ReadonlySet<number>, options?: AnonymizeOptions): AnonymizeResult;
|
|
60
|
+
//# sourceMappingURL=anonymize-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-export.d.ts","sourceRoot":"","sources":["../src/anonymize-export.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,kBAAkB,CAAC;AAcrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAiJ9E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAmGjB"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { MutablePropertyView, StoreEditor } from '@ifc-lite/mutations';
|
|
5
|
+
import { getEffectiveEntityIndex } from './effective-index.js';
|
|
6
|
+
import { getSubsetEntityIds, IFC_ROOT_TYPES, identifyingTypesFor } from './subset-roots.js';
|
|
7
|
+
import { attrIndex, readEntityArgs, stepSourceSchema } from './subset-entity-reader.js';
|
|
8
|
+
import { collectReferencedEntityIds, refGroupFromArg, relationshipRefsSurviveExclusion, } from './reference-collector.js';
|
|
9
|
+
import { applyPlacementAnonymization } from './anonymize-placement.js';
|
|
10
|
+
import { applyScrub } from './anonymize-scrub.js';
|
|
11
|
+
import { StepExporter } from './step-exporter.js';
|
|
12
|
+
import { isPropertySetDefinitionClass } from './type-owned-psets.js';
|
|
13
|
+
/**
|
|
14
|
+
* Drop every `IfcPropertySet`/`IfcElementQuantity` id out of `includedIds`
|
|
15
|
+
* unless `keepPropertySets` is on (#3351 item 2, the SDK-path half `#3361`
|
|
16
|
+
* left open): `applyScrub`'s `keepPropertySets` handling only ever clears an
|
|
17
|
+
* `IfcTypeObject`'s `HasPropertySets` SLOT, so a pset that reached
|
|
18
|
+
* `includedIds` some other way — a caller's own
|
|
19
|
+
* `collectRelatedEntities(..., { IfcRelDefinesByProperties: true })` walk, or
|
|
20
|
+
* a hand-built id set — survived complete, values included, with
|
|
21
|
+
* `keepPropertySets` at its documented `false` default.
|
|
22
|
+
*
|
|
23
|
+
* DROP means EXCLUDE, not "emit scrubbed": this pass never queues a mutation
|
|
24
|
+
* on a pset entity, it removes the id from the set the exporter's closure
|
|
25
|
+
* ever sees, the same way the CLI's `--keep-psets` already behaves (it
|
|
26
|
+
* drives both this exclusion, via `RelatedEntityOptions.IfcRelDefinesByProperties`,
|
|
27
|
+
* and `keepPropertySets` from one flag) and the same way the viewer's two
|
|
28
|
+
* toggles are now coupled (`AnonymizationOptionsPanel.tsx`). Scrubbing in
|
|
29
|
+
* place was considered and rejected: a property/quantity VALUE is left
|
|
30
|
+
* unscrubbed by design everywhere else in this module (only NAMES are
|
|
31
|
+
* pseudonymized), so a scrubbed-but-kept pset would still carry
|
|
32
|
+
* `IFCPROPERTYSINGLEVALUE('Owner',$,IFCTEXT('jane.doe@acme-corp.example'),$)`
|
|
33
|
+
* verbatim — exactly the leak this exists to close. Exclusion is the only
|
|
34
|
+
* one of the two that actually removes it.
|
|
35
|
+
*
|
|
36
|
+
* Must run BEFORE `pruneUnresolvableRelationships`: dropping a pset id here
|
|
37
|
+
* feeds straight into that pass's `getSubsetEntityIds` exclusion set, so an
|
|
38
|
+
* `IfcRelDefinesByProperties` whose `RelatingPropertyDefinition` named only a
|
|
39
|
+
* now-dropped pset is pruned the same way any other relationship with an
|
|
40
|
+
* excluded mandatory single-valued reference is — never left dangling.
|
|
41
|
+
*
|
|
42
|
+
* Returns the surviving set plus every id this pass dropped, reported
|
|
43
|
+
* distinctly (the same shape `prunedRelationshipIds` already uses on
|
|
44
|
+
* `AnonymizeResult.stats`) so a caller can tell "excluded because it is a
|
|
45
|
+
* property set" from any other reason an id might be missing, without
|
|
46
|
+
* grepping `warnings` text.
|
|
47
|
+
*/
|
|
48
|
+
function excludePropertySetsUnlessKept(index, includedIds, keepPropertySets) {
|
|
49
|
+
if (keepPropertySets)
|
|
50
|
+
return { includedIds: new Set(includedIds), droppedPropertySetIds: [] };
|
|
51
|
+
const kept = new Set();
|
|
52
|
+
const droppedPropertySetIds = [];
|
|
53
|
+
for (const id of includedIds) {
|
|
54
|
+
if (isPropertySetDefinitionClass(index.typeOf(id))) {
|
|
55
|
+
droppedPropertySetIds.push(id);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
kept.add(id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
droppedPropertySetIds.sort((a, b) => a - b);
|
|
62
|
+
return { includedIds: kept, droppedPropertySetIds };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Null `PropertyReference` when an emitted `IfcPropertyReferenceValue` names
|
|
66
|
+
* an entity the subset excludes. The value can be reached by the forward
|
|
67
|
+
* closure rather than appearing in the caller's seed set, hence `closureIds`.
|
|
68
|
+
*/
|
|
69
|
+
function dropExcludedPropertyReferences(store, index, closureIds, excludedIds, view, schema) {
|
|
70
|
+
const droppedIds = [];
|
|
71
|
+
for (const id of closureIds) {
|
|
72
|
+
if ((index.typeOf(id) ?? '') !== 'IFCPROPERTYREFERENCEVALUE')
|
|
73
|
+
continue;
|
|
74
|
+
const record = readEntityArgs(store, index, id);
|
|
75
|
+
if (!record)
|
|
76
|
+
continue;
|
|
77
|
+
const idx = attrIndex('IFCPROPERTYREFERENCEVALUE', 'PropertyReference', schema);
|
|
78
|
+
if (idx === -1 || idx >= record.args.length)
|
|
79
|
+
continue;
|
|
80
|
+
const ref = refGroupFromArg(record.args[idx]);
|
|
81
|
+
if (typeof ref !== 'number' || !excludedIds.has(ref))
|
|
82
|
+
continue;
|
|
83
|
+
view.setPositionalAttribute(id, idx, null);
|
|
84
|
+
droppedIds.push(id);
|
|
85
|
+
}
|
|
86
|
+
return droppedIds;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Every id in `includedIds` whose EXPRESS type is an `IfcRel*` (an
|
|
90
|
+
* `IFC_ROOT_TYPES` member starting `IFCREL`), and whose own STEP record
|
|
91
|
+
* `relationshipRefsSurviveExclusion` would refuse to bridge or emit — i.e.
|
|
92
|
+
* one that names, in a single-valued attribute, an id NOT in `includedIds`
|
|
93
|
+
* (and not infrastructure), or whose every member of a SET/LIST attribute is
|
|
94
|
+
* likewise excluded. Everything ELSE in `includedIds` is left exactly as the
|
|
95
|
+
* caller passed it: this only ever REMOVES relationship ids, never adds or
|
|
96
|
+
* removes anything else.
|
|
97
|
+
*
|
|
98
|
+
* "Excluded" here is computed the same way the export's own closure would
|
|
99
|
+
* (`getSubsetEntityIds`'s `excludedIds` — every `IFC_ROOT_TYPES` /
|
|
100
|
+
* `IDENTIFYING_TYPES` id not in `includedIds`), so a relationship this
|
|
101
|
+
* function prunes is exactly one `StepExporter` would otherwise have had to
|
|
102
|
+
* withhold on its own.
|
|
103
|
+
*/
|
|
104
|
+
function pruneUnresolvableRelationships(store, index, includedIds) {
|
|
105
|
+
// Deliberately the DEFAULT identifying set, not the caller's narrowed one:
|
|
106
|
+
// this pass only decides which relationship members to trim, and a kept
|
|
107
|
+
// georeference entity is rooted by `getSubsetEntityIds` before it gets here.
|
|
108
|
+
// Threading the narrowed set in was measured dead -- mutating it failed zero
|
|
109
|
+
// tests -- so it is not carried.
|
|
110
|
+
const { excludedIds } = getSubsetEntityIds(index, includedIds);
|
|
111
|
+
const isExcluded = (id) => excludedIds.has(id);
|
|
112
|
+
const relationshipIds = [...includedIds]
|
|
113
|
+
.filter((id) => (index.typeOf(id) ?? '').startsWith('IFCREL'))
|
|
114
|
+
.sort((a, b) => a - b);
|
|
115
|
+
const prunedRelationshipIds = [];
|
|
116
|
+
const finalIncludedIds = new Set(includedIds);
|
|
117
|
+
for (const id of relationshipIds) {
|
|
118
|
+
const record = readEntityArgs(store, index, id);
|
|
119
|
+
// Unreadable (no source bytes, or an unparseable line): leave it for
|
|
120
|
+
// `StepExporter`'s own gates to decide, rather than guessing here.
|
|
121
|
+
if (!record)
|
|
122
|
+
continue;
|
|
123
|
+
const groups = record.args
|
|
124
|
+
.map(refGroupFromArg)
|
|
125
|
+
.filter((g) => g !== undefined);
|
|
126
|
+
if (!relationshipRefsSurviveExclusion(groups, isExcluded)) {
|
|
127
|
+
prunedRelationshipIds.push(id);
|
|
128
|
+
finalIncludedIds.delete(id);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { prunedRelationshipIds, finalIncludedIds };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Export `includedIds` (plus infrastructure and their forward closure — see
|
|
135
|
+
* `subset-roots.ts`) as an anonymized STEP file. Every `AnonymizeOptions`
|
|
136
|
+
* field defaults to the maximally-scrubbed direction (see that interface's
|
|
137
|
+
* own doc), so calling this with no options at all is the intended common
|
|
138
|
+
* case, not a partial anonymization a caller must opt further into.
|
|
139
|
+
*
|
|
140
|
+
* Throws when `store` has no source bytes to read entity records from — a
|
|
141
|
+
* server-parsed or synthetic store with `source.byteLength === 0` has
|
|
142
|
+
* nothing for `readEntityArgs`/`StepExporter`'s source-iteration pass to
|
|
143
|
+
* read, and every module this orchestrator calls assumes source-backed
|
|
144
|
+
* records exist for at least the infrastructure/relationship entities it
|
|
145
|
+
* touches.
|
|
146
|
+
*/
|
|
147
|
+
export function exportAnonymizedSubset(store, includedIds, options = {}) {
|
|
148
|
+
if (!store.source || store.source.byteLength <= 0) {
|
|
149
|
+
throw new Error('exportAnonymizedSubset: the store has no source bytes to export from '
|
|
150
|
+
+ '(a server-parsed or synthetic store with source.byteLength === 0 '
|
|
151
|
+
+ 'cannot be anonymized — this feature reads and rewrites the original '
|
|
152
|
+
+ 'STEP records).');
|
|
153
|
+
}
|
|
154
|
+
// One private overlay for this call only — never the caller's own
|
|
155
|
+
// mutation view, and never written into `store`. See the module doc.
|
|
156
|
+
const view = new MutablePropertyView(null, 'anonymize');
|
|
157
|
+
const editor = new StoreEditor(store, view);
|
|
158
|
+
const index = getEffectiveEntityIndex(store, view, true);
|
|
159
|
+
// Runs BEFORE relationship pruning — see that function's own doc for why
|
|
160
|
+
// the order matters (a dropped pset must be visible to the exclusion set
|
|
161
|
+
// relationship pruning reads).
|
|
162
|
+
const { includedIds: psetFilteredIds, droppedPropertySetIds } = excludePropertySetsUnlessKept(index, includedIds, options.keepPropertySets ?? false);
|
|
163
|
+
const { prunedRelationshipIds, finalIncludedIds } = pruneUnresolvableRelationships(store, index, psetFilteredIds);
|
|
164
|
+
const subsetIdentifyingTypes = identifyingTypesFor(options?.removeGeoreferencing !== false);
|
|
165
|
+
const subset = getSubsetEntityIds(index, finalIncludedIds, subsetIdentifyingTypes);
|
|
166
|
+
const exportClosure = collectReferencedEntityIds(subset.roots, store.source, index, subset.excludedIds);
|
|
167
|
+
const droppedPropertyReferenceIds = dropExcludedPropertyReferences(store, index, exportClosure, subset.excludedIds, view, stepSourceSchema(store.schemaVersion));
|
|
168
|
+
const placementResult = applyPlacementAnonymization(store, index, finalIncludedIds, editor, view, options);
|
|
169
|
+
const scrubResult = applyScrub(store, index, finalIncludedIds, view, options);
|
|
170
|
+
const exportResult = new StepExporter(store, view).export({
|
|
171
|
+
schema: store.schemaVersion,
|
|
172
|
+
subsetEntityIds: finalIncludedIds,
|
|
173
|
+
subsetIdentifyingTypes,
|
|
174
|
+
filename: options.filename ?? 'anonymized.ifc',
|
|
175
|
+
// Header scrub per the decision doc: author/organization/authorization
|
|
176
|
+
// blanked outright (never inherited from the source header — an empty
|
|
177
|
+
// string is a deliberate override, not "no override", per
|
|
178
|
+
// `step-header.ts`'s `??` wiring). `description` gets the same
|
|
179
|
+
// unconditional override: `buildStepHeader` falls through to the SOURCE
|
|
180
|
+
// FILE_DESCRIPTION items verbatim whenever this orchestrator leaves
|
|
181
|
+
// `description` undefined — an authoring tool's free-text
|
|
182
|
+
// "Comment [...]" item there is exactly as identifying as the
|
|
183
|
+
// author/organization fields beside it, so it is blanked the same way,
|
|
184
|
+
// not merely left to whatever the source happened to carry.
|
|
185
|
+
// `originating_system` is blanked under `scrubOwnerHistory` (a
|
|
186
|
+
// vendor build string such as `26.0.0 NOR FULL` encodes the licence
|
|
187
|
+
// region); `preprocessor_version` comes from `application`, left unset
|
|
188
|
+
// here (defaults to 'ifc-lite').
|
|
189
|
+
author: '',
|
|
190
|
+
organization: '',
|
|
191
|
+
authorization: '',
|
|
192
|
+
description: '',
|
|
193
|
+
...((options.scrubOwnerHistory ?? true) ? { originatingSystem: '' } : {}),
|
|
194
|
+
timeStamp: options.timeStamp,
|
|
195
|
+
guidRandom: options.guidRandom,
|
|
196
|
+
});
|
|
197
|
+
const includedRootEntityCount = [...finalIncludedIds]
|
|
198
|
+
.filter((id) => IFC_ROOT_TYPES.has(index.typeOf(id) ?? '')).length;
|
|
199
|
+
return {
|
|
200
|
+
content: exportResult.content,
|
|
201
|
+
guidMap: scrubResult.guidMap,
|
|
202
|
+
stats: {
|
|
203
|
+
entityCount: exportResult.stats.entityCount,
|
|
204
|
+
includedRootEntityCount,
|
|
205
|
+
prunedRelationshipIds,
|
|
206
|
+
droppedPropertySetIds,
|
|
207
|
+
droppedPropertyReferenceIds,
|
|
208
|
+
zeroedPlacements: placementResult.zeroedPlacements,
|
|
209
|
+
warnings: [
|
|
210
|
+
...placementResult.warnings,
|
|
211
|
+
...scrubResult.warnings,
|
|
212
|
+
...exportResult.stats.warnings,
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=anonymize-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-export.js","sourceRoot":"","sources":["../src/anonymize-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root-placement zeroing and georeferencing/address blanking for the
|
|
3
|
+
* "anonymized isolated export" feature (#2934, plan section A4).
|
|
4
|
+
*
|
|
5
|
+
* Coordinates are the strongest identifying signal a reproduction carries —
|
|
6
|
+
* an absolute site position pins the model to a real address — but the
|
|
7
|
+
* ROTATION in the placement chain and any non-orthogonal cuts are exactly
|
|
8
|
+
* what a parsing bug reproduction needs to keep. So this module zeroes only
|
|
9
|
+
* the TRANSLATION of each root `IfcLocalPlacement` (`PlacementRelTo = $`),
|
|
10
|
+
* leaving `Axis`/`RefDirection` and every child placement untouched.
|
|
11
|
+
*
|
|
12
|
+
* **Clone, never rewrite.** `IfcCartesianPoint` and `IfcAxis2Placement3D` /
|
|
13
|
+
* `2D` records are routinely SHARED — two storeys placed at the same origin,
|
|
14
|
+
* or a template point reused across a model — so rewriting one in place would
|
|
15
|
+
* silently move every other placement that happens to reference the same
|
|
16
|
+
* point. Each zeroed root gets its own freshly-cloned point and axis via
|
|
17
|
+
* `StoreEditor.addEntity`, and only the root's `RelativePlacement` slot is
|
|
18
|
+
* repointed (`setPositionalAttribute`) to the clone. Nothing else in the
|
|
19
|
+
* model ever sees the edit.
|
|
20
|
+
*
|
|
21
|
+
* The same clone-and-repoint mechanism handles
|
|
22
|
+
* `IfcGeometricRepresentationContext.WorldCoordinateSystem` (a second, less
|
|
23
|
+
* obvious place a survey offset can live — #2934's plan A4 step 4) and is
|
|
24
|
+
* shared between both call sites as {@link zeroAxisPlacementSlot}.
|
|
25
|
+
*
|
|
26
|
+
* `IfcGridPlacement` / `IfcLinearPlacement` roots have no `RelativePlacement`
|
|
27
|
+
* → `IfcCartesianPoint` chain to clone against, so they are left untouched
|
|
28
|
+
* and reported as a warning rather than silently ignored or corrupted.
|
|
29
|
+
*
|
|
30
|
+
* Reads go through {@link readEntityArgs} / {@link attrIndex}
|
|
31
|
+
* (`subset-entity-reader.ts`) so a positional slot is always resolved BY
|
|
32
|
+
* EXPRESS NAME against the schema registry, never a hand-counted index that
|
|
33
|
+
* would silently drift the day an entity's attribute layout changes.
|
|
34
|
+
*/
|
|
35
|
+
import type { IfcSourceBytes } from '@ifc-lite/parser';
|
|
36
|
+
import type { MutablePropertyView, StoreEditor } from '@ifc-lite/mutations';
|
|
37
|
+
import type { EffectiveEntityIndex } from './effective-index.js';
|
|
38
|
+
import type { AnonymizeOptions } from './anonymize-types.js';
|
|
39
|
+
/** The slice of {@link AnonymizeOptions} this module reads. */
|
|
40
|
+
export type PlacementAnonymizationOptions = Pick<AnonymizeOptions, 'zeroRootPlacement' | 'removeGeoreferencing'>;
|
|
41
|
+
/** What {@link applyPlacementAnonymization} did — folded into
|
|
42
|
+
* `AnonymizeResult.stats` by the orchestrator (`anonymize-export.ts`). */
|
|
43
|
+
export interface PlacementAnonymizationResult {
|
|
44
|
+
/** Each root `IfcLocalPlacement` this call zeroed, and the ORIGINAL
|
|
45
|
+
* (pre-zero) translation it removed. */
|
|
46
|
+
zeroedPlacements: {
|
|
47
|
+
expressId: number;
|
|
48
|
+
translation: number[];
|
|
49
|
+
}[];
|
|
50
|
+
/** Non-fatal notices: an unsupported root placement kind, an unreadable
|
|
51
|
+
* chain, multiple roots collapsing onto one origin, or a chain this walk
|
|
52
|
+
* bounded before it reached one (256-hop cap, see "Bounding walks over
|
|
53
|
+
* file-supplied references", AGENTS.md). */
|
|
54
|
+
warnings: string[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Zero every root `IfcLocalPlacement` translation reachable from
|
|
58
|
+
* `includedIds`, zero `WorldCoordinateSystem` on every
|
|
59
|
+
* `IfcGeometricRepresentationContext` (always exported — it is an
|
|
60
|
+
* `INFRASTRUCTURE_TYPES` member, `reference-collector.ts`), and blank
|
|
61
|
+
* `IfcSite` / `IfcBuilding` georeferencing and address attributes.
|
|
62
|
+
*
|
|
63
|
+
* `store`/`index` are read from (never mutated directly) — every change goes
|
|
64
|
+
* through `editor` (new entities, positional overrides) or `view` (named
|
|
65
|
+
* attribute overrides), so the private `MutablePropertyView` overlay the
|
|
66
|
+
* orchestrator built stays the ONE place this export's edits live.
|
|
67
|
+
*/
|
|
68
|
+
export declare function applyPlacementAnonymization(store: {
|
|
69
|
+
readonly source: IfcSourceBytes;
|
|
70
|
+
}, index: EffectiveEntityIndex, includedIds: ReadonlySet<number>, editor: StoreEditor, view: MutablePropertyView, opts?: PlacementAnonymizationOptions): PlacementAnonymizationResult;
|
|
71
|
+
//# sourceMappingURL=anonymize-placement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-placement.d.ts","sourceRoot":"","sources":["../src/anonymize-placement.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAK7D,+DAA+D;AAC/D,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAC9C,gBAAgB,EAChB,mBAAmB,GAAG,sBAAsB,CAC7C,CAAC;AAEF;2EAC2E;AAC3E,MAAM,WAAW,4BAA4B;IAC3C;6CACyC;IACzC,gBAAgB,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACjE;;;iDAG6C;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAUD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,EAC1C,KAAK,EAAE,oBAAoB,EAC3B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,mBAAmB,EACzB,IAAI,CAAC,EAAE,6BAA6B,GACnC,4BAA4B,CAc9B"}
|