@xeokit/xeokit-sdk 2.6.69 → 2.6.72
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/xeokit-sdk.cjs.js +4332 -207
- package/dist/xeokit-sdk.es.js +4332 -208
- package/dist/xeokit-sdk.es5.js +221 -204
- package/dist/xeokit-sdk.min.cjs.js +10 -4
- package/dist/xeokit-sdk.min.es.js +11 -5
- package/dist/xeokit-sdk.min.es5.js +10 -4
- package/package.json +3 -1
- package/src/extras/ContextMenu/ContextMenu.js +11 -9
- package/src/plugins/AnnotationsPlugin/Annotation.js +28 -16
- package/src/plugins/CxConverterIFCLoaderPlugin/CxConverterIFCLoaderPlugin.js +86 -0
- package/src/plugins/CxConverterIFCLoaderPlugin/index.js +1 -0
- package/src/plugins/LASLoaderPlugin/LASDefaultDataSource.js +13 -1
- package/src/plugins/LASLoaderPlugin/LASLoaderPlugin.js +89 -43
- package/src/plugins/NavCubePlugin/CubeTextureCanvas.js +2 -2
- package/src/plugins/NavCubePlugin/NavCubePlugin.js +10 -10
- package/src/plugins/SectionPlanesPlugin/Control.js +2 -2
- package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +4 -3
- package/src/plugins/ZonesPlugin/ZonesPlugin.js +6 -151
- package/src/plugins/index.js +1 -0
- package/src/plugins/lib/ui/index.js +592 -34
- package/src/viewer/scene/geometry/ReadableGeometry.js +60 -0
- package/src/viewer/scene/geometry/builders/buildPlaneGeometry.js +1 -1
- package/src/viewer/scene/math/math.js +14 -2
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLineSnapInitRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapInitRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapInitRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/points/renderers/VBOBatchingPointsSnapRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapInitRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +2 -0
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapInitRenderer.js +1 -24
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +2 -19
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapInitRenderer.js +1 -24
- package/src/viewer/scene/model/vbo/instancing/points/renderers/VBOInstancingPointsSnapRenderer.js +1 -19
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapInitRenderer.js +1 -24
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +2 -19
- package/src/viewer/scene/scene/Scene.js +2 -3
- package/src/viewer/scene/sectionCaps/SectionCaps.js +46 -65
- package/types/plugins/CxConverterIFCLoaderPlugin/CxConverterIFCLoaderPlugin.d.ts +36 -0
- package/types/plugins/CxConverterIFCLoaderPlugin/index.d.ts +1 -0
- package/types/plugins/NavCubePlugin/NavCubePlugin.d.ts +1 -1
- package/types/plugins/index.d.ts +1 -0
- package/types/viewer/scene/ImagePlane/ImagePlane.d.ts +397 -0
- package/types/viewer/scene/ImagePlane/index.d.ts +1 -0
- package/types/viewer/scene/geometry/builders/index.d.ts +1 -0
- package/types/viewer/scene/index.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xeokit/xeokit-sdk",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.72",
|
|
4
4
|
"description": "3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision",
|
|
5
5
|
"module": "./dist/xeokit-sdk.es.js",
|
|
6
6
|
"main": "./dist/xeokit-sdk.cjs.js",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"homepage": "https://xeokit.io",
|
|
55
55
|
"dependencies": {
|
|
56
|
+
"@creooxag/cx-converter": "^0.0.12-alpha",
|
|
56
57
|
"@loaders.gl/core": "^4.3.3",
|
|
57
58
|
"@loaders.gl/gltf": "^4.3.3",
|
|
58
59
|
"@loaders.gl/las": "^4.3.3",
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
"eslint": "^8.13.0",
|
|
77
78
|
"parse5": "^7.0.0",
|
|
78
79
|
"rollup": "^2.70.2",
|
|
80
|
+
"rollup-plugin-banner": "^0.2.1",
|
|
79
81
|
"rollup-plugin-terser": "^7.0.2",
|
|
80
82
|
"typedoc": "^0.22.15"
|
|
81
83
|
},
|
|
@@ -282,6 +282,7 @@ class ContextMenu {
|
|
|
282
282
|
* @param {Boolean} [cfg.enabled=true] Whether this ````ContextMenu```` is initially enabled. {@link ContextMenu#show} does nothing while this is ````false````.
|
|
283
283
|
* @param {Boolean} [cfg.hideOnMouseDown=true] Whether this ````ContextMenu```` automatically hides whenever we mouse-down or tap anywhere in the page.
|
|
284
284
|
* @param {Boolean} [cfg.hideOnAction=true] Whether this ````ContextMenu```` automatically hides after we select a menu item. Se false if we want the menu to remain shown and show any updates to its item titles, after we've selected an item.
|
|
285
|
+
* @param {Node | undefined} [cfg.parentNode] Optional reference to an existing DOM Node (e.g. ShadowRoot), to which the menu's HTML element will be appended, defaults to ````document.body````.
|
|
285
286
|
*/
|
|
286
287
|
constructor(cfg = {}) {
|
|
287
288
|
|
|
@@ -296,6 +297,7 @@ class ContextMenu {
|
|
|
296
297
|
this._itemMap = {}; // Items mapped to their IDs
|
|
297
298
|
this._shown = false; // True when the ContextMenu is visible
|
|
298
299
|
this._nextId = 0;
|
|
300
|
+
this._parentNode = cfg.parentNode || document.body;
|
|
299
301
|
|
|
300
302
|
/**
|
|
301
303
|
* Subscriptions to events fired at this ContextMenu.
|
|
@@ -304,12 +306,12 @@ class ContextMenu {
|
|
|
304
306
|
this._eventSubs = {};
|
|
305
307
|
|
|
306
308
|
if (cfg.hideOnMouseDown !== false) {
|
|
307
|
-
|
|
309
|
+
this._parentNode.addEventListener("mousedown", (event) => {
|
|
308
310
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
309
311
|
this.hide();
|
|
310
312
|
}
|
|
311
313
|
});
|
|
312
|
-
|
|
314
|
+
this._parentNode.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => {
|
|
313
315
|
if (!event.target.classList.contains("xeokit-context-menu-item")) {
|
|
314
316
|
this.hide();
|
|
315
317
|
}
|
|
@@ -613,7 +615,10 @@ class ContextMenu {
|
|
|
613
615
|
const groups = menu.groups;
|
|
614
616
|
const html = [];
|
|
615
617
|
|
|
616
|
-
|
|
618
|
+
const menuElement= document.createElement("div");
|
|
619
|
+
menuElement.classList.add("xeokit-context-menu", menu.id);
|
|
620
|
+
menuElement.style.zIndex = 300000;
|
|
621
|
+
menuElement.style.position = "absolute";
|
|
617
622
|
|
|
618
623
|
html.push('<ul>');
|
|
619
624
|
|
|
@@ -664,13 +669,10 @@ class ContextMenu {
|
|
|
664
669
|
}
|
|
665
670
|
|
|
666
671
|
html.push('</ul>');
|
|
667
|
-
html.push('</div>');
|
|
668
672
|
|
|
669
673
|
const htmlString = html.join("");
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
const menuElement = document.querySelector("." + menu.id);
|
|
674
|
+
menuElement.innerHTML = htmlString;
|
|
675
|
+
this._parentNode.appendChild(menuElement);
|
|
674
676
|
|
|
675
677
|
menu.menuElement = menuElement;
|
|
676
678
|
|
|
@@ -704,7 +706,7 @@ class ContextMenu {
|
|
|
704
706
|
const item = groupItems[j];
|
|
705
707
|
const itemSubMenu = item.subMenu;
|
|
706
708
|
|
|
707
|
-
item.itemElement =
|
|
709
|
+
item.itemElement = this._parentNode.querySelector(`#${item.id}`);
|
|
708
710
|
|
|
709
711
|
if (!item.itemElement) {
|
|
710
712
|
console.error("ContextMenu item element not found: " + item.id);
|
|
@@ -7,6 +7,8 @@ const tempVec3a = math.vec3();
|
|
|
7
7
|
const tempVec3b = math.vec3();
|
|
8
8
|
const tempVec3c = math.vec3();
|
|
9
9
|
|
|
10
|
+
const px = x => x + "px";
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* A {@link Marker} with an HTML label attached to it, managed by an {@link AnnotationsPlugin}.
|
|
12
14
|
*
|
|
@@ -213,22 +215,29 @@ class Annotation extends Marker {
|
|
|
213
215
|
* @private
|
|
214
216
|
*/
|
|
215
217
|
_updateWithCurWidths() {
|
|
216
|
-
const px = x => x + "px";
|
|
217
218
|
const boundary = this.scene.canvas.boundary;
|
|
218
219
|
const left = boundary[0] + this.canvasPos[0];
|
|
219
220
|
const top = boundary[1] + this.canvasPos[1];
|
|
220
|
-
|
|
221
|
-
const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
|
|
222
|
-
const markerCenter = left + markerDir * (markerWidth / 2 - 12);
|
|
223
|
-
this._marker.style.left = px(markerCenter - markerWidth / 2);
|
|
224
|
-
this._marker.style.top = px(top - 12);
|
|
225
|
-
this._marker.style["z-index"] = 90005 + Math.floor(this._viewPos[2]) + 1;
|
|
226
|
-
|
|
227
|
-
const labelWidth = this._curLabelWidth;
|
|
228
|
-
const labelDir = Math.sign(this._labelPosition);
|
|
229
|
-
this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
|
|
221
|
+
this._marker.style.top = px(top - 12);
|
|
230
222
|
this._label.style.top = px(top - 17);
|
|
231
|
-
|
|
223
|
+
|
|
224
|
+
if (this._markerAlign === "legacy") {
|
|
225
|
+
this._marker.style.left = px(left - 12);
|
|
226
|
+
this._label.style.left = px(left + 40);
|
|
227
|
+
} else {
|
|
228
|
+
const markerWidth = this._curMarkerWidth;
|
|
229
|
+
const markerDir = (this._markerAlign === "right") ? -1 : ((this._markerAlign === "center") ? 0 : 1);
|
|
230
|
+
const markerCenter = left + markerDir * (markerWidth / 2 - 12);
|
|
231
|
+
this._marker.style.left = px(markerCenter - markerWidth / 2);
|
|
232
|
+
|
|
233
|
+
const labelWidth = this._curLabelWidth;
|
|
234
|
+
const labelDir = Math.sign(this._labelPosition);
|
|
235
|
+
this._label.style.left = px(markerCenter + labelDir * (markerWidth / 2 + Math.abs(this._labelPosition) + labelWidth / 2) - labelWidth / 2);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const zIndex = 90005 + Math.floor(this._viewPos[2]) + 1;
|
|
239
|
+
this._marker.style["z-index"] = zIndex;
|
|
240
|
+
this._label.style["z-index"] = zIndex;
|
|
232
241
|
}
|
|
233
242
|
|
|
234
243
|
/**
|
|
@@ -259,7 +268,8 @@ class Annotation extends Marker {
|
|
|
259
268
|
* @private
|
|
260
269
|
*/
|
|
261
270
|
_updatePosition() {
|
|
262
|
-
|
|
271
|
+
const isLegacy = this._markerAlign === "legacy";
|
|
272
|
+
if ((! isLegacy) && (this._curMarkerWidth === undefined)) {
|
|
263
273
|
this._updateIfWidthsChanged();
|
|
264
274
|
} else {
|
|
265
275
|
// Update position with cached width values
|
|
@@ -267,7 +277,9 @@ class Annotation extends Marker {
|
|
|
267
277
|
// so they don't interfere with e.g. interactive scene manipulation
|
|
268
278
|
this._updateWithCurWidths();
|
|
269
279
|
window.clearTimeout(this._widthTimeout);
|
|
270
|
-
|
|
280
|
+
if (! isLegacy) {
|
|
281
|
+
this._widthTimeout = window.setTimeout(() => this._updateIfWidthsChanged(), 500);
|
|
282
|
+
}
|
|
271
283
|
}
|
|
272
284
|
}
|
|
273
285
|
|
|
@@ -305,10 +317,10 @@ class Annotation extends Marker {
|
|
|
305
317
|
/**
|
|
306
318
|
* Sets the horizontal alignment of the Annotation's marker HTML.
|
|
307
319
|
*
|
|
308
|
-
* @param {String} align Either "left", "center", "right" (default "left")
|
|
320
|
+
* @param {String} align Either "left", "center", "right", "legacy" (default "left")
|
|
309
321
|
*/
|
|
310
322
|
setMarkerAlign(align) {
|
|
311
|
-
const valid = [ "left", "center", "right" ];
|
|
323
|
+
const valid = [ "left", "center", "right", "legacy" ];
|
|
312
324
|
if (! valid.includes(align)) {
|
|
313
325
|
this.error("Param 'align' should be one of: " + JSON.stringify(valid));
|
|
314
326
|
} else {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Plugin } from "../../viewer/Plugin.js";
|
|
2
|
+
import { GLTFLoaderPlugin } from "../GLTFLoaderPlugin/GLTFLoaderPlugin.js";
|
|
3
|
+
import { ifc2gltf } from "@creooxag/cx-converter";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fetches a file from the given URL and returns its contents as text.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} url - The URL to fetch the file from.
|
|
9
|
+
* @returns {Promise<string>} A promise that resolves to the file contents.
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
12
|
+
async function fetchFile(url) {
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(url);
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
return response.text();
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error('Error fetching file:', error);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* {@link Viewer} plugin that uses [CxConverter](https://github.com/Creoox/cxconverter) to load BIM models directly from IFC files, using its WebAssembly buid from [npm package](https://www.npmjs.com/package/@creooxag/cx-converter).
|
|
26
|
+
*
|
|
27
|
+
* ## Overview
|
|
28
|
+
* The WebAssembly build of CxConverter is still in alfa stage, so it may not work as expected. This documentation will be updated as the library and the plugin evolve. The example below shows how to use the plugin:
|
|
29
|
+
* ````javascript
|
|
30
|
+
* import { CxConverterIFCLoaderPlugin, Viewer } from "../../dist/xeokit-sdk.es.js";
|
|
31
|
+
* const cxConverterIFCLoaderPlugin = new CxConverterIFCLoaderPlugin(viewer);
|
|
32
|
+
*
|
|
33
|
+
* const sceneModel = await cxConverterIFCLoaderPlugin.load({
|
|
34
|
+
* src: "../../assets/models/ifc/Duplex.ifc"
|
|
35
|
+
* });
|
|
36
|
+
* ````
|
|
37
|
+
See the code in action [here](https://xeokit.github.io/xeokit-sdk/examples/buildings/#cxConverterIFC_vbo_Duplex).
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
class CxConverterIFCLoaderPlugin extends Plugin {
|
|
41
|
+
/**
|
|
42
|
+
* @constructor
|
|
43
|
+
* @param {Viewer} viewer The Viewer.
|
|
44
|
+
* @param {Object} [cfg={}] Plugin configuration.
|
|
45
|
+
*/
|
|
46
|
+
constructor(viewer, cfg = {}) {
|
|
47
|
+
super("ifcLoader", viewer, cfg);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The GLTFLoaderPlugin used internally to load the converted GLTF.
|
|
51
|
+
* @type {GLTFLoaderPlugin}
|
|
52
|
+
*/
|
|
53
|
+
this.gltfLoader = new GLTFLoaderPlugin(this.viewer);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Loads an IFC model from the given source.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} [params={}] Loading parameters.
|
|
60
|
+
* @param {string} params.src Path to an IFC file.
|
|
61
|
+
* @param {Function} [params.progressCallback] Callback to track loading progress.
|
|
62
|
+
* @param {Function} [params.progressTextCallback] Callback to track loading progress with text updates.
|
|
63
|
+
* @returns {Promise<SceneModel>} A promise that resolves to the loaded SceneModel.
|
|
64
|
+
*/
|
|
65
|
+
async load(params = {}) {
|
|
66
|
+
if (!params.src) {
|
|
67
|
+
this.error("load() param expected: src");
|
|
68
|
+
}
|
|
69
|
+
const data = await fetchFile(params.src);
|
|
70
|
+
const { gltf, metaData } = await ifc2gltf(
|
|
71
|
+
data,
|
|
72
|
+
{
|
|
73
|
+
remote: true,
|
|
74
|
+
progressCallback: params.progressCallback,
|
|
75
|
+
progressTextCallback: params.progressTextCallback
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
const sceneModel = this.gltfLoader.load({
|
|
79
|
+
id: "myModel",
|
|
80
|
+
gltf: gltf,
|
|
81
|
+
metaModelJSON: metaData
|
|
82
|
+
});
|
|
83
|
+
return sceneModel;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export { CxConverterIFCLoaderPlugin };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./CxConverterIFCLoaderPlugin.js";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {utils} from "../../viewer/scene/utils.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Default data access strategy for {@link LASLoaderPlugin}.
|
|
3
5
|
*/
|
|
@@ -60,13 +62,23 @@ class LASDefaultDataSource {
|
|
|
60
62
|
if (request.status === 200) {
|
|
61
63
|
ok(request.response);
|
|
62
64
|
} else {
|
|
63
|
-
error('
|
|
65
|
+
error('getLAS error : ' + request.response);
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
};
|
|
67
69
|
request.send(null);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
72
|
+
|
|
73
|
+
getManifest(manifestSrc, ok, error) {
|
|
74
|
+
utils.loadJSON(this._cacheBusterURL(manifestSrc),
|
|
75
|
+
(json) => {
|
|
76
|
+
ok(json);
|
|
77
|
+
},
|
|
78
|
+
function (errMsg) {
|
|
79
|
+
error(errMsg);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
export {LASDefaultDataSource};
|
|
@@ -430,6 +430,8 @@ class LASLoaderPlugin extends Plugin {
|
|
|
430
430
|
* @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.
|
|
431
431
|
* @param {String} [params.src] Path to a LAS file, as an alternative to the ````las```` parameter.
|
|
432
432
|
* @param {ArrayBuffer} [params.las] The LAS file data, as an alternative to the ````src```` parameter.
|
|
433
|
+
* @param {String} [params.manifestSrc] Path or URL to a JSON manifest file that provides paths to ````.laz```` || ````.las```` files to load as parts of the model. Use this option to load models that have been split into
|
|
434
|
+
* @param {Object} [params.manifest] A JSON manifest object (as an alternative to a path or URL) that provides paths to ````.laz```` || ````.las```` files to load as parts of the model. Use this option to load models that have been split into
|
|
433
435
|
* @param {Boolean} [params.loadMetadata=true] Whether to load metadata for the LAS model.
|
|
434
436
|
* @param {Number[]} [params.origin=[0,0,0]] The model's World-space double-precision 3D origin. Use this to position the model within xeokit's World coordinate system, using double-precision coordinates.
|
|
435
437
|
* @param {Number[]} [params.position=[0,0,0]] The model single-precision 3D position, relative to the ````origin```` parameter.
|
|
@@ -451,7 +453,7 @@ class LASLoaderPlugin extends Plugin {
|
|
|
451
453
|
isModel: true
|
|
452
454
|
}));
|
|
453
455
|
|
|
454
|
-
if (!params.src && !params.las) {
|
|
456
|
+
if (!params.src && !params.las && !params.manifest && !params.manifestSrc) {
|
|
455
457
|
this.error("load() param expected: src or las");
|
|
456
458
|
return sceneModel; // Return new empty model
|
|
457
459
|
}
|
|
@@ -464,18 +466,77 @@ class LASLoaderPlugin extends Plugin {
|
|
|
464
466
|
}
|
|
465
467
|
};
|
|
466
468
|
|
|
469
|
+
const spinner = this.viewer.scene.canvas.spinner;
|
|
470
|
+
const done = () => {
|
|
471
|
+
sceneModel.scene.once("tick", () => {
|
|
472
|
+
if (sceneModel.destroyed) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events
|
|
476
|
+
sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers
|
|
477
|
+
});
|
|
478
|
+
spinner.processes--;
|
|
479
|
+
}
|
|
480
|
+
const error = (errMsg) => {
|
|
481
|
+
spinner.processes--;
|
|
482
|
+
this.error(errMsg);
|
|
483
|
+
sceneModel.fire("error", errMsg);
|
|
484
|
+
}
|
|
485
|
+
|
|
467
486
|
if (params.src) {
|
|
468
487
|
this._loadModel(params.src, params, options, sceneModel);
|
|
469
|
-
} else {
|
|
470
|
-
const spinner = this.viewer.scene.canvas.spinner;
|
|
488
|
+
} else if(params.las) {
|
|
471
489
|
spinner.processes++;
|
|
472
|
-
this._parseModel(params.las, params, options, sceneModel).then(
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
490
|
+
this._parseModel(params.las, params, options, sceneModel).then(done, error);
|
|
491
|
+
} else if (params.manifest || params.manifestSrc) {
|
|
492
|
+
const baseDir = params.manifestSrc ? getBaseDirectory(params.manifestSrc) : "";
|
|
493
|
+
const loadAllFiles = (lasFiles) => {
|
|
494
|
+
let i = 0;
|
|
495
|
+
const modelsLoaded = new Array(lasFiles.length);
|
|
496
|
+
const loadNext = () => {
|
|
497
|
+
if (sceneModel.destroyed) {
|
|
498
|
+
done();
|
|
499
|
+
} else if (i >= lasFiles.length) {
|
|
500
|
+
return
|
|
501
|
+
} else {
|
|
502
|
+
modelsLoaded[i] = false;
|
|
503
|
+
this._dataSource.getLAS(`${baseDir}${lasFiles[i]}`, (arrayBuffer) => {
|
|
504
|
+
const modelParams = utils.apply(params, {isManifest: true, index: i});
|
|
505
|
+
this._parseModel(arrayBuffer, modelParams, options, sceneModel).then(() => {
|
|
506
|
+
modelsLoaded[modelParams.index] = true;
|
|
507
|
+
let allLoaded = true;
|
|
508
|
+
modelsLoaded.forEach((loaded) => {
|
|
509
|
+
if(!loaded) allLoaded = false;
|
|
510
|
+
})
|
|
511
|
+
if(allLoaded) done();
|
|
512
|
+
});
|
|
513
|
+
i++;
|
|
514
|
+
this.scheduleTask(loadNext, 200);
|
|
515
|
+
}, error);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
loadNext();
|
|
519
|
+
};
|
|
520
|
+
const loadManifestData = (manifestData) => {
|
|
521
|
+
if(sceneModel.destroyed) return;
|
|
522
|
+
const files = manifestData.lasFiles || manifestData.lazFiles;
|
|
523
|
+
if(!files || files.length <= 0) {
|
|
524
|
+
this.error(`load(): Failed to load model manifest - manifest not valid`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
loadAllFiles(files);
|
|
528
|
+
}
|
|
529
|
+
if(params.manifestSrc) {
|
|
530
|
+
this._dataSource.getManifest(params.manifestSrc, (manifestData) => {
|
|
531
|
+
loadManifestData(manifestData);
|
|
532
|
+
}, (errMsg) => {
|
|
533
|
+
this.error(errMsg);
|
|
534
|
+
sceneModel.fire("error", errMsg);
|
|
535
|
+
})
|
|
536
|
+
} else {
|
|
537
|
+
const manifestData = params.manifest;
|
|
538
|
+
loadManifestData(manifestData);
|
|
539
|
+
}
|
|
479
540
|
}
|
|
480
541
|
|
|
481
542
|
return sceneModel;
|
|
@@ -486,6 +547,13 @@ class LASLoaderPlugin extends Plugin {
|
|
|
486
547
|
spinner.processes++;
|
|
487
548
|
this._dataSource.getLAS(params.src, (arrayBuffer) => {
|
|
488
549
|
this._parseModel(arrayBuffer, params, options, sceneModel).then(() => {
|
|
550
|
+
sceneModel.scene.once("tick", () => {
|
|
551
|
+
if (sceneModel.destroyed) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events
|
|
555
|
+
sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers
|
|
556
|
+
});
|
|
489
557
|
spinner.processes--;
|
|
490
558
|
}, (errMsg) => {
|
|
491
559
|
spinner.processes--;
|
|
@@ -668,7 +736,7 @@ class LASLoaderPlugin extends Plugin {
|
|
|
668
736
|
const meshIds = [];
|
|
669
737
|
|
|
670
738
|
for (let i = 0, len = pointsChunks.length; i < len; i++) {
|
|
671
|
-
const meshId =
|
|
739
|
+
const meshId = `${params.isManifest ? 'model'+params.index : ''}pointsMesh${i}`;
|
|
672
740
|
meshIds.push(meshId);
|
|
673
741
|
sceneModel.createMesh({
|
|
674
742
|
id: meshId,
|
|
@@ -677,30 +745,6 @@ class LASLoaderPlugin extends Plugin {
|
|
|
677
745
|
colorsCompressed: (i < colorsChunks.length) ? colorsChunks[i] : null
|
|
678
746
|
});
|
|
679
747
|
}
|
|
680
|
-
/*
|
|
681
|
-
const pointsChunks = chunkArray(positionsValue, MAX_VERTICES * 3);
|
|
682
|
-
const colorsChunks = chunkArray(colorsCompressed, MAX_VERTICES * 4);
|
|
683
|
-
const meshIds = [];
|
|
684
|
-
|
|
685
|
-
for (let i = 0, len = pointsChunks.length; i < len; i++) {
|
|
686
|
-
|
|
687
|
-
const geometryId = `geometryMesh${i}`;
|
|
688
|
-
const meshId = `pointsMesh${i}`;
|
|
689
|
-
meshIds.push(meshId);
|
|
690
|
-
|
|
691
|
-
sceneModel.createGeometry({
|
|
692
|
-
id: geometryId,
|
|
693
|
-
primitive: "points",
|
|
694
|
-
positions: pointsChunks[i],
|
|
695
|
-
colorsCompressed: (i < colorsChunks.length) ? colorsChunks[i] : null
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
sceneModel.createMesh({
|
|
699
|
-
id: meshId,
|
|
700
|
-
geometryId
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
*/
|
|
704
748
|
|
|
705
749
|
const pointsObjectId = params.entityId || math.createUUID();
|
|
706
750
|
|
|
@@ -743,14 +787,6 @@ class LASLoaderPlugin extends Plugin {
|
|
|
743
787
|
this.viewer.metaScene.createMetaModel(metaModelId, metadata, options);
|
|
744
788
|
}
|
|
745
789
|
|
|
746
|
-
sceneModel.scene.once("tick", () => {
|
|
747
|
-
if (sceneModel.destroyed) {
|
|
748
|
-
return;
|
|
749
|
-
}
|
|
750
|
-
sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events
|
|
751
|
-
sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers
|
|
752
|
-
});
|
|
753
|
-
|
|
754
790
|
resolve();
|
|
755
791
|
});
|
|
756
792
|
} catch (e) {
|
|
@@ -772,4 +808,14 @@ function chunkArray(array, chunkSize) {
|
|
|
772
808
|
return result;
|
|
773
809
|
}
|
|
774
810
|
|
|
811
|
+
function getBaseDirectory(filePath) {
|
|
812
|
+
if (filePath.indexOf('?') > -1) {
|
|
813
|
+
filePath = filePath.split('?')[0];
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const pathArray = filePath.split('/');
|
|
817
|
+
pathArray.pop(); // Remove the file name or the last segment of the path
|
|
818
|
+
return pathArray.join('/') + '/';
|
|
819
|
+
}
|
|
820
|
+
|
|
775
821
|
export {LASLoaderPlugin};
|
|
@@ -8,6 +8,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
8
8
|
const cubeColor = "lightgrey";
|
|
9
9
|
const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)";
|
|
10
10
|
const textColor = cfg.textColor || "black";
|
|
11
|
+
const parentNode = cfg.canvasElement || document.body;
|
|
11
12
|
|
|
12
13
|
const height = 500;
|
|
13
14
|
const width = height + (height / 3);
|
|
@@ -119,8 +120,7 @@ function CubeTextureCanvas(viewer, navCubeScene, cfg = {}) {
|
|
|
119
120
|
this._textureCanvas.style.visibility = "hidden";
|
|
120
121
|
this._textureCanvas.style["z-index"] = 2000000;
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
body.appendChild(this._textureCanvas);
|
|
123
|
+
parentNode.appendChild(this._textureCanvas);
|
|
124
124
|
|
|
125
125
|
const context = this._textureCanvas.getContext("2d");
|
|
126
126
|
|
|
@@ -115,7 +115,7 @@ class NavCubePlugin extends Plugin {
|
|
|
115
115
|
this._navCubeScene = new Scene(viewer, {
|
|
116
116
|
canvasId: cfg.canvasId,
|
|
117
117
|
canvasElement: cfg.canvasElement,
|
|
118
|
-
transparent: true
|
|
118
|
+
transparent: true,
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
this._navCubeCanvas = this._navCubeScene.canvas.canvas;
|
|
@@ -361,7 +361,7 @@ class NavCubePlugin extends Plugin {
|
|
|
361
361
|
}
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
-
|
|
364
|
+
self._navCubeCanvas.addEventListener("mouseup", self._onMouseUp = function (e) {
|
|
365
365
|
if (e.which !== 1) {// Left button
|
|
366
366
|
return;
|
|
367
367
|
}
|
|
@@ -378,7 +378,7 @@ class NavCubePlugin extends Plugin {
|
|
|
378
378
|
if (hit.uv) {
|
|
379
379
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
380
380
|
if (areaId >= 0) {
|
|
381
|
-
|
|
381
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
382
382
|
if (lastAreaId >= 0) {
|
|
383
383
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
384
384
|
self._repaint();
|
|
@@ -404,7 +404,7 @@ class NavCubePlugin extends Plugin {
|
|
|
404
404
|
self._repaint();
|
|
405
405
|
lastAreaId = -1;
|
|
406
406
|
}
|
|
407
|
-
|
|
407
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
408
408
|
if (lastAreaId >= 0) {
|
|
409
409
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
410
410
|
self._repaint();
|
|
@@ -423,7 +423,7 @@ class NavCubePlugin extends Plugin {
|
|
|
423
423
|
}
|
|
424
424
|
});
|
|
425
425
|
|
|
426
|
-
|
|
426
|
+
self._navCubeCanvas.addEventListener("mousemove", self._onMouseMove = function (e) {
|
|
427
427
|
if (lastAreaId >= 0) {
|
|
428
428
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
429
429
|
self._repaint();
|
|
@@ -435,7 +435,7 @@ class NavCubePlugin extends Plugin {
|
|
|
435
435
|
if (down) {
|
|
436
436
|
var posX = e.clientX;
|
|
437
437
|
var posY = e.clientY;
|
|
438
|
-
|
|
438
|
+
self._navCubeCanvas.style.cursor = "move";
|
|
439
439
|
actionMove(posX, posY);
|
|
440
440
|
return;
|
|
441
441
|
}
|
|
@@ -449,7 +449,7 @@ class NavCubePlugin extends Plugin {
|
|
|
449
449
|
});
|
|
450
450
|
if (hit) {
|
|
451
451
|
if (hit.uv) {
|
|
452
|
-
|
|
452
|
+
self._navCubeCanvas.style.cursor = "pointer";
|
|
453
453
|
var areaId = self._cubeTextureCanvas.getArea(hit.uv);
|
|
454
454
|
if (areaId === lastAreaId) {
|
|
455
455
|
return;
|
|
@@ -464,7 +464,7 @@ class NavCubePlugin extends Plugin {
|
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
} else {
|
|
467
|
-
|
|
467
|
+
self._navCubeCanvas.style.cursor = "default";
|
|
468
468
|
if (lastAreaId >= 0) {
|
|
469
469
|
self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false);
|
|
470
470
|
self._repaint();
|
|
@@ -727,8 +727,8 @@ class NavCubePlugin extends Plugin {
|
|
|
727
727
|
this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave);
|
|
728
728
|
this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown);
|
|
729
729
|
|
|
730
|
-
|
|
731
|
-
|
|
730
|
+
this._navCubeCanvas.removeEventListener("mousemove", this._onMouseMove);
|
|
731
|
+
this._navCubeCanvas.removeEventListener("mouseup", this._onMouseUp);
|
|
732
732
|
|
|
733
733
|
this._navCubeCanvas = null;
|
|
734
734
|
this._cubeTextureCanvas.destroy();
|
|
@@ -482,8 +482,8 @@ class Control {
|
|
|
482
482
|
const canvasPos = math.vec2();
|
|
483
483
|
|
|
484
484
|
const copyCanvasPos = (event, vec2) => {
|
|
485
|
-
vec2[0] = event.
|
|
486
|
-
vec2[1] = event.
|
|
485
|
+
vec2[0] = event.pageX;
|
|
486
|
+
vec2[1] = event.pageY;
|
|
487
487
|
transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
|
|
488
488
|
};
|
|
489
489
|
|
|
@@ -464,7 +464,8 @@ export class TreeViewPlugin extends Plugin {
|
|
|
464
464
|
const indeterminate = this._showIndeterminate
|
|
465
465
|
&& parent.numVisibleEntities > 0
|
|
466
466
|
&& parent.numVisibleEntities < parent.numEntities;
|
|
467
|
-
|
|
467
|
+
parent.checked = parent.numVisibleEntities > 0;
|
|
468
|
+
this._renderService.setCheckbox(parent.nodeId, parent.checked, indeterminate);
|
|
468
469
|
|
|
469
470
|
parent = parent.parent;
|
|
470
471
|
}
|
|
@@ -539,7 +540,6 @@ export class TreeViewPlugin extends Plugin {
|
|
|
539
540
|
|
|
540
541
|
let parent = checkedNode.parent;
|
|
541
542
|
while (parent) {
|
|
542
|
-
parent.checked = visible;
|
|
543
543
|
|
|
544
544
|
if (visible) {
|
|
545
545
|
parent.numVisibleEntities += numUpdated;
|
|
@@ -549,7 +549,8 @@ export class TreeViewPlugin extends Plugin {
|
|
|
549
549
|
const indeterminate = this._showIndeterminate
|
|
550
550
|
&& parent.numVisibleEntities > 0
|
|
551
551
|
&& parent.numVisibleEntities < parent.numEntities;
|
|
552
|
-
|
|
552
|
+
parent.checked = parent.numVisibleEntities > 0;
|
|
553
|
+
this._renderService.setCheckbox(parent.nodeId, parent.checked, indeterminate);
|
|
553
554
|
|
|
554
555
|
parent = parent.parent;
|
|
555
556
|
}
|