@ifc-lite/export 3.0.0 → 3.1.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 +34 -0
- package/dist/anonymize-export.d.ts +60 -0
- package/dist/anonymize-export.d.ts.map +1 -0
- package/dist/anonymize-export.js +117 -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 +312 -0
- package/dist/anonymize-scrub.js.map +1 -0
- package/dist/anonymize-types.d.ts +212 -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 +19 -8
- package/dist/declared-property-type.d.ts.map +1 -1
- package/dist/declared-property-type.js +31 -9
- 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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/merged-exporter.d.ts +19 -0
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +1 -1
- package/dist/merged-exporter.js.map +1 -1
- package/dist/parquet-exporter.d.ts +1 -3
- package/dist/parquet-exporter.d.ts.map +1 -1
- package/dist/parquet-exporter.js +11 -10
- package/dist/parquet-exporter.js.map +1 -1
- package/dist/property-value-serialization.d.ts +54 -0
- package/dist/property-value-serialization.d.ts.map +1 -0
- package/dist/property-value-serialization.js +134 -0
- package/dist/property-value-serialization.js.map +1 -0
- package/dist/reference-collector.d.ts +47 -0
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +88 -156
- 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 +259 -0
- package/dist/related-entities.js.map +1 -0
- package/dist/schema-converter.d.ts.map +1 -1
- package/dist/schema-converter.js +46 -96
- package/dist/schema-converter.js.map +1 -1
- package/dist/source-ref-bounds.d.ts +3 -3
- package/dist/source-ref-bounds.js +3 -3
- package/dist/step-attribute-mutations.d.ts +0 -42
- package/dist/step-attribute-mutations.d.ts.map +1 -1
- package/dist/step-attribute-mutations.js +17 -147
- package/dist/step-attribute-mutations.js.map +1 -1
- package/dist/step-attribute-serializers.d.ts +41 -0
- package/dist/step-attribute-serializers.d.ts.map +1 -0
- package/dist/step-attribute-serializers.js +74 -0
- package/dist/step-attribute-serializers.js.map +1 -0
- package/dist/step-collection.d.ts +2 -2
- package/dist/step-collection.d.ts.map +1 -1
- package/dist/step-collection.js +38 -8
- package/dist/step-collection.js.map +1 -1
- package/dist/step-export-contexts.d.ts +5 -7
- package/dist/step-export-contexts.d.ts.map +1 -1
- package/dist/step-export-contexts.js +6 -7
- package/dist/step-export-contexts.js.map +1 -1
- package/dist/step-export-types.d.ts +27 -0
- package/dist/step-export-types.d.ts.map +1 -1
- package/dist/step-export-types.js.map +1 -1
- package/dist/step-exporter.d.ts +3 -3
- package/dist/step-exporter.js +4 -4
- package/dist/step-exporter.js.map +1 -1
- package/dist/step-geometry-types.d.ts +1 -17
- package/dist/step-geometry-types.d.ts.map +1 -1
- package/dist/step-geometry-types.js +51 -35
- package/dist/step-geometry-types.js.map +1 -1
- package/dist/step-georeferencing.d.ts +0 -10
- package/dist/step-georeferencing.d.ts.map +1 -1
- package/dist/step-georeferencing.js +46 -94
- package/dist/step-georeferencing.js.map +1 -1
- package/dist/step-header.d.ts +11 -1
- package/dist/step-header.d.ts.map +1 -1
- package/dist/step-header.js +2 -9
- package/dist/step-header.js.map +1 -1
- package/dist/step-map-unit.d.ts +90 -0
- package/dist/step-map-unit.d.ts.map +1 -0
- package/dist/step-map-unit.js +277 -0
- package/dist/step-map-unit.js.map +1 -0
- package/dist/step-overlay-attribute-overrides.d.ts +32 -0
- package/dist/step-overlay-attribute-overrides.d.ts.map +1 -0
- package/dist/step-overlay-attribute-overrides.js +83 -0
- package/dist/step-overlay-attribute-overrides.js.map +1 -0
- package/dist/step-overlay-entities.d.ts +3 -3
- package/dist/step-pass-builder.d.ts +4 -3
- package/dist/step-pass-builder.d.ts.map +1 -1
- package/dist/step-pass-builder.js.map +1 -1
- package/dist/step-property-set-collection.d.ts +24 -0
- package/dist/step-property-set-collection.d.ts.map +1 -0
- package/dist/step-property-set-collection.js +286 -0
- package/dist/step-property-set-collection.js.map +1 -0
- package/dist/step-property-set-generators.d.ts +20 -0
- package/dist/step-property-set-generators.d.ts.map +1 -0
- package/dist/step-property-set-generators.js +98 -0
- package/dist/step-property-set-generators.js.map +1 -0
- package/dist/step-property-set-index.d.ts +25 -0
- package/dist/step-property-set-index.d.ts.map +1 -0
- package/dist/step-property-set-index.js +69 -0
- package/dist/step-property-set-index.js.map +1 -0
- package/dist/step-property-set-readers.d.ts +158 -0
- package/dist/step-property-set-readers.d.ts.map +1 -0
- package/dist/step-property-set-readers.js +251 -0
- package/dist/step-property-set-readers.js.map +1 -0
- package/dist/step-property-sets.d.ts +2 -186
- package/dist/step-property-sets.d.ts.map +1 -1
- package/dist/step-property-sets.js +22 -674
- package/dist/step-property-sets.js.map +1 -1
- package/dist/step-serialization.d.ts +17 -51
- package/dist/step-serialization.d.ts.map +1 -1
- package/dist/step-serialization.js +19 -128
- package/dist/step-serialization.js.map +1 -1
- package/dist/step-source-iteration.d.ts +7 -5
- package/dist/step-source-iteration.d.ts.map +1 -1
- package/dist/step-source-iteration.js +3 -3
- package/dist/step-source-iteration.js.map +1 -1
- package/dist/subset-entity-reader.d.ts +103 -0
- package/dist/subset-entity-reader.d.ts.map +1 -0
- package/dist/subset-entity-reader.js +102 -0
- package/dist/subset-entity-reader.js.map +1 -0
- package/dist/subset-roots.d.ts +58 -0
- package/dist/subset-roots.d.ts.map +1 -0
- package/dist/subset-roots.js +103 -0
- package/dist/subset-roots.js.map +1 -0
- package/package.json +7 -7
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
|
|
@@ -134,6 +167,7 @@ const lod1 = await generateLod1(bytes, { quality: 'medium' });
|
|
|
134
167
|
## Also exported
|
|
135
168
|
|
|
136
169
|
- `MergedExporter` - merge several parsed models into one STEP export
|
|
170
|
+
- `collectRelatedEntities` / `exportAnonymizedSubset` - anonymized isolated export (see above)
|
|
137
171
|
- `convertEntityType` / `convertStepLine` / `needsConversion` - IFC2X3 / IFC4 / IFC4X3 schema conversion helpers
|
|
138
172
|
- `parseGLB` / `parseGLBToMeshData` / `extractGlbMapping` - GLB round-trip readers
|
|
139
173
|
|
|
@@ -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;AAUrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAmD9E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CA0DjB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
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 } from './subset-roots.js';
|
|
7
|
+
import { readEntityArgs } from './subset-entity-reader.js';
|
|
8
|
+
import { 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
|
+
/**
|
|
13
|
+
* Every id in `includedIds` whose EXPRESS type is an `IfcRel*` (an
|
|
14
|
+
* `IFC_ROOT_TYPES` member starting `IFCREL`), and whose own STEP record
|
|
15
|
+
* `relationshipRefsSurviveExclusion` would refuse to bridge or emit — i.e.
|
|
16
|
+
* one that names, in a single-valued attribute, an id NOT in `includedIds`
|
|
17
|
+
* (and not infrastructure), or whose every member of a SET/LIST attribute is
|
|
18
|
+
* likewise excluded. Everything ELSE in `includedIds` is left exactly as the
|
|
19
|
+
* caller passed it: this only ever REMOVES relationship ids, never adds or
|
|
20
|
+
* removes anything else.
|
|
21
|
+
*
|
|
22
|
+
* "Excluded" here is computed the same way the export's own closure would
|
|
23
|
+
* (`getSubsetEntityIds`'s `excludedIds` — every `IFC_ROOT_TYPES` /
|
|
24
|
+
* `IDENTIFYING_TYPES` id not in `includedIds`), so a relationship this
|
|
25
|
+
* function prunes is exactly one `StepExporter` would otherwise have had to
|
|
26
|
+
* withhold on its own.
|
|
27
|
+
*/
|
|
28
|
+
function pruneUnresolvableRelationships(store, index, includedIds) {
|
|
29
|
+
const { excludedIds } = getSubsetEntityIds(index, includedIds);
|
|
30
|
+
const isExcluded = (id) => excludedIds.has(id);
|
|
31
|
+
const relationshipIds = [...includedIds]
|
|
32
|
+
.filter((id) => (index.typeOf(id) ?? '').startsWith('IFCREL'))
|
|
33
|
+
.sort((a, b) => a - b);
|
|
34
|
+
const prunedRelationshipIds = [];
|
|
35
|
+
const finalIncludedIds = new Set(includedIds);
|
|
36
|
+
for (const id of relationshipIds) {
|
|
37
|
+
const record = readEntityArgs(store, index, id);
|
|
38
|
+
// Unreadable (no source bytes, or an unparseable line): leave it for
|
|
39
|
+
// `StepExporter`'s own gates to decide, rather than guessing here.
|
|
40
|
+
if (!record)
|
|
41
|
+
continue;
|
|
42
|
+
const groups = record.args
|
|
43
|
+
.map(refGroupFromArg)
|
|
44
|
+
.filter((g) => g !== undefined);
|
|
45
|
+
if (!relationshipRefsSurviveExclusion(groups, isExcluded)) {
|
|
46
|
+
prunedRelationshipIds.push(id);
|
|
47
|
+
finalIncludedIds.delete(id);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { prunedRelationshipIds, finalIncludedIds };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Export `includedIds` (plus infrastructure and their forward closure — see
|
|
54
|
+
* `subset-roots.ts`) as an anonymized STEP file. Every `AnonymizeOptions`
|
|
55
|
+
* field defaults to the maximally-scrubbed direction (see that interface's
|
|
56
|
+
* own doc), so calling this with no options at all is the intended common
|
|
57
|
+
* case, not a partial anonymization a caller must opt further into.
|
|
58
|
+
*
|
|
59
|
+
* Throws when `store` has no source bytes to read entity records from — a
|
|
60
|
+
* server-parsed or synthetic store with `source.byteLength === 0` has
|
|
61
|
+
* nothing for `readEntityArgs`/`StepExporter`'s source-iteration pass to
|
|
62
|
+
* read, and every module this orchestrator calls assumes source-backed
|
|
63
|
+
* records exist for at least the infrastructure/relationship entities it
|
|
64
|
+
* touches.
|
|
65
|
+
*/
|
|
66
|
+
export function exportAnonymizedSubset(store, includedIds, options = {}) {
|
|
67
|
+
if (!store.source || store.source.byteLength <= 0) {
|
|
68
|
+
throw new Error('exportAnonymizedSubset: the store has no source bytes to export from '
|
|
69
|
+
+ '(a server-parsed or synthetic store with source.byteLength === 0 '
|
|
70
|
+
+ 'cannot be anonymized — this feature reads and rewrites the original '
|
|
71
|
+
+ 'STEP records).');
|
|
72
|
+
}
|
|
73
|
+
// One private overlay for this call only — never the caller's own
|
|
74
|
+
// mutation view, and never written into `store`. See the module doc.
|
|
75
|
+
const view = new MutablePropertyView(null, 'anonymize');
|
|
76
|
+
const editor = new StoreEditor(store, view);
|
|
77
|
+
const index = getEffectiveEntityIndex(store, view, true);
|
|
78
|
+
const { prunedRelationshipIds, finalIncludedIds } = pruneUnresolvableRelationships(store, index, includedIds);
|
|
79
|
+
const placementResult = applyPlacementAnonymization(store, index, finalIncludedIds, editor, view, options);
|
|
80
|
+
const scrubResult = applyScrub(store, index, finalIncludedIds, view, options);
|
|
81
|
+
const exportResult = new StepExporter(store, view).export({
|
|
82
|
+
schema: store.schemaVersion,
|
|
83
|
+
subsetEntityIds: finalIncludedIds,
|
|
84
|
+
filename: options.filename ?? 'anonymized.ifc',
|
|
85
|
+
// Header scrub per the decision doc: author/organization/authorization
|
|
86
|
+
// blanked outright (never inherited from the source header — an empty
|
|
87
|
+
// string is a deliberate override, not "no override", per
|
|
88
|
+
// `step-header.ts`'s `??` wiring). `originating_system` is blanked under
|
|
89
|
+
// `scrubOwnerHistory` (a vendor build string such as `26.0.0 NOR FULL`
|
|
90
|
+
// encodes the licence region); `preprocessor_version` comes from
|
|
91
|
+
// `application`, left unset here (defaults to 'ifc-lite').
|
|
92
|
+
author: '',
|
|
93
|
+
organization: '',
|
|
94
|
+
authorization: '',
|
|
95
|
+
...((options.scrubOwnerHistory ?? true) ? { originatingSystem: '' } : {}),
|
|
96
|
+
timeStamp: options.timeStamp,
|
|
97
|
+
guidRandom: options.guidRandom,
|
|
98
|
+
});
|
|
99
|
+
const includedRootEntityCount = [...finalIncludedIds]
|
|
100
|
+
.filter((id) => IFC_ROOT_TYPES.has(index.typeOf(id) ?? '')).length;
|
|
101
|
+
return {
|
|
102
|
+
content: exportResult.content,
|
|
103
|
+
guidMap: scrubResult.guidMap,
|
|
104
|
+
stats: {
|
|
105
|
+
entityCount: exportResult.stats.entityCount,
|
|
106
|
+
includedRootEntityCount,
|
|
107
|
+
prunedRelationshipIds,
|
|
108
|
+
zeroedPlacements: placementResult.zeroedPlacements,
|
|
109
|
+
warnings: [
|
|
110
|
+
...placementResult.warnings,
|
|
111
|
+
...scrubResult.warnings,
|
|
112
|
+
...exportResult.stats.warnings,
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# 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"}
|
|
@@ -0,0 +1,266 @@
|
|
|
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 { attrIndex, readEntityArgs } from './subset-entity-reader.js';
|
|
5
|
+
import { splitTopLevelArgs } from './step-argument-parser.js';
|
|
6
|
+
import { entityRef, stepReal } from './step-serialization.js';
|
|
7
|
+
const IFC_SITE_ADDRESS_ATTRIBUTES = [
|
|
8
|
+
'RefLatitude',
|
|
9
|
+
'RefLongitude',
|
|
10
|
+
'RefElevation',
|
|
11
|
+
'LandTitleNumber',
|
|
12
|
+
'SiteAddress',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Zero every root `IfcLocalPlacement` translation reachable from
|
|
16
|
+
* `includedIds`, zero `WorldCoordinateSystem` on every
|
|
17
|
+
* `IfcGeometricRepresentationContext` (always exported — it is an
|
|
18
|
+
* `INFRASTRUCTURE_TYPES` member, `reference-collector.ts`), and blank
|
|
19
|
+
* `IfcSite` / `IfcBuilding` georeferencing and address attributes.
|
|
20
|
+
*
|
|
21
|
+
* `store`/`index` are read from (never mutated directly) — every change goes
|
|
22
|
+
* through `editor` (new entities, positional overrides) or `view` (named
|
|
23
|
+
* attribute overrides), so the private `MutablePropertyView` overlay the
|
|
24
|
+
* orchestrator built stays the ONE place this export's edits live.
|
|
25
|
+
*/
|
|
26
|
+
export function applyPlacementAnonymization(store, index, includedIds, editor, view, opts) {
|
|
27
|
+
const warnings = [];
|
|
28
|
+
const zeroedPlacements = [];
|
|
29
|
+
if (opts?.zeroRootPlacement !== false) {
|
|
30
|
+
zeroRootPlacements(store, index, includedIds, editor, warnings, zeroedPlacements);
|
|
31
|
+
zeroWorldCoordinateSystems(store, index, editor, warnings);
|
|
32
|
+
}
|
|
33
|
+
if (opts?.removeGeoreferencing !== false) {
|
|
34
|
+
blankSiteAndBuildingAddresses(index, includedIds, view);
|
|
35
|
+
}
|
|
36
|
+
return { zeroedPlacements, warnings };
|
|
37
|
+
}
|
|
38
|
+
function zeroRootPlacements(store, index, includedIds, editor, warnings, zeroedPlacements) {
|
|
39
|
+
// Memoised by placementId: the root a placement chain terminates at is a
|
|
40
|
+
// pure function of that id ("Bounding walks", AGENTS.md — global memoising
|
|
41
|
+
// is the right scope here, not path-scoped, since the answer never
|
|
42
|
+
// accumulates across callers), and many products in a subset commonly
|
|
43
|
+
// share one storey/building placement chain.
|
|
44
|
+
const rootCache = new Map();
|
|
45
|
+
const localPlacementRoots = new Set();
|
|
46
|
+
for (const id of includedIds) {
|
|
47
|
+
const rec = readEntityArgs(store, index, id);
|
|
48
|
+
if (!rec)
|
|
49
|
+
continue;
|
|
50
|
+
const objectPlacementIdx = attrIndex(rec.type, 'ObjectPlacement'); // declared on IfcProduct itself — slot order checked identical across ENTITIES_IFC2X3/_IFC4/_IFC4X3, no `schema` arg needed (#3309)
|
|
51
|
+
if (objectPlacementIdx < 0 || objectPlacementIdx >= rec.args.length)
|
|
52
|
+
continue;
|
|
53
|
+
const placementId = parseRef(rec.args[objectPlacementIdx]);
|
|
54
|
+
if (placementId === null)
|
|
55
|
+
continue;
|
|
56
|
+
let root = rootCache.get(placementId);
|
|
57
|
+
if (root === undefined) {
|
|
58
|
+
root = findRootPlacement(store, index, placementId, warnings);
|
|
59
|
+
rootCache.set(placementId, root);
|
|
60
|
+
}
|
|
61
|
+
if (!root)
|
|
62
|
+
continue;
|
|
63
|
+
if (root.rootType !== 'IFCLOCALPLACEMENT') {
|
|
64
|
+
warnings.push(`#${root.rootId} (${root.rootType}) is a root placement this export cannot zero — only ` +
|
|
65
|
+
`IfcLocalPlacement roots are supported; left untouched, so its absolute position is still in the file.`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
localPlacementRoots.add(root.rootId);
|
|
69
|
+
}
|
|
70
|
+
for (const rootId of localPlacementRoots) {
|
|
71
|
+
const translation = zeroAxisPlacementSlot(store, index, editor, rootId, 'IFCLOCALPLACEMENT', 'RelativePlacement', warnings);
|
|
72
|
+
if (translation)
|
|
73
|
+
zeroedPlacements.push({ expressId: rootId, translation });
|
|
74
|
+
}
|
|
75
|
+
if (zeroedPlacements.length > 1) {
|
|
76
|
+
warnings.push(`${zeroedPlacements.length} independent root placements were each zeroed to the origin; ` +
|
|
77
|
+
`their original relative offset from one another is not preserved.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Follow `PlacementRelTo` from `startPlacementId` while the current record is
|
|
82
|
+
* an `IfcLocalPlacement`, and return the terminal placement — either an
|
|
83
|
+
* `IfcLocalPlacement` with `PlacementRelTo = $` (a zeroable root) or a
|
|
84
|
+
* non-`IfcLocalPlacement` record the chain cannot continue past (an
|
|
85
|
+
* `IfcGridPlacement` / `IfcLinearPlacement`, reported by the caller). `null`
|
|
86
|
+
* when the chain could not be safely walked at all — a cycle, a hop past the
|
|
87
|
+
* 256-hop cap, or a link that does not resolve to a readable record — each
|
|
88
|
+
* case appending its own warning before returning.
|
|
89
|
+
*/
|
|
90
|
+
function findRootPlacement(store, index, startPlacementId, warnings) {
|
|
91
|
+
const visited = new Set();
|
|
92
|
+
let currentId = startPlacementId;
|
|
93
|
+
let hops = 0;
|
|
94
|
+
for (;;) {
|
|
95
|
+
if (visited.has(currentId)) {
|
|
96
|
+
warnings.push(`Placement chain from #${startPlacementId} revisits #${currentId} (PlacementRelTo cycle); left untouched.`);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
visited.add(currentId);
|
|
100
|
+
hops++;
|
|
101
|
+
if (hops > 256) {
|
|
102
|
+
warnings.push(`Placement chain from #${startPlacementId} exceeds 256 hops; left untouched rather than followed indefinitely.`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const rec = readEntityArgs(store, index, currentId);
|
|
106
|
+
if (!rec) {
|
|
107
|
+
warnings.push(`Placement #${currentId} in the chain from #${startPlacementId} could not be read; left untouched.`);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (rec.type !== 'IFCLOCALPLACEMENT') {
|
|
111
|
+
return { rootId: currentId, rootType: rec.type };
|
|
112
|
+
}
|
|
113
|
+
const relToIdx = attrIndex(rec.type, 'PlacementRelTo'); // `rec.type` is always IFCLOCALPLACEMENT here — order verified identical across all 3 schemas (#3309)
|
|
114
|
+
const parentId = relToIdx >= 0 && relToIdx < rec.args.length ? parseRef(rec.args[relToIdx]) : null;
|
|
115
|
+
if (parentId === null) {
|
|
116
|
+
return { rootId: currentId, rootType: rec.type };
|
|
117
|
+
}
|
|
118
|
+
currentId = parentId;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// IfcGeometricRepresentationContext.WorldCoordinateSystem
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
/**
|
|
125
|
+
* Every `IfcGeometricRepresentationContext` in the model — not just
|
|
126
|
+
* `includedIds` — because it is an `INFRASTRUCTURE_TYPES` member
|
|
127
|
+
* (`reference-collector.ts`) and is therefore always carried into the
|
|
128
|
+
* export regardless of what the caller selected. A plain, non-recursive
|
|
129
|
+
* pass over `index`: bounded by the model's own (small) count of
|
|
130
|
+
* representation contexts, not a reference walk that needs its own guard.
|
|
131
|
+
*/
|
|
132
|
+
function zeroWorldCoordinateSystems(store, index, editor, warnings) {
|
|
133
|
+
for (const [id, ref] of index) {
|
|
134
|
+
if (index.effectiveType(id, ref.type) !== 'IFCGEOMETRICREPRESENTATIONCONTEXT')
|
|
135
|
+
continue;
|
|
136
|
+
// `TrueNorth` is deliberately left alone — only the origin offset is
|
|
137
|
+
// identifying; the survey rotation is exactly the kind of
|
|
138
|
+
// geometry-relevant signal this feature is written to keep (#2934).
|
|
139
|
+
zeroAxisPlacementSlot(store, index, editor, id, 'IFCGEOMETRICREPRESENTATIONCONTEXT', 'WorldCoordinateSystem', warnings);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Shared clone-and-repoint primitive
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
/**
|
|
146
|
+
* Zero the `IfcCartesianPoint.Location` reachable through
|
|
147
|
+
* `entityId.<slotName>` → `IfcAxis2Placement2D|3D` → `Location`, by CLONING
|
|
148
|
+
* the point and the axis placement (never rewriting either — see the module
|
|
149
|
+
* doc) and repointing `entityId.<slotName>` at the clone.
|
|
150
|
+
*
|
|
151
|
+
* Returns the original (pre-zero) coordinates when a zero-clone was
|
|
152
|
+
* performed, or `null` when there was nothing to do: the slot is `$`, it
|
|
153
|
+
* does not resolve to an `IfcAxis2Placement2D/3D` → `IfcCartesianPoint`
|
|
154
|
+
* chain (warned), or the point is already at the origin.
|
|
155
|
+
*/
|
|
156
|
+
function zeroAxisPlacementSlot(store, index, editor, entityId, entityType, slotName, warnings) {
|
|
157
|
+
const slotIdx = attrIndex(entityType, slotName); // entityType/slotName always fixed literals, order verified identical across all 3 schemas (#3309)
|
|
158
|
+
if (slotIdx < 0)
|
|
159
|
+
return null;
|
|
160
|
+
const rec = readEntityArgs(store, index, entityId);
|
|
161
|
+
if (!rec || slotIdx >= rec.args.length)
|
|
162
|
+
return null;
|
|
163
|
+
const axisId = parseRef(rec.args[slotIdx]);
|
|
164
|
+
if (axisId === null)
|
|
165
|
+
return null; // `$` — nothing placed here to zero.
|
|
166
|
+
const axisRec = readEntityArgs(store, index, axisId);
|
|
167
|
+
if (!axisRec) {
|
|
168
|
+
warnings.push(`#${entityId} ${slotName} references #${axisId}, which could not be read; left untouched.`);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const is3D = axisRec.type === 'IFCAXIS2PLACEMENT3D';
|
|
172
|
+
const is2D = axisRec.type === 'IFCAXIS2PLACEMENT2D';
|
|
173
|
+
if (!is3D && !is2D) {
|
|
174
|
+
warnings.push(`#${entityId} ${slotName} resolves to #${axisId} (${axisRec.type}), not an ` +
|
|
175
|
+
`IfcAxis2Placement2D/3D; left untouched.`);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const locationIdx = attrIndex(axisRec.type, 'Location'); // IfcAxis2Placement2D/3D — same verified-stable guarantee as slotIdx above (#3309)
|
|
179
|
+
const pointId = locationIdx >= 0 ? parseRef(axisRec.args[locationIdx]) : null;
|
|
180
|
+
if (pointId === null)
|
|
181
|
+
return null;
|
|
182
|
+
const pointRec = readEntityArgs(store, index, pointId);
|
|
183
|
+
if (!pointRec || pointRec.type !== 'IFCCARTESIANPOINT') {
|
|
184
|
+
warnings.push(`#${entityId} ${slotName} → #${axisId} → Location #${pointId} is not an IfcCartesianPoint; left untouched.`);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const coords = parseCoordinateList(pointRec.args[0]);
|
|
188
|
+
if (!coords || coords.every((c) => c === 0))
|
|
189
|
+
return null; // absent, or already at the origin.
|
|
190
|
+
// Clone the point at the origin, same dimensionality.
|
|
191
|
+
const newPoint = editor.addEntity('IfcCartesianPoint', [coords.map(() => stepReal(0))]);
|
|
192
|
+
// Clone the axis placement, carrying `Axis`/`RefDirection` over VERBATIM —
|
|
193
|
+
// the rotation is exactly what a reproduction needs to keep.
|
|
194
|
+
const newAxisAttrs = [entityRef(newPoint.expressId)];
|
|
195
|
+
for (const name of is3D ? ['Axis', 'RefDirection'] : ['RefDirection']) {
|
|
196
|
+
const idx = attrIndex(axisRec.type, name); // same guarantee as locationIdx above (#3309)
|
|
197
|
+
newAxisAttrs.push(idx >= 0 ? verbatimAttr(axisRec.args[idx]) : null);
|
|
198
|
+
}
|
|
199
|
+
const newAxis = editor.addEntity(is3D ? 'IfcAxis2Placement3D' : 'IfcAxis2Placement2D', newAxisAttrs);
|
|
200
|
+
editor.setPositionalAttribute(entityId, slotIdx, entityRef(newAxis.expressId));
|
|
201
|
+
return coords;
|
|
202
|
+
}
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// IfcSite / IfcBuilding georeferencing + address blanking
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
/**
|
|
207
|
+
* `IfcMapConversion(Scaled)` / `IfcProjectedCRS` need no handling here: they
|
|
208
|
+
* are `IDENTIFYING_TYPES` (`subset-roots.ts`), excluded from the export
|
|
209
|
+
* outright, and only inverse-referenced from these fields — so they are
|
|
210
|
+
* simply absent from the output once nothing still points at them.
|
|
211
|
+
*
|
|
212
|
+
* All six blanked slots are OPTIONAL but not all STRING-typed — a LIST OF
|
|
213
|
+
* INTEGER, a REAL, and two entity refs among them — so `$` (via
|
|
214
|
+
* `setPositionalAttribute` + `null`) is the only blank valid for all of them;
|
|
215
|
+
* `setAttribute` only emits a quoted STEP string and would corrupt the rest.
|
|
216
|
+
*/
|
|
217
|
+
function blankSiteAndBuildingAddresses(index, includedIds, view) {
|
|
218
|
+
for (const id of includedIds) {
|
|
219
|
+
const type = index.typeOf(id);
|
|
220
|
+
if (type === 'IFCSITE') {
|
|
221
|
+
for (const attr of IFC_SITE_ADDRESS_ATTRIBUTES) {
|
|
222
|
+
const idx = attrIndex(type, attr); // IfcSite's address slots verified stable across all 3 schemas (#3309)
|
|
223
|
+
if (idx >= 0)
|
|
224
|
+
view.setPositionalAttribute(id, idx, null);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (type === 'IFCBUILDING') {
|
|
228
|
+
const idx = attrIndex(type, 'BuildingAddress'); // verified stable across all 3 schemas (#3309)
|
|
229
|
+
if (idx >= 0)
|
|
230
|
+
view.setPositionalAttribute(id, idx, null);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// Token helpers
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
/** `"#42"` → `42`; anything else (`$`, a literal, missing) → `null`. */
|
|
238
|
+
function parseRef(token) {
|
|
239
|
+
if (!token)
|
|
240
|
+
return null;
|
|
241
|
+
const match = /^#(\d+)$/.exec(token.trim());
|
|
242
|
+
return match ? Number(match[1]) : null;
|
|
243
|
+
}
|
|
244
|
+
/** Carry a verbatim STEP token (`$` or `#N`) into `StoreEditor.addEntity`'s
|
|
245
|
+
* attribute conventions: `$` becomes `null`, a reference token is passed
|
|
246
|
+
* through as the `"#42"` string `addEntity` recognizes. */
|
|
247
|
+
function verbatimAttr(token) {
|
|
248
|
+
if (!token)
|
|
249
|
+
return null;
|
|
250
|
+
const trimmed = token.trim();
|
|
251
|
+
return trimmed === '$' || trimmed === '' ? null : trimmed;
|
|
252
|
+
}
|
|
253
|
+
/** Parse an `IfcCartesianPoint.Coordinates` token — a parenthesized,
|
|
254
|
+
* top-level-comma-separated REAL list (`(1000.,2000.,30.)`) — into numbers.
|
|
255
|
+
* `null` when the token isn't a list, or any member doesn't parse as a
|
|
256
|
+
* finite number. */
|
|
257
|
+
function parseCoordinateList(token) {
|
|
258
|
+
if (!token)
|
|
259
|
+
return null;
|
|
260
|
+
const trimmed = token.trim();
|
|
261
|
+
if (!trimmed.startsWith('(') || !trimmed.endsWith(')'))
|
|
262
|
+
return null;
|
|
263
|
+
const numbers = splitTopLevelArgs(trimmed.slice(1, -1)).map((part) => Number(part.trim()));
|
|
264
|
+
return numbers.every((n) => Number.isFinite(n)) ? numbers : null;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=anonymize-placement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymize-placement.js","sourceRoot":"","sources":["../src/anonymize-placement.ts"],"names":[],"mappings":"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"}
|