@xeokit/xeokit-sdk 2.6.9 → 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.
Files changed (38) hide show
  1. package/dist/web-ifc.wasm +0 -0
  2. package/dist/xeokit-sdk.cjs.js +1164 -134
  3. package/dist/xeokit-sdk.es.js +1163 -135
  4. package/dist/xeokit-sdk.es5.js +521 -53
  5. package/dist/xeokit-sdk.min.cjs.js +5 -5
  6. package/dist/xeokit-sdk.min.es.js +5 -5
  7. package/dist/xeokit-sdk.min.es5.js +4 -4
  8. package/package.json +1 -1
  9. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsControl.js +10 -0
  10. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js +9 -0
  11. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js +9 -0
  12. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +182 -42
  13. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsControl.js +11 -0
  14. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js +11 -0
  15. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.js +18 -1
  16. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +15 -0
  17. package/src/plugins/DotBIMLoaderPlugin/DotBIMDefaultDataSource.js +29 -0
  18. package/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js +536 -0
  19. package/src/plugins/DotBIMLoaderPlugin/index.js +2 -0
  20. package/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js +74 -0
  21. package/src/plugins/GLTFLoaderPlugin/GLTFSceneModelLoader.js +53 -58
  22. package/src/plugins/LASLoaderPlugin/LASLoaderPlugin.js +59 -2
  23. package/src/plugins/index.js +2 -1
  24. package/src/plugins/lib/html/Dot.js +38 -6
  25. package/src/plugins/lib/html/Label.js +48 -7
  26. package/src/plugins/lib/html/Wire.js +38 -6
  27. package/src/viewer/Viewer.js +1 -1
  28. package/src/viewer/scene/CameraControl/lib/handlers/MouseMiscHandler.js +2 -2
  29. package/src/viewer/scene/marker/Marker.js +3 -3
  30. package/src/viewer/scene/model/SceneModel.js +17 -9
  31. package/src/viewer/utils/os.js +11 -0
  32. package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsControl.d.ts +7 -0
  33. package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.d.ts +8 -0
  34. package/types/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.d.ts +8 -0
  35. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.d.ts +70 -0
  36. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsControl.d.ts +7 -0
  37. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.d.ts +8 -0
  38. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.d.ts +8 -0
@@ -141,6 +141,7 @@ function parseGLTF(plugin, src, gltf, metaModelJSON, options, sceneModel, ok) {
141
141
  }).then((gltfData) => {
142
142
  const ctx = {
143
143
  src: src,
144
+ entityId: options.entityId,
144
145
  metaModelCorrections: metaModelJSON ? getMetaModelCorrections(metaModelJSON) : null,
145
146
  loadBuffer: options.loadBuffer,
146
147
  basePath: options.basePath,
@@ -586,29 +587,9 @@ function loadNode(ctx, node, depth, matrix) {
586
587
  meshCfg.origin = origin;
587
588
  }
588
589
 
589
- // if (createEntity) {
590
- // if (createEntity.colorize) {
591
- // meshCfg.color = createEntity.colorize;
592
- // }
593
- // if (createEntity.opacity !== undefined && createEntity.opacity !== null) {
594
- // meshCfg.opacity = createEntity.opacity;
595
- // }
596
- // }
597
-
598
590
  sceneModel.createMesh(meshCfg);
599
591
  deferredMeshIds.push(meshCfg.id);
600
592
  }
601
- // if (createEntity) {
602
- // sceneModel.createEntity(utils.apply(createEntity, {
603
- // meshIds: deferredMeshIds,
604
- // isObject: true
605
- // }));
606
- // } else {
607
- // sceneModel.createEntity({
608
- // meshIds: deferredMeshIds,
609
- // isObject: true
610
- // });
611
- // }
612
593
  }
613
594
  }
614
595
 
@@ -622,48 +603,62 @@ function loadNode(ctx, node, depth, matrix) {
622
603
 
623
604
  // Post-order visit scene node
624
605
 
625
- const nodeName = node.name;
626
- if (((nodeName !== undefined && nodeName !== null) || depth === 0) && deferredMeshIds.length > 0) {
627
- if (nodeName === undefined || nodeName === null) {
628
- ctx.log(`Warning: 'name' properties not found on glTF scene nodes - will randomly-generate object IDs in XKT`);
606
+ if (ctx.entityId) {
607
+ if (depth ===0) {
608
+ sceneModel.createEntity({
609
+ id: ctx.entityId,
610
+ meshIds: deferredMeshIds,
611
+ isObject: true
612
+ });
613
+ deferredMeshIds.length = 0;
629
614
  }
630
- let entityId = nodeName; // Fall back on generated ID when `name` not found on glTF scene node(s)
631
- // if (!!entityId && sceneModel.entities[entityId]) {
632
- // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${nodeName} - will randomly-generating an object ID in XKT`);
633
- // }
634
- // while (!entityId || sceneModel.entities[entityId]) {
635
- // entityId = "entity-" + ctx.nextId++;
636
- // }
637
- if (ctx.metaModelCorrections) {
638
- // Merging meshes into XKTObjects that map to metaobjects
639
- const rootMetaObject = ctx.metaModelCorrections.eachChildRoot[entityId];
640
- if (rootMetaObject) {
641
- const rootMetaObjectStats = ctx.metaModelCorrections.eachRootStats[rootMetaObject.id];
642
- rootMetaObjectStats.countChildren++;
643
- if (rootMetaObjectStats.countChildren >= rootMetaObjectStats.numChildren) {
644
- sceneModel.createEntity({
645
- id: rootMetaObject.id,
646
- meshIds: deferredMeshIds
647
- });
648
- deferredMeshIds.length = 0;
615
+ } else {
616
+ const nodeName = node.name;
617
+ if (((nodeName !== undefined && nodeName !== null) || depth === 0) && deferredMeshIds.length > 0) {
618
+ if (nodeName === undefined || nodeName === null) {
619
+ ctx.log(`Warning: 'name' properties not found on glTF scene nodes - will randomly-generate object IDs in XKT`);
620
+ }
621
+ let entityId = nodeName; // Fall back on generated ID when `name` not found on glTF scene node(s)
622
+ // if (!!entityId && sceneModel.entities[entityId]) {
623
+ // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${nodeName} - will randomly-generating an object ID in XKT`);
624
+ // }
625
+ // while (!entityId || sceneModel.entities[entityId]) {
626
+ // entityId = "entity-" + ctx.nextId++;
627
+ // }
628
+ if (ctx.metaModelCorrections) {
629
+ // Merging meshes into XKTObjects that map to metaobjects
630
+ const rootMetaObject = ctx.metaModelCorrections.eachChildRoot[entityId];
631
+ if (rootMetaObject) {
632
+ const rootMetaObjectStats = ctx.metaModelCorrections.eachRootStats[rootMetaObject.id];
633
+ rootMetaObjectStats.countChildren++;
634
+ if (rootMetaObjectStats.countChildren >= rootMetaObjectStats.numChildren) {
635
+ sceneModel.createEntity({
636
+ id: rootMetaObject.id,
637
+ meshIds: deferredMeshIds,
638
+ isObject: true
639
+ });
640
+ deferredMeshIds.length = 0;
641
+ }
642
+ } else {
643
+ const metaObject = ctx.metaModelCorrections.metaObjectsMap[entityId];
644
+ if (metaObject) {
645
+ sceneModel.createEntity({
646
+ id: entityId,
647
+ meshIds: deferredMeshIds,
648
+ isObject: true
649
+ });
650
+ deferredMeshIds.length = 0;
651
+ }
649
652
  }
650
653
  } else {
651
- const metaObject = ctx.metaModelCorrections.metaObjectsMap[entityId];
652
- if (metaObject) {
653
- sceneModel.createEntity({
654
- id: entityId,
655
- meshIds: deferredMeshIds
656
- });
657
- deferredMeshIds.length = 0;
658
- }
654
+ // Create an XKTObject from the meshes at each named glTF node, don't care about metaobjects
655
+ sceneModel.createEntity({
656
+ id: entityId,
657
+ meshIds: deferredMeshIds,
658
+ isObject: true
659
+ });
660
+ deferredMeshIds.length = 0;
659
661
  }
660
- } else {
661
- // Create an XKTObject from the meshes at each named glTF node, don't care about metaobjects
662
- sceneModel.createEntity({
663
- id: entityId,
664
- meshIds: deferredMeshIds
665
- });
666
- deferredMeshIds.length = 0;
667
662
  }
668
663
  }
669
664
  }
@@ -143,6 +143,60 @@ const MAX_VERTICES = 500000; // TODO: Rough estimate
143
143
  * });
144
144
  * ````
145
145
  *
146
+ * ## Showing a LAS/LAZ model in TreeViewPlugin
147
+ *
148
+ * We can use the `load()` method's `elementId` parameter
149
+ * to make LASLoaderPlugin load the entire model into a single Entity that gets this ID.
150
+ *
151
+ * In conjunction with that parameter, we can then use the `load()` method's `metaModelJSON` parameter to create a MetaModel that
152
+ * contains a MetaObject that corresponds to that Entity.
153
+ *
154
+ * When we've done that, then xeokit's {@link TreeViewPlugin} is able to have a node that represents the model and controls
155
+ * the visibility of that Entity (ie. to control the visibility of the entire model).
156
+ *
157
+ * The snippet below shows how this is done.
158
+ *
159
+ * ````javascript
160
+ * import {Viewer, LASLoaderPlugin, NavCubePlugin, TreeViewPlugin} from "../../dist/xeokit-sdk.es.js";
161
+ *
162
+ * const viewer = new Viewer({
163
+ * canvasId: "myCanvas",
164
+ * transparent: true
165
+ * });
166
+ *
167
+ * new TreeViewPlugin(viewer, {
168
+ * containerElement: document.getElementById("treeViewContainer"),
169
+ * hierarchy: "containment"
170
+ * });
171
+ *
172
+ * const lasLoader = new LASLoaderPlugin(viewer);
173
+ *
174
+ * const sceneModel = lasLoader.load({ // Creates a SceneModel with ID "myScanModel"
175
+ * id: "myScanModel",
176
+ * src: "../../assets/models/las/Nalls_Pumpkin_Hill.laz",
177
+ * rotation: [-90, 0, 0],
178
+ *
179
+ * entityId: "3toKckUfH2jBmd$7uhJHa4", // Creates an Entity with this ID
180
+ *
181
+ * metaModelJSON: { // Creates a MetaModel with ID "myScanModel"
182
+ * "metaObjects": [
183
+ * {
184
+ * "id": "3toKckUfH2jBmd$7uhJHa6", // Creates this MetaObject with this ID
185
+ * "name": "My Project",
186
+ * "type": "Default",
187
+ * "parent": null
188
+ * },
189
+ * {
190
+ * "id": "3toKckUfH2jBmd$7uhJHa4", // Creates this MetaObject with this ID
191
+ * "name": "My Scan",
192
+ * "type": "Default",
193
+ * "parent": "3toKckUfH2jBmd$7uhJHa6"
194
+ * }
195
+ * ]
196
+ * }
197
+ * });
198
+ * ````
199
+ *
146
200
  * @class LASLoaderPlugin
147
201
  * @since 2.0.17
148
202
  */
@@ -493,7 +547,7 @@ class LASLoaderPlugin extends Plugin {
493
547
  }
494
548
  */
495
549
 
496
- const pointsObjectId = math.createUUID();
550
+ const pointsObjectId = params.entityId || math.createUUID();
497
551
 
498
552
  sceneModel.createEntity({
499
553
  id: pointsObjectId,
@@ -503,7 +557,10 @@ class LASLoaderPlugin extends Plugin {
503
557
 
504
558
  sceneModel.finalize();
505
559
 
506
- if (params.loadMetadata !== false) {
560
+ if (params.metaModelJSON) {
561
+ const metaModelId = sceneModel.id;
562
+ this.viewer.metaScene.createMetaModel(metaModelId, params.metaModelJSON, options);
563
+ } else if (params.loadMetadata !== false) {
507
564
  const rootMetaObjectId = math.createUUID();
508
565
  const metadata = {
509
566
  projectId: "",
@@ -18,4 +18,5 @@ export * from "./XKTLoaderPlugin/index.js";
18
18
  export * from "./XML3DLoaderPlugin/index.js";
19
19
  export * from "./WebIFCLoaderPlugin/index.js";
20
20
  export * from "./LASLoaderPlugin/index.js";
21
- export * from "./CityJSONLoaderPlugin/index.js";
21
+ export * from "./CityJSONLoaderPlugin/index.js";
22
+ export * from "./DotBIMLoaderPlugin/index.js";
@@ -1,3 +1,4 @@
1
+ import { os } from "../../../viewer/utils/os.js";
1
2
  /** @private */
2
3
  class Dot {
3
4
 
@@ -97,11 +98,42 @@ class Dot {
97
98
  }
98
99
 
99
100
  if (cfg.onContextMenu) {
100
- dotClickable.addEventListener('contextmenu', (event) => {
101
- cfg.onContextMenu(event, this);
102
- event.preventDefault();
103
- event.stopPropagation();
104
- });
101
+ if(os.isIphoneSafari()){
102
+ dotClickable.addEventListener('touchstart', (event) => {
103
+ event.preventDefault();
104
+ if(this._timeout){
105
+ clearTimeout(this._timeout);
106
+ this._timeout = null;
107
+ }
108
+ this._timeout = setTimeout(() => {
109
+ event.clientX = event.touches[0].clientX;
110
+ event.clientY = event.touches[0].clientY;
111
+ cfg.onContextMenu(event, this);
112
+ clearTimeout(this._timeout);
113
+ this._timeout = null;
114
+ }, 500);
115
+ })
116
+
117
+ dotClickable.addEventListener('touchend', (event) => {
118
+ event.preventDefault();
119
+ //stops short touches from calling the timeout
120
+ if(this._timeout) {
121
+ clearTimeout(this._timeout);
122
+ this._timeout = null;
123
+ }
124
+ } )
125
+
126
+ }
127
+ else {
128
+ dotClickable.addEventListener('contextmenu', (event) => {
129
+ console.log(event);
130
+ cfg.onContextMenu(event, this);
131
+ event.preventDefault();
132
+ event.stopPropagation();
133
+ console.log("Label context menu")
134
+ });
135
+ }
136
+
105
137
  }
106
138
 
107
139
  this.setPos(cfg.x || 0, cfg.y || 0);
@@ -150,7 +182,7 @@ class Dot {
150
182
  }
151
183
 
152
184
  setClickable(clickable) {
153
- this._dotClickable.style["pointer-events"] = (!!clickable) ? "all" : "none";
185
+ this._dotClickable.style["pointer-events"] = (clickable) ? "all" : "none";
154
186
  }
155
187
 
156
188
  setHighlighted(highlighted) {
@@ -1,3 +1,4 @@
1
+ import { os } from "../../../viewer/utils/os.js";
1
2
  /** @private */
2
3
  class Label {
3
4
 
@@ -13,6 +14,7 @@ class Label {
13
14
 
14
15
  this._label = document.createElement('div');
15
16
  this._label.className += this._label.className ? ' viewer-ruler-label' : 'viewer-ruler-label';
17
+ this._timeout = null;
16
18
 
17
19
  var label = this._label;
18
20
  var style = label.style;
@@ -84,12 +86,42 @@ class Label {
84
86
  }
85
87
 
86
88
  if (cfg.onContextMenu) {
87
- label.addEventListener('contextmenu', (event) => {
88
- cfg.onContextMenu(event, this);
89
- event.preventDefault();
90
- event.stopPropagation();
91
- console.log("Label context menu")
92
- });
89
+ if(os.isIphoneSafari()){
90
+ label.addEventListener('touchstart', (event) => {
91
+ event.preventDefault();
92
+ if(this._timeout){
93
+ clearTimeout(this._timeout);
94
+ this._timeout = null;
95
+ }
96
+ this._timeout = setTimeout(() => {
97
+ event.clientX = event.touches[0].clientX;
98
+ event.clientY = event.touches[0].clientY;
99
+ cfg.onContextMenu(event, this);
100
+ clearTimeout(this._timeout);
101
+ this._timeout = null;
102
+ }, 500);
103
+ })
104
+
105
+ label.addEventListener('touchend', (event) => {
106
+ event.preventDefault();
107
+ //stops short touches from calling the timeout
108
+ if(this._timeout) {
109
+ clearTimeout(this._timeout);
110
+ this._timeout = null;
111
+ }
112
+ } )
113
+
114
+ }
115
+ else {
116
+ label.addEventListener('contextmenu', (event) => {
117
+ console.log(event);
118
+ cfg.onContextMenu(event, this);
119
+ event.preventDefault();
120
+ event.stopPropagation();
121
+ console.log("Label context menu")
122
+ });
123
+ }
124
+
93
125
  }
94
126
  }
95
127
 
@@ -164,7 +196,14 @@ class Label {
164
196
  }
165
197
 
166
198
  setClickable(clickable) {
167
- this._label.style["pointer-events"] = (!!clickable) ? "all" : "none";
199
+ this._label.style["pointer-events"] = (clickable) ? "all" : "none";
200
+ }
201
+
202
+ setPrefix(prefix) {
203
+ if(this._prefix === prefix){
204
+ return;
205
+ }
206
+ this._prefix = prefix;
168
207
  }
169
208
 
170
209
  destroy() {
@@ -172,6 +211,8 @@ class Label {
172
211
  this._label.parentElement.removeChild(this._label);
173
212
  }
174
213
  }
214
+
215
+
175
216
  }
176
217
 
177
218
  export {Label};
@@ -1,3 +1,4 @@
1
+ import { os } from "../../../viewer/utils/os.js";
1
2
  /** @private */
2
3
  class Wire {
3
4
 
@@ -114,11 +115,42 @@ class Wire {
114
115
  }
115
116
 
116
117
  if (cfg.onContextMenu) {
117
- wireClickable.addEventListener('contextmenu', (event) => {
118
- cfg.onContextMenu(event, this);
119
- event.preventDefault();
120
- event.stopPropagation();
121
- });
118
+ if(os.isIphoneSafari()){
119
+ wireClickable.addEventListener('touchstart', (event) => {
120
+ event.preventDefault();
121
+ if(this._timeout){
122
+ clearTimeout(this._timeout);
123
+ this._timeout = null;
124
+ }
125
+ this._timeout = setTimeout(() => {
126
+ event.clientX = event.touches[0].clientX;
127
+ event.clientY = event.touches[0].clientY;
128
+ cfg.onContextMenu(event, this);
129
+ clearTimeout(this._timeout);
130
+ this._timeout = null;
131
+ }, 500);
132
+ })
133
+
134
+ wireClickable.addEventListener('touchend', (event) => {
135
+ event.preventDefault();
136
+ //stops short touches from calling the timeout
137
+ if(this._timeout) {
138
+ clearTimeout(this._timeout);
139
+ this._timeout = null;
140
+ }
141
+ } )
142
+
143
+ }
144
+ else {
145
+ wireClickable.addEventListener('contextmenu', (event) => {
146
+ console.log(event);
147
+ cfg.onContextMenu(event, this);
148
+ event.preventDefault();
149
+ event.stopPropagation();
150
+ console.log("Label context menu")
151
+ });
152
+ }
153
+
122
154
  }
123
155
 
124
156
  this._x1 = 0;
@@ -193,7 +225,7 @@ class Wire {
193
225
  }
194
226
 
195
227
  setClickable(clickable) {
196
- this._wireClickable.style["pointer-events"] = (!!clickable) ? "all" : "none";
228
+ this._wireClickable.style["pointer-events"] = (clickable) ? "all" : "none";
197
229
  }
198
230
 
199
231
  setHighlighted(highlighted) {
@@ -3,7 +3,7 @@ import {CameraFlightAnimation} from "./scene/camera/CameraFlightAnimation.js";
3
3
  import {CameraControl} from "./scene/CameraControl/CameraControl.js";
4
4
  import {MetaScene} from "./metadata/MetaScene.js";
5
5
  import {LocaleService} from "./localization/LocaleService.js";
6
- import html2canvas from 'html2canvas/dist/html2canvas.esm.js';
6
+ import html2canvas from '../../node_modules/html2canvas/dist/html2canvas.esm.js';
7
7
 
8
8
  /**
9
9
  * The 3D Viewer at the heart of the xeokit SDK.
@@ -59,8 +59,8 @@ function getCanvasPosFromEvent(event, canvas, canvasPos) {
59
59
  canvasPos[1] = event.y;
60
60
  } else {
61
61
  const { left, top } = canvas.getBoundingClientRect();
62
- canvasPos[0] = event.clientX - left - window.scrollX;
63
- canvasPos[1] = event.clientY - top - window.scrollY;
62
+ canvasPos[0] = event.clientX - left;
63
+ canvasPos[1] = event.clientY - top;
64
64
  }
65
65
  return canvasPos;
66
66
  }
@@ -65,7 +65,7 @@ const tempVec4b = math.vec4();
65
65
  * });
66
66
  *
67
67
  * // Create the Marker, associated with our Mesh Entity
68
- * const myMarker = new Marker({
68
+ * const myMarker = new Marker(viewer, {
69
69
  * entity: entity,
70
70
  * worldPos: [10,0,0],
71
71
  * occludable: true
@@ -196,7 +196,7 @@ class Marker extends Component {
196
196
  return;
197
197
  }
198
198
  if (this._onEntityDestroyed !== null) {
199
- this._entity.off(this._onEntityDestroyed);
199
+ this._entity.model.off(this._onEntityDestroyed);
200
200
  this._onEntityDestroyed = null;
201
201
  }
202
202
  if (this._onEntityModelDestroyed !== null) {
@@ -212,7 +212,7 @@ class Marker extends Component {
212
212
  this._onEntityModelDestroyed = null;
213
213
  });
214
214
  } else {
215
- this._onEntityDestroyed = this._entity.on("destroyed", () => {
215
+ this._onEntityDestroyed = this._entity.model.on("destroyed", () => {
216
216
  this._entity = null;
217
217
  this._onEntityDestroyed = null;
218
218
  });
@@ -43,6 +43,7 @@ import {SceneModelTransform} from "./SceneModelTransform.js";
43
43
  const tempVec3a = math.vec3();
44
44
 
45
45
  const tempOBB3 = math.OBB3();
46
+ const tempQuaternion = math.vec4();
46
47
 
47
48
  const DEFAULT_SCALE = math.vec3([1, 1, 1]);
48
49
  const DEFAULT_POSITION = math.vec3([0, 0, 0]);
@@ -2723,6 +2724,7 @@ export class SceneModel extends Component {
2723
2724
  * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position of the mesh. Overridden by ````transformId````.
2724
2725
  * @param {Number[]} [cfg.scale=[1,1,1]] Scale of the mesh. Overridden by ````transformId````.
2725
2726
  * @param {Number[]} [cfg.rotation=[0,0,0]] Rotation of the mesh as Euler angles given in degrees, for each of the X, Y and Z axis. Overridden by ````transformId````.
2727
+ * @param {Number[]} [cfg.quaternion] Rotation of the mesh as a quaternion. Overridden by ````rotation````.
2726
2728
  * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Mesh modelling transform matrix. Overrides the ````position````, ````scale```` and ````rotation```` parameters. Also overridden by ````transformId````.
2727
2729
  * @param {Number[]} [cfg.color=[1,1,1]] RGB color in range ````[0..1, 0..1, 0..1]````. Overridden by texture set ````colorTexture````. Overrides ````colors```` and ````colorsCompressed````.
2728
2730
  * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````.
@@ -2797,12 +2799,15 @@ export class SceneModel extends Component {
2797
2799
 
2798
2800
  if (cfg.matrix) {
2799
2801
  cfg.meshMatrix = cfg.matrix;
2800
- } else if (cfg.scale || cfg.rotation || cfg.position) {
2802
+ } else if (cfg.scale || cfg.rotation || cfg.position || cfg.quaternion) {
2801
2803
  const scale = cfg.scale || DEFAULT_SCALE;
2802
2804
  const position = cfg.position || DEFAULT_POSITION;
2803
- const rotation = cfg.rotation || DEFAULT_ROTATION;
2804
- math.eulerToQuaternion(rotation, "XYZ", DEFAULT_QUATERNION);
2805
- cfg.meshMatrix = math.composeMat4(position, DEFAULT_QUATERNION, scale, math.mat4());
2805
+ if (cfg.rotation) {
2806
+ math.eulerToQuaternion(cfg.rotation, "XYZ", tempQuaternion);
2807
+ cfg.meshMatrix = math.composeMat4(position, tempQuaternion, scale, math.mat4());
2808
+ } else {
2809
+ cfg.meshMatrix = math.composeMat4(position, cfg.quaternion || DEFAULT_QUATERNION, scale, math.mat4());
2810
+ }
2806
2811
  }
2807
2812
 
2808
2813
  if (cfg.positionsDecodeBoundary) {
@@ -2990,13 +2995,16 @@ export class SceneModel extends Component {
2990
2995
  // MATRIX
2991
2996
 
2992
2997
  if (cfg.matrix) {
2993
- cfg.meshMatrix = cfg.matrix.slice();
2994
- } else {
2998
+ cfg.meshMatrix = cfg.matrix;
2999
+ } else if (cfg.scale || cfg.rotation || cfg.position || cfg.quaternion) {
2995
3000
  const scale = cfg.scale || DEFAULT_SCALE;
2996
3001
  const position = cfg.position || DEFAULT_POSITION;
2997
- const rotation = cfg.rotation || DEFAULT_ROTATION;
2998
- math.eulerToQuaternion(rotation, "XYZ", DEFAULT_QUATERNION);
2999
- cfg.meshMatrix = math.composeMat4(position, DEFAULT_QUATERNION, scale, math.mat4());
3002
+ if (cfg.rotation) {
3003
+ math.eulerToQuaternion(cfg.rotation, "XYZ", tempQuaternion);
3004
+ cfg.meshMatrix = math.composeMat4(position, tempQuaternion, scale, math.mat4());
3005
+ } else {
3006
+ cfg.meshMatrix = math.composeMat4(position, cfg.quaternion || DEFAULT_QUATERNION, scale, math.mat4());
3007
+ }
3000
3008
  }
3001
3009
 
3002
3010
  math.AABB3ToOBB3(cfg.geometry.aabb, tempOBB3);
@@ -0,0 +1,11 @@
1
+ const os = {
2
+ isIphoneSafari() {
3
+ const userAgent = window.navigator.userAgent;
4
+ const isIphone = /iPhone/i.test(userAgent);
5
+ const isSafari = /Safari/i.test(userAgent) && !/Chrome/i.test(userAgent);
6
+
7
+ return isIphone && isSafari;
8
+ }
9
+ };
10
+
11
+ export {os};
@@ -55,6 +55,13 @@ export declare class AngleMeasurementsControl extends Component {
55
55
  */
56
56
  deactivate(): void;
57
57
 
58
+ /**
59
+ * Gets the {@link AngleMeasurement} under construction by this AngleMeasurementsControl, if any.
60
+ *
61
+ * @returns {null|AngleMeasurement}
62
+ */
63
+ get currentMeasurement() : AngleMeasurement
64
+
58
65
  /**
59
66
  * Resets this AngleMeasurementsControl.
60
67
  *
@@ -1,6 +1,7 @@
1
1
  import {AngleMeasurementsControl} from "./AngleMeasurementsControl.js";
2
2
  import {AngleMeasurementsPlugin} from "./AngleMeasurementsPlugin";
3
3
  import {PointerLens} from "../../extras/";
4
+ import {AngleMeasurement} from "./AngleMeasurement";
4
5
 
5
6
  /**
6
7
  * Creates {@link AngleMeasurement}s in an {@link AngleMeasurementsPlugin} from mouse input.
@@ -87,6 +88,13 @@ export class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
87
88
  */
88
89
  reset(): void;
89
90
 
91
+ /**
92
+ * Gets the {@link AngleMeasurement} under construction by this AngleMeasurementsMouseControl, if any.
93
+ *
94
+ * @returns {null|AngleMeasurement}
95
+ */
96
+ get currentMeasurement() : AngleMeasurement
97
+
90
98
  /**
91
99
  * Destroys this AngleMeasurementsMouseControl.
92
100
  */
@@ -1,6 +1,7 @@
1
1
  import { AngleMeasurementsControl } from "./AngleMeasurementsControl";
2
2
  import {AngleMeasurementsPlugin} from "./AngleMeasurementsPlugin";
3
3
  import {PointerLens} from "../../extras/";
4
+ import {AngleMeasurement} from "./AngleMeasurement";
4
5
 
5
6
  /**
6
7
  * Creates {@link AngleMeasurement}s in an {@link AngleMeasurementsPlugin} from touch input.
@@ -87,6 +88,13 @@ export class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
87
88
  */
88
89
  reset(): void;
89
90
 
91
+ /**
92
+ * Gets the {@link AngleMeasurement} under construction by this AngleMeasurementsTouchControl, if any.
93
+ *
94
+ * @returns {null|AngleMeasurement}
95
+ */
96
+ get currentMeasurement() : AngleMeasurement
97
+
90
98
  /**
91
99
  * Destroys this AngleMeasurementsTouchControl.
92
100
  */