@inweb/viewer-three 26.9.3 → 26.9.4
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/dist/plugins/components/AxesHelperComponent.js +23 -22
- package/dist/plugins/components/AxesHelperComponent.js.map +1 -1
- package/dist/plugins/components/AxesHelperComponent.min.js +23 -0
- package/dist/plugins/components/AxesHelperComponent.module.js +31 -9
- package/dist/plugins/components/AxesHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/ExtentsHelperComponent.js +23 -22
- package/dist/plugins/components/ExtentsHelperComponent.js.map +1 -1
- package/dist/plugins/components/ExtentsHelperComponent.min.js +23 -0
- package/dist/plugins/components/ExtentsHelperComponent.module.js +28 -6
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/LightHelperComponent.js +23 -22
- package/dist/plugins/components/LightHelperComponent.js.map +1 -1
- package/dist/plugins/components/LightHelperComponent.min.js +23 -0
- package/dist/plugins/components/LightHelperComponent.module.js +35 -9
- package/dist/plugins/components/LightHelperComponent.module.js.map +1 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js +23 -97
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +1 -1
- package/dist/plugins/components/RoomEnvironmentComponent.min.js +23 -0
- package/dist/plugins/components/RoomEnvironmentComponent.module.js +27 -7
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +1 -1
- package/dist/plugins/components/StatsPanelComponent.js +23 -92
- package/dist/plugins/components/StatsPanelComponent.js.map +1 -1
- package/dist/plugins/components/StatsPanelComponent.min.js +23 -0
- package/dist/plugins/components/StatsPanelComponent.module.js +26 -5
- package/dist/plugins/components/StatsPanelComponent.module.js.map +1 -1
- package/dist/plugins/loaders/GLTFCloudLoader.js +31 -2515
- package/dist/plugins/loaders/GLTFCloudLoader.js.map +1 -1
- package/dist/plugins/loaders/GLTFCloudLoader.min.js +23 -0
- package/dist/plugins/loaders/GLTFCloudLoader.module.js +35 -20
- package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +1 -1
- package/dist/plugins/loaders/IFCXLoader.js +35 -689
- package/dist/plugins/loaders/IFCXLoader.js.map +1 -1
- package/dist/plugins/loaders/IFCXLoader.min.js +23 -0
- package/dist/plugins/loaders/IFCXLoader.module.js +833 -859
- package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -1
- package/dist/plugins/loaders/PotreeLoader.js +26 -70
- package/dist/plugins/loaders/PotreeLoader.js.map +1 -1
- package/dist/plugins/loaders/PotreeLoader.min.js +23 -0
- package/dist/plugins/loaders/PotreeLoader.module.js +37 -15
- package/dist/plugins/loaders/PotreeLoader.module.js.map +1 -1
- package/dist/viewer-three.js +1502 -55140
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +26 -3
- package/dist/viewer-three.module.js +3584 -3660
- package/dist/viewer-three.module.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,931 +1,919 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
24
|
+
import { Loader as Loader$1, GLTFLoadingManager, ModelImpl, loaders } from '@inweb/viewer-three';
|
|
25
|
+
import { Box3, Vector3, Scene, PerspectiveCamera, Group, Matrix4, BufferGeometry, BufferAttribute, MeshLambertMaterial, Mesh, LineBasicMaterial, Line, Float32BufferAttribute, MeshStandardMaterial, Color, Euler, PointsMaterial, Points, Loader, FileLoader } from 'three';
|
|
26
|
+
import { PCDLoader } from 'three/examples/jsm/loaders/PCDLoader.js';
|
|
6
27
|
|
|
7
28
|
const THREE = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
Box3,
|
|
30
|
+
BufferAttribute,
|
|
31
|
+
BufferGeometry,
|
|
32
|
+
Color,
|
|
33
|
+
Euler,
|
|
34
|
+
Float32BufferAttribute,
|
|
35
|
+
Group,
|
|
36
|
+
Line,
|
|
37
|
+
LineBasicMaterial,
|
|
38
|
+
Matrix4,
|
|
39
|
+
Mesh,
|
|
40
|
+
MeshLambertMaterial,
|
|
41
|
+
MeshStandardMaterial,
|
|
42
|
+
Points,
|
|
43
|
+
PointsMaterial,
|
|
44
|
+
PerspectiveCamera,
|
|
45
|
+
Scene,
|
|
46
|
+
Vector3,
|
|
26
47
|
};
|
|
27
|
-
|
|
28
48
|
var StackedLayerProvider = class {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
providers;
|
|
50
|
+
constructor(providers) {
|
|
51
|
+
this.providers = providers;
|
|
52
|
+
}
|
|
53
|
+
async GetLayerByURI(uri) {
|
|
54
|
+
let errorStack = [];
|
|
55
|
+
for (let provider of this.providers) {
|
|
56
|
+
let layer = await provider.GetLayerByURI(uri);
|
|
57
|
+
if (!(layer instanceof Error)) {
|
|
58
|
+
return layer;
|
|
59
|
+
} else {
|
|
60
|
+
errorStack.push(layer);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return new Error(JSON.stringify(errorStack));
|
|
64
|
+
}
|
|
45
65
|
};
|
|
46
|
-
|
|
47
66
|
var InMemoryLayerProvider = class {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
layers;
|
|
68
|
+
constructor() {
|
|
69
|
+
this.layers = new Map();
|
|
70
|
+
}
|
|
71
|
+
GetLayerByURI(uri) {
|
|
72
|
+
if (!this.layers.has(uri)) {
|
|
73
|
+
return new Error(`File with uri "${uri}" not found`);
|
|
74
|
+
}
|
|
75
|
+
return Promise.resolve(this.layers.get(uri));
|
|
76
|
+
}
|
|
77
|
+
add(file) {
|
|
78
|
+
if (this.layers.has(file.header.id)) {
|
|
79
|
+
throw new Error(`Inserting file with duplicate ID "${file.header.id}"`);
|
|
80
|
+
}
|
|
81
|
+
this.layers.set(file.header.id, file);
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
AddAll(files) {
|
|
85
|
+
files.forEach((f) => this.add(f));
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
69
88
|
};
|
|
70
|
-
|
|
71
89
|
function log(bla) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
90
|
+
{
|
|
91
|
+
console.log(`${JSON.stringify(arguments)}`);
|
|
92
|
+
}
|
|
75
93
|
}
|
|
76
|
-
|
|
77
94
|
var FetchLayerProvider = class {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
return await result.json();
|
|
89
|
-
} catch (e) {
|
|
90
|
-
log(url);
|
|
91
|
-
return new Error(`Failed to parse json at ${url}: ${e}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
async GetLayerByURI(uri) {
|
|
95
|
-
if (!this.layers.has(uri)) {
|
|
96
|
-
let fetched = await this.FetchJson(uri);
|
|
97
|
-
if (fetched instanceof Error) {
|
|
98
|
-
return new Error(`File with id "${uri}" not found`);
|
|
99
|
-
}
|
|
100
|
-
let file = fetched;
|
|
101
|
-
this.layers.set(uri, file);
|
|
102
|
-
return file;
|
|
103
|
-
}
|
|
104
|
-
return this.layers.get(uri);
|
|
95
|
+
layers;
|
|
96
|
+
constructor() {
|
|
97
|
+
this.layers = new Map();
|
|
98
|
+
}
|
|
99
|
+
async FetchJson(url) {
|
|
100
|
+
let result = await fetch(url);
|
|
101
|
+
if (!result.ok) {
|
|
102
|
+
return new Error(`Failed to fetch ${url}: ${result.status}`);
|
|
105
103
|
}
|
|
104
|
+
try {
|
|
105
|
+
return await result.json();
|
|
106
|
+
} catch (e) {
|
|
107
|
+
log(url);
|
|
108
|
+
return new Error(`Failed to parse json at ${url}: ${e}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async GetLayerByURI(uri) {
|
|
112
|
+
if (!this.layers.has(uri)) {
|
|
113
|
+
let fetched = await this.FetchJson(uri);
|
|
114
|
+
if (fetched instanceof Error) {
|
|
115
|
+
return new Error(`File with id "${uri}" not found`);
|
|
116
|
+
}
|
|
117
|
+
let file = fetched;
|
|
118
|
+
this.layers.set(uri, file);
|
|
119
|
+
return file;
|
|
120
|
+
}
|
|
121
|
+
return this.layers.get(uri);
|
|
122
|
+
}
|
|
106
123
|
};
|
|
107
|
-
|
|
108
124
|
function MMSet(map, key, value) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
125
|
+
if (map.has(key)) {
|
|
126
|
+
map.get(key)?.push(value);
|
|
127
|
+
} else {
|
|
128
|
+
map.set(key, [value]);
|
|
129
|
+
}
|
|
114
130
|
}
|
|
115
|
-
|
|
116
131
|
var CycleError = class extends Error {};
|
|
117
|
-
|
|
118
132
|
function FindRootsOrCycles(nodes) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
});
|
|
126
|
-
Object.keys(node.children).forEach(childName => {
|
|
127
|
-
MMSet(dependencies, path, node.children[childName]);
|
|
128
|
-
MMSet(dependents, node.children[childName], path);
|
|
129
|
-
});
|
|
133
|
+
let dependencies = new Map();
|
|
134
|
+
let dependents = new Map();
|
|
135
|
+
nodes.forEach((node, path) => {
|
|
136
|
+
Object.keys(node.inherits).forEach((inheritName) => {
|
|
137
|
+
MMSet(dependencies, path, node.inherits[inheritName]);
|
|
138
|
+
MMSet(dependents, node.inherits[inheritName], path);
|
|
130
139
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
140
|
+
Object.keys(node.children).forEach((childName) => {
|
|
141
|
+
MMSet(dependencies, path, node.children[childName]);
|
|
142
|
+
MMSet(dependents, node.children[childName], path);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
let paths = [...nodes.keys()];
|
|
146
|
+
let perm = {};
|
|
147
|
+
let temp = {};
|
|
148
|
+
function visit(path) {
|
|
149
|
+
if (perm[path]) return;
|
|
150
|
+
if (temp[path]) throw new Error(`CYCLE!`);
|
|
151
|
+
temp[path] = true;
|
|
152
|
+
let deps = dependencies.get(path);
|
|
153
|
+
if (deps) {
|
|
154
|
+
deps.forEach((dep) => visit(dep));
|
|
155
|
+
}
|
|
156
|
+
perm[path] = true;
|
|
157
|
+
}
|
|
158
|
+
let roots = new Set();
|
|
159
|
+
try {
|
|
160
|
+
paths.forEach((path) => {
|
|
161
|
+
if (!dependents.has(path) && path.indexOf("/") === -1) {
|
|
162
|
+
roots.add(path);
|
|
163
|
+
}
|
|
164
|
+
visit(path);
|
|
165
|
+
});
|
|
166
|
+
} catch (e) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
return roots;
|
|
156
170
|
}
|
|
157
|
-
|
|
158
171
|
function GetHead(path) {
|
|
159
|
-
|
|
172
|
+
return path.split("/")[0];
|
|
160
173
|
}
|
|
161
|
-
|
|
162
174
|
function GetTail(path) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
175
|
+
let parts = path.split("/");
|
|
176
|
+
parts.shift();
|
|
177
|
+
return parts.join("/");
|
|
166
178
|
}
|
|
167
|
-
|
|
168
179
|
function MakePostCompositionNode(node) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
180
|
+
return {
|
|
181
|
+
node,
|
|
182
|
+
children: new Map(),
|
|
183
|
+
attributes: new Map(),
|
|
184
|
+
};
|
|
174
185
|
}
|
|
175
|
-
|
|
176
186
|
function GetChildNodeWithPath(node, path) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
if (path === "") return node;
|
|
188
|
+
let parts = path.split("/");
|
|
189
|
+
let child = node.children.get(parts[0]);
|
|
190
|
+
if (child) {
|
|
191
|
+
if (parts.length === 1) {
|
|
192
|
+
return child;
|
|
193
|
+
}
|
|
194
|
+
return GetChildNodeWithPath(child, GetTail(path));
|
|
195
|
+
} else {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
188
198
|
}
|
|
189
|
-
|
|
190
199
|
function FlattenPathToPreCompositionNode(path, inputNodes) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
});
|
|
201
|
-
Object.keys(node.inherits).forEach(inheritName => {
|
|
202
|
-
let ih = node.inherits[inheritName];
|
|
203
|
-
if (ih === null) {
|
|
204
|
-
delete compositionNode.inherits[inheritName];
|
|
205
|
-
} else {
|
|
206
|
-
compositionNode.inherits[inheritName] = ih;
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
Object.keys(node.attributes).forEach(attrName => {
|
|
210
|
-
compositionNode.attributes[attrName] = node.attributes[attrName];
|
|
211
|
-
});
|
|
200
|
+
let compositionNode = {
|
|
201
|
+
path,
|
|
202
|
+
children: {},
|
|
203
|
+
inherits: {},
|
|
204
|
+
attributes: {},
|
|
205
|
+
};
|
|
206
|
+
inputNodes.forEach((node) => {
|
|
207
|
+
Object.keys(node.children).forEach((childName) => {
|
|
208
|
+
compositionNode.children[childName] = node.children[childName];
|
|
212
209
|
});
|
|
213
|
-
|
|
210
|
+
Object.keys(node.inherits).forEach((inheritName) => {
|
|
211
|
+
let ih = node.inherits[inheritName];
|
|
212
|
+
if (ih === null) {
|
|
213
|
+
delete compositionNode.inherits[inheritName];
|
|
214
|
+
} else {
|
|
215
|
+
compositionNode.inherits[inheritName] = ih;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
Object.keys(node.attributes).forEach((attrName) => {
|
|
219
|
+
compositionNode.attributes[attrName] = node.attributes[attrName];
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
return compositionNode;
|
|
214
223
|
}
|
|
215
|
-
|
|
216
224
|
function FlattenCompositionInput(input) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
225
|
+
let compositionNodes = new Map();
|
|
226
|
+
for (let [path, inputNodes] of input) {
|
|
227
|
+
compositionNodes.set(path, FlattenPathToPreCompositionNode(path, inputNodes));
|
|
228
|
+
}
|
|
229
|
+
return compositionNodes;
|
|
222
230
|
}
|
|
223
|
-
|
|
224
231
|
function ExpandFirstRootInInput(nodes) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
let roots = FindRootsOrCycles(nodes);
|
|
233
|
+
if (!roots) {
|
|
234
|
+
throw new CycleError();
|
|
235
|
+
}
|
|
236
|
+
return ComposeNodeFromPath([...roots.values()][0], nodes);
|
|
230
237
|
}
|
|
231
|
-
|
|
232
238
|
function CreateArtificialRoot(nodes) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
let roots = FindRootsOrCycles(nodes);
|
|
240
|
+
if (!roots) {
|
|
241
|
+
throw new CycleError();
|
|
242
|
+
}
|
|
243
|
+
let pseudoRoot = {
|
|
244
|
+
node: "",
|
|
245
|
+
attributes: new Map(),
|
|
246
|
+
children: new Map(),
|
|
247
|
+
};
|
|
248
|
+
roots.forEach((root) => {
|
|
249
|
+
pseudoRoot.children.set(root, ComposeNodeFromPath(root, nodes));
|
|
250
|
+
});
|
|
251
|
+
return pseudoRoot;
|
|
246
252
|
}
|
|
247
|
-
|
|
248
253
|
function ComposeNodeFromPath(path, preCompositionNodes) {
|
|
249
|
-
|
|
254
|
+
return ComposeNode(path, MakePostCompositionNode(path), preCompositionNodes);
|
|
250
255
|
}
|
|
251
|
-
|
|
252
256
|
function ComposeNode(path, postCompositionNode, preCompositionNodes) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
257
|
+
let preCompositionNode = preCompositionNodes.get(path);
|
|
258
|
+
if (preCompositionNode) {
|
|
259
|
+
AddDataFromPreComposition(preCompositionNode, postCompositionNode, preCompositionNodes);
|
|
260
|
+
}
|
|
261
|
+
postCompositionNode.children.forEach((child, name) => {
|
|
262
|
+
ComposeNode(`${path}/${name}`, child, preCompositionNodes);
|
|
263
|
+
});
|
|
264
|
+
return postCompositionNode;
|
|
261
265
|
}
|
|
262
|
-
|
|
263
266
|
function AddDataFromPreComposition(input, node, nodes) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
});
|
|
271
|
-
for (let [attrID, attr] of subnode.attributes) {
|
|
272
|
-
node.attributes.set(attrID, attr);
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
Object.entries(input.children).forEach(([childName, child]) => {
|
|
276
|
-
if (child !== null) {
|
|
277
|
-
let classNode = ComposeNodeFromPath(GetHead(child), nodes);
|
|
278
|
-
let subnode = GetChildNodeWithPath(classNode, GetTail(child));
|
|
279
|
-
if (!subnode) throw new Error(`Unknown node ${child}`);
|
|
280
|
-
node.children.set(childName, subnode);
|
|
281
|
-
} else {
|
|
282
|
-
node.children.delete(childName);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
Object.entries(input.attributes).forEach(([attrID, attr]) => {
|
|
286
|
-
node.attributes.set(attrID, attr);
|
|
267
|
+
Object.values(input.inherits).forEach((inheritPath) => {
|
|
268
|
+
let classNode = ComposeNodeFromPath(GetHead(inheritPath), nodes);
|
|
269
|
+
let subnode = GetChildNodeWithPath(classNode, GetTail(inheritPath));
|
|
270
|
+
if (!subnode) throw new Error(`Unknown node ${inheritPath}`);
|
|
271
|
+
subnode.children.forEach((child, childName) => {
|
|
272
|
+
node.children.set(childName, child);
|
|
287
273
|
});
|
|
274
|
+
for (let [attrID, attr] of subnode.attributes) {
|
|
275
|
+
node.attributes.set(attrID, attr);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
Object.entries(input.children).forEach(([childName, child]) => {
|
|
279
|
+
if (child !== null) {
|
|
280
|
+
let classNode = ComposeNodeFromPath(GetHead(child), nodes);
|
|
281
|
+
let subnode = GetChildNodeWithPath(classNode, GetTail(child));
|
|
282
|
+
if (!subnode) throw new Error(`Unknown node ${child}`);
|
|
283
|
+
node.children.set(childName, subnode);
|
|
284
|
+
} else {
|
|
285
|
+
node.children.delete(childName);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
Object.entries(input.attributes).forEach(([attrID, attr]) => {
|
|
289
|
+
node.attributes.set(attrID, attr);
|
|
290
|
+
});
|
|
288
291
|
}
|
|
289
|
-
|
|
290
292
|
var SchemaValidationError = class extends Error {};
|
|
291
|
-
|
|
292
293
|
function ValidateAttributeValue(desc, value, path, schemas) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
294
|
+
if (desc.optional && value === void 0) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (desc.inherits) {
|
|
298
|
+
desc.inherits.forEach((inheritedSchemaID) => {
|
|
299
|
+
let inheritedSchema = schemas[inheritedSchemaID];
|
|
300
|
+
if (!inheritedSchema) {
|
|
301
|
+
throw new SchemaValidationError(`Unknown inherited schema id "${desc.inherits}"`);
|
|
302
|
+
}
|
|
303
|
+
ValidateAttributeValue(inheritedSchema.value, value, path, schemas);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (desc.dataType === "Boolean") {
|
|
307
|
+
if (typeof value !== "boolean") {
|
|
308
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type boolean`);
|
|
309
|
+
}
|
|
310
|
+
} else if (desc.dataType === "String") {
|
|
311
|
+
if (typeof value !== "string") {
|
|
312
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type string`);
|
|
313
|
+
}
|
|
314
|
+
} else if (desc.dataType === "DateTime") {
|
|
315
|
+
if (typeof value !== "string") {
|
|
316
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type date`);
|
|
317
|
+
}
|
|
318
|
+
} else if (desc.dataType === "Enum") {
|
|
319
|
+
if (typeof value !== "string") {
|
|
320
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type string`);
|
|
321
|
+
}
|
|
322
|
+
let found = desc.enumRestrictions.options.filter((option) => option === value).length === 1;
|
|
323
|
+
if (!found) {
|
|
324
|
+
throw new SchemaValidationError(`Expected "${value}" to be one of [${desc.enumRestrictions.options.join(",")}]`);
|
|
325
|
+
}
|
|
326
|
+
} else if (desc.dataType === "Integer") {
|
|
327
|
+
if (typeof value !== "number") {
|
|
328
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type int`);
|
|
329
|
+
}
|
|
330
|
+
} else if (desc.dataType === "Real") {
|
|
331
|
+
if (typeof value !== "number") {
|
|
332
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type real`);
|
|
333
|
+
}
|
|
334
|
+
} else if (desc.dataType === "Reference") {
|
|
335
|
+
if (typeof value !== "string") {
|
|
336
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type string`);
|
|
337
|
+
}
|
|
338
|
+
} else if (desc.dataType === "Object") {
|
|
339
|
+
if (typeof value !== "object") {
|
|
340
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type object`);
|
|
341
|
+
}
|
|
342
|
+
if (desc.objectRestrictions) {
|
|
343
|
+
Object.keys(desc.objectRestrictions.values).forEach((key) => {
|
|
344
|
+
let optional = desc.objectRestrictions.values[key].optional;
|
|
345
|
+
let hasOwn = Object.hasOwn(value, key);
|
|
346
|
+
if (optional && !hasOwn) return;
|
|
347
|
+
if (!hasOwn) {
|
|
348
|
+
throw new SchemaValidationError(`Expected "${value}" to have key ${key}`);
|
|
349
|
+
}
|
|
350
|
+
ValidateAttributeValue(desc.objectRestrictions.values[key], value[key], path + "." + key, schemas);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
} else if (desc.dataType === "Array") {
|
|
354
|
+
if (!Array.isArray(value)) {
|
|
355
|
+
throw new SchemaValidationError(`Expected "${value}" to be of type array`);
|
|
356
|
+
}
|
|
357
|
+
value.forEach((entry) => {
|
|
358
|
+
ValidateAttributeValue(desc.arrayRestrictions.value, entry, path + ".<array>.", schemas);
|
|
359
|
+
});
|
|
360
|
+
} else {
|
|
361
|
+
throw new SchemaValidationError(`Unexpected datatype ${desc.dataType}`);
|
|
362
|
+
}
|
|
362
363
|
}
|
|
363
|
-
|
|
364
364
|
function Validate(schemas, inputNodes) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
365
|
+
inputNodes.forEach((node) => {
|
|
366
|
+
Object.keys(node.attributes)
|
|
367
|
+
.filter((v) => !v.startsWith("__internal"))
|
|
368
|
+
.forEach((schemaID) => {
|
|
369
|
+
if (!schemas[schemaID]) {
|
|
370
|
+
throw new SchemaValidationError(`Missing schema "${schemaID}" referenced by ["${node.path}"].attributes`);
|
|
371
|
+
}
|
|
372
|
+
let schema = schemas[schemaID];
|
|
373
|
+
let value = node.attributes[schemaID];
|
|
374
|
+
try {
|
|
375
|
+
ValidateAttributeValue(schema.value, value, "", schemas);
|
|
376
|
+
} catch (e) {
|
|
377
|
+
if (e instanceof SchemaValidationError) {
|
|
378
|
+
throw new SchemaValidationError(
|
|
379
|
+
`Error validating ["${node.path}"].attributes["${schemaID}"]: ${e.message}`
|
|
380
|
+
);
|
|
381
|
+
} else {
|
|
382
|
+
throw e;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
});
|
|
383
387
|
}
|
|
384
|
-
|
|
385
388
|
function ToInputNodes(data) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
389
|
+
let inputNodes = new Map();
|
|
390
|
+
data.forEach((ifcxNode) => {
|
|
391
|
+
let node = {
|
|
392
|
+
path: ifcxNode.path,
|
|
393
|
+
children: ifcxNode.children ? ifcxNode.children : {},
|
|
394
|
+
inherits: ifcxNode.inherits ? ifcxNode.inherits : {},
|
|
395
|
+
attributes: ifcxNode.attributes ? ifcxNode.attributes : {},
|
|
396
|
+
};
|
|
397
|
+
MMSet(inputNodes, node.path, node);
|
|
398
|
+
});
|
|
399
|
+
return inputNodes;
|
|
397
400
|
}
|
|
398
|
-
|
|
399
401
|
function LoadIfcxFile(file, checkSchemas = true, createArtificialRoot = true) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
402
|
+
let inputNodes = ToInputNodes(file.data);
|
|
403
|
+
let compositionNodes = FlattenCompositionInput(inputNodes);
|
|
404
|
+
try {
|
|
405
|
+
if (checkSchemas) {
|
|
406
|
+
Validate(file.schemas, compositionNodes);
|
|
407
|
+
}
|
|
408
|
+
} catch (e) {
|
|
409
|
+
throw e;
|
|
410
|
+
}
|
|
411
|
+
if (createArtificialRoot) {
|
|
412
|
+
return CreateArtificialRoot(compositionNodes);
|
|
413
|
+
} else {
|
|
414
|
+
return ExpandFirstRootInInput(compositionNodes);
|
|
415
|
+
}
|
|
414
416
|
}
|
|
415
|
-
|
|
416
417
|
function Federate(files) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
418
|
+
if (files.length === 0) {
|
|
419
|
+
throw new Error(`Trying to federate empty set of files`);
|
|
420
|
+
}
|
|
421
|
+
let result = {
|
|
422
|
+
header: files[0].header,
|
|
423
|
+
schemas: {},
|
|
424
|
+
data: [],
|
|
425
|
+
};
|
|
426
|
+
files.forEach((file) => {
|
|
427
|
+
Object.keys(file.schemas).forEach((schemaID) => (result.schemas[schemaID] = file.schemas[schemaID]));
|
|
428
|
+
});
|
|
429
|
+
files.forEach((file) => {
|
|
430
|
+
file.data.forEach((node) => result.data.push(node));
|
|
431
|
+
});
|
|
432
|
+
return Prune(result);
|
|
432
433
|
}
|
|
433
|
-
|
|
434
434
|
function Collapse(nodes, deleteEmpty = false) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
});
|
|
445
|
-
Object.keys(node.inherits).forEach(name => {
|
|
446
|
-
result.inherits[name] = node.inherits[name];
|
|
447
|
-
});
|
|
448
|
-
Object.keys(node.attributes).forEach(name => {
|
|
449
|
-
result.attributes[name] = node.attributes[name];
|
|
450
|
-
});
|
|
435
|
+
let result = {
|
|
436
|
+
path: nodes[0].path,
|
|
437
|
+
children: {},
|
|
438
|
+
inherits: {},
|
|
439
|
+
attributes: {},
|
|
440
|
+
};
|
|
441
|
+
nodes.forEach((node) => {
|
|
442
|
+
Object.keys(node.children).forEach((name) => {
|
|
443
|
+
result.children[name] = node.children[name];
|
|
451
444
|
});
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
445
|
+
Object.keys(node.inherits).forEach((name) => {
|
|
446
|
+
result.inherits[name] = node.inherits[name];
|
|
447
|
+
});
|
|
448
|
+
Object.keys(node.attributes).forEach((name) => {
|
|
449
|
+
result.attributes[name] = node.attributes[name];
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
if (deleteEmpty) {
|
|
453
|
+
let empty = true;
|
|
454
|
+
Object.keys(result.children).forEach((name) => {
|
|
455
|
+
if (result.children[name] !== null) empty = false;
|
|
456
|
+
});
|
|
457
|
+
Object.keys(result.inherits).forEach((name) => {
|
|
458
|
+
if (result.inherits[name] !== null) empty = false;
|
|
459
|
+
});
|
|
460
|
+
Object.keys(result.attributes).forEach((name) => {
|
|
461
|
+
if (result.attributes[name] !== null) empty = false;
|
|
462
|
+
});
|
|
463
|
+
if (empty) return null;
|
|
464
|
+
}
|
|
465
|
+
return result;
|
|
466
466
|
}
|
|
467
|
-
|
|
468
467
|
function Prune(file, deleteEmpty = false) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
468
|
+
let result = {
|
|
469
|
+
header: file.header,
|
|
470
|
+
imports: [],
|
|
471
|
+
schemas: file.schemas,
|
|
472
|
+
data: [],
|
|
473
|
+
};
|
|
474
|
+
let inputNodes = ToInputNodes(file.data);
|
|
475
|
+
inputNodes.forEach((nodes) => {
|
|
476
|
+
let collapsed = Collapse(nodes, deleteEmpty);
|
|
477
|
+
if (collapsed)
|
|
478
|
+
result.data.push({
|
|
479
|
+
path: collapsed.path,
|
|
480
|
+
children: collapsed.children,
|
|
481
|
+
inherits: collapsed.inherits,
|
|
482
|
+
attributes: collapsed.attributes,
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
return result;
|
|
486
486
|
}
|
|
487
|
-
|
|
488
487
|
var IfcxLayerStack = class {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
488
|
+
layers;
|
|
489
|
+
tree;
|
|
490
|
+
schemas;
|
|
491
|
+
federated;
|
|
492
|
+
constructor(layers) {
|
|
493
|
+
this.layers = layers;
|
|
494
|
+
this.Compose();
|
|
495
|
+
}
|
|
496
|
+
GetLayerIds() {
|
|
497
|
+
return this.layers.map((l) => l.header.id);
|
|
498
|
+
}
|
|
499
|
+
Compose() {
|
|
500
|
+
this.federated = Federate(this.layers);
|
|
501
|
+
this.schemas = this.federated.schemas;
|
|
502
|
+
this.tree = LoadIfcxFile(this.federated);
|
|
503
|
+
}
|
|
504
|
+
GetFullTree() {
|
|
505
|
+
this.Compose();
|
|
506
|
+
return this.tree;
|
|
507
|
+
}
|
|
508
|
+
GetFederatedLayer() {
|
|
509
|
+
return this.federated;
|
|
510
|
+
}
|
|
511
|
+
GetSchemas() {
|
|
512
|
+
return this.schemas;
|
|
513
|
+
}
|
|
515
514
|
};
|
|
516
|
-
|
|
517
515
|
var IfcxLayerStackBuilder = class {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
}
|
|
533
|
-
try {
|
|
534
|
-
return new IfcxLayerStack(layers);
|
|
535
|
-
} catch (e) {
|
|
536
|
-
return e;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
async SatisfyDependencies(activeLayer, placed, orderedLayers) {
|
|
540
|
-
let pending = [];
|
|
541
|
-
for (const impt of activeLayer.imports) {
|
|
542
|
-
if (!placed.has(impt.uri)) {
|
|
543
|
-
let layer = await this.provider.GetLayerByURI(impt.uri);
|
|
544
|
-
if (layer instanceof Error) {
|
|
545
|
-
return layer;
|
|
546
|
-
}
|
|
547
|
-
pending.push(layer);
|
|
548
|
-
placed.set(impt.uri, true);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
let temp = [];
|
|
552
|
-
for (const layer of pending) {
|
|
553
|
-
temp.push(layer);
|
|
554
|
-
let layers = await this.SatisfyDependencies(layer, placed, orderedLayers);
|
|
555
|
-
if (layers instanceof Error) {
|
|
556
|
-
return layers;
|
|
557
|
-
}
|
|
558
|
-
temp.push(...layers);
|
|
559
|
-
}
|
|
560
|
-
temp.forEach(t => orderedLayers.push(t));
|
|
561
|
-
return temp;
|
|
562
|
-
}
|
|
563
|
-
async BuildLayerSet(activeLayerID) {
|
|
564
|
-
let activeLayer = await this.provider.GetLayerByURI(activeLayerID);
|
|
565
|
-
if (activeLayer instanceof Error) {
|
|
566
|
-
return activeLayer;
|
|
567
|
-
}
|
|
568
|
-
let layerSet = [ activeLayer ];
|
|
569
|
-
let placed = new Map;
|
|
570
|
-
placed.set(activeLayer.header.id, true);
|
|
571
|
-
let result = await this.SatisfyDependencies(activeLayer, placed, layerSet);
|
|
572
|
-
if (result instanceof Error) {
|
|
573
|
-
return result;
|
|
574
|
-
}
|
|
575
|
-
return layerSet;
|
|
516
|
+
provider;
|
|
517
|
+
mainLayerId = null;
|
|
518
|
+
constructor(provider) {
|
|
519
|
+
this.provider = provider;
|
|
520
|
+
}
|
|
521
|
+
FromId(id) {
|
|
522
|
+
this.mainLayerId = id;
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
525
|
+
async Build() {
|
|
526
|
+
if (!this.mainLayerId) throw new Error(`no main layer ID specified`);
|
|
527
|
+
let layers = await this.BuildLayerSet(this.mainLayerId);
|
|
528
|
+
if (layers instanceof Error) {
|
|
529
|
+
return layers;
|
|
576
530
|
}
|
|
531
|
+
try {
|
|
532
|
+
return new IfcxLayerStack(layers);
|
|
533
|
+
} catch (e) {
|
|
534
|
+
return e;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async SatisfyDependencies(activeLayer, placed, orderedLayers) {
|
|
538
|
+
let pending = [];
|
|
539
|
+
for (const impt of activeLayer.imports) {
|
|
540
|
+
if (!placed.has(impt.uri)) {
|
|
541
|
+
let layer = await this.provider.GetLayerByURI(impt.uri);
|
|
542
|
+
if (layer instanceof Error) {
|
|
543
|
+
return layer;
|
|
544
|
+
}
|
|
545
|
+
pending.push(layer);
|
|
546
|
+
placed.set(impt.uri, true);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
let temp = [];
|
|
550
|
+
for (const layer of pending) {
|
|
551
|
+
temp.push(layer);
|
|
552
|
+
let layers = await this.SatisfyDependencies(layer, placed, orderedLayers);
|
|
553
|
+
if (layers instanceof Error) {
|
|
554
|
+
return layers;
|
|
555
|
+
}
|
|
556
|
+
temp.push(...layers);
|
|
557
|
+
}
|
|
558
|
+
temp.forEach((t) => orderedLayers.push(t));
|
|
559
|
+
return temp;
|
|
560
|
+
}
|
|
561
|
+
async BuildLayerSet(activeLayerID) {
|
|
562
|
+
let activeLayer = await this.provider.GetLayerByURI(activeLayerID);
|
|
563
|
+
if (activeLayer instanceof Error) {
|
|
564
|
+
return activeLayer;
|
|
565
|
+
}
|
|
566
|
+
let layerSet = [activeLayer];
|
|
567
|
+
let placed = new Map();
|
|
568
|
+
placed.set(activeLayer.header.id, true);
|
|
569
|
+
let result = await this.SatisfyDependencies(activeLayer, placed, layerSet);
|
|
570
|
+
if (result instanceof Error) {
|
|
571
|
+
return result;
|
|
572
|
+
}
|
|
573
|
+
return layerSet;
|
|
574
|
+
}
|
|
577
575
|
};
|
|
578
|
-
|
|
579
576
|
function TreeNodeToComposedObject(path, node, schemas) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
577
|
+
let co = {
|
|
578
|
+
name: path,
|
|
579
|
+
attributes: {},
|
|
580
|
+
children: [],
|
|
581
|
+
};
|
|
582
|
+
node.children.forEach((childNode, childName) => {
|
|
583
|
+
co.children?.push(TreeNodeToComposedObject(`${path}/${childName}`, childNode, schemas));
|
|
584
|
+
});
|
|
585
|
+
node.attributes.forEach((attr, attrName) => {
|
|
586
|
+
if (attr && typeof attr === "object" && !Array.isArray(attr)) {
|
|
587
|
+
Object.keys(attr).forEach((compname) => {
|
|
588
|
+
co.attributes[`${attrName}::${compname}`] = attr[compname];
|
|
589
|
+
});
|
|
590
|
+
} else {
|
|
591
|
+
let schema = schemas[attrName];
|
|
592
|
+
if (schema && schema.value.quantityKind) {
|
|
593
|
+
let postfix = "";
|
|
594
|
+
let quantityKind = schema.value.quantityKind;
|
|
595
|
+
if (quantityKind === "Length") {
|
|
596
|
+
postfix = "m";
|
|
597
|
+
} else if (quantityKind === "Volume") {
|
|
598
|
+
postfix = "m" + String.fromCodePoint(179);
|
|
599
|
+
}
|
|
600
|
+
co.attributes[attrName] = `${attr} ${postfix}`;
|
|
601
|
+
} else {
|
|
602
|
+
co.attributes[attrName] = attr;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
if (Object.keys(co.attributes).length === 0) delete co.attributes;
|
|
607
|
+
return co;
|
|
611
608
|
}
|
|
612
|
-
|
|
613
609
|
async function compose3(files) {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
userDefinedOrder
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
634
|
-
|
|
610
|
+
let userDefinedOrder = {
|
|
611
|
+
header: { ...files[0].header },
|
|
612
|
+
imports: files.map((f) => {
|
|
613
|
+
return { uri: f.header.id };
|
|
614
|
+
}),
|
|
615
|
+
schemas: {},
|
|
616
|
+
data: [],
|
|
617
|
+
};
|
|
618
|
+
userDefinedOrder.header.id = "USER_DEF";
|
|
619
|
+
let provider = new StackedLayerProvider([
|
|
620
|
+
new InMemoryLayerProvider().AddAll([userDefinedOrder, ...files]),
|
|
621
|
+
new FetchLayerProvider(),
|
|
622
|
+
]);
|
|
623
|
+
let layerStack = await new IfcxLayerStackBuilder(provider).FromId(userDefinedOrder.header.id).Build();
|
|
624
|
+
if (layerStack instanceof Error) {
|
|
625
|
+
throw layerStack;
|
|
626
|
+
}
|
|
627
|
+
layerStack.GetFederatedLayer().data.forEach((n, i) => {
|
|
628
|
+
n.attributes = n.attributes || {};
|
|
629
|
+
n.attributes[`__internal_${i}`] = n.path;
|
|
630
|
+
});
|
|
631
|
+
return TreeNodeToComposedObject("", layerStack.GetFullTree(), layerStack.GetSchemas());
|
|
635
632
|
}
|
|
636
|
-
|
|
637
633
|
var scene;
|
|
638
|
-
|
|
639
634
|
var camera;
|
|
640
|
-
|
|
641
635
|
var datas = [];
|
|
642
|
-
|
|
643
636
|
var autoCamera = true;
|
|
644
|
-
|
|
645
637
|
var objectMap = {};
|
|
646
|
-
|
|
647
638
|
var primMap = {};
|
|
648
|
-
|
|
649
639
|
var envMap;
|
|
650
|
-
|
|
651
640
|
function init() {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
641
|
+
scene = new THREE.Scene();
|
|
642
|
+
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
|
|
643
|
+
camera.up.set(0, 0, 1);
|
|
644
|
+
camera.position.set(50, 50, 50);
|
|
645
|
+
camera.lookAt(0, 0, 0);
|
|
646
|
+
scene.add(camera);
|
|
647
|
+
return scene;
|
|
659
648
|
}
|
|
660
|
-
|
|
661
649
|
function HasAttr(node, attrName) {
|
|
662
|
-
|
|
663
|
-
|
|
650
|
+
if (!node || !node.attributes) return false;
|
|
651
|
+
return !!node.attributes[attrName];
|
|
664
652
|
}
|
|
665
|
-
|
|
666
653
|
function tryCreateMeshGltfMaterial(path) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
material.
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
654
|
+
for (let p of path) {
|
|
655
|
+
if (!p.attributes) {
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
const pbrMetallicRoughness = p.attributes["gltf::material::pbrMetallicRoughness"];
|
|
659
|
+
const normalTexture = p.attributes["gltf::material::normalTexture"];
|
|
660
|
+
const occlusionTexture = p.attributes["gltf::material::occlusionTexture"];
|
|
661
|
+
const emissiveTexture = p.attributes["gltf::material::emissiveTexture"];
|
|
662
|
+
const emissiveFactor = p.attributes["gltf::material::emissiveFactor"];
|
|
663
|
+
const alphaMode = p.attributes["gltf::material::alphaMode"];
|
|
664
|
+
const alphaCutoff = p.attributes["gltf::material::alphaCutoff"];
|
|
665
|
+
const doubleSided = p.attributes["gltf::material::doubleSided"];
|
|
666
|
+
if (
|
|
667
|
+
!pbrMetallicRoughness &&
|
|
668
|
+
!normalTexture &&
|
|
669
|
+
!occlusionTexture &&
|
|
670
|
+
!emissiveTexture &&
|
|
671
|
+
!emissiveFactor &&
|
|
672
|
+
!alphaMode &&
|
|
673
|
+
!alphaCutoff &&
|
|
674
|
+
!doubleSided
|
|
675
|
+
) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
let material = new THREE.MeshStandardMaterial();
|
|
679
|
+
material.color = new THREE.Color(1, 1, 1);
|
|
680
|
+
material.metalness = 1;
|
|
681
|
+
material.roughness = 1;
|
|
682
|
+
if (pbrMetallicRoughness) {
|
|
683
|
+
let baseColorFactor = pbrMetallicRoughness["baseColorFactor"];
|
|
684
|
+
if (baseColorFactor) {
|
|
685
|
+
material.color = new THREE.Color(baseColorFactor[0], baseColorFactor[1], baseColorFactor[2]);
|
|
686
|
+
}
|
|
687
|
+
let metallicFactor = pbrMetallicRoughness["metallicFactor"];
|
|
688
|
+
if (metallicFactor !== void 0) {
|
|
689
|
+
material.metalness = metallicFactor;
|
|
690
|
+
}
|
|
691
|
+
let roughnessFactor = pbrMetallicRoughness["roughnessFactor"];
|
|
692
|
+
if (roughnessFactor !== void 0) {
|
|
693
|
+
material.roughness = roughnessFactor;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
material.envMap = envMap;
|
|
697
|
+
material.needsUpdate = true;
|
|
698
|
+
material.envMapRotation = new THREE.Euler(0.5 * Math.PI, 0, 0);
|
|
699
|
+
return material;
|
|
700
|
+
}
|
|
701
|
+
return void 0;
|
|
706
702
|
}
|
|
707
|
-
|
|
708
703
|
function createMaterialFromParent(path) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
704
|
+
let material = {
|
|
705
|
+
color: new THREE.Color(0.6, 0.6, 0.6),
|
|
706
|
+
transparent: false,
|
|
707
|
+
opacity: 1,
|
|
708
|
+
};
|
|
709
|
+
for (let p of path) {
|
|
710
|
+
const color = p.attributes ? p.attributes["bsi::ifc::presentation::diffuseColor"] : null;
|
|
711
|
+
if (color) {
|
|
712
|
+
material.color = new THREE.Color(...color);
|
|
713
|
+
const opacity = p.attributes["bsi::ifc::presentation::opacity"];
|
|
714
|
+
if (opacity) {
|
|
715
|
+
material.transparent = true;
|
|
716
|
+
material.opacity = opacity;
|
|
717
|
+
}
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return material;
|
|
727
722
|
}
|
|
728
|
-
|
|
729
723
|
function createCurveFromJson(path) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
lineMaterial.color.multiplyScalar(.8);
|
|
738
|
-
return new THREE.Line(geometry, lineMaterial);
|
|
724
|
+
let points = new Float32Array(path[0].attributes["usd::usdgeom::basiscurves::points"].flat());
|
|
725
|
+
const geometry = new THREE.BufferGeometry();
|
|
726
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(points, 3));
|
|
727
|
+
const material = createMaterialFromParent(path);
|
|
728
|
+
let lineMaterial = new THREE.LineBasicMaterial({ ...material });
|
|
729
|
+
lineMaterial.color.multiplyScalar(0.8);
|
|
730
|
+
return new THREE.Line(geometry, lineMaterial);
|
|
739
731
|
}
|
|
740
|
-
|
|
741
732
|
function createMeshFromJson(path) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
return new THREE.Mesh(geometry, meshMaterial);
|
|
733
|
+
let points = new Float32Array(path[0].attributes["usd::usdgeom::mesh::points"].flat());
|
|
734
|
+
let indices = new Uint16Array(path[0].attributes["usd::usdgeom::mesh::faceVertexIndices"]);
|
|
735
|
+
const geometry = new THREE.BufferGeometry();
|
|
736
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(points, 3));
|
|
737
|
+
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
|
|
738
|
+
geometry.computeVertexNormals();
|
|
739
|
+
var meshMaterial;
|
|
740
|
+
let gltfPbrMaterial = tryCreateMeshGltfMaterial(path);
|
|
741
|
+
if (gltfPbrMaterial) {
|
|
742
|
+
meshMaterial = gltfPbrMaterial;
|
|
743
|
+
} else {
|
|
744
|
+
const m = createMaterialFromParent(path);
|
|
745
|
+
meshMaterial = new THREE.MeshLambertMaterial({ ...m });
|
|
746
|
+
}
|
|
747
|
+
return new THREE.Mesh(geometry, meshMaterial);
|
|
759
748
|
}
|
|
760
|
-
|
|
761
749
|
function createPointsFromJsonPcdBase64(path) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
750
|
+
const base64_string = path[0].attributes["pcd::base64"];
|
|
751
|
+
const decoded = atob(base64_string);
|
|
752
|
+
const len = decoded.length;
|
|
753
|
+
const bytes = new Uint8Array(len);
|
|
754
|
+
for (let i = 0; i < len; i++) {
|
|
755
|
+
bytes[i] = decoded.charCodeAt(i);
|
|
756
|
+
}
|
|
757
|
+
const loader = new PCDLoader();
|
|
758
|
+
const points = loader.parse(bytes.buffer);
|
|
759
|
+
points.material.sizeAttenuation = false;
|
|
760
|
+
points.material.size = 2;
|
|
761
|
+
return points;
|
|
774
762
|
}
|
|
775
|
-
|
|
776
763
|
function createPoints(geometry, withColors) {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
764
|
+
const material = new THREE.PointsMaterial();
|
|
765
|
+
material.sizeAttenuation = false;
|
|
766
|
+
material.fog = true;
|
|
767
|
+
material.size = 5;
|
|
768
|
+
material.color = new THREE.Color(withColors ? 16777215 : 0);
|
|
769
|
+
if (withColors) {
|
|
770
|
+
material.vertexColors = true;
|
|
771
|
+
}
|
|
772
|
+
return new THREE.Points(geometry, material);
|
|
786
773
|
}
|
|
787
|
-
|
|
788
774
|
function createPointsFromJsonArray(path) {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
775
|
+
const geometry = new THREE.BufferGeometry();
|
|
776
|
+
const positions = new Float32Array(path[0].attributes["points::array::positions"].flat());
|
|
777
|
+
geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
|
|
778
|
+
const colors = path[0].attributes["points::array::colors"];
|
|
779
|
+
if (colors) {
|
|
780
|
+
const colors_ = new Float32Array(colors.flat());
|
|
781
|
+
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors_, 3));
|
|
782
|
+
}
|
|
783
|
+
return createPoints(geometry, colors);
|
|
798
784
|
}
|
|
799
|
-
|
|
800
785
|
function base64ToArrayBuffer(str) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
786
|
+
let binary;
|
|
787
|
+
try {
|
|
788
|
+
binary = atob(str);
|
|
789
|
+
} catch (e) {
|
|
790
|
+
throw new Error("base64 encoded string is invalid");
|
|
791
|
+
}
|
|
792
|
+
const bytes = new Uint8Array(binary.length);
|
|
793
|
+
for (let i = 0; i < binary.length; ++i) {
|
|
794
|
+
bytes[i] = binary.charCodeAt(i);
|
|
795
|
+
}
|
|
796
|
+
return bytes.buffer;
|
|
812
797
|
}
|
|
813
|
-
|
|
814
798
|
function createPointsFromJsonPositionBase64(path) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
799
|
+
const geometry = new THREE.BufferGeometry();
|
|
800
|
+
const positions_base64 = path[0].attributes["points::base64::positions"];
|
|
801
|
+
const positions_bytes = base64ToArrayBuffer(positions_base64);
|
|
802
|
+
if (!positions_bytes) {
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
const positions = new Float32Array(positions_bytes);
|
|
806
|
+
geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
|
|
807
|
+
const colors_base64 = path[0].attributes["points::base64::colors"];
|
|
808
|
+
if (colors_base64) {
|
|
809
|
+
const colors_bytes = base64ToArrayBuffer(colors_base64);
|
|
810
|
+
if (colors_bytes) {
|
|
811
|
+
const colors = new Float32Array(colors_bytes);
|
|
812
|
+
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return createPoints(geometry, colors_base64);
|
|
832
816
|
}
|
|
833
|
-
|
|
834
817
|
function traverseTree(path, parent, pathMapping) {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
818
|
+
const node = path[0];
|
|
819
|
+
let elem = new THREE.Group();
|
|
820
|
+
if (HasAttr(node, "usd::usdgeom::visibility::visibility")) {
|
|
821
|
+
if (node.attributes["usd::usdgeom::visibility::visibility"] === "invisible") {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
} else if (HasAttr(node, "usd::usdgeom::mesh::points")) {
|
|
825
|
+
elem = createMeshFromJson(path);
|
|
826
|
+
} else if (HasAttr(node, "usd::usdgeom::basiscurves::points")) {
|
|
827
|
+
elem = createCurveFromJson(path);
|
|
828
|
+
} else if (HasAttr(node, "pcd::base64")) {
|
|
829
|
+
elem = createPointsFromJsonPcdBase64(path);
|
|
830
|
+
} else if (HasAttr(node, "points::array::positions")) {
|
|
831
|
+
elem = createPointsFromJsonArray(path);
|
|
832
|
+
} else if (HasAttr(node, "points::base64::positions")) {
|
|
833
|
+
elem = createPointsFromJsonPositionBase64(path);
|
|
834
|
+
}
|
|
835
|
+
objectMap[node.name] = elem;
|
|
836
|
+
primMap[node.name] = node;
|
|
837
|
+
elem.userData.path = node.name;
|
|
838
|
+
for (let path2 of Object.entries(node.attributes || {})
|
|
839
|
+
.filter(([k, _]) => k.startsWith("__internal_"))
|
|
840
|
+
.map(([_, v]) => v)) {
|
|
841
|
+
(pathMapping[String(path2)] = pathMapping[String(path2)] || []).push(node.name);
|
|
842
|
+
}
|
|
843
|
+
parent.add(elem);
|
|
844
|
+
if (path.length > 1) {
|
|
845
|
+
elem.matrixAutoUpdate = false;
|
|
846
|
+
let matrixNode =
|
|
847
|
+
node.attributes && node.attributes["usd::xformop::transform"]
|
|
848
|
+
? node.attributes["usd::xformop::transform"].flat()
|
|
849
|
+
: null;
|
|
850
|
+
if (matrixNode) {
|
|
851
|
+
let matrix = new THREE.Matrix4();
|
|
852
|
+
matrix.set(...matrixNode);
|
|
853
|
+
matrix.transpose();
|
|
854
|
+
elem.matrix = matrix;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
(node.children || []).forEach((child) => traverseTree([child, ...path], elem || parent, pathMapping));
|
|
870
858
|
}
|
|
871
|
-
|
|
872
859
|
async function composeAndRender() {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
860
|
+
if (scene) {
|
|
861
|
+
scene.children = [];
|
|
862
|
+
}
|
|
863
|
+
objectMap = {};
|
|
864
|
+
primMap = {};
|
|
865
|
+
if (datas.length === 0) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
let tree = null;
|
|
869
|
+
let dataArray = datas.map((arr) => arr[1]);
|
|
870
|
+
tree = await compose3(dataArray);
|
|
871
|
+
if (!tree) {
|
|
872
|
+
console.error("No result from composition");
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (!scene) {
|
|
876
|
+
init();
|
|
877
|
+
}
|
|
878
|
+
let pathMapping = {};
|
|
879
|
+
traverseTree([tree], scene, pathMapping);
|
|
880
|
+
if (autoCamera) {
|
|
881
|
+
const boundingBox = new THREE.Box3();
|
|
882
|
+
boundingBox.setFromObject(scene);
|
|
883
|
+
if (!boundingBox.isEmpty()) {
|
|
884
|
+
let avg = boundingBox.min.clone().add(boundingBox.max).multiplyScalar(0.5);
|
|
885
|
+
let ext = boundingBox.max.clone().sub(boundingBox.min).length();
|
|
886
|
+
camera.position.copy(avg.clone().add(new THREE.Vector3(1, 1, 1).normalize().multiplyScalar(ext)));
|
|
887
|
+
camera.far = ext * 3;
|
|
888
|
+
camera.updateProjectionMatrix();
|
|
889
|
+
autoCamera = false;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
905
892
|
}
|
|
906
|
-
|
|
907
893
|
async function parse(m, name) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
894
|
+
datas.push([name, m]);
|
|
895
|
+
await composeAndRender();
|
|
896
|
+
return scene;
|
|
911
897
|
}
|
|
912
|
-
|
|
913
898
|
function clear() {
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
899
|
+
scene = undefined;
|
|
900
|
+
datas.length = 0;
|
|
901
|
+
autoCamera = true;
|
|
917
902
|
}
|
|
918
903
|
|
|
919
904
|
class IFCXLoader extends Loader {
|
|
920
905
|
load(url, onLoad, onProgress, onError) {
|
|
921
906
|
const manager = this.manager;
|
|
922
907
|
manager.itemStart(url);
|
|
923
|
-
const _onLoad = scene => {
|
|
908
|
+
const _onLoad = (scene) => {
|
|
924
909
|
onLoad(scene);
|
|
925
910
|
manager.itemEnd(url);
|
|
926
911
|
};
|
|
927
|
-
const _onError = e => {
|
|
928
|
-
if (onError)
|
|
912
|
+
const _onError = (e) => {
|
|
913
|
+
if (onError)
|
|
914
|
+
onError(e);
|
|
915
|
+
else
|
|
916
|
+
console.error(e);
|
|
929
917
|
manager.itemError(url);
|
|
930
918
|
manager.itemEnd(url);
|
|
931
919
|
};
|
|
@@ -934,10 +922,13 @@ class IFCXLoader extends Loader {
|
|
|
934
922
|
loader.setResponseType("json");
|
|
935
923
|
loader.setRequestHeader(this.requestHeader);
|
|
936
924
|
loader.setWithCredentials(this.withCredentials);
|
|
937
|
-
loader.load(url, json => this.parse(json, _onLoad, _onError), onProgress, onError);
|
|
925
|
+
loader.load(url, (json) => this.parse(json, _onLoad, _onError), onProgress, onError);
|
|
938
926
|
}
|
|
939
927
|
parse(json, onLoad, onError) {
|
|
940
|
-
parse(json)
|
|
928
|
+
parse(json)
|
|
929
|
+
.then((scene) => onLoad(scene))
|
|
930
|
+
.catch((err) => onError(err))
|
|
931
|
+
.finally(() => clear());
|
|
941
932
|
}
|
|
942
933
|
}
|
|
943
934
|
|
|
@@ -947,7 +938,8 @@ class IFCXFileLoader extends Loader$1 {
|
|
|
947
938
|
this.viewer = viewer;
|
|
948
939
|
}
|
|
949
940
|
isSupport(file, format) {
|
|
950
|
-
return (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
941
|
+
return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
942
|
+
/(ifcx)$/i.test(format));
|
|
951
943
|
}
|
|
952
944
|
async load(file, format, params) {
|
|
953
945
|
const manager = new GLTFLoadingManager(file, params);
|
|
@@ -955,23 +947,17 @@ class IFCXFileLoader extends Loader$1 {
|
|
|
955
947
|
loader.setPath(manager.path);
|
|
956
948
|
loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
|
|
957
949
|
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
958
|
-
const progress = event => {
|
|
959
|
-
const {
|
|
950
|
+
const progress = (event) => {
|
|
951
|
+
const { lengthComputable, loaded, total } = event;
|
|
960
952
|
const progress = lengthComputable ? loaded / total : 1;
|
|
961
|
-
this.viewer.emitEvent({
|
|
962
|
-
type: "geometryprogress",
|
|
963
|
-
data: progress,
|
|
964
|
-
file: file
|
|
965
|
-
});
|
|
953
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
966
954
|
};
|
|
967
955
|
const scene = await loader.loadAsync(manager.fileURL, progress);
|
|
968
|
-
if (!this.viewer.scene)
|
|
956
|
+
if (!this.viewer.scene)
|
|
957
|
+
return this;
|
|
969
958
|
let handle = 0;
|
|
970
|
-
scene.traverse(object => {
|
|
971
|
-
object.userData = {
|
|
972
|
-
handle: handle,
|
|
973
|
-
...object.userData
|
|
974
|
-
};
|
|
959
|
+
scene.traverse((object) => {
|
|
960
|
+
object.userData = { handle, ...object.userData };
|
|
975
961
|
handle++;
|
|
976
962
|
});
|
|
977
963
|
const modelImpl = new ModelImpl(scene);
|
|
@@ -982,11 +968,7 @@ class IFCXFileLoader extends Loader$1 {
|
|
|
982
968
|
this.viewer.syncOptions();
|
|
983
969
|
this.viewer.syncOverlay();
|
|
984
970
|
this.viewer.update();
|
|
985
|
-
this.viewer.emitEvent({
|
|
986
|
-
type: "databasechunk",
|
|
987
|
-
data: scene,
|
|
988
|
-
file: file
|
|
989
|
-
});
|
|
971
|
+
this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
|
|
990
972
|
return this;
|
|
991
973
|
}
|
|
992
974
|
}
|
|
@@ -997,28 +979,25 @@ class IFCXCloudLoader extends Loader$1 {
|
|
|
997
979
|
this.viewer = viewer;
|
|
998
980
|
}
|
|
999
981
|
isSupport(file) {
|
|
1000
|
-
return typeof file === "object" &&
|
|
982
|
+
return (typeof file === "object" &&
|
|
983
|
+
typeof file.type === "string" &&
|
|
984
|
+
typeof file.download === "function" &&
|
|
985
|
+
/.ifcx$/i.test(file.type));
|
|
1001
986
|
}
|
|
1002
987
|
async load(file) {
|
|
1003
|
-
const progress = progress => {
|
|
1004
|
-
this.viewer.emitEvent({
|
|
1005
|
-
type: "geometryprogress",
|
|
1006
|
-
data: progress,
|
|
1007
|
-
file: file
|
|
1008
|
-
});
|
|
988
|
+
const progress = (progress) => {
|
|
989
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
1009
990
|
};
|
|
1010
991
|
const arrayBuffer = await file.download(progress, this.abortController.signal);
|
|
1011
|
-
if (!this.viewer.scene)
|
|
1012
|
-
|
|
992
|
+
if (!this.viewer.scene)
|
|
993
|
+
return this;
|
|
994
|
+
const textDecoder = new TextDecoder();
|
|
1013
995
|
const json = JSON.parse(textDecoder.decode(arrayBuffer));
|
|
1014
996
|
const scene = await parse(json);
|
|
1015
997
|
clear();
|
|
1016
998
|
let handle = 0;
|
|
1017
|
-
scene.traverse(object => {
|
|
1018
|
-
object.userData = {
|
|
1019
|
-
handle: handle,
|
|
1020
|
-
...object.userData
|
|
1021
|
-
};
|
|
999
|
+
scene.traverse((object) => {
|
|
1000
|
+
object.userData = { handle, ...object.userData };
|
|
1022
1001
|
handle++;
|
|
1023
1002
|
});
|
|
1024
1003
|
const modelImpl = new ModelImpl(scene);
|
|
@@ -1029,16 +1008,11 @@ class IFCXCloudLoader extends Loader$1 {
|
|
|
1029
1008
|
this.viewer.syncOptions();
|
|
1030
1009
|
this.viewer.syncOverlay();
|
|
1031
1010
|
this.viewer.update();
|
|
1032
|
-
this.viewer.emitEvent({
|
|
1033
|
-
type: "databasechunk",
|
|
1034
|
-
data: scene,
|
|
1035
|
-
file: file
|
|
1036
|
-
});
|
|
1011
|
+
this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
|
|
1037
1012
|
return this;
|
|
1038
1013
|
}
|
|
1039
1014
|
}
|
|
1040
1015
|
|
|
1041
|
-
loaders.registerLoader("ifcx-file", viewer => new IFCXFileLoader(viewer));
|
|
1042
|
-
|
|
1043
|
-
loaders.registerLoader("ifcx-cloud", viewer => new IFCXCloudLoader(viewer));
|
|
1016
|
+
loaders.registerLoader("ifcx-file", (viewer) => new IFCXFileLoader(viewer));
|
|
1017
|
+
loaders.registerLoader("ifcx-cloud", (viewer) => new IFCXCloudLoader(viewer));
|
|
1044
1018
|
//# sourceMappingURL=IFCXLoader.module.js.map
|