@xeokit/xeokit-sdk 2.6.63 → 2.6.64

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.
@@ -10,6 +10,7 @@ import {Node} from "../../viewer/scene/nodes/Node.js";
10
10
  import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
11
11
  import {buildSphereGeometry} from "../../viewer/scene/geometry/builders/buildSphereGeometry.js";
12
12
  import {worldToRTCPos} from "../../viewer/scene/math/rtcCoords.js";
13
+ import {transformToNode} from "../lib/ui/index.js";
13
14
 
14
15
  const zeroVec = new Float64Array([0, 0, 1]);
15
16
  const quat = new Float64Array(4);
@@ -34,1045 +35,476 @@ class Control {
34
35
  */
35
36
  this.id = null;
36
37
 
37
- this._viewer = plugin.viewer;
38
+ const viewer = plugin.viewer;
39
+ const camera = viewer.camera;
40
+ const cameraControl = viewer.cameraControl;
41
+ const scene = viewer.scene;
42
+ const canvas = scene.canvas.canvas;
38
43
 
39
44
  this._visible = false;
40
- this._pos = math.vec3(); // Full-precision position of the center of the Control
41
- this._origin = math.vec3();
42
- this._rtcPos = math.vec3();
43
45
 
44
- this._baseDir = math.vec3(); // Saves direction of clip plane when we start dragging an arrow or ring.
45
- this._rootNode = null; // Root of Node graph that represents this control in the 3D scene
46
- this._displayMeshes = null; // Meshes that are always visible
47
- this._affordanceMeshes = null; // Meshes displayed momentarily for affordance
48
-
49
- this._ignoreNextSectionPlaneDirUpdate = false;
50
-
51
- this._createNodes();
52
- this._bindEvents();
53
- }
54
-
55
- /**
56
- * Called by SectionPlanesPlugin to assign this Control to a SectionPlane.
57
- * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool.
58
- * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to.
59
- * @private
60
- */
61
- _setSectionPlane(sectionPlane) {
62
- if (this._sectionPlane) {
63
- this._sectionPlane.off(this._onSectionPlanePos);
64
- this._sectionPlane.off(this._onSectionPlaneDir);
65
- this._onSectionPlanePos = null;
66
- this._onSectionPlaneDir = null;
67
- this._sectionPlane = null;
68
- }
69
- if (sectionPlane) {
70
- this.id = sectionPlane.id;
71
- this._setPos(sectionPlane.pos);
72
- this._setDir(sectionPlane.dir);
73
- this._sectionPlane = sectionPlane;
74
- this._onSectionPlanePos = sectionPlane.on("pos", () => {
75
- this._setPos(this._sectionPlane.pos);
76
- });
77
- this._onSectionPlaneDir = sectionPlane.on("dir", () => {
78
- if (!this._ignoreNextSectionPlaneDirUpdate) {
79
- this._setDir(this._sectionPlane.dir);
80
- } else {
81
- this._ignoreNextSectionPlaneDirUpdate = false;
82
- }
83
- });
84
- }
85
- }
86
-
87
- /**
88
- * Gets the {@link SectionPlane} controlled by this Control.
89
- * @returns {SectionPlane} The SectionPlane.
90
- */
91
- get sectionPlane() {
92
- return this._sectionPlane;
93
- }
94
-
95
- /** @private */
96
- _setPos(xyz) {
97
-
98
- this._pos.set(xyz);
99
-
100
- worldToRTCPos(this._pos, this._origin, this._rtcPos);
101
-
102
- this._rootNode.origin = this._origin;
103
- this._rootNode.position = this._rtcPos;
104
- }
105
-
106
- /** @private */
107
- _setDir(xyz) {
108
- this._baseDir.set(xyz);
109
- this._rootNode.quaternion = math.vec3PairToQuaternion(zeroVec, xyz, quat);
110
- }
111
-
112
- _setSectionPlaneDir(dir) {
113
- if (this._sectionPlane) {
114
- this._ignoreNextSectionPlaneDirUpdate = true;
115
- this._sectionPlane.dir = dir;
116
- }
117
- }
118
-
119
- /**
120
- * Sets if this Control is visible.
121
- *
122
- * @type {Boolean}
123
- */
124
- setVisible(visible = true) {
125
- if (this._visible === visible) {
126
- return;
127
- }
128
- this._visible = visible;
129
- var id;
130
- for (id in this._displayMeshes) {
131
- if (this._displayMeshes.hasOwnProperty(id)) {
132
- this._displayMeshes[id].visible = visible;
133
- }
134
- }
135
- if (!visible) {
136
- for (id in this._affordanceMeshes) {
137
- if (this._affordanceMeshes.hasOwnProperty(id)) {
138
- this._affordanceMeshes[id].visible = visible;
139
- }
140
- }
141
- }
142
- }
143
-
144
- /**
145
- * Gets if this Control is visible.
146
- *
147
- * @type {Boolean}
148
- */
149
- getVisible() {
150
- return this._visible;
151
- }
152
-
153
- /**
154
- * Sets if this Control is culled. This is called by SectionPlanesPlugin to
155
- * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot().
156
- * @param culled
157
- */
158
- setCulled(culled) {
159
- var id;
160
- for (id in this._displayMeshes) {
161
- if (this._displayMeshes.hasOwnProperty(id)) {
162
- this._displayMeshes[id].culled = culled;
163
- }
164
- }
165
- if (!culled) {
166
- for (id in this._affordanceMeshes) {
167
- if (this._affordanceMeshes.hasOwnProperty(id)) {
168
- this._affordanceMeshes[id].culled = culled;
169
- }
170
- }
171
- }
172
- }
173
-
174
- /**
175
- * Builds the Entities that represent this Control.
176
- * @private
177
- */
178
- _createNodes() {
46
+ let ignoreNextSectionPlaneDirUpdate = false;
179
47
 
48
+ // Builds the Entities that represent this Control.
180
49
  const NO_STATE_INHERIT = false;
181
- const scene = this._viewer.scene;
182
- const radius = 1.0;
183
- const handleTubeRadius = 0.06;
184
- const hoopRadius = radius - 0.2;
50
+ const arrowLength = 1.0;
51
+ const handleRadius = 0.09;
185
52
  const tubeRadius = 0.01;
186
- const arrowRadius = 0.07;
187
53
 
188
- this._rootNode = new Node(scene, {
54
+ const rootNode = new Node(scene, { // Root of Node graph that represents this control in the 3D scene
189
55
  position: [0, 0, 0],
190
56
  scale: [5, 5, 5],
191
57
  isObject: false
192
58
  });
193
59
 
194
- const rootNode = this._rootNode;
60
+ const pos = math.vec3();
61
+ const setPos = (function() {
62
+ const origin = math.vec3();
63
+ const rtcPos = math.vec3();
64
+ return function(p) {
65
+ pos.set(p);
66
+ worldToRTCPos(p, origin, rtcPos);
67
+ rootNode.origin = origin;
68
+ rootNode.position = rtcPos;
69
+ };
70
+ })();
195
71
 
196
- const shapes = {// Reusable geometries
72
+ const arrowGeometry = (radiusBottom, height) => new ReadableGeometry(rootNode, buildCylinderGeometry({
73
+ radiusTop: 0.001,
74
+ radiusBottom: radiusBottom,
75
+ radialSegments: 32,
76
+ heightSegments: 1,
77
+ height: height,
78
+ openEnded: false
79
+ }));
80
+
81
+ const tubeGeometry = (radius, height, radialSegments) => new ReadableGeometry(rootNode, buildCylinderGeometry({
82
+ radiusTop: radius,
83
+ radiusBottom: radius,
84
+ radialSegments: radialSegments,
85
+ heightSegments: 1,
86
+ height: height,
87
+ openEnded: false
88
+ }));
89
+
90
+ const torusGeometry = (tube, arcFraction, tubeSegments) => new ReadableGeometry(rootNode, buildTorusGeometry({
91
+ radius: arrowLength - 0.2,
92
+ tube: tube,
93
+ radialSegments: 64,
94
+ tubeSegments: tubeSegments,
95
+ arc: (Math.PI * 2.0) * arcFraction
96
+ }));
197
97
 
198
- arrowHead: new ReadableGeometry(rootNode, buildCylinderGeometry({
199
- radiusTop: 0.001,
200
- radiusBottom: arrowRadius,
201
- radialSegments: 32,
202
- heightSegments: 1,
203
- height: 0.2,
204
- openEnded: false
205
- })),
206
-
207
- arrowHeadBig: new ReadableGeometry(rootNode, buildCylinderGeometry({
208
- radiusTop: 0.001,
209
- radiusBottom: 0.09,
210
- radialSegments: 32,
211
- heightSegments: 1,
212
- height: 0.25,
213
- openEnded: false
214
- })),
215
-
216
- arrowHeadHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({
217
- radiusTop: 0.09,
218
- radiusBottom: 0.09,
219
- radialSegments: 8,
220
- heightSegments: 1,
221
- height: 0.37,
222
- openEnded: false
223
- })),
224
-
225
- curve: new ReadableGeometry(rootNode, buildTorusGeometry({
226
- radius: hoopRadius,
227
- tube: tubeRadius,
228
- radialSegments: 64,
229
- tubeSegments: 14,
230
- arc: (Math.PI * 2.0) / 4.0
231
- })),
232
-
233
- curveHandle: new ReadableGeometry(rootNode, buildTorusGeometry({
234
- radius: hoopRadius,
235
- tube: handleTubeRadius,
236
- radialSegments: 64,
237
- tubeSegments: 14,
238
- arc: (Math.PI * 2.0) / 4.0
239
- })),
240
-
241
- hoop: new ReadableGeometry(rootNode, buildTorusGeometry({
242
- radius: hoopRadius,
243
- tube: tubeRadius,
244
- radialSegments: 64,
245
- tubeSegments: 8,
246
- arc: (Math.PI * 2.0)
247
- })),
248
-
249
- axis: new ReadableGeometry(rootNode, buildCylinderGeometry({
250
- radiusTop: tubeRadius,
251
- radiusBottom: tubeRadius,
252
- radialSegments: 20,
253
- heightSegments: 1,
254
- height: radius,
255
- openEnded: false
256
- })),
257
-
258
- axisHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({
259
- radiusTop: 0.08,
260
- radiusBottom: 0.08,
261
- radialSegments: 20,
262
- heightSegments: 1,
263
- height: radius,
264
- openEnded: false
265
- }))
266
- };
98
+ const shapes = {// Reusable geometries
267
99
 
268
- const materials = { // Reusable materials
269
-
270
- pickable: new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area
271
- diffuse: [1, 1, 0],
272
- alpha: 0, // Invisible
273
- alphaMode: "blend"
274
- }),
275
-
276
- red: new PhongMaterial(rootNode, {
277
- diffuse: [1, 0.0, 0.0],
278
- emissive: [1, 0.0, 0.0],
279
- ambient: [0.0, 0.0, 0.0],
280
- specular: [.6, .6, .3],
281
- shininess: 80,
282
- lineWidth: 2
283
- }),
284
-
285
- highlightRed: new EmphasisMaterial(rootNode, { // Emphasis for red rotation affordance hoop
286
- edges: false,
287
- fill: true,
288
- fillColor: [1, 0, 0],
289
- fillAlpha: 0.6
290
- }),
291
-
292
- green: new PhongMaterial(rootNode, {
293
- diffuse: [0.0, 1, 0.0],
294
- emissive: [0.0, 1, 0.0],
295
- ambient: [0.0, 0.0, 0.0],
296
- specular: [.6, .6, .3],
297
- shininess: 80,
298
- lineWidth: 2
299
- }),
300
-
301
- highlightGreen: new EmphasisMaterial(rootNode, { // Emphasis for green rotation affordance hoop
302
- edges: false,
303
- fill: true,
304
- fillColor: [0, 1, 0],
305
- fillAlpha: 0.6
306
- }),
307
-
308
- blue: new PhongMaterial(rootNode, {
309
- diffuse: [0.0, 0.0, 1],
310
- emissive: [0.0, 0.0, 1],
311
- ambient: [0.0, 0.0, 0.0],
312
- specular: [.6, .6, .3],
313
- shininess: 80,
314
- lineWidth: 2
315
- }),
316
-
317
- highlightBlue: new EmphasisMaterial(rootNode, { // Emphasis for blue rotation affordance hoop
318
- edges: false,
319
- fill: true,
320
- fillColor: [0, 0, 1],
321
- fillAlpha: 0.2
322
- }),
323
-
324
- center: new PhongMaterial(rootNode, {
325
- diffuse: [0.0, 0.0, 0.0],
326
- emissive: [0, 0, 0],
327
- ambient: [0.0, 0.0, 0.0],
328
- specular: [.6, .6, .3],
329
- shininess: 80
330
- }),
331
-
332
- highlightBall: new EmphasisMaterial(rootNode, {
333
- edges: false,
334
- fill: true,
335
- fillColor: [0.5, 0.5, 0.5],
336
- fillAlpha: 0.5,
337
- vertices: false
338
- }),
339
-
340
- highlightPlane: new EmphasisMaterial(rootNode, {
341
- edges: true,
342
- edgeWidth: 3,
343
- fill: false,
344
- fillColor: [0.5, 0.5, .5],
345
- fillAlpha: 0.5,
346
- vertices: false
347
- })
348
- };
100
+ curve: torusGeometry(tubeRadius, 0.25, 14),
101
+ curveHandle: torusGeometry(handleRadius, 0.25, 14),
102
+ hoop: torusGeometry(tubeRadius, 1, 8),
349
103
 
