@xeokit/xeokit-sdk 2.6.10 → 2.6.13
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/web-ifc.wasm +0 -0
- package/dist/xeokit-sdk.cjs.js +1161 -131
- package/dist/xeokit-sdk.es.js +1160 -132
- package/dist/xeokit-sdk.es5.js +519 -51
- package/dist/xeokit-sdk.min.cjs.js +5 -5
- package/dist/xeokit-sdk.min.es.js +5 -5
- package/dist/xeokit-sdk.min.es5.js +4 -4
- package/package.json +1 -1
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsControl.js +10 -0
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js +9 -0
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js +9 -0
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +182 -42
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsControl.js +11 -0
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js +11 -0
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.js +18 -1
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +15 -0
- package/src/plugins/DotBIMLoaderPlugin/DotBIMDefaultDataSource.js +29 -0
- package/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js +536 -0
- package/src/plugins/DotBIMLoaderPlugin/index.js +2 -0
- package/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js +74 -0
- package/src/plugins/GLTFLoaderPlugin/GLTFSceneModelLoader.js +53 -58
- package/src/plugins/LASLoaderPlugin/LASLoaderPlugin.js +59 -2
- package/src/plugins/index.js +2 -1
- package/src/plugins/lib/html/Dot.js +38 -6
- package/src/plugins/lib/html/Label.js +48 -7
- package/src/plugins/lib/html/Wire.js +38 -6
- package/src/viewer/Viewer.js +1 -1
- package/src/viewer/scene/marker/Marker.js +2 -2
- package/src/viewer/scene/model/SceneModel.js +17 -9
- package/src/viewer/utils/os.js +11 -0
- package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsControl.d.ts +7 -0
- package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.d.ts +8 -0
- package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.d.ts +8 -0
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.d.ts +70 -0
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsControl.d.ts +7 -0
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.d.ts +8 -0
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.d.ts +8 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import {Plugin, SceneModel, utils} from "../../viewer/index.js"
|
|
2
|
+
import {math} from "../../viewer/scene/math/math.js";
|
|
3
|
+
import {DotBIMDefaultDataSource} from "./DotBIMDefaultDataSource.js";
|
|
4
|
+
import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* {@link Viewer} plugin that loads models from [.bim](https://dotbim.net/) format.
|
|
8
|
+
*
|
|
9
|
+
* [<img src="https://xeokit.github.io/xeokit-sdk/assets/images/DotBIMLoaderPlugin-house.png">](https://xeokit.github.io/xeokit-sdk/examples/buildings/#dotbim_House)
|
|
10
|
+
*
|
|
11
|
+
* [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/buildings/#dotbim_House)]
|
|
12
|
+
*
|
|
13
|
+
* * Creates an {@link Entity} representing each .bim model it loads, which will have {@link Entity#isModel} set ````true````
|
|
14
|
+
* and will be registered by {@link Entity#id} in {@link Scene#models}.
|
|
15
|
+
* * Creates an {@link Entity} for each object within the .bim model. Those Entities will have {@link Entity#isObject}
|
|
16
|
+
* set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}.
|
|
17
|
+
* * When loading, can set the World-space position, scale and rotation of each model within World space,
|
|
18
|
+
* along with initial properties for all the model's {@link Entity}s.
|
|
19
|
+
* * Allows to mask which IFC types we want to load.
|
|
20
|
+
* * Allows to configure initial viewer state for specified IFC types (color, visibility, selection, highlighted, X-rayed, pickable, etc).
|
|
21
|
+
*
|
|
22
|
+
* ## Usage
|
|
23
|
+
*
|
|
24
|
+
* In the example below we'll load a house model from a [.bim file](/assets/models/dotbim/House.bim).
|
|
25
|
+
*
|
|
26
|
+
* This will create a bunch of {@link Entity}s that represents the model and its objects, along with
|
|
27
|
+
* a {@link MetaModel} and {@link MetaObject}s that hold their metadata.
|
|
28
|
+
*
|
|
29
|
+
* ````javascript
|
|
30
|
+
* import {Viewer, DotBIMLoaderPlugin} from "xeokit-sdk.es.js";
|
|
31
|
+
*
|
|
32
|
+
* //------------------------------------------------------------------------------------------------------------------
|
|
33
|
+
* // 1. Create a Viewer,
|
|
34
|
+
* // 2. Arrange the camera,
|
|
35
|
+
* // 3. Tweak the selection material (tone it down a bit)
|
|
36
|
+
* //------------------------------------------------------------------------------------------------------------------
|
|
37
|
+
*
|
|
38
|
+
* // 1
|
|
39
|
+
* const viewer = new Viewer({
|
|
40
|
+
* canvasId: "myCanvas",
|
|
41
|
+
* transparent: true
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // 2
|
|
45
|
+
* viewer.camera.orbitPitch(20);
|
|
46
|
+
* viewer.camera.orbitYaw(-45);
|
|
47
|
+
*
|
|
48
|
+
* // 3
|
|
49
|
+
* viewer.scene.selectedMaterial.fillAlpha = 0.1;
|
|
50
|
+
*
|
|
51
|
+
* //------------------------------------------------------------------------------------------------------------------
|
|
52
|
+
* // 1. Create a .bim loader plugin,
|
|
53
|
+
* // 2. Load a .bim building model, emphasizing the edges to make it look nicer
|
|
54
|
+
* //------------------------------------------------------------------------------------------------------------------
|
|
55
|
+
*
|
|
56
|
+
* // 1
|
|
57
|
+
* const dotBIMLoader = new DotBIMLoaderPlugin(viewer);
|
|
58
|
+
*
|
|
59
|
+
* // 2
|
|
60
|
+
* var model = dotBIMLoader.load({ // Returns an Entity that represents the model
|
|
61
|
+
* id: "myModel",
|
|
62
|
+
* src: "House.bim",
|
|
63
|
+
* edges: true
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // Find the model Entity by ID
|
|
67
|
+
* model = viewer.scene.models["myModel"];
|
|
68
|
+
*
|
|
69
|
+
* // Destroy the model
|
|
70
|
+
* model.destroy();
|
|
71
|
+
* ````
|
|
72
|
+
*
|
|
73
|
+
* ## Transforming
|
|
74
|
+
*
|
|
75
|
+
* We have the option to rotate, scale and translate each *````.bim````* model as we load it.
|
|
76
|
+
*
|
|
77
|
+
* This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other.
|
|
78
|
+
*
|
|
79
|
+
* In the example below, we'll rotate our model 90 degrees about its local X-axis, then
|
|
80
|
+
* translate it 100 units along its X axis.
|
|
81
|
+
*
|
|
82
|
+
* ````javascript
|
|
83
|
+
* const model = dotBIMLoader.load({
|
|
84
|
+
* src: "House.bim",
|
|
85
|
+
* rotation: [90,0,0],
|
|
86
|
+
* position: [100, 0, 0]
|
|
87
|
+
* });
|
|
88
|
+
* ````
|
|
89
|
+
*
|
|
90
|
+
* ## Including and excluding IFC types
|
|
91
|
+
*
|
|
92
|
+
* We can also load only those objects that have the specified IFC types. In the example below, we'll load only the
|
|
93
|
+
* objects that represent walls.
|
|
94
|
+
*
|
|
95
|
+
* ````javascript
|
|
96
|
+
* const model = dotBIMLoader.load({
|
|
97
|
+
* id: "myModel",
|
|
98
|
+
* src: "House.bim",
|
|
99
|
+
* includeTypes: ["IfcWallStandardCase"]
|
|
100
|
+
* });
|
|
101
|
+
* ````
|
|
102
|
+
*
|
|
103
|
+
* We can also load only those objects that **don't** have the specified IFC types. In the example below, we'll load only the
|
|
104
|
+
* objects that do not represent empty space.
|
|
105
|
+
*
|
|
106
|
+
* ````javascript
|
|
107
|
+
* const model = dotBIMLoader.load({
|
|
108
|
+
* id: "myModel",
|
|
109
|
+
* src: "House.bim",
|
|
110
|
+
* excludeTypes: ["IfcSpace"]
|
|
111
|
+
* });
|
|
112
|
+
* ````
|
|
113
|
+
*
|
|
114
|
+
* # Configuring initial IFC object appearances
|
|
115
|
+
*
|
|
116
|
+
* We can specify the custom initial appearance of loaded objects according to their IFC types.
|
|
117
|
+
*
|
|
118
|
+
* This is useful for things like:
|
|
119
|
+
*
|
|
120
|
+
* * setting the colors to our objects according to their IFC types,
|
|
121
|
+
* * automatically hiding ````IfcSpace```` objects, and
|
|
122
|
+
* * ensuring that ````IfcWindow```` objects are always transparent.
|
|
123
|
+
* <br>
|
|
124
|
+
* In the example below, we'll load a model, while configuring ````IfcSpace```` elements to be always initially invisible,
|
|
125
|
+
* and ````IfcWindow```` types to be always translucent blue.
|
|
126
|
+
*
|
|
127
|
+
* ````javascript
|
|
128
|
+
* const myObjectDefaults = {
|
|
129
|
+
*
|
|
130
|
+
* IfcSpace: {
|
|
131
|
+
* visible: false
|
|
132
|
+
* },
|
|
133
|
+
* IfcWindow: {
|
|
134
|
+
* colorize: [0.337255, 0.303922, 0.870588], // Blue
|
|
135
|
+
* opacity: 0.3
|
|
136
|
+
* },
|
|
137
|
+
*
|
|
138
|
+
* //...
|
|
139
|
+
*
|
|
140
|
+
* DEFAULT: {
|
|
141
|
+
* colorize: [0.5, 0.5, 0.5]
|
|
142
|
+
* }
|
|
143
|
+
* };
|
|
144
|
+
*
|
|
145
|
+
* const model4 = dotBIMLoader.load({
|
|
146
|
+
* id: "myModel4",
|
|
147
|
+
* src: "House.bim",
|
|
148
|
+
* objectDefaults: myObjectDefaults // Use our custom initial default states for object Entities
|
|
149
|
+
* });
|
|
150
|
+
* ````
|
|
151
|
+
*
|
|
152
|
+
* When we don't customize the appearance of IFC types, as just above, then IfcSpace elements tend to obscure other
|
|
153
|
+
* elements, which can be confusing.
|
|
154
|
+
*
|
|
155
|
+
* It's often helpful to make IfcSpaces transparent and unpickable, like this:
|
|
156
|
+
*
|
|
157
|
+
* ````javascript
|
|
158
|
+
* const dotBIMLoader = new DotBIMLoaderPlugin(viewer, {
|
|
159
|
+
* objectDefaults: {
|
|
160
|
+
* IfcSpace: {
|
|
161
|
+
* pickable: false,
|
|
162
|
+
* opacity: 0.2
|
|
163
|
+
* }
|
|
164
|
+
* }
|
|
165
|
+
* });
|
|
166
|
+
* ````
|
|
167
|
+
*
|
|
168
|
+
* Alternatively, we could just make IfcSpaces invisible, which also makes them unpickable:
|
|
169
|
+
*
|
|
170
|
+
* ````javascript
|
|
171
|
+
* const dotBIMLoader = new DotBIMLoaderPlugin(viewer, {
|
|
172
|
+
* objectDefaults: {
|
|
173
|
+
* IfcSpace: {
|
|
174
|
+
* visible: false
|
|
175
|
+
* }
|
|
176
|
+
* }
|
|
177
|
+
* });
|
|
178
|
+
* ````
|
|
179
|
+
*
|
|
180
|
+
* # Configuring a custom data source
|
|
181
|
+
*
|
|
182
|
+
* By default, DotBIMLoaderPlugin will load *````.bim````* files and metadata JSON over HTTP.
|
|
183
|
+
*
|
|
184
|
+
* In the example below, we'll customize the way DotBIMLoaderPlugin loads the files by configuring it with our own data source
|
|
185
|
+
* object. For simplicity, our custom data source example also uses HTTP, using a couple of xeokit utility functions.
|
|
186
|
+
*
|
|
187
|
+
* ````javascript
|
|
188
|
+
* import {utils} from "xeokit-sdk.es.js";
|
|
189
|
+
*
|
|
190
|
+
* class MyDataSource {
|
|
191
|
+
*
|
|
192
|
+
* constructor() {
|
|
193
|
+
* }
|
|
194
|
+
*
|
|
195
|
+
* // Gets the contents of the given .bim file in a JSON object
|
|
196
|
+
* getDotBIM(src, ok, error) {
|
|
197
|
+
* utils.loadJSON(dotBIMSrc,
|
|
198
|
+
* (json) => {
|
|
199
|
+
* ok(json);
|
|
200
|
+
* },
|
|
201
|
+
* function (errMsg) {
|
|
202
|
+
* error(errMsg);
|
|
203
|
+
* });
|
|
204
|
+
* }
|
|
205
|
+
* }
|
|
206
|
+
*
|
|
207
|
+
* const dotBIMLoader2 = new DotBIMLoaderPlugin(viewer, {
|
|
208
|
+
* dataSource: new MyDataSource()
|
|
209
|
+
* });
|
|
210
|
+
*
|
|
211
|
+
* const model5 = dotBIMLoader2.load({
|
|
212
|
+
* id: "myModel5",
|
|
213
|
+
* src: "House.bim"
|
|
214
|
+
* });
|
|
215
|
+
* ````
|
|
216
|
+
* @class DotBIMLoaderPlugin
|
|
217
|
+
*/
|
|
218
|
+
export class DotBIMLoaderPlugin extends Plugin {
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @constructor
|
|
222
|
+
*
|
|
223
|
+
* @param {Viewer} viewer The Viewer.
|
|
224
|
+
* @param {Object} cfg Plugin configuration.
|
|
225
|
+
* @param {String} [cfg.id="DotBIMLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
|
|
226
|
+
* @param {Object} [cfg.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}.
|
|
227
|
+
* @param {Object} [cfg.dataSource] A custom data source through which the DotBIMLoaderPlugin can load metadata, glTF and binary attachments. Defaults to an instance of {@link DotBIMDefaultDataSource}, which loads over HTTP.
|
|
228
|
+
*/
|
|
229
|
+
constructor(viewer, cfg = {}) {
|
|
230
|
+
|
|
231
|
+
super("DotBIMLoader", viewer, cfg);
|
|
232
|
+
|
|
233
|
+
this.dataSource = cfg.dataSource;
|
|
234
|
+
this.objectDefaults = cfg.objectDefaults;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Sets a custom data source through which the DotBIMLoaderPlugin can .BIM files.
|
|
239
|
+
*
|
|
240
|
+
* Default value is {@link DotBIMDefaultDataSource}, which loads via an XMLHttpRequest.
|
|
241
|
+
*
|
|
242
|
+
* @type {Object}
|
|
243
|
+
*/
|
|
244
|
+
set dataSource(value) {
|
|
245
|
+
this._dataSource = value || new DotBIMDefaultDataSource();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Gets the custom data source through which the DotBIMLoaderPlugin can load .BIM files.
|
|
250
|
+
*
|
|
251
|
+
* Default value is {@link DotBIMDefaultDataSource}, which loads via an XMLHttpRequest.
|
|
252
|
+
*
|
|
253
|
+
* @type {Object}
|
|
254
|
+
*/
|
|
255
|
+
get dataSource() {
|
|
256
|
+
return this._dataSource;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Sets map of initial default states for each loaded {@link Entity} that represents an object.
|
|
261
|
+
*
|
|
262
|
+
* Default value is {@link IFCObjectDefaults}.
|
|
263
|
+
*
|
|
264
|
+
* @type {{String: Object}}
|
|
265
|
+
*/
|
|
266
|
+
set objectDefaults(value) {
|
|
267
|
+
this._objectDefaults = value || IFCObjectDefaults;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Gets map of initial default states for each loaded {@link Entity} that represents an object.
|
|
272
|
+
*
|
|
273
|
+
* Default value is {@link IFCObjectDefaults}.
|
|
274
|
+
*
|
|
275
|
+
* @type {{String: Object}}
|
|
276
|
+
*/
|
|
277
|
+
get objectDefaults() {
|
|
278
|
+
return this._objectDefaults;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Loads a .BIM model from a file into this DotBIMLoaderPlugin's {@link Viewer}.
|
|
283
|
+
*
|
|
284
|
+
* @param {*} params Loading parameters.
|
|
285
|
+
* @param {String} [params.id] ID to assign to the root {@link Entity#id}, unique among all components in the Viewer's {@link Scene}, generated automatically by default.
|
|
286
|
+
* @param {String} [params.src] Path to a .BIM file, as an alternative to the ````bim```` parameter.
|
|
287
|
+
* @param {*} [params.bim] .BIM JSON, as an alternative to the ````src```` parameter.
|
|
288
|
+
* @param {{String:Object}} [params.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}.
|
|
289
|
+
* @param {String[]} [params.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list.
|
|
290
|
+
* @param {String[]} [params.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list.
|
|
291
|
+
* @param {Number[]} [params.origin=[0,0,0]] The double-precision World-space origin of the model's coordinates.
|
|
292
|
+
* @param {Number[]} [params.position=[0,0,0]] The single-precision position, relative to ````origin````.
|
|
293
|
+
* @param {Number[]} [params.scale=[1,1,1]] The model's scale.
|
|
294
|
+
* @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, as Euler angles given in degrees, for each of the X, Y and Z axis.
|
|
295
|
+
* @param {Boolean} [params.backfaces=true] When true, always show backfaces, even on objects for which the .BIM material is single-sided. When false, only show backfaces on geometries whenever the .BIM material is double-sided.
|
|
296
|
+
* @param {Boolean} [params.dtxEnabled=true] When ````true```` (default) use data textures (DTX), where appropriate, to
|
|
297
|
+
* represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
|
|
298
|
+
* to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
|
|
299
|
+
* primitives. Only works while {@link DTX#enabled} is also ````true````.
|
|
300
|
+
* @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}
|
|
301
|
+
*/
|
|
302
|
+
load(params = {}) {
|
|
303
|
+
|
|
304
|
+
if (params.id && this.viewer.scene.components[params.id]) {
|
|
305
|
+
this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID");
|
|
306
|
+
delete params.id;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const sceneModel = new SceneModel(this.viewer.scene, utils.apply(params, {
|
|
310
|
+
isModel: true,
|
|
311
|
+
backfaces: params.backfaces,
|
|
312
|
+
dtxEnabled: params.dtxEnabled,
|
|
313
|
+
rotation: params.rotation,
|
|
314
|
+
origin: params.origin
|
|
315
|
+
}));
|
|
316
|
+
|
|
317
|
+
const modelId = sceneModel.id; // In case ID was auto-generated
|
|
318
|
+
|
|
319
|
+
if (!params.src && !params.dotBIM) {
|
|
320
|
+
this.error("load() param expected: src or dotBIM");
|
|
321
|
+
return sceneModel; // Return new empty model
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const objectDefaults = params.objectDefaults || this._objectDefaults || IFCObjectDefaults;
|
|
325
|
+
|
|
326
|
+
let includeTypes;
|
|
327
|
+
if (params.includeTypes) {
|
|
328
|
+
includeTypes = {};
|
|
329
|
+
for (let i = 0, len = params.includeTypes.length; i < len; i++) {
|
|
330
|
+
includeTypes[params.includeTypes[i]] = true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let excludeTypes;
|
|
335
|
+
if (params.excludeTypes) {
|
|
336
|
+
excludeTypes = {};
|
|
337
|
+
if (!includeTypes) {
|
|
338
|
+
includeTypes = {};
|
|
339
|
+
}
|
|
340
|
+
for (let i = 0, len = params.excludeTypes.length; i < len; i++) {
|
|
341
|
+
includeTypes[params.excludeTypes[i]] = true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const parseDotBIM = (ctx) => {
|
|
346
|
+
|
|
347
|
+
const fileData = ctx.fileData;
|
|
348
|
+
const sceneModel = ctx.sceneModel;
|
|
349
|
+
|
|
350
|
+
const dbMeshIndices = {};
|
|
351
|
+
const dbMeshLoaded = {};
|
|
352
|
+
|
|
353
|
+
const ifcProjectId = math.createUUID();
|
|
354
|
+
const ifcSiteId = math.createUUID();
|
|
355
|
+
const ifcBuildingId = math.createUUID();
|
|
356
|
+
const ifcBuildingStoryId = math.createUUID();
|
|
357
|
+
|
|
358
|
+
const metaModelData = {
|
|
359
|
+
metaObjects: [
|
|
360
|
+
{
|
|
361
|
+
id: ifcProjectId,
|
|
362
|
+
name: "IfcProject",
|
|
363
|
+
type: "IfcProject",
|
|
364
|
+
parent: null
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: ifcSiteId,
|
|
368
|
+
name: "IfcSite",
|
|
369
|
+
type: "IfcSite",
|
|
370
|
+
parent: ifcProjectId
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
id: ifcBuildingId,
|
|
374
|
+
name: "IfcBuilding",
|
|
375
|
+
type: "IfcBuilding",
|
|
376
|
+
parent: ifcSiteId
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: ifcBuildingStoryId,
|
|
380
|
+
name: "IfcBuildingStorey",
|
|
381
|
+
type: "IfcBuildingStorey",
|
|
382
|
+
parent: ifcBuildingId
|
|
383
|
+
}
|
|
384
|
+
],
|
|
385
|
+
propertySets: []
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
for (let i = 0, len = fileData.meshes.length; i < len; i++) {
|
|
389
|
+
const dbMesh = fileData.meshes[i];
|
|
390
|
+
dbMeshIndices[dbMesh.mesh_id] = i;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const parseDBMesh = (dbMeshId) => {
|
|
394
|
+
if (dbMeshLoaded[dbMeshId]) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const dbMeshIndex = dbMeshIndices[dbMeshId];
|
|
398
|
+
const dbMesh = fileData.meshes[dbMeshIndex];
|
|
399
|
+
sceneModel.createGeometry({
|
|
400
|
+
id: dbMeshId,
|
|
401
|
+
primitive: "triangles",
|
|
402
|
+
positions: dbMesh.coordinates,
|
|
403
|
+
indices: dbMesh.indices
|
|
404
|
+
});
|
|
405
|
+
dbMeshLoaded[dbMeshId] = true;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const dbElements = fileData.elements;
|
|
409
|
+
for (let i = 0, len = dbElements.length; i < len; i++) {
|
|
410
|
+
const element = dbElements[i];
|
|
411
|
+
const elementType = element.type;
|
|
412
|
+
if (excludeTypes && excludeTypes[elementType]) {
|
|
413
|
+
continue;
|
|
414
|
+
|
|
415
|
+
}
|
|
416
|
+
if (includeTypes && (!includeTypes[elementType])) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const info = element.info;
|
|
420
|
+
const objectId =
|
|
421
|
+
element.guid !== undefined
|
|
422
|
+
? `${element.guid}`
|
|
423
|
+
: (info !== undefined && info.id !== undefined
|
|
424
|
+
? info.id
|
|
425
|
+
: i);
|
|
426
|
+
|
|
427
|
+
const dbMeshId = element.mesh_id;
|
|
428
|
+
|
|
429
|
+
parseDBMesh(dbMeshId);
|
|
430
|
+
|
|
431
|
+
const meshId = `${objectId}-mesh`;
|
|
432
|
+
const vector = element.vector;
|
|
433
|
+
const rotation = element.rotation;
|
|
434
|
+
const props = objectDefaults ? objectDefaults[elementType] || objectDefaults["DEFAULT"] : null;
|
|
435
|
+
|
|
436
|
+
let visible = true;
|
|
437
|
+
let pickable = true;
|
|
438
|
+
let color = element.color ? [element.color.r / 255, element.color.g / 255, element.color.b / 255] : [1, 1, 1];
|
|
439
|
+
let opacity = element.color ? element.color.a / 255 : 1.0;
|
|
440
|
+
|
|
441
|
+
if (props) {
|
|
442
|
+
if (props.visible === false) {
|
|
443
|
+
visible = false;
|
|
444
|
+
}
|
|
445
|
+
if (props.pickable === false) {
|
|
446
|
+
pickable = false;
|
|
447
|
+
}
|
|
448
|
+
if (props.colorize) {
|
|
449
|
+
color = props.colorize;
|
|
450
|
+
}
|
|
451
|
+
if (props.opacity !== undefined && props.opacity !== null) {
|
|
452
|
+
opacity = props.opacity;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
sceneModel.createMesh({
|
|
457
|
+
id: meshId,
|
|
458
|
+
geometryId: dbMeshId,
|
|
459
|
+
color,
|
|
460
|
+
opacity,
|
|
461
|
+
quaternion: rotation && (rotation.qz !== 0 || rotation.qy !== 0 || rotation.qx !== 0 || rotation.qw !== 1.0) ? [rotation.qx, rotation.qy, rotation.qz, rotation.qw] : undefined,
|
|
462
|
+
position: vector ? [vector.x, vector.y, vector.z] : undefined
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
sceneModel.createEntity({
|
|
466
|
+
id: objectId,
|
|
467
|
+
meshIds: [meshId],
|
|
468
|
+
visible,
|
|
469
|
+
pickable,
|
|
470
|
+
isObject: true
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
metaModelData.metaObjects.push({
|
|
474
|
+
id: objectId,
|
|
475
|
+
name: info && info.Name && info.Name !== "None" ? info.Name : `${element.type} ${objectId}`,
|
|
476
|
+
type: element.type,
|
|
477
|
+
parent: ifcBuildingStoryId
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
sceneModel.finalize();
|
|
482
|
+
|
|
483
|
+
this.viewer.metaScene.createMetaModel(modelId, metaModelData);
|
|
484
|
+
|
|
485
|
+
sceneModel.scene.once("tick", () => {
|
|
486
|
+
if (sceneModel.destroyed) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events
|
|
490
|
+
sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (params.src) {
|
|
495
|
+
const src = params.src;
|
|
496
|
+
this.viewer.scene.canvas.spinner.processes++;
|
|
497
|
+
this._dataSource.getDotBIM(src, (fileData) => { // OK
|
|
498
|
+
const ctx = {
|
|
499
|
+
fileData,
|
|
500
|
+
sceneModel,
|
|
501
|
+
nextId: 0,
|
|
502
|
+
error: function (errMsg) {
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
parseDotBIM(ctx);
|
|
506
|
+
this.viewer.scene.canvas.spinner.processes--;
|
|
507
|
+
},
|
|
508
|
+
(err) => {
|
|
509
|
+
this.viewer.scene.canvas.spinner.processes--;
|
|
510
|
+
this.error(err);
|
|
511
|
+
});
|
|
512
|
+
} else if (params.dotBIM) {
|
|
513
|
+
const ctx = {
|
|
514
|
+
fileData: params.dotBIM,
|
|
515
|
+
sceneModel,
|
|
516
|
+
nextId: 0,
|
|
517
|
+
error: function (errMsg) {
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
parseDotBIM(ctx);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
sceneModel.once("destroyed", () => {
|
|
524
|
+
this.viewer.metaScene.destroyMetaModel(modelId);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
return sceneModel;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Destroys this DotBIMLoaderPlugin.
|
|
532
|
+
*/
|
|
533
|
+
destroy() {
|
|
534
|
+
super.destroy();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
@@ -156,6 +156,79 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
156
156
|
* excludeTypes: ["IfcSpace"]
|
|
157
157
|
* });
|
|
158
158
|
* ````
|
|
159
|
+
*
|
|
160
|
+
* ## Showing a glTF model in TreeViewPlugin when metadata is not available
|
|
161
|
+
*
|
|
162
|
+
* When GLTFLoaderPlugin loads a glTF model, it creates an object Entity for each `node` in the glTF `scene` hierarchy that has a
|
|
163
|
+
* `name` attribute, giving the Entity an ID that has the value of the `name` attribute.
|
|
164
|
+
*
|
|
165
|
+
* Those name attributes are created by converter tools, such as by [IFC2GLTFCxConverter](https://github.com/Creoox/creoox-ifc2gltfcxconverter) when it generates glTF from IFC files. However, those name attributes are not
|
|
166
|
+
* ordinarily present in glTF that comes from other sources, such as LiDAR scanners. For such glTF models, GLTFLoaderPlugin
|
|
167
|
+
* will create Entities, but they will have randomly-generated IDs, and therefore cannot be associated with MetaObjects in any
|
|
168
|
+
* MetaModels that we create alongside the model.
|
|
169
|
+
*
|
|
170
|
+
* For glTF models containing `nodes` that don't have `name` attributes, we can use the `load()` method's `elementId` parameter
|
|
171
|
+
* to make GLTFLoaderPlugin load the entire model into a single Entity that gets this ID.
|
|
172
|
+
*
|
|
173
|
+
* In conjunction with that parameter, we can then use the `load()` method's `metaModelJSON` parameter to create a MetaModel that
|
|
174
|
+
* contains a MetaObject that corresponds to that Entity.
|
|
175
|
+
*
|
|
176
|
+
* When we've done that, then xeokit's {@link TreeViewPlugin} is able to have a node that represents the glTF model and controls
|
|
177
|
+
* the visibility of that Entity (ie. to control the visibility of the entire model).
|
|
178
|
+
*
|
|
179
|
+
* The snippet below shows how this is done.
|
|
180
|
+
*
|
|
181
|
+
* ````javascript
|
|
182
|
+
* import {Viewer, GLTFLoaderPlugin, NavCubePlugin, TreeViewPlugin} from "../../dist/xeokit-sdk.es.js";
|
|
183
|
+
*
|
|
184
|
+
* const viewer = new Viewer({
|
|
185
|
+
* canvasId: "myCanvas",
|
|
186
|
+
* transparent: true
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* new TreeViewPlugin(viewer, {
|
|
190
|
+
* containerElement: document.getElementById("treeViewContainer"),
|
|
191
|
+
* hierarchy: "containment"
|
|
192
|
+
* });
|
|
193
|
+
*
|
|
194
|
+
* const gltfLoader = new GLTFLoaderPlugin(viewer);
|
|
195
|
+
*
|
|
196
|
+
* const sceneModel = gltfLoader.load({ // Creates a SceneModel with ID "myScanModel"
|
|
197
|
+
* id: "myScanModel",
|
|
198
|
+
* src: "public-use-sample-apartment.glb",
|
|
199
|
+
*
|
|
200
|
+
* //-------------------------------------------------------------------------
|
|
201
|
+
* // Specify an `elementId` parameter, which causes the
|
|
202
|
+
* // entire model to be loaded into a single Entity that gets this ID.
|
|
203
|
+
* //-------------------------------------------------------------------------
|
|
204
|
+
*
|
|
205
|
+
* entityId: "3toKckUfH2jBmd$7uhJHa4", // Creates an Entity with this ID
|
|
206
|
+
*
|
|
207
|
+
* //-------------------------------------------------------------------------
|
|
208
|
+
* // Specify a `metaModelJSON` parameter, which creates a
|
|
209
|
+
* // MetaModel with two MetaObjects, one of which corresponds
|
|
210
|
+
* // to our Entity. Then the TreeViewPlugin is able to have a node
|
|
211
|
+
* // that can represent the model and control the visibility of the Entity.
|
|
212
|
+
* //--------------------------------------------------------------------------
|
|
213
|
+
*
|
|
214
|
+
* metaModelJSON: { // Creates a MetaModel with ID "myScanModel"
|
|
215
|
+
* "metaObjects": [
|
|
216
|
+
* {
|
|
217
|
+
* "id": "3toKckUfH2jBmd$7uhJHa6", // Creates a MetaObject with this ID
|
|
218
|
+
* "name": "My Project",
|
|
219
|
+
* "type": "Default",
|
|
220
|
+
* "parent": null
|
|
221
|
+
* },
|
|
222
|
+
* {
|
|
223
|
+
* "id": "3toKckUfH2jBmd$7uhJHa4", // Creates a MetaObject with this ID (same ID as our Entity)
|
|
224
|
+
* "name": "My Scan",
|
|
225
|
+
* "type": "Default",
|
|
226
|
+
* "parent": "3toKckUfH2jBmd$7uhJHa6"
|
|
227
|
+
* }
|
|
228
|
+
* ]
|
|
229
|
+
* }
|
|
230
|
+
* });
|
|
231
|
+
* ````
|
|
159
232
|
* @class GLTFLoaderPlugin
|
|
160
233
|
*/
|
|
161
234
|
class GLTFLoaderPlugin extends Plugin {
|
|
@@ -250,6 +323,7 @@ class GLTFLoaderPlugin extends Plugin {
|
|
|
250
323
|
* represent the returned model. Set false to always use vertex buffer objects (VBOs). Note that DTX is only applicable
|
|
251
324
|
* to non-textured triangle meshes, and that VBOs are always used for meshes that have textures, line segments, or point
|
|
252
325
|
* primitives. Only works while {@link DTX#enabled} is also ````true````.
|
|
326
|
+
* @param {String} [params.entityId] When supplied, causes the entire model to be loaded into a single {@link Entity} that gets this ID.
|
|
253
327
|
* @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}
|
|
254
328
|
*/
|
|
255
329
|
load(params = {}) {
|