350
- this._displayMeshes = {
104
+ arrowHead: arrowGeometry(0.07, 0.2),
105
+ arrowHeadBig: arrowGeometry(0.09, 0.25),
106
+ arrowHeadHandle: tubeGeometry(handleRadius, 0.37, 8),
351
107
 
352
- plane: rootNode.addChild(new Mesh(rootNode, {
353
- geometry: new ReadableGeometry(rootNode, {
354
- primitive: "triangles",
355
- positions: [
356
- 0.5, 0.5, 0.0, 0.5, -0.5, 0.0, // 0
357
- -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, // 1
358
- 0.5, 0.5, -0.0, 0.5, -0.5, -0.0, // 2
359
- -0.5, -0.5, -0.0, -0.5, 0.5, -0.0 // 3
360
- ],
361
- indices: [0, 1, 2, 2, 3, 0]
362
- }),
363
- material: new PhongMaterial(rootNode, {
364
- emissive: [0, 0.0, 0],
365
- diffuse: [0, 0, 0],
366
- backfaces: true
367
- }),
368
- opacity: 0.6,
369
- ghosted: true,
370
- ghostMaterial: new EmphasisMaterial(rootNode, {
371
- edges: false,
372
- filled: true,
373
- fillColor: [1, 1, 0],
374
- edgeColor: [0, 0, 0],
375
- fillAlpha: 0.1,
376
- backfaces: true
377
- }),
378
- pickable: false,
379
- collidable: true,
380
- clippable: false,
381
- visible: false,
382
- scale: [2.4, 2.4, 1],
383
- isObject: false
384
- }), NO_STATE_INHERIT),
108
+ axis: tubeGeometry(tubeRadius, arrowLength, 20),
109
+ axisHandle: tubeGeometry(handleRadius, arrowLength, 20)
110
+ };
385
111
 
386
- planeFrame: rootNode.addChild(new Mesh(rootNode, { // Visible frame
387
- geometry: new ReadableGeometry(rootNode, buildTorusGeometry({
388
- center: [0, 0, 0],
389
- radius: 1.7,
390
- tube: tubeRadius * 2,
391
- radialSegments: 4,
392
- tubeSegments: 4,
393
- arc: Math.PI * 2.0
394
- })),
395
- material: new PhongMaterial(rootNode, {
396
- emissive: [0, 0, 0],
397
- diffuse: [0, 0, 0],
398
- specular: [0, 0, 0],
399
- shininess: 0
400
- }),
401
- //highlighted: true,
402
- highlightMaterial: new EmphasisMaterial(rootNode, {
403
- edges: false,
404
- edgeColor: [0.0, 0.0, 0.0],
405
- filled: true,
406
- fillColor: [0.8, 0.8, 0.8],
407
- fillAlpha: 1.0
408
- }),
409
- pickable: false,
410
- collidable: false,
411
- clippable: false,
412
- visible: false,
413
- scale: [1, 1, .1],
414
- rotation: [0, 0, 45],
415
- isObject: false
416
- }), NO_STATE_INHERIT),
112
+ const colorMaterial = (rgb) => new PhongMaterial(rootNode, {
113
+ diffuse: rgb,
114
+ emissive: rgb,
115
+ ambient: [0.0, 0.0, 0.0],
116
+ specular: [.6, .6, .3],
117
+ shininess: 80,
118
+ lineWidth: 2
119
+ });
417
120
 
418
- //----------------------------------------------------------------------------------------------------------
419
- //
420
- //----------------------------------------------------------------------------------------------------------
121
+ const highlightMaterial = (rgb, fillAlpha) => new EmphasisMaterial(rootNode, {
122
+ edges: false,
123
+ fill: true,
124
+ fillColor: rgb,
125
+ fillAlpha: fillAlpha
126
+ });
421
127
 
422
- xCurve: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis
423
- geometry: shapes.curve,
424
- material: materials.red,
425
- matrix: (function () {
426
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
427
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
428
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
429
- })(),
430
- pickable: false,
431
- collidable: true,
432
- clippable: false,
433
- backfaces: true,
434
- visible: false,
435
- isObject: false
436
- }), NO_STATE_INHERIT),
128
+ const pickableMaterial = new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area
129
+ diffuse: [1, 1, 0],
130
+ alpha: 0, // Invisible
131
+ alphaMode: "blend"
132
+ });
437
133
 
438
- xCurveHandle: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis
439
- geometry: shapes.curveHandle,
440
- material: materials.pickable,
441
- matrix: (function () {
442
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
443
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
444
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
445
- })(),
446
- pickable: true,
447
- collidable: true,
448
- clippable: false,
449
- backfaces: true,
450
- visible: false,
451
- isObject: false
452
- }), NO_STATE_INHERIT),
134
+ const handlers = { };
135
+ const addAxis = (rgb, axisDirection, hoopDirection) => {
136
+ const material = colorMaterial(rgb);
453
137
 
454
- xCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
455
- geometry: shapes.arrowHead,
456
- material: materials.red,
457
- matrix: (function () {
458
- const translate = math.translateMat4c(0., -0.07, -0.8, math.identityMat4());
459
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
460
- const rotate = math.rotationMat4v(0 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
461
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
462
- })(),
463
- pickable: true,
464
- collidable: true,
465
- clippable: false,
466
- visible: false,
467
- isObject: false
468
- }), NO_STATE_INHERIT),
138
+ const rotateToHorizontal = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
139
+ const hoopRotation = math.quaternionToRotationMat4(math.vec3PairToQuaternion([ 0, 1, 0 ], hoopDirection), math.identityMat4());
140
+ const hoopMatrix = math.mulMat4(hoopRotation, rotateToHorizontal, math.identityMat4());
469
141
 
470
- xCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
471
- geometry: shapes.arrowHead,
472
- material: materials.red,
473
- matrix: (function () {
474
- const translate = math.translateMat4c(0.0, -0.8, -0.07, math.identityMat4());
475
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
476
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
477
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
478
- })(),
479
- pickable: true,
480
- collidable: true,
481
- clippable: false,
482
- visible: false,
483
- isObject: false
484
- }), NO_STATE_INHERIT),
142
+ const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
485
143
 
486
- //----------------------------------------------------------------------------------------------------------
487
- //
488
- //----------------------------------------------------------------------------------------------------------
144
+ const scaledArrowMatrix = (t, matR) => {
145
+ const matT = math.translateMat4v(t, math.identityMat4());
146
+ const ret = math.identityMat4();
147
+ math.mulMat4(matT, matR, ret);
148
+ math.mulMat4(hoopMatrix, ret, ret);
149
+ return math.mulMat4(ret, scale, math.identityMat4());
150
+ };
489
151
 
490
- yCurve: rootNode.addChild(new Mesh(rootNode, {
152
+ const curve = rootNode.addChild(new Mesh(rootNode, {
491
153
  geometry: shapes.curve,
492
- material: materials.green,
493
- rotation: [-90, 0, 0],
154
+ material: material,
155
+ matrix: hoopMatrix,
494
156
  pickable: false,
495
157
  collidable: true,
496
158
  clippable: false,
497
159
  backfaces: true,
498
160
  visible: false,
499
161
  isObject: false
500
- }), NO_STATE_INHERIT),
162
+ }), NO_STATE_INHERIT);
501
163
 
502
- yCurveHandle: rootNode.addChild(new Mesh(rootNode, {
164
+ const rotateHandle = rootNode.addChild(new Mesh(rootNode, {
503
165
  geometry: shapes.curveHandle,
504
- material: materials.pickable,
505
- rotation: [-90, 0, 0],
166
+ material: pickableMaterial,
167
+ matrix: hoopMatrix,
506
168
  pickable: true,
507
169
  collidable: true,
508
170
  clippable: false,
509
171
  backfaces: true,
510
172
  visible: false,
511
173
  isObject: false
512
- }), NO_STATE_INHERIT),
174
+ }), NO_STATE_INHERIT);
513
175
 
514
- yCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
176
+ const arrow1 = rootNode.addChild(new Mesh(rootNode, {
515
177
  geometry: shapes.arrowHead,
516
- material: materials.green,
517
- matrix: (function () {
518
- const translate = math.translateMat4c(0.07, 0, -0.8, math.identityMat4());
519
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
520
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
521
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
522
- })(),
523
- pickable: true,
524
- collidable: true,
525
- clippable: false,
526
- visible: false,
527
- isObject: false
528
- }), NO_STATE_INHERIT),
529
-
530
- yCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
531
- geometry: shapes.arrowHead,
532
- material: materials.green,
533
- matrix: (function () {
534
- const translate = math.translateMat4c(0.8, 0.0, -0.07, math.identityMat4());
535
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
536
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
537
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
538
- })(),
539
- pickable: true,
540
- collidable: true,
541
- clippable: false,
542
- visible: false,
543
- isObject: false
544
- }), NO_STATE_INHERIT),
545
-
546
- //----------------------------------------------------------------------------------------------------------
547
- //
548
- //----------------------------------------------------------------------------------------------------------
549
-
550
- zCurve: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis
551
- geometry: shapes.curve,
552
- material: materials.blue,
553
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
554
- pickable: false,
555
- collidable: true,
556
- clippable: false,
557
- visible: false,
558
- isObject: false
559
- }), NO_STATE_INHERIT),
560
-
561
- zCurveHandle: rootNode.addChild(new Mesh(rootNode, {
562
- geometry: shapes.curveHandle,
563
- material: materials.pickable,
564
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
565
- pickable: true,
566
- collidable: true,
567
- clippable: false,
568
- visible: false,
569
- isObject: false
570
- }), NO_STATE_INHERIT),
571
-
572
- zCurveCurveArrow1: rootNode.addChild(new Mesh(rootNode, {
573
- geometry: shapes.arrowHead,
574
- material: materials.blue,
575
- matrix: (function () {
576
- const translate = math.translateMat4c(.8, -0.07, 0, math.identityMat4());
577
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
578
- return math.mulMat4(translate, scale, math.identityMat4());
579
- })(),
580
- pickable: true,
581
- collidable: true,
582
- clippable: false,
583
- visible: false,
584
- isObject: false
585
- }), NO_STATE_INHERIT),
586
-
587
- zCurveArrow2: rootNode.addChild(new Mesh(rootNode, {
588
- geometry: shapes.arrowHead,
589
- material: materials.blue,
590
- matrix: (function () {
591
- const translate = math.translateMat4c(.05, -0.8, 0, math.identityMat4());
592
- const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4());
593
- const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
594
- return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4());
595
- })(),
596
- pickable: true,
597
- collidable: true,
598
- clippable: false,
599
- visible: false,
600
- isObject: false
601
- }), NO_STATE_INHERIT),
602
-
603
- //----------------------------------------------------------------------------------------------------------
604
- //
605
- //----------------------------------------------------------------------------------------------------------
606
-
607
- center: rootNode.addChild(new Mesh(rootNode, {
608
- geometry: new ReadableGeometry(rootNode, buildSphereGeometry({
609
- radius: 0.05
610
- })),
611
- material: materials.center,
612
- pickable: false,
613
- collidable: true,
614
- clippable: false,
615
- visible: false,
616
- isObject: false
617
- }), NO_STATE_INHERIT),
618
-
619
- //----------------------------------------------------------------------------------------------------------
620
- //
621
- //----------------------------------------------------------------------------------------------------------
622
-
623
- xAxisArrow: rootNode.addChild(new Mesh(rootNode, {
624
- geometry: shapes.arrowHead,
625
- material: materials.red,
626
- matrix: (function () {
627
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
628
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
629
- return math.mulMat4(rotate, translate, math.identityMat4());
630
- })(),
631
- pickable: false,
632
- collidable: true,
633
- clippable: false,
634
- visible: false,
635
- isObject: false
636
- }), NO_STATE_INHERIT),
637
-
638
- xAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
639
- geometry: shapes.arrowHeadHandle,
640
- material: materials.pickable,
641
- matrix: (function () {
642
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
643
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
644
- return math.mulMat4(rotate, translate, math.identityMat4());
645
- })(),
646
- pickable: true,
647
- collidable: true,
648
- clippable: false,
649
- visible: false,
650
- isObject: false
651
- }), NO_STATE_INHERIT),
652
-
653
- xAxis: rootNode.addChild(new Mesh(rootNode, {
654
- geometry: shapes.axis,
655
- material: materials.red,
656
- matrix: (function () {
657
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
658
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
659
- return math.mulMat4(rotate, translate, math.identityMat4());
660
- })(),
661
- pickable: false,
662
- collidable: true,
663
- clippable: false,
664
- visible: false,
665
- isObject: false
666
- }), NO_STATE_INHERIT),
667
-
668
- xAxisHandle: rootNode.addChild(new Mesh(rootNode, {
669
- geometry: shapes.axisHandle,
670
- material: materials.pickable,
671
- matrix: (function () {
672
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
673
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
674
- return math.mulMat4(rotate, translate, math.identityMat4());
675
- })(),
178
+ material: material,
179
+ matrix: scaledArrowMatrix([ .8, .07, 0 ], math.rotationMat4v(180 * math.DEGTORAD, [0, 0, 1], math.identityMat4())),
676
180
  pickable: true,
677
181
  collidable: true,
678
182
  clippable: false,
679
- visible: false,
680
- isObject: false
681
- }), NO_STATE_INHERIT),
682
-
683
- //----------------------------------------------------------------------------------------------------------
684
- //
685
- //----------------------------------------------------------------------------------------------------------
686
-
687
- yAxisArrow: rootNode.addChild(new Mesh(rootNode, {
688
- geometry: shapes.arrowHead,
689
- material: materials.green,
690
- matrix: (function () {
691
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
692
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
693
- return math.mulMat4(rotate, translate, math.identityMat4());
694
- })(),
695
- pickable: false,
696
- collidable: true,
697
- clippable: false,
698
- visible: false,
699
- isObject: false
700
- }), NO_STATE_INHERIT),
701
-
702
- yAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
703
- geometry: shapes.arrowHeadHandle,
704
- material: materials.pickable,
705
- matrix: (function () {
706
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
707
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
708
- return math.mulMat4(rotate, translate, math.identityMat4());
709
- })(),
710
- pickable: true,
711
- collidable: true,
712
- clippable: false,
713
- visible: false,
714
- opacity: 0.2,
715
- isObject: false
716
- }), NO_STATE_INHERIT),
717
-
718
- yShaft: rootNode.addChild(new Mesh(rootNode, {
719
- geometry: shapes.axis,
720
- material: materials.green,
721
- position: [0, -radius / 2, 0],
722
- pickable: false,
723
- collidable: true,
724
- clippable: false,
725
- visible: false,
726
- isObject: false
727
- }), NO_STATE_INHERIT),
728
-
729
- yShaftHandle: rootNode.addChild(new Mesh(rootNode, {
730
- geometry: shapes.axisHandle,
731
- material: materials.pickable,
732
- position: [0, -radius / 2, 0],
733
- pickable: true,
734
- collidable: true,
735
- clippable: false,
736
- visible: false,
737
- isObject: false
738
- }), NO_STATE_INHERIT),
739
-
740
- //----------------------------------------------------------------------------------------------------------
741
- //
742
- //----------------------------------------------------------------------------------------------------------
743
-
744
- zAxisArrow: rootNode.addChild(new Mesh(rootNode, {
745
- geometry: shapes.arrowHead,
746
- material: materials.blue,
747
- matrix: (function () {
748
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
749
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
750
- return math.mulMat4(rotate, translate, math.identityMat4());
751
- })(),
752
- pickable: false,
753
- collidable: true,
754
- clippable: false,
755
- visible: false,
756
- isObject: false
757
- }), NO_STATE_INHERIT),
758
-
759
- zAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, {
760
- geometry: shapes.arrowHeadHandle,
761
- material: materials.pickable,
762
- matrix: (function () {
763
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
764
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
765
- return math.mulMat4(rotate, translate, math.identityMat4());
766
- })(),
767
- pickable: true,
768
- collidable: true,
769
- clippable: false,
770
- visible: false,
771
- isObject: false
772
- }), NO_STATE_INHERIT),
773
-
774
-
775
- zShaft: rootNode.addChild(new Mesh(rootNode, {
776
- geometry: shapes.axis,
777
- material: materials.blue,
778
- matrix: (function () {
779
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
780
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
781
- return math.mulMat4(rotate, translate, math.identityMat4());
782
- })(),
783
- clippable: false,
784
- pickable: false,
785
- collidable: true,
786
- visible: false,
787
- isObject: false
788
- }), NO_STATE_INHERIT),
789
-
790
- zAxisHandle: rootNode.addChild(new Mesh(rootNode, {
791
- geometry: shapes.axisHandle,
792
- material: materials.pickable,
793
- matrix: (function () {
794
- const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4());
795
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
796
- return math.mulMat4(rotate, translate, math.identityMat4());
797
- })(),
798
- clippable: false,
799
- pickable: true,
800
- collidable: true,
801
- visible: false,
802
- isObject: false
803
- }), NO_STATE_INHERIT)
804
- };
805
-
806
- this._affordanceMeshes = {
807
-
808
- planeFrame: rootNode.addChild(new Mesh(rootNode, {
809
- geometry: new ReadableGeometry(rootNode, buildTorusGeometry({
810
- center: [0, 0, 0],
811
- radius: 2,
812
- tube: tubeRadius,
813
- radialSegments: 4,
814
- tubeSegments: 4,
815
- arc: Math.PI * 2.0
816
- })),
817
- material: new PhongMaterial(rootNode, {
818
- ambient: [1, 1, 1],
819
- diffuse: [0, 0, 0],
820
- emissive: [1, 1, 0]
821
- }),
822
- highlighted: true,
823
- highlightMaterial: new EmphasisMaterial(rootNode, {
824
- edges: false,
825
- filled: true,
826
- fillColor: [1, 1, 0],
827
- fillAlpha: 1.0
828
- }),
829
- pickable: false,
830
- collidable: false,
183
+ visible: false,
184
+ isObject: false
185
+ }), NO_STATE_INHERIT);
186
+
187
+ const arrow2 = rootNode.addChild(new Mesh(rootNode, {
188
+ geometry: shapes.arrowHead,
189
+ material: material,
190
+ matrix: scaledArrowMatrix([ .07, .8, 0 ], math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4())),
191
+ pickable: true,
192
+ collidable: true,
831
193
  clippable: false,
832
194
  visible: false,
833
- scale: [1, 1, 1],
834
- rotation: [0, 0, 45],
835
195
  isObject: false
836
- }), NO_STATE_INHERIT),
196
+ }), NO_STATE_INHERIT);
837
197
 
838
- xHoop: rootNode.addChild(new Mesh(rootNode, { // Full
198
+ const hoop = rootNode.addChild(new Mesh(rootNode, {
839
199
  geometry: shapes.hoop,
840
- material: materials.red,
200
+ material: material,
841
201
  highlighted: true,
842
- highlightMaterial: materials.highlightRed,
843
- matrix: (function () {
844
- const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4());
845
- const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
846
- return math.mulMat4(rotate1, rotate2, math.identityMat4());
847
- })(),
202
+ highlightMaterial: highlightMaterial(rgb, 0.6),
203
+ matrix: hoopMatrix,
848
204
  pickable: false,
849
205
  collidable: true,
850
206
  clippable: false,
851
207
  visible: false,
852
208
  isObject: false
853
- }), NO_STATE_INHERIT),
209
+ }), NO_STATE_INHERIT);
854
210
 
855
- yHoop: rootNode.addChild(new Mesh(rootNode, {
856
- geometry: shapes.hoop,
857
- material: materials.green,
858
- highlighted: true,
859
- highlightMaterial: materials.highlightGreen,
860
- rotation: [-90, 0, 0],
211
+
212
+ const axisRotation = math.quaternionToRotationMat4(math.vec3PairToQuaternion([ 0, 1, 0 ], axisDirection), math.identityMat4());
213
+
214
+ const translatedAxisMatrix = (yOffset) => math.mulMat4(axisRotation, math.translateMat4c(0, yOffset, 0, math.identityMat4()), math.identityMat4());
215
+ const arrowMatrix = translatedAxisMatrix(arrowLength + .1);
216
+ const shaftMatrix = translatedAxisMatrix(arrowLength / 2);
217
+
218
+ const arrow = rootNode.addChild(new Mesh(rootNode, {
219
+ geometry: shapes.arrowHead,
220
+ material: material,
221
+ matrix: arrowMatrix,
861
222
  pickable: false,
862
223
  collidable: true,
863
224
  clippable: false,
864
225
  visible: false,
865
226
  isObject: false
866
- }), NO_STATE_INHERIT),
227
+ }), NO_STATE_INHERIT);
867
228
 
868
- zHoop: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis
869
- geometry: shapes.hoop,
870
- material: materials.blue,
871
- highlighted: true,
872
- highlightMaterial: materials.highlightBlue,
873
- matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()),
874
- pickable: false,
229
+ const arrowHandle = rootNode.addChild(new Mesh(rootNode, {
230
+ geometry: shapes.arrowHeadHandle,
231
+ material: pickableMaterial,
232
+ matrix: arrowMatrix,
233
+ pickable: true,
875
234
  collidable: true,
876
235
  clippable: false,
877
- backfaces: true,
878
236
  visible: false,
879
237
  isObject: false
880
- }), NO_STATE_INHERIT),
238
+ }), NO_STATE_INHERIT);
881
239
 
882
- xAxisArrow: rootNode.addChild(new Mesh(rootNode, {
883
- geometry: shapes.arrowHeadBig,
884
- material: materials.red,
885
- matrix: (function () {
886
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
887
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4());
888
- return math.mulMat4(rotate, translate, math.identityMat4());
889
- })(),
240
+ const shaft = rootNode.addChild(new Mesh(rootNode, {
241
+ geometry: shapes.axis,
242
+ material: material,
243
+ matrix: shaftMatrix,
890
244
  pickable: false,
891
245
  collidable: true,
892
246
  clippable: false,
893
247
  visible: false,
894
248
  isObject: false
895
- }), NO_STATE_INHERIT),
249
+ }), NO_STATE_INHERIT);
896
250
 
897
- yAxisArrow: rootNode.addChild(new Mesh(rootNode, {
898
- geometry: shapes.arrowHeadBig,
899
- material: materials.green,
900
- matrix: (function () {
901
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
902
- const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4());
903
- return math.mulMat4(rotate, translate, math.identityMat4());
904
- })(),
905
- pickable: false,
251
+ const shaftHandle = rootNode.addChild(new Mesh(rootNode, {
252
+ geometry: shapes.axisHandle,
253
+ material: pickableMaterial,
254
+ matrix: shaftMatrix,
255
+ pickable: true,
906
256
  collidable: true,
907
257
  clippable: false,
908
258
  visible: false,
909
259
  isObject: false
910
- }), NO_STATE_INHERIT),
260
+ }), NO_STATE_INHERIT);
911
261
 
912
- zAxisArrow: rootNode.addChild(new Mesh(rootNode, {
262
+ const bigArrowHead = rootNode.addChild(new Mesh(rootNode, {
913
263
  geometry: shapes.arrowHeadBig,
914
- material: materials.blue,
915
- matrix: (function () {
916
- const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4());
917
- const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4());
918
- return math.mulMat4(rotate, translate, math.identityMat4());
919
- })(),
264
+ material: material,
265
+ matrix: arrowMatrix,
920
266
  pickable: false,
921
267
  collidable: true,
922
268
  clippable: false,
923
269
  visible: false,
924
270
  isObject: false
925
- }), NO_STATE_INHERIT)
926
- };
927
- }
928
-
929
- _bindEvents() {
930
-
931
- const self = this;
271
+ }), NO_STATE_INHERIT);
932
272
 
933
- var grabbed = false;
273
+ const closestPointOnAxis = (function() {
274
+ const worldAxis = math.vec4();
275
+ const org = math.vec3();
276
+ const dir = math.vec3();
277
+ return (canvasPos, dst) => {
278
+ localToWorldVec(rgb, worldAxis);
934
279
 
935
- const DRAG_ACTIONS = {
936
- none: -1,
937
- xTranslate: 0,
938
- yTranslate: 1,
939
- zTranslate: 2,
940
- xRotate: 3,
941
- yRotate: 4,
942
- zRotate: 5
943
- };
280
+ const P = pos;
281
+ const D = worldAxis;
944
282
 
945
- const rootNode = this._rootNode;
283
+ math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, org, dir);
946
284
 
947
- var nextDragAction = null; // As we hover grabbed an arrow or hoop, self is the action we would do if we then dragged it.
948
- var dragAction = null; // Action we're doing while we drag an arrow or hoop.
949
- const lastCanvasPos = math.vec2();
285
+ const d01 = math.dotVec3(D, dir);
286
+ const v = math.subVec3(org, P, dst);
287
+ const v0 = math.dotVec3(v, D);
288
+ const v1 = math.dotVec3(v, dir);
289
+ const det = 1 - d01 * d01;
950
290
 
951
- const xBaseAxis = math.vec3([1, 0, 0]);
952
- const yBaseAxis = math.vec3([0, 1, 0]);
953
- const zBaseAxis = math.vec3([0, 0, 1]);
291
+ if (Math.abs(det) > 1e-10) { // if lines are not parallel
292
+ const s = (v0 - d01 * v1) / det;
293
+ math.addVec3(P, math.mulVec3Scalar(D, s, dst), dst);
294
+ return true;
295
+ } else {
296
+ return false;
297
+ }
298
+ };
299
+ })();
300
+ const initOffset = math.vec3();
301
+ const tempVec3 = math.vec3();
302
+ handlers[arrowHandle.id] = handlers[shaftHandle.id] = {
303
+ setActivated: a => bigArrowHead.visible = a,
304
+ initDragAction: (initCanvasPos) => {
305
+ return closestPointOnAxis(initCanvasPos, initOffset) && math.subVec3(initOffset, pos, initOffset) && ((canvasPos) => {
306
+ if (closestPointOnAxis(canvasPos, tempVec3)) {
307
+ math.subVec3(tempVec3, initOffset, tempVec3);
308
+ setPos(tempVec3);
309
+ if (self._sectionPlane) {
310
+ self._sectionPlane.pos = tempVec3;
311
+ }
312
+ }
313
+ });
314
+ }
315
+ };
954
316
 
955
- const canvas = this._viewer.scene.canvas.canvas;
956
- const camera = this._viewer.camera;
957
- const scene = this._viewer.scene;
317
+ const lastCanvasPos = math.vec2();
318
+ handlers[rotateHandle.id] = {
319
+ setActivated: a => hoop.visible = a,
320
+ initDragAction: (initCanvasPos) => {
321
+ lastCanvasPos.set(initCanvasPos);
322
+ return canvasPos => {
323
+ dragRotateSectionPlane(rgb, lastCanvasPos, canvasPos);
324
+ lastCanvasPos.set(canvasPos);
325
+ };
326
+ }
327
+ };
958
328
 
959
- { // Keep gizmo screen size constant
329
+ return {
330
+ set visible(v) {
331
+ arrow.visible = arrowHandle.visible = shaft.visible = shaftHandle.visible = curve.visible = rotateHandle.visible = arrow1.visible = arrow2.visible = v;
332
+ if (! v) {
333
+ bigArrowHead.visible = v;
334
+ hoop.visible = v;
335
+ }
336
+ },
337
+ set culled(c) {
338
+ arrow.culled = arrowHandle.culled = shaft.culled = shaftHandle.culled = curve.culled = rotateHandle.culled = arrow1.culled = arrow2.culled = c;
339
+ if (! c) {
340
+ bigArrowHead.culled = c;
341
+ hoop.culled = c;
342
+ }
343
+ }
344
+ };
345
+ };
960
346
 
961
- const tempVec3a = math.vec3([0, 0, 0]);
347
+ this._displayMeshes = [ // Meshes that are always visible
348
+ rootNode.addChild(new Mesh(rootNode, { // plane
349
+ geometry: new ReadableGeometry(rootNode, {
350
+ primitive: "triangles",
351
+ positions: [
352
+ 0.5, 0.5, 0.0, 0.5, -0.5, 0.0, // 0
353
+ -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, // 1
354
+ 0.5, 0.5, -0.0, 0.5, -0.5, -0.0, // 2
355
+ -0.5, -0.5, -0.0, -0.5, 0.5, -0.0 // 3
356
+ ],
357
+ indices: [0, 1, 2, 2, 3, 0]
358
+ }),
359
+ material: new PhongMaterial(rootNode, {
360
+ emissive: [0, 0.0, 0],
361
+ diffuse: [0, 0, 0],
362
+ backfaces: true
363
+ }),
364
+ opacity: 0.6,
365
+ ghosted: true,
366
+ ghostMaterial: new EmphasisMaterial(rootNode, {
367
+ edges: false,
368
+ filled: true,
369
+ fillColor: [1, 1, 0],
370
+ edgeColor: [0, 0, 0],
371
+ fillAlpha: 0.1,
372
+ backfaces: true
373
+ }),
374
+ pickable: false,
375
+ collidable: true,
376
+ clippable: false,
377
+ visible: false,
378
+ scale: [2.4, 2.4, 1],
379
+ isObject: false
380
+ }), NO_STATE_INHERIT),
962
381
 
963
- let distDirty = true;
964
- let lastDist = -1;
382
+ rootNode.addChild(new Mesh(rootNode, { // Visible frame
383
+ geometry: new ReadableGeometry(rootNode, buildTorusGeometry({
384
+ center: [0, 0, 0],
385
+ radius: 1.7,
386
+ tube: tubeRadius * 2,
387
+ radialSegments: 4,
388
+ tubeSegments: 4,
389
+ arc: Math.PI * 2.0
390
+ })),
391
+ material: new PhongMaterial(rootNode, {
392
+ emissive: [0, 0, 0],
393
+ diffuse: [0, 0, 0],
394
+ specular: [0, 0, 0],
395
+ shininess: 0
396
+ }),
397
+ //highlighted: true,
398
+ highlightMaterial: new EmphasisMaterial(rootNode, {
399
+ edges: false,
400
+ edgeColor: [0.0, 0.0, 0.0],
401
+ filled: true,
402
+ fillColor: [0.8, 0.8, 0.8],
403
+ fillAlpha: 1.0
404
+ }),
405
+ pickable: false,
406
+ collidable: false,
407
+ clippable: false,
408
+ visible: false,
409
+ scale: [1, 1, .1],
410
+ rotation: [0, 0, 45],
411
+ isObject: false
412
+ }), NO_STATE_INHERIT),
965
413
 
966
- this._onCameraViewMatrix = scene.camera.on("viewMatrix", () => {
967
- distDirty = true;
968
- });
414
+ rootNode.addChild(new Mesh(rootNode, { // center
415
+ geometry: new ReadableGeometry(rootNode, buildSphereGeometry({
416
+ radius: 0.05
417
+ })),
418
+ material: new PhongMaterial(rootNode, {
419
+ diffuse: [0.0, 0.0, 0.0],
420
+ emissive: [0, 0, 0],
421
+ ambient: [0.0, 0.0, 0.0],
422
+ specular: [.6, .6, .3],
423
+ shininess: 80
424
+ }),
425
+ pickable: false,
426
+ collidable: true,
427
+ clippable: false,
428
+ visible: false,
429
+ isObject: false
430
+ }), NO_STATE_INHERIT),
969
431
 
970
- this._onCameraProjMatrix = scene.camera.on("projMatrix", () => {
971
- distDirty = true;
972
- });
432
+ //----------------------------------------------------------------------------------------------------------
433
+ //
434
+ //----------------------------------------------------------------------------------------------------------
973
435
 
974
- this._onSceneTick = scene.on("tick", () => {
436
+ addAxis([1,0,0], [ 1, 0, 0 ], [ 1, 0, 0 ]),
437
+ addAxis([0,1,0], [ 0, -1, 0 ], [ 0, 1, 0 ]),
438
+ addAxis([0,0,1], [ 0, 0, -1 ], [ 0, 0, -1 ])
439
+ ];
975
440
 
976
- const dist = Math.abs(math.lenVec3(math.subVec3(scene.camera.eye, this._pos, tempVec3a)));
441
+ const cleanups = [ ];
977
442
 
978
- if (dist !== lastDist) {
979
- if (camera.projection === "perspective") {
980
- const worldSize = (Math.tan(camera.perspective.fov * math.DEGTORAD)) * dist;
981
- const size = 0.07 * worldSize;
982
- rootNode.scale = [size, size, size];
983
- lastDist = dist;
443
+ { // Keep gizmo screen size constant
444
+ let lastDist = -1;
445
+ const setRootNodeScale = size => rootNode.scale = [size, size, size];
446
+ const onSceneTick = scene.on("tick", () => {
447
+ const dist = Math.abs(math.distVec3(camera.eye, pos));
448
+ if (camera.projection === "perspective") {
449
+ if (dist !== lastDist) {
450
+ setRootNodeScale(0.07 * dist * Math.tan(camera.perspective.fov * math.DEGTORAD));
984
451
  }
452
+ } else if (camera.projection === "ortho") {
453
+ setRootNodeScale(camera.ortho.scale / 10);
985
454
  }
986
-
987
- if (camera.projection === "ortho") {
988
- const worldSize = camera.ortho.scale / 10;
989
- const size = worldSize;
990
- rootNode.scale = [size, size, size];
991
- lastDist = dist;
992
- }
455
+ lastDist = dist;
993
456
  });
457
+ cleanups.push(() => scene.off(onSceneTick));
994
458
  }
995
459
 
996
- const getClickCoordsWithinElement = (function () {
997
- const canvasPos = new Float64Array(2);
998
- return function (event) {
999
- if (!event) {
1000
- event = window.event;
1001
- canvasPos[0] = event.x;
1002
- canvasPos[1] = event.y;
1003
- } else {
1004
- var element = event.target;
1005
- var totalOffsetLeft = 0;
1006
- var totalOffsetTop = 0;
1007
-
1008
- while (element.offsetParent) {
1009
- totalOffsetLeft += element.offsetLeft;
1010
- totalOffsetTop += element.offsetTop;
1011
- element = element.offsetParent;
1012
- }
1013
- canvasPos[0] = event.pageX - totalOffsetLeft;
1014
- canvasPos[1] = event.pageY - totalOffsetTop;
1015
- }
1016
- return canvasPos;
1017
- };
1018
- })();
460
+ const getClickCoordsWithinElement = (event, canvasPos) => {
461
+ if (!event) {
462
+ event = window.event;
463
+ canvasPos[0] = event.x;
464
+ canvasPos[1] = event.y;
465
+ } else {
466
+ const element = event.target;
467
+ const rect = element.getBoundingClientRect();
468
+ canvasPos[0] = event.clientX - rect.left;
469
+ canvasPos[1] = event.clientY - rect.top;
470
+ }
471
+ };
1019
472
 
1020
473
  const localToWorldVec = (function () {
1021
474
  const mat = math.mat4();
1022
475
  return function (localVec, worldVec) {
1023
- math.quaternionToMat4(self._rootNode.quaternion, mat);
476
+ math.quaternionToMat4(rootNode.quaternion, mat);
1024
477
  math.transformVec3(mat, localVec, worldVec);
1025
478
  math.normalizeVec3(worldVec);
1026
479
  return worldVec;
1027
480
  };
1028
481
  })();
1029
482
 
1030
- var getTranslationPlane = (function () {
1031
- const planeNormal = math.vec3();
1032
- return function (worldAxis) {
1033
- const absX = Math.abs(worldAxis[0]);
1034
- if (absX > Math.abs(worldAxis[1]) && absX > Math.abs(worldAxis[2])) {
1035
- math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal);
1036
- } else {
1037
- math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal);
1038
- }
1039
- math.cross3Vec3(planeNormal, worldAxis, planeNormal);
1040
- math.normalizeVec3(planeNormal);
1041
- return planeNormal;
1042
- }
1043
- })();
1044
-
1045
- const dragTranslateSectionPlane = (function () {
1046
- const p1 = math.vec3();
1047
- const p2 = math.vec3();
1048
- const worldAxis = math.vec4();
1049
- return function (baseAxis, fromMouse, toMouse) {
1050
- localToWorldVec(baseAxis, worldAxis);
1051
- const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
1052
- getPointerPlaneIntersect(fromMouse, planeNormal, p1);
1053
- getPointerPlaneIntersect(toMouse, planeNormal, p2);
1054
- math.subVec3(p2, p1);
1055
- const dot = math.dotVec3(p2, worldAxis);
1056
- self._pos[0] += worldAxis[0] * dot;
1057
- self._pos[1] += worldAxis[1] * dot;
1058
- self._pos[2] += worldAxis[2] * dot;
1059
- self._rootNode.position = self._pos;
1060
- if (self._sectionPlane) {
1061
- self._sectionPlane.pos = self._pos;
1062
- }
483
+ const getTranslationPlane = (worldAxis, planeNormal) => {
484
+ const absX = Math.abs(worldAxis[0]);
485
+ if (absX > Math.abs(worldAxis[1]) && absX > Math.abs(worldAxis[2])) {
486
+ math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal);
487
+ } else {
488
+ math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal);
1063
489
  }
1064
- })();
490
+ math.cross3Vec3(planeNormal, worldAxis, planeNormal);
491
+ math.normalizeVec3(planeNormal);
492
+ };
1065
493
 
494
+ const self = this;
1066
495
  var dragRotateSectionPlane = (function () {
1067
496
  const p1 = math.vec4();
1068
497
  const p2 = math.vec4();
1069
498
  const c = math.vec4();
1070
499
  const worldAxis = math.vec4();
500
+ const dir = math.vec3();
501
+ const mat = math.mat4();
502
+ const planeNormal = math.vec3();
1071
503
  return function (baseAxis, fromMouse, toMouse) {
1072
504
  localToWorldVec(baseAxis, worldAxis);
1073
505
  const hasData = getPointerPlaneIntersect(fromMouse, worldAxis, p1) && getPointerPlaneIntersect(toMouse, worldAxis, p2);
1074
506
  if (!hasData) { // Find intersections with view plane and project down to origin
1075
- const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse);
507
+ getTranslationPlane(worldAxis, planeNormal);
1076
508
  getPointerPlaneIntersect(fromMouse, planeNormal, p1, 1); // Ensure plane moves closer to camera so angles become workable
1077
509
  getPointerPlaneIntersect(toMouse, planeNormal, p2, 1);
1078
510
  var dot = math.dotVec3(p1, worldAxis);
@@ -1093,9 +525,15 @@ class Control {
1093
525
  if (math.dotVec3(c, worldAxis) < 0.0) {
1094
526
  incDegrees = -incDegrees;
1095
527
  }
1096
- self._rootNode.rotate(baseAxis, incDegrees);
1097
- rotateSectionPlane();
1098
- }
528
+ rootNode.rotate(baseAxis, incDegrees);
529
+
530
+ if (self._sectionPlane) {
531
+ math.quaternionToMat4(rootNode.quaternion, mat); // << ---
532
+ math.transformVec3(mat, [0, 0, 1], dir);
533
+ ignoreNextSectionPlaneDirUpdate = true;
534
+ self._sectionPlane.dir = dir;
535
+ }
536
+ };
1099
537
  })();
1100
538
 
1101
539
  var getPointerPlaneIntersect = (function () {
@@ -1124,240 +562,211 @@ class Control {
1124
562
  return true;
1125
563
  }
1126
564
  return false;
1127
- }
1128
- })();
1129
-
1130
- const rotateSectionPlane = (function () {
1131
- const dir = math.vec3();
1132
- const mat = math.mat4();
1133
- return function () {
1134
- if (self.sectionPlane) {
1135
- math.quaternionToMat4(rootNode.quaternion, mat); // << ---
1136
- math.transformVec3(mat, [0, 0, 1], dir);
1137
- self._setSectionPlaneDir(dir);
1138
- }
1139
565
  };
1140
566
  })();
1141
567
 
1142
568
  {
1143
- var mouseDownLeft;
1144
- var mouseDownMiddle;
1145
- var mouseDownRight;
1146
- var down = false;
1147
- var lastAffordanceMesh;
1148
-
1149
- this._onCameraControlHover = this._viewer.cameraControl.on("hoverEnter", (hit) => {
1150
- if (!this._visible) {
1151
- return;
1152
- }
1153
- if (down) {
1154
- return;
1155
- }
1156
- grabbed = false;
1157
- if (lastAffordanceMesh) {
1158
- lastAffordanceMesh.visible = false;
1159
- }
1160
- var affordanceMesh;
1161
- const meshId = hit.entity.id;
1162
- switch (meshId) {
1163
-
1164
- case this._displayMeshes.xAxisArrowHandle.id:
1165
- affordanceMesh = this._affordanceMeshes.xAxisArrow;
1166
- nextDragAction = DRAG_ACTIONS.xTranslate;
1167
- break;
1168
-
1169
- case this._displayMeshes.xAxisHandle.id:
1170
- affordanceMesh = this._affordanceMeshes.xAxisArrow;
1171
- nextDragAction = DRAG_ACTIONS.xTranslate;
1172
- break;
1173
-
1174
- case this._displayMeshes.yAxisArrowHandle.id:
1175
- affordanceMesh = this._affordanceMeshes.yAxisArrow;
1176
- nextDragAction = DRAG_ACTIONS.yTranslate;
1177
- break;
1178
-
1179
- case this._displayMeshes.yShaftHandle.id:
1180
- affordanceMesh = this._affordanceMeshes.yAxisArrow;
1181
- nextDragAction = DRAG_ACTIONS.yTranslate;
1182
- break;
1183
-
1184
- case this._displayMeshes.zAxisArrowHandle.id:
1185
- affordanceMesh = this._affordanceMeshes.zAxisArrow;
1186
- nextDragAction = DRAG_ACTIONS.zTranslate;
1187
- break;
1188
-
1189
- case this._displayMeshes.zAxisHandle.id:
1190
- affordanceMesh = this._affordanceMeshes.zAxisArrow;
1191
- nextDragAction = DRAG_ACTIONS.zTranslate;
1192
- break;
1193
-
1194
- case this._displayMeshes.xCurveHandle.id:
1195
- affordanceMesh = this._affordanceMeshes.xHoop;
1196
- nextDragAction = DRAG_ACTIONS.xRotate;
1197
- break;
1198
-
1199
- case this._displayMeshes.yCurveHandle.id:
1200
- affordanceMesh = this._affordanceMeshes.yHoop;
1201
- nextDragAction = DRAG_ACTIONS.yRotate;
1202
- break;
1203
-
1204
- case this._displayMeshes.zCurveHandle.id:
1205
- affordanceMesh = this._affordanceMeshes.zHoop;
1206
- nextDragAction = DRAG_ACTIONS.zRotate;
1207
- break;
1208
-
1209
- default:
1210
- nextDragAction = DRAG_ACTIONS.none;
1211
- return; // Not clicked an arrow or hoop
569
+ let deactivateActive = null;
570
+ let currentDrag = null;
571
+ cleanups.push(() => { if (currentDrag) { currentDrag.cleanup(); } });
572
+ const canvasPos = math.vec2();
573
+
574
+ const copyCanvasPos = (event, vec2) => {
575
+ vec2[0] = event.clientX;
576
+ vec2[1] = event.clientY;
577
+ transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
578
+ };
579
+
580
+ const pickHandler = (e) => {
581
+ copyCanvasPos(e, canvasPos);
582
+ const pickResult = viewer.scene.pick({ canvasPos: canvasPos });
583
+ const pickEntity = pickResult && pickResult.entity;
584
+ const pickId = pickEntity && pickEntity.id;
585
+ return (pickId in handlers) && handlers[pickId];
586
+ };
587
+
588
+ const startDrag = (event, matchesEvent) => {
589
+ const handler = pickHandler(matchesEvent(event));
590
+ if (handler) {
591
+ if (currentDrag) {
592
+ currentDrag.cleanup();
593
+ }
594
+
595
+ const dragAction = handler.initDragAction(canvasPos);
596
+ if (dragAction) {
597
+ cameraControl.pointerEnabled = false; // or .active = false ?
598
+ handler.setActivated(true);
599
+
600
+ currentDrag = {
601
+ onChange: event => {
602
+ const e = matchesEvent(event);
603
+ if (e) {
604
+ copyCanvasPos(e, canvasPos);
605
+ dragAction(canvasPos);
606
+ }
607
+ },
608
+ cleanup: function() {
609
+ currentDrag = null;
610
+ cameraControl.pointerEnabled = true; // or .active = true ?
611
+ handler.setActivated(false);
612
+ }
613
+ };
614
+ }
1212
615
  }
1213
- if (affordanceMesh) {
1214
- affordanceMesh.visible = true;
616
+ };
617
+
618
+ const addCanvasEventListener = (type, listener) => {
619
+ canvas.addEventListener(type, listener);
620
+ cleanups.push(() => canvas.removeEventListener(type, listener));
621
+ };
622
+
623
+ addCanvasEventListener("mousedown", (e) => {
624
+ e.preventDefault();
625
+ if (e.which === 1) {
626
+ startDrag(e, event => (event.which === 1) && event);
1215
627
  }
1216
- lastAffordanceMesh = affordanceMesh;
1217
- grabbed = true;
1218
628
  });
1219
629
 
1220
- this._onCameraControlHoverLeave = this._viewer.cameraControl.on("hoverOutEntity", (hit) => {
1221
- if (!this._visible) {
1222
- return;
1223
- }
1224
- if (lastAffordanceMesh) {
1225
- lastAffordanceMesh.visible = false;
630
+ addCanvasEventListener("mousemove", (e) => {
631
+ if (currentDrag) {
632
+ currentDrag.onChange(e);
633
+ } else {
634
+ if (deactivateActive) {
635
+ deactivateActive();
636
+ }
637
+ const handler = pickHandler(e);
638
+ if (handler) {
639
+ handler.setActivated(true);
640
+ deactivateActive = () => handler.setActivated(false);
641
+ } else {
642
+ deactivateActive = null;
643
+ }
1226
644
  }
1227
- lastAffordanceMesh = null;
1228
- nextDragAction = DRAG_ACTIONS.none;
1229
645
  });
1230
646
 
1231
- canvas.addEventListener("mousedown", this._canvasMouseDownListener = (e) => {
1232
- e.preventDefault();
1233
- if (!this._visible) {
1234
- return;
1235
- }
1236
- if (!grabbed) {
1237
- return;
1238
- }
1239
- this._viewer.cameraControl.pointerEnabled = false;
1240
- switch (e.which) {
1241
- case 1: // Left button
1242
- mouseDownLeft = true;
1243
- down = true;
1244
- var canvasPos = getClickCoordsWithinElement(e);
1245
- dragAction = nextDragAction;
1246
- lastCanvasPos[0] = canvasPos[0];
1247
- lastCanvasPos[1] = canvasPos[1];
1248
- break;
1249
-
1250
- default:
1251
- break;
647
+ addCanvasEventListener("mouseup", (e) => {
648
+ if (currentDrag) {
649
+ currentDrag.onChange(e);
650
+ currentDrag.cleanup();
1252
651
  }
1253
652
  });
1254
653
 
1255
- canvas.addEventListener("mousemove", this._canvasMouseMoveListener = (e) => {
1256
- if (!this._visible) {
1257
- return;
1258
- }
1259
- if (!down) {
1260
- return;
1261
- }
1262
- var canvasPos = getClickCoordsWithinElement(e);
1263
- const x = canvasPos[0];
1264
- const y = canvasPos[1];
1265
-
1266
- switch (dragAction) {
1267
- case DRAG_ACTIONS.xTranslate:
1268
- dragTranslateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos);
1269
- break;
1270
- case DRAG_ACTIONS.yTranslate:
1271
- dragTranslateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos);
1272
- break;
1273
- case DRAG_ACTIONS.zTranslate:
1274
- dragTranslateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos);
1275
- break;
1276
- case DRAG_ACTIONS.xRotate:
1277
- dragRotateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos);
1278
- break;
1279
- case DRAG_ACTIONS.yRotate:
1280
- dragRotateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos);
1281
- break;
1282
- case DRAG_ACTIONS.zRotate:
1283
- dragRotateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos);
1284
- break;
654
+
655
+ addCanvasEventListener("touchstart", event => {
656
+ event.preventDefault();
657
+ if (event.touches.length === 1)
658
+ {
659
+ const touchStartId = event.touches[0].identifier;
660
+ startDrag(event, event => [...event.changedTouches].find(e => e.identifier === touchStartId));
1285
661
  }
662
+ });
1286
663
 
1287
- lastCanvasPos[0] = x;
1288
- lastCanvasPos[1] = y;
664
+ addCanvasEventListener("touchmove", event => {
665
+ event.preventDefault();
666
+ currentDrag && currentDrag.onChange(event);
1289
667
  });
1290
668
 
1291
- canvas.addEventListener("mouseup", this._canvasMouseUpListener = (e) => {
1292
- if (!this._visible) {
1293
- return;
1294
- }
1295
- this._viewer.cameraControl.pointerEnabled = true;
1296
- if (!down) {
1297
- return;
669
+ addCanvasEventListener("touchend", event => {
670
+ event.preventDefault();
671
+ if (currentDrag) {
672
+ currentDrag.onChange(event);
673
+ currentDrag.cleanup();
1298
674
  }
1299
- switch (e.which) {
1300
- case 1: // Left button
1301
- mouseDownLeft = false;
1302
- break;
1303
- case 2: // Middle/both buttons
1304
- mouseDownMiddle = false;
1305
- break;
1306
- case 3: // Right button
1307
- mouseDownRight = false;
1308
- break;
1309
- default:
1310
- break;
1311
- }
1312
- down = false;
1313
- grabbed = false;
1314
675
  });
676
+ }
1315
677
 
1316
- canvas.addEventListener("wheel", this._canvasWheelListener = (e) => {
1317
- if (!this._visible) {
1318
- return;
1319
- }
1320
- var delta = Math.max(-1, Math.min(1, -e.deltaY * 40));
1321
- if (delta === 0) {
1322
- return;
678
+ this._unbindSectionPlane = () => { };
679
+
680
+ this.__setSectionPlane = sectionPlane => {
681
+ this.id = sectionPlane.id;
682
+ this._sectionPlane = sectionPlane;
683
+ const setPosFromSectionPlane = () => setPos(sectionPlane.pos);
684
+ const setDirFromSectionPlane = () => rootNode.quaternion = math.vec3PairToQuaternion(zeroVec, sectionPlane.dir, quat);
685
+ setPosFromSectionPlane();
686
+ setDirFromSectionPlane();
687
+ const onSectionPlanePos = sectionPlane.on("pos", setPosFromSectionPlane);
688
+ const onSectionPlaneDir = sectionPlane.on("dir", () => {
689
+ if (!ignoreNextSectionPlaneDirUpdate) {
690
+ setDirFromSectionPlane();
691
+ } else {
692
+ ignoreNextSectionPlaneDirUpdate = false;
1323
693
  }
1324
694
  });
1325
- }
695
+
696
+ this._unbindSectionPlane = () => {
697
+ this.id = null;
698
+ this._sectionPlane = null;
699
+ sectionPlane.off(onSectionPlanePos);
700
+ sectionPlane.off(onSectionPlaneDir);
701
+ this._unbindSectionPlane = () => { };
702
+ };
703
+ };
704
+
705
+ this.__destroy = () => {
706
+ cleanups.forEach(c => c());
707
+ this._unbindSectionPlane();
708
+ rootNode.destroy();
709
+ this._displayMeshes = [ ];
710
+ for (let id in handlers) {
711
+ delete handlers[id];
712
+ }
713
+ };
1326
714
  }
1327
715
 
1328
716
  _destroy() {
1329
- this._unbindEvents();
1330
- this._destroyNodes();
717
+ this.__destroy();
1331
718
  }
1332
719
 
1333
- _unbindEvents() {
1334
-
1335
- const viewer = this._viewer;
1336
- const scene = viewer.scene;
1337
- const canvas = scene.canvas.canvas;
1338
- const camera = viewer.camera;
1339
- const cameraControl = viewer.cameraControl;
1340
-
1341
- scene.off(this._onSceneTick);
720
+ /**
721
+ * Called by SectionPlanesPlugin to assign this Control to a SectionPlane.
722
+ * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool.
723
+ * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to.
724
+ * @private
725
+ */
726
+ _setSectionPlane(sectionPlane) {
727
+ this._unbindSectionPlane();
728
+ if (sectionPlane) {
729
+ this.__setSectionPlane(sectionPlane);
730
+ }
731
+ }
1342
732
 
1343
- canvas.removeEventListener("mousedown", this._canvasMouseDownListener);
1344
- canvas.removeEventListener("mousemove", this._canvasMouseMoveListener);
1345
- canvas.removeEventListener("mouseup", this._canvasMouseUpListener);
1346
- canvas.removeEventListener("wheel", this._canvasWheelListener);
733
+ /**
734
+ * Gets the {@link SectionPlane} controlled by this Control.
735
+ * @returns {SectionPlane} The SectionPlane.
736
+ */
737
+ get sectionPlane() {
738
+ return this._sectionPlane;
739
+ }
1347
740
 
1348
- camera.off(this._onCameraViewMatrix);
1349
- camera.off(this._onCameraProjMatrix);
741
+ /**
742
+ * Sets if this Control is visible.
743
+ *
744
+ * @type {Boolean}
745
+ */
746
+ setVisible(visible = true) {
747
+ if (this._visible !== visible) {
748
+ this._visible = visible;
749
+ this._displayMeshes.forEach(m => m.visible = visible);
750
+ }
751
+ }
1350
752
 
1351
- cameraControl.off(this._onCameraControlHover);
1352
- cameraControl.off(this._onCameraControlHoverLeave);
753
+ /**
754
+ * Gets if this Control is visible.
755
+ *
756
+ * @type {Boolean}
757
+ */
758
+ getVisible() {
759
+ return this._visible;
1353
760
  }
1354
761
 
1355
- _destroyNodes() {
1356
- this._setSectionPlane(null);
1357
- this._rootNode.destroy();
1358
- this._displayMeshes = {};
1359
- this._affordanceMeshes = {};
762
+ /**
763
+ * Sets if this Control is culled. This is called by SectionPlanesPlugin to
764
+ * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot().
765
+ * @param culled
766
+ */
767
+ setCulled(culled) {
768
+ this._displayMeshes.forEach(m => m.culled = culled);
1360
769
  }
1361
770
  }
1362
771
 
1363
- export {Control};
772
+ export {Control};