@2112-lab/central-plant 0.1.0

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 (54) hide show
  1. package/README.md +0 -0
  2. package/dist/bundle/index.js +14259 -0
  3. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +353 -0
  4. package/dist/cjs/node_modules/three/examples/jsm/controls/OrbitControls.js +1292 -0
  5. package/dist/cjs/node_modules/three/examples/jsm/controls/TransformControls.js +1543 -0
  6. package/dist/cjs/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4374 -0
  7. package/dist/cjs/node_modules/three/examples/jsm/loaders/RGBELoader.js +465 -0
  8. package/dist/cjs/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +117 -0
  9. package/dist/cjs/src/ConnectionManager.js +114 -0
  10. package/dist/cjs/src/Pathfinder.js +88 -0
  11. package/dist/cjs/src/animationManager.js +121 -0
  12. package/dist/cjs/src/componentManager.js +151 -0
  13. package/dist/cjs/src/debugLogger.js +176 -0
  14. package/dist/cjs/src/disposalManager.js +185 -0
  15. package/dist/cjs/src/environmentManager.js +1015 -0
  16. package/dist/cjs/src/hotReloadManager.js +252 -0
  17. package/dist/cjs/src/index.js +126 -0
  18. package/dist/cjs/src/keyboardControlsManager.js +206 -0
  19. package/dist/cjs/src/modelPreloader.js +360 -0
  20. package/dist/cjs/src/nameUtils.js +106 -0
  21. package/dist/cjs/src/pathfindingManager.js +321 -0
  22. package/dist/cjs/src/performanceMonitor.js +718 -0
  23. package/dist/cjs/src/sceneExportManager.js +292 -0
  24. package/dist/cjs/src/sceneInitializationManager.js +540 -0
  25. package/dist/cjs/src/sceneOperationsManager.js +560 -0
  26. package/dist/cjs/src/textureConfig.js +195 -0
  27. package/dist/cjs/src/transformControlsManager.js +851 -0
  28. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +328 -0
  29. package/dist/esm/node_modules/three/examples/jsm/controls/OrbitControls.js +1287 -0
  30. package/dist/esm/node_modules/three/examples/jsm/controls/TransformControls.js +1537 -0
  31. package/dist/esm/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4370 -0
  32. package/dist/esm/node_modules/three/examples/jsm/loaders/RGBELoader.js +461 -0
  33. package/dist/esm/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +113 -0
  34. package/dist/esm/src/ConnectionManager.js +110 -0
  35. package/dist/esm/src/Pathfinder.js +84 -0
  36. package/dist/esm/src/animationManager.js +112 -0
  37. package/dist/esm/src/componentManager.js +123 -0
  38. package/dist/esm/src/debugLogger.js +167 -0
  39. package/dist/esm/src/disposalManager.js +155 -0
  40. package/dist/esm/src/environmentManager.js +989 -0
  41. package/dist/esm/src/hotReloadManager.js +244 -0
  42. package/dist/esm/src/index.js +117 -0
  43. package/dist/esm/src/keyboardControlsManager.js +196 -0
  44. package/dist/esm/src/modelPreloader.js +337 -0
  45. package/dist/esm/src/nameUtils.js +99 -0
  46. package/dist/esm/src/pathfindingManager.js +295 -0
  47. package/dist/esm/src/performanceMonitor.js +712 -0
  48. package/dist/esm/src/sceneExportManager.js +286 -0
  49. package/dist/esm/src/sceneInitializationManager.js +513 -0
  50. package/dist/esm/src/sceneOperationsManager.js +536 -0
  51. package/dist/esm/src/textureConfig.js +168 -0
  52. package/dist/esm/src/transformControlsManager.js +827 -0
  53. package/dist/index.d.ts +259 -0
  54. package/package.json +53 -0
@@ -0,0 +1,1537 @@
1
+ import { Raycaster, Vector3, Quaternion, Object3D, Euler, Matrix4, MeshBasicMaterial, LineBasicMaterial, CylinderGeometry, BoxGeometry, BufferGeometry, Float32BufferAttribute, Mesh, OctahedronGeometry, Line, SphereGeometry, TorusGeometry, PlaneGeometry, DoubleSide } from 'three';
2
+
3
+ const _raycaster = new Raycaster();
4
+
5
+ const _tempVector = new Vector3();
6
+ const _tempVector2 = new Vector3();
7
+ const _tempQuaternion = new Quaternion();
8
+ const _unit = {
9
+ X: new Vector3( 1, 0, 0 ),
10
+ Y: new Vector3( 0, 1, 0 ),
11
+ Z: new Vector3( 0, 0, 1 )
12
+ };
13
+
14
+ const _changeEvent = { type: 'change' };
15
+ const _mouseDownEvent = { type: 'mouseDown' };
16
+ const _mouseUpEvent = { type: 'mouseUp', mode: null };
17
+ const _objectChangeEvent = { type: 'objectChange' };
18
+
19
+ class TransformControls extends Object3D {
20
+
21
+ constructor( camera, domElement ) {
22
+
23
+ super();
24
+
25
+ if ( domElement === undefined ) {
26
+
27
+ console.warn( 'THREE.TransformControls: The second parameter "domElement" is now mandatory.' );
28
+ domElement = document;
29
+
30
+ }
31
+
32
+ this.isTransformControls = true;
33
+
34
+ this.visible = false;
35
+ this.domElement = domElement;
36
+ this.domElement.style.touchAction = 'none'; // disable touch scroll
37
+
38
+ const _gizmo = new TransformControlsGizmo();
39
+ this._gizmo = _gizmo;
40
+ this.add( _gizmo );
41
+
42
+ const _plane = new TransformControlsPlane();
43
+ this._plane = _plane;
44
+ this.add( _plane );
45
+
46
+ const scope = this;
47
+
48
+ // Defined getter, setter and store for a property
49
+ function defineProperty( propName, defaultValue ) {
50
+
51
+ let propValue = defaultValue;
52
+
53
+ Object.defineProperty( scope, propName, {
54
+
55
+ get: function () {
56
+
57
+ return propValue !== undefined ? propValue : defaultValue;
58
+
59
+ },
60
+
61
+ set: function ( value ) {
62
+
63
+ if ( propValue !== value ) {
64
+
65
+ propValue = value;
66
+ _plane[ propName ] = value;
67
+ _gizmo[ propName ] = value;
68
+
69
+ scope.dispatchEvent( { type: propName + '-changed', value: value } );
70
+ scope.dispatchEvent( _changeEvent );
71
+
72
+ }
73
+
74
+ }
75
+
76
+ } );
77
+
78
+ scope[ propName ] = defaultValue;
79
+ _plane[ propName ] = defaultValue;
80
+ _gizmo[ propName ] = defaultValue;
81
+
82
+ }
83
+
84
+ // Define properties with getters/setter
85
+ // Setting the defined property will automatically trigger change event
86
+ // Defined properties are passed down to gizmo and plane
87
+
88
+ defineProperty( 'camera', camera );
89
+ defineProperty( 'object', undefined );
90
+ defineProperty( 'enabled', true );
91
+ defineProperty( 'axis', null );
92
+ defineProperty( 'mode', 'translate' );
93
+ defineProperty( 'translationSnap', null );
94
+ defineProperty( 'rotationSnap', null );
95
+ defineProperty( 'scaleSnap', null );
96
+ defineProperty( 'space', 'world' );
97
+ defineProperty( 'size', 1 );
98
+ defineProperty( 'dragging', false );
99
+ defineProperty( 'showX', true );
100
+ defineProperty( 'showY', true );
101
+ defineProperty( 'showZ', true );
102
+
103
+ // Reusable utility variables
104
+
105
+ const worldPosition = new Vector3();
106
+ const worldPositionStart = new Vector3();
107
+ const worldQuaternion = new Quaternion();
108
+ const worldQuaternionStart = new Quaternion();
109
+ const cameraPosition = new Vector3();
110
+ const cameraQuaternion = new Quaternion();
111
+ const pointStart = new Vector3();
112
+ const pointEnd = new Vector3();
113
+ const rotationAxis = new Vector3();
114
+ const rotationAngle = 0;
115
+ const eye = new Vector3();
116
+
117
+ // TODO: remove properties unused in plane and gizmo
118
+
119
+ defineProperty( 'worldPosition', worldPosition );
120
+ defineProperty( 'worldPositionStart', worldPositionStart );
121
+ defineProperty( 'worldQuaternion', worldQuaternion );
122
+ defineProperty( 'worldQuaternionStart', worldQuaternionStart );
123
+ defineProperty( 'cameraPosition', cameraPosition );
124
+ defineProperty( 'cameraQuaternion', cameraQuaternion );
125
+ defineProperty( 'pointStart', pointStart );
126
+ defineProperty( 'pointEnd', pointEnd );
127
+ defineProperty( 'rotationAxis', rotationAxis );
128
+ defineProperty( 'rotationAngle', rotationAngle );
129
+ defineProperty( 'eye', eye );
130
+
131
+ this._offset = new Vector3();
132
+ this._startNorm = new Vector3();
133
+ this._endNorm = new Vector3();
134
+ this._cameraScale = new Vector3();
135
+
136
+ this._parentPosition = new Vector3();
137
+ this._parentQuaternion = new Quaternion();
138
+ this._parentQuaternionInv = new Quaternion();
139
+ this._parentScale = new Vector3();
140
+
141
+ this._worldScaleStart = new Vector3();
142
+ this._worldQuaternionInv = new Quaternion();
143
+ this._worldScale = new Vector3();
144
+
145
+ this._positionStart = new Vector3();
146
+ this._quaternionStart = new Quaternion();
147
+ this._scaleStart = new Vector3();
148
+
149
+ this._getPointer = getPointer.bind( this );
150
+ this._onPointerDown = onPointerDown.bind( this );
151
+ this._onPointerHover = onPointerHover.bind( this );
152
+ this._onPointerMove = onPointerMove.bind( this );
153
+ this._onPointerUp = onPointerUp.bind( this );
154
+
155
+ this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
156
+ this.domElement.addEventListener( 'pointermove', this._onPointerHover );
157
+ this.domElement.addEventListener( 'pointerup', this._onPointerUp );
158
+
159
+ }
160
+
161
+ // updateMatrixWorld updates key transformation variables
162
+ updateMatrixWorld() {
163
+
164
+ if ( this.object !== undefined ) {
165
+
166
+ this.object.updateMatrixWorld();
167
+
168
+ if ( this.object.parent === null ) {
169
+
170
+ console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' );
171
+
172
+ } else {
173
+
174
+ this.object.parent.matrixWorld.decompose( this._parentPosition, this._parentQuaternion, this._parentScale );
175
+
176
+ }
177
+
178
+ this.object.matrixWorld.decompose( this.worldPosition, this.worldQuaternion, this._worldScale );
179
+
180
+ this._parentQuaternionInv.copy( this._parentQuaternion ).invert();
181
+ this._worldQuaternionInv.copy( this.worldQuaternion ).invert();
182
+
183
+ }
184
+
185
+ this.camera.updateMatrixWorld();
186
+ this.camera.matrixWorld.decompose( this.cameraPosition, this.cameraQuaternion, this._cameraScale );
187
+
188
+ if ( this.camera.isOrthographicCamera ) {
189
+
190
+ this.camera.getWorldDirection( this.eye ).negate();
191
+
192
+ } else {
193
+
194
+ this.eye.copy( this.cameraPosition ).sub( this.worldPosition ).normalize();
195
+
196
+ }
197
+
198
+ super.updateMatrixWorld( this );
199
+
200
+ }
201
+
202
+ pointerHover( pointer ) {
203
+
204
+ if ( this.object === undefined || this.dragging === true ) return;
205
+
206
+ _raycaster.setFromCamera( pointer, this.camera );
207
+
208
+ const intersect = intersectObjectWithRay( this._gizmo.picker[ this.mode ], _raycaster );
209
+
210
+ if ( intersect ) {
211
+
212
+ this.axis = intersect.object.name;
213
+
214
+ } else {
215
+
216
+ this.axis = null;
217
+
218
+ }
219
+
220
+ }
221
+
222
+ pointerDown( pointer ) {
223
+
224
+ if ( this.object === undefined || this.dragging === true || pointer.button !== 0 ) return;
225
+
226
+ if ( this.axis !== null ) {
227
+
228
+ _raycaster.setFromCamera( pointer, this.camera );
229
+
230
+ const planeIntersect = intersectObjectWithRay( this._plane, _raycaster, true );
231
+
232
+ if ( planeIntersect ) {
233
+
234
+ this.object.updateMatrixWorld();
235
+ this.object.parent.updateMatrixWorld();
236
+
237
+ this._positionStart.copy( this.object.position );
238
+ this._quaternionStart.copy( this.object.quaternion );
239
+ this._scaleStart.copy( this.object.scale );
240
+
241
+ this.object.matrixWorld.decompose( this.worldPositionStart, this.worldQuaternionStart, this._worldScaleStart );
242
+
243
+ this.pointStart.copy( planeIntersect.point ).sub( this.worldPositionStart );
244
+
245
+ }
246
+
247
+ this.dragging = true;
248
+ _mouseDownEvent.mode = this.mode;
249
+ this.dispatchEvent( _mouseDownEvent );
250
+
251
+ }
252
+
253
+ }
254
+
255
+ pointerMove( pointer ) {
256
+
257
+ const axis = this.axis;
258
+ const mode = this.mode;
259
+ const object = this.object;
260
+ let space = this.space;
261
+
262
+ if ( mode === 'scale' ) {
263
+
264
+ space = 'local';
265
+
266
+ } else if ( axis === 'E' || axis === 'XYZE' || axis === 'XYZ' ) {
267
+
268
+ space = 'world';
269
+
270
+ }
271
+
272
+ if ( object === undefined || axis === null || this.dragging === false || pointer.button !== - 1 ) return;
273
+
274
+ _raycaster.setFromCamera( pointer, this.camera );
275
+
276
+ const planeIntersect = intersectObjectWithRay( this._plane, _raycaster, true );
277
+
278
+ if ( ! planeIntersect ) return;
279
+
280
+ this.pointEnd.copy( planeIntersect.point ).sub( this.worldPositionStart );
281
+
282
+ if ( mode === 'translate' ) {
283
+
284
+ // Apply translate
285
+
286
+ this._offset.copy( this.pointEnd ).sub( this.pointStart );
287
+
288
+ if ( space === 'local' && axis !== 'XYZ' ) {
289
+
290
+ this._offset.applyQuaternion( this._worldQuaternionInv );
291
+
292
+ }
293
+
294
+ if ( axis.indexOf( 'X' ) === - 1 ) this._offset.x = 0;
295
+ if ( axis.indexOf( 'Y' ) === - 1 ) this._offset.y = 0;
296
+ if ( axis.indexOf( 'Z' ) === - 1 ) this._offset.z = 0;
297
+
298
+ if ( space === 'local' && axis !== 'XYZ' ) {
299
+
300
+ this._offset.applyQuaternion( this._quaternionStart ).divide( this._parentScale );
301
+
302
+ } else {
303
+
304
+ this._offset.applyQuaternion( this._parentQuaternionInv ).divide( this._parentScale );
305
+
306
+ }
307
+
308
+ object.position.copy( this._offset ).add( this._positionStart );
309
+
310
+ // Apply translation snap
311
+
312
+ if ( this.translationSnap ) {
313
+
314
+ if ( space === 'local' ) {
315
+
316
+ object.position.applyQuaternion( _tempQuaternion.copy( this._quaternionStart ).invert() );
317
+
318
+ if ( axis.search( 'X' ) !== - 1 ) {
319
+
320
+ object.position.x = Math.round( object.position.x / this.translationSnap ) * this.translationSnap;
321
+
322
+ }
323
+
324
+ if ( axis.search( 'Y' ) !== - 1 ) {
325
+
326
+ object.position.y = Math.round( object.position.y / this.translationSnap ) * this.translationSnap;
327
+
328
+ }
329
+
330
+ if ( axis.search( 'Z' ) !== - 1 ) {
331
+
332
+ object.position.z = Math.round( object.position.z / this.translationSnap ) * this.translationSnap;
333
+
334
+ }
335
+
336
+ object.position.applyQuaternion( this._quaternionStart );
337
+
338
+ }
339
+
340
+ if ( space === 'world' ) {
341
+
342
+ if ( object.parent ) {
343
+
344
+ object.position.add( _tempVector.setFromMatrixPosition( object.parent.matrixWorld ) );
345
+
346
+ }
347
+
348
+ if ( axis.search( 'X' ) !== - 1 ) {
349
+
350
+ object.position.x = Math.round( object.position.x / this.translationSnap ) * this.translationSnap;
351
+
352
+ }
353
+
354
+ if ( axis.search( 'Y' ) !== - 1 ) {
355
+
356
+ object.position.y = Math.round( object.position.y / this.translationSnap ) * this.translationSnap;
357
+
358
+ }
359
+
360
+ if ( axis.search( 'Z' ) !== - 1 ) {
361
+
362
+ object.position.z = Math.round( object.position.z / this.translationSnap ) * this.translationSnap;
363
+
364
+ }
365
+
366
+ if ( object.parent ) {
367
+
368
+ object.position.sub( _tempVector.setFromMatrixPosition( object.parent.matrixWorld ) );
369
+
370
+ }
371
+
372
+ }
373
+
374
+ }
375
+
376
+ } else if ( mode === 'scale' ) {
377
+
378
+ if ( axis.search( 'XYZ' ) !== - 1 ) {
379
+
380
+ let d = this.pointEnd.length() / this.pointStart.length();
381
+
382
+ if ( this.pointEnd.dot( this.pointStart ) < 0 ) d *= - 1;
383
+
384
+ _tempVector2.set( d, d, d );
385
+
386
+ } else {
387
+
388
+ _tempVector.copy( this.pointStart );
389
+ _tempVector2.copy( this.pointEnd );
390
+
391
+ _tempVector.applyQuaternion( this._worldQuaternionInv );
392
+ _tempVector2.applyQuaternion( this._worldQuaternionInv );
393
+
394
+ _tempVector2.divide( _tempVector );
395
+
396
+ if ( axis.search( 'X' ) === - 1 ) {
397
+
398
+ _tempVector2.x = 1;
399
+
400
+ }
401
+
402
+ if ( axis.search( 'Y' ) === - 1 ) {
403
+
404
+ _tempVector2.y = 1;
405
+
406
+ }
407
+
408
+ if ( axis.search( 'Z' ) === - 1 ) {
409
+
410
+ _tempVector2.z = 1;
411
+
412
+ }
413
+
414
+ }
415
+
416
+ // Apply scale
417
+
418
+ object.scale.copy( this._scaleStart ).multiply( _tempVector2 );
419
+
420
+ if ( this.scaleSnap ) {
421
+
422
+ if ( axis.search( 'X' ) !== - 1 ) {
423
+
424
+ object.scale.x = Math.round( object.scale.x / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
425
+
426
+ }
427
+
428
+ if ( axis.search( 'Y' ) !== - 1 ) {
429
+
430
+ object.scale.y = Math.round( object.scale.y / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
431
+
432
+ }
433
+
434
+ if ( axis.search( 'Z' ) !== - 1 ) {
435
+
436
+ object.scale.z = Math.round( object.scale.z / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
437
+
438
+ }
439
+
440
+ }
441
+
442
+ } else if ( mode === 'rotate' ) {
443
+
444
+ this._offset.copy( this.pointEnd ).sub( this.pointStart );
445
+
446
+ const ROTATION_SPEED = 20 / this.worldPosition.distanceTo( _tempVector.setFromMatrixPosition( this.camera.matrixWorld ) );
447
+
448
+ if ( axis === 'E' ) {
449
+
450
+ this.rotationAxis.copy( this.eye );
451
+ this.rotationAngle = this.pointEnd.angleTo( this.pointStart );
452
+
453
+ this._startNorm.copy( this.pointStart ).normalize();
454
+ this._endNorm.copy( this.pointEnd ).normalize();
455
+
456
+ this.rotationAngle *= ( this._endNorm.cross( this._startNorm ).dot( this.eye ) < 0 ? 1 : - 1 );
457
+
458
+ } else if ( axis === 'XYZE' ) {
459
+
460
+ this.rotationAxis.copy( this._offset ).cross( this.eye ).normalize();
461
+ this.rotationAngle = this._offset.dot( _tempVector.copy( this.rotationAxis ).cross( this.eye ) ) * ROTATION_SPEED;
462
+
463
+ } else if ( axis === 'X' || axis === 'Y' || axis === 'Z' ) {
464
+
465
+ this.rotationAxis.copy( _unit[ axis ] );
466
+
467
+ _tempVector.copy( _unit[ axis ] );
468
+
469
+ if ( space === 'local' ) {
470
+
471
+ _tempVector.applyQuaternion( this.worldQuaternion );
472
+
473
+ }
474
+
475
+ this.rotationAngle = this._offset.dot( _tempVector.cross( this.eye ).normalize() ) * ROTATION_SPEED;
476
+
477
+ }
478
+
479
+ // Apply rotation snap
480
+
481
+ if ( this.rotationSnap ) this.rotationAngle = Math.round( this.rotationAngle / this.rotationSnap ) * this.rotationSnap;
482
+
483
+ // Apply rotate
484
+ if ( space === 'local' && axis !== 'E' && axis !== 'XYZE' ) {
485
+
486
+ object.quaternion.copy( this._quaternionStart );
487
+ object.quaternion.multiply( _tempQuaternion.setFromAxisAngle( this.rotationAxis, this.rotationAngle ) ).normalize();
488
+
489
+ } else {
490
+
491
+ this.rotationAxis.applyQuaternion( this._parentQuaternionInv );
492
+ object.quaternion.copy( _tempQuaternion.setFromAxisAngle( this.rotationAxis, this.rotationAngle ) );
493
+ object.quaternion.multiply( this._quaternionStart ).normalize();
494
+
495
+ }
496
+
497
+ }
498
+
499
+ this.dispatchEvent( _changeEvent );
500
+ this.dispatchEvent( _objectChangeEvent );
501
+
502
+ }
503
+
504
+ pointerUp( pointer ) {
505
+
506
+ if ( pointer.button !== 0 ) return;
507
+
508
+ if ( this.dragging && ( this.axis !== null ) ) {
509
+
510
+ _mouseUpEvent.mode = this.mode;
511
+ this.dispatchEvent( _mouseUpEvent );
512
+
513
+ }
514
+
515
+ this.dragging = false;
516
+ this.axis = null;
517
+
518
+ }
519
+
520
+ dispose() {
521
+
522
+ this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
523
+ this.domElement.removeEventListener( 'pointermove', this._onPointerHover );
524
+ this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
525
+ this.domElement.removeEventListener( 'pointerup', this._onPointerUp );
526
+
527
+ this.traverse( function ( child ) {
528
+
529
+ if ( child.geometry ) child.geometry.dispose();
530
+ if ( child.material ) child.material.dispose();
531
+
532
+ } );
533
+
534
+ }
535
+
536
+ // Set current object
537
+ attach( object ) {
538
+
539
+ this.object = object;
540
+ this.visible = true;
541
+
542
+ return this;
543
+
544
+ }
545
+
546
+ // Detach from object
547
+ detach() {
548
+
549
+ this.object = undefined;
550
+ this.visible = false;
551
+ this.axis = null;
552
+
553
+ return this;
554
+
555
+ }
556
+
557
+ reset() {
558
+
559
+ if ( ! this.enabled ) return;
560
+
561
+ if ( this.dragging ) {
562
+
563
+ this.object.position.copy( this._positionStart );
564
+ this.object.quaternion.copy( this._quaternionStart );
565
+ this.object.scale.copy( this._scaleStart );
566
+
567
+ this.dispatchEvent( _changeEvent );
568
+ this.dispatchEvent( _objectChangeEvent );
569
+
570
+ this.pointStart.copy( this.pointEnd );
571
+
572
+ }
573
+
574
+ }
575
+
576
+ getRaycaster() {
577
+
578
+ return _raycaster;
579
+
580
+ }
581
+
582
+ // TODO: deprecate
583
+
584
+ getMode() {
585
+
586
+ return this.mode;
587
+
588
+ }
589
+
590
+ setMode( mode ) {
591
+
592
+ this.mode = mode;
593
+
594
+ }
595
+
596
+ setTranslationSnap( translationSnap ) {
597
+
598
+ this.translationSnap = translationSnap;
599
+
600
+ }
601
+
602
+ setRotationSnap( rotationSnap ) {
603
+
604
+ this.rotationSnap = rotationSnap;
605
+
606
+ }
607
+
608
+ setScaleSnap( scaleSnap ) {
609
+
610
+ this.scaleSnap = scaleSnap;
611
+
612
+ }
613
+
614
+ setSize( size ) {
615
+
616
+ this.size = size;
617
+
618
+ }
619
+
620
+ setSpace( space ) {
621
+
622
+ this.space = space;
623
+
624
+ }
625
+
626
+ }
627
+
628
+ // mouse / touch event handlers
629
+
630
+ function getPointer( event ) {
631
+
632
+ if ( this.domElement.ownerDocument.pointerLockElement ) {
633
+
634
+ return {
635
+ x: 0,
636
+ y: 0,
637
+ button: event.button
638
+ };
639
+
640
+ } else {
641
+
642
+ const rect = this.domElement.getBoundingClientRect();
643
+
644
+ return {
645
+ x: ( event.clientX - rect.left ) / rect.width * 2 - 1,
646
+ y: - ( event.clientY - rect.top ) / rect.height * 2 + 1,
647
+ button: event.button
648
+ };
649
+
650
+ }
651
+
652
+ }
653
+
654
+ function onPointerHover( event ) {
655
+
656
+ if ( ! this.enabled ) return;
657
+
658
+ switch ( event.pointerType ) {
659
+
660
+ case 'mouse':
661
+ case 'pen':
662
+ this.pointerHover( this._getPointer( event ) );
663
+ break;
664
+
665
+ }
666
+
667
+ }
668
+
669
+ function onPointerDown( event ) {
670
+
671
+ if ( ! this.enabled ) return;
672
+
673
+ if ( ! document.pointerLockElement ) {
674
+
675
+ this.domElement.setPointerCapture( event.pointerId );
676
+
677
+ }
678
+
679
+ this.domElement.addEventListener( 'pointermove', this._onPointerMove );
680
+
681
+ this.pointerHover( this._getPointer( event ) );
682
+ this.pointerDown( this._getPointer( event ) );
683
+
684
+ }
685
+
686
+ function onPointerMove( event ) {
687
+
688
+ if ( ! this.enabled ) return;
689
+
690
+ this.pointerMove( this._getPointer( event ) );
691
+
692
+ }
693
+
694
+ function onPointerUp( event ) {
695
+
696
+ if ( ! this.enabled ) return;
697
+
698
+ this.domElement.releasePointerCapture( event.pointerId );
699
+
700
+ this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
701
+
702
+ this.pointerUp( this._getPointer( event ) );
703
+
704
+ }
705
+
706
+ function intersectObjectWithRay( object, raycaster, includeInvisible ) {
707
+
708
+ const allIntersections = raycaster.intersectObject( object, true );
709
+
710
+ for ( let i = 0; i < allIntersections.length; i ++ ) {
711
+
712
+ if ( allIntersections[ i ].object.visible || includeInvisible ) {
713
+
714
+ return allIntersections[ i ];
715
+
716
+ }
717
+
718
+ }
719
+
720
+ return false;
721
+
722
+ }
723
+
724
+ //
725
+
726
+ // Reusable utility variables
727
+
728
+ const _tempEuler = new Euler();
729
+ const _alignVector = new Vector3( 0, 1, 0 );
730
+ const _zeroVector = new Vector3( 0, 0, 0 );
731
+ const _lookAtMatrix = new Matrix4();
732
+ const _tempQuaternion2 = new Quaternion();
733
+ const _identityQuaternion = new Quaternion();
734
+ const _dirVector = new Vector3();
735
+ const _tempMatrix = new Matrix4();
736
+
737
+ const _unitX = new Vector3( 1, 0, 0 );
738
+ const _unitY = new Vector3( 0, 1, 0 );
739
+ const _unitZ = new Vector3( 0, 0, 1 );
740
+
741
+ const _v1 = new Vector3();
742
+ const _v2 = new Vector3();
743
+ const _v3 = new Vector3();
744
+
745
+ class TransformControlsGizmo extends Object3D {
746
+
747
+ constructor() {
748
+
749
+ super();
750
+
751
+ this.isTransformControlsGizmo = true;
752
+
753
+ this.type = 'TransformControlsGizmo';
754
+
755
+ // shared materials
756
+
757
+ const gizmoMaterial = new MeshBasicMaterial( {
758
+ depthTest: false,
759
+ depthWrite: false,
760
+ fog: false,
761
+ toneMapped: false,
762
+ transparent: true
763
+ } );
764
+
765
+ const gizmoLineMaterial = new LineBasicMaterial( {
766
+ depthTest: false,
767
+ depthWrite: false,
768
+ fog: false,
769
+ toneMapped: false,
770
+ transparent: true
771
+ } );
772
+
773
+ // Make unique material for each axis/color
774
+
775
+ const matInvisible = gizmoMaterial.clone();
776
+ matInvisible.opacity = 0.15;
777
+
778
+ const matHelper = gizmoLineMaterial.clone();
779
+ matHelper.opacity = 0.5;
780
+
781
+ const matRed = gizmoMaterial.clone();
782
+ matRed.color.setHex( 0xff0000 );
783
+
784
+ const matGreen = gizmoMaterial.clone();
785
+ matGreen.color.setHex( 0x00ff00 );
786
+
787
+ const matBlue = gizmoMaterial.clone();
788
+ matBlue.color.setHex( 0x0000ff );
789
+
790
+ const matRedTransparent = gizmoMaterial.clone();
791
+ matRedTransparent.color.setHex( 0xff0000 );
792
+ matRedTransparent.opacity = 0.5;
793
+
794
+ const matGreenTransparent = gizmoMaterial.clone();
795
+ matGreenTransparent.color.setHex( 0x00ff00 );
796
+ matGreenTransparent.opacity = 0.5;
797
+
798
+ const matBlueTransparent = gizmoMaterial.clone();
799
+ matBlueTransparent.color.setHex( 0x0000ff );
800
+ matBlueTransparent.opacity = 0.5;
801
+
802
+ const matWhiteTransparent = gizmoMaterial.clone();
803
+ matWhiteTransparent.opacity = 0.25;
804
+
805
+ const matYellowTransparent = gizmoMaterial.clone();
806
+ matYellowTransparent.color.setHex( 0xffff00 );
807
+ matYellowTransparent.opacity = 0.25;
808
+
809
+ const matYellow = gizmoMaterial.clone();
810
+ matYellow.color.setHex( 0xffff00 );
811
+
812
+ const matGray = gizmoMaterial.clone();
813
+ matGray.color.setHex( 0x787878 );
814
+
815
+ // reusable geometry
816
+
817
+ const arrowGeometry = new CylinderGeometry( 0, 0.04, 0.1, 12 );
818
+ arrowGeometry.translate( 0, 0.05, 0 );
819
+
820
+ const scaleHandleGeometry = new BoxGeometry( 0.08, 0.08, 0.08 );
821
+ scaleHandleGeometry.translate( 0, 0.04, 0 );
822
+
823
+ const lineGeometry = new BufferGeometry();
824
+ lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
825
+
826
+ const lineGeometry2 = new CylinderGeometry( 0.0075, 0.0075, 0.5, 3 );
827
+ lineGeometry2.translate( 0, 0.25, 0 );
828
+
829
+ function CircleGeometry( radius, arc ) {
830
+
831
+ const geometry = new TorusGeometry( radius, 0.0075, 3, 64, arc * Math.PI * 2 );
832
+ geometry.rotateY( Math.PI / 2 );
833
+ geometry.rotateX( Math.PI / 2 );
834
+ return geometry;
835
+
836
+ }
837
+
838
+ // Special geometry for transform helper. If scaled with position vector it spans from [0,0,0] to position
839
+
840
+ function TranslateHelperGeometry() {
841
+
842
+ const geometry = new BufferGeometry();
843
+
844
+ geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 1, 1, 1 ], 3 ) );
845
+
846
+ return geometry;
847
+
848
+ }
849
+
850
+ // Gizmo definitions - custom hierarchy definitions for setupGizmo() function
851
+
852
+ const gizmoTranslate = {
853
+ X: [
854
+ [ new Mesh( arrowGeometry, matRed ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
855
+ [ new Mesh( arrowGeometry, matRed ), [ - 0.5, 0, 0 ], [ 0, 0, Math.PI / 2 ]],
856
+ [ new Mesh( lineGeometry2, matRed ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]]
857
+ ],
858
+ Y: [
859
+ [ new Mesh( arrowGeometry, matGreen ), [ 0, 0.5, 0 ]],
860
+ [ new Mesh( arrowGeometry, matGreen ), [ 0, - 0.5, 0 ], [ Math.PI, 0, 0 ]],
861
+ [ new Mesh( lineGeometry2, matGreen ) ]
862
+ ],
863
+ Z: [
864
+ [ new Mesh( arrowGeometry, matBlue ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ]],
865
+ [ new Mesh( arrowGeometry, matBlue ), [ 0, 0, - 0.5 ], [ - Math.PI / 2, 0, 0 ]],
866
+ [ new Mesh( lineGeometry2, matBlue ), null, [ Math.PI / 2, 0, 0 ]]
867
+ ],
868
+ XYZ: [
869
+ [ new Mesh( new OctahedronGeometry( 0.1, 0 ), matWhiteTransparent.clone() ), [ 0, 0, 0 ]]
870
+ ],
871
+ XY: [
872
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matBlueTransparent.clone() ), [ 0.15, 0.15, 0 ]]
873
+ ],
874
+ YZ: [
875
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matRedTransparent.clone() ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
876
+ ],
877
+ XZ: [
878
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matGreenTransparent.clone() ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
879
+ ]
880
+ };
881
+
882
+ const pickerTranslate = {
883
+ X: [
884
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0.3, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
885
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ - 0.3, 0, 0 ], [ 0, 0, Math.PI / 2 ]]
886
+ ],
887
+ Y: [
888
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0.3, 0 ]],
889
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, - 0.3, 0 ], [ 0, 0, Math.PI ]]
890
+ ],
891
+ Z: [
892
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, 0.3 ], [ Math.PI / 2, 0, 0 ]],
893
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, - 0.3 ], [ - Math.PI / 2, 0, 0 ]]
894
+ ],
895
+ XYZ: [
896
+ [ new Mesh( new OctahedronGeometry( 0.2, 0 ), matInvisible ) ]
897
+ ],
898
+ XY: [
899
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0.15, 0 ]]
900
+ ],
901
+ YZ: [
902
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
903
+ ],
904
+ XZ: [
905
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
906
+ ]
907
+ };
908
+
909
+ const helperTranslate = {
910
+ START: [
911
+ [ new Mesh( new OctahedronGeometry( 0.01, 2 ), matHelper ), null, null, null, 'helper' ]
912
+ ],
913
+ END: [
914
+ [ new Mesh( new OctahedronGeometry( 0.01, 2 ), matHelper ), null, null, null, 'helper' ]
915
+ ],
916
+ DELTA: [
917
+ [ new Line( TranslateHelperGeometry(), matHelper ), null, null, null, 'helper' ]
918
+ ],
919
+ X: [
920
+ [ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
921
+ ],
922
+ Y: [
923
+ [ new Line( lineGeometry, matHelper.clone() ), [ 0, - 1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], 'helper' ]
924
+ ],
925
+ Z: [
926
+ [ new Line( lineGeometry, matHelper.clone() ), [ 0, 0, - 1e3 ], [ 0, - Math.PI / 2, 0 ], [ 1e6, 1, 1 ], 'helper' ]
927
+ ]
928
+ };
929
+
930
+ const gizmoRotate = {
931
+ XYZE: [
932
+ [ new Mesh( CircleGeometry( 0.5, 1 ), matGray ), null, [ 0, Math.PI / 2, 0 ]]
933
+ ],
934
+ X: [
935
+ [ new Mesh( CircleGeometry( 0.5, 0.5 ), matRed ) ]
936
+ ],
937
+ Y: [
938
+ [ new Mesh( CircleGeometry( 0.5, 0.5 ), matGreen ), null, [ 0, 0, - Math.PI / 2 ]]
939
+ ],
940
+ Z: [
941
+ [ new Mesh( CircleGeometry( 0.5, 0.5 ), matBlue ), null, [ 0, Math.PI / 2, 0 ]]
942
+ ],
943
+ E: [
944
+ [ new Mesh( CircleGeometry( 0.75, 1 ), matYellowTransparent ), null, [ 0, Math.PI / 2, 0 ]]
945
+ ]
946
+ };
947
+
948
+ const helperRotate = {
949
+ AXIS: [
950
+ [ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
951
+ ]
952
+ };
953
+
954
+ const pickerRotate = {
955
+ XYZE: [
956
+ [ new Mesh( new SphereGeometry( 0.25, 10, 8 ), matInvisible ) ]
957
+ ],
958
+ X: [
959
+ [ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ]],
960
+ ],
961
+ Y: [
962
+ [ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ]],
963
+ ],
964
+ Z: [
965
+ [ new Mesh( new TorusGeometry( 0.5, 0.1, 4, 24 ), matInvisible ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
966
+ ],
967
+ E: [
968
+ [ new Mesh( new TorusGeometry( 0.75, 0.1, 2, 24 ), matInvisible ) ]
969
+ ]
970
+ };
971
+
972
+ const gizmoScale = {
973
+ X: [
974
+ [ new Mesh( scaleHandleGeometry, matRed ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
975
+ [ new Mesh( lineGeometry2, matRed ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
976
+ [ new Mesh( scaleHandleGeometry, matRed ), [ - 0.5, 0, 0 ], [ 0, 0, Math.PI / 2 ]],
977
+ ],
978
+ Y: [
979
+ [ new Mesh( scaleHandleGeometry, matGreen ), [ 0, 0.5, 0 ]],
980
+ [ new Mesh( lineGeometry2, matGreen ) ],
981
+ [ new Mesh( scaleHandleGeometry, matGreen ), [ 0, - 0.5, 0 ], [ 0, 0, Math.PI ]],
982
+ ],
983
+ Z: [
984
+ [ new Mesh( scaleHandleGeometry, matBlue ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ]],
985
+ [ new Mesh( lineGeometry2, matBlue ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ]],
986
+ [ new Mesh( scaleHandleGeometry, matBlue ), [ 0, 0, - 0.5 ], [ - Math.PI / 2, 0, 0 ]]
987
+ ],
988
+ XY: [
989
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matBlueTransparent ), [ 0.15, 0.15, 0 ]]
990
+ ],
991
+ YZ: [
992
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matRedTransparent ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]]
993
+ ],
994
+ XZ: [
995
+ [ new Mesh( new BoxGeometry( 0.15, 0.15, 0.01 ), matGreenTransparent ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]]
996
+ ],
997
+ XYZ: [
998
+ [ new Mesh( new BoxGeometry( 0.1, 0.1, 0.1 ), matWhiteTransparent.clone() ) ],
999
+ ]
1000
+ };
1001
+
1002
+ const pickerScale = {
1003
+ X: [
1004
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0.3, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
1005
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ - 0.3, 0, 0 ], [ 0, 0, Math.PI / 2 ]]
1006
+ ],
1007
+ Y: [
1008
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0.3, 0 ]],
1009
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, - 0.3, 0 ], [ 0, 0, Math.PI ]]
1010
+ ],
1011
+ Z: [
1012
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, 0.3 ], [ Math.PI / 2, 0, 0 ]],
1013
+ [ new Mesh( new CylinderGeometry( 0.2, 0, 0.6, 4 ), matInvisible ), [ 0, 0, - 0.3 ], [ - Math.PI / 2, 0, 0 ]]
1014
+ ],
1015
+ XY: [
1016
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0.15, 0 ]],
1017
+ ],
1018
+ YZ: [
1019
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]],
1020
+ ],
1021
+ XZ: [
1022
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.01 ), matInvisible ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]],
1023
+ ],
1024
+ XYZ: [
1025
+ [ new Mesh( new BoxGeometry( 0.2, 0.2, 0.2 ), matInvisible ), [ 0, 0, 0 ]],
1026
+ ]
1027
+ };
1028
+
1029
+ const helperScale = {
1030
+ X: [
1031
+ [ new Line( lineGeometry, matHelper.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
1032
+ ],
1033
+ Y: [
1034
+ [ new Line( lineGeometry, matHelper.clone() ), [ 0, - 1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], 'helper' ]
1035
+ ],
1036
+ Z: [
1037
+ [ new Line( lineGeometry, matHelper.clone() ), [ 0, 0, - 1e3 ], [ 0, - Math.PI / 2, 0 ], [ 1e6, 1, 1 ], 'helper' ]
1038
+ ]
1039
+ };
1040
+
1041
+ // Creates an Object3D with gizmos described in custom hierarchy definition.
1042
+
1043
+ function setupGizmo( gizmoMap ) {
1044
+
1045
+ const gizmo = new Object3D();
1046
+
1047
+ for ( const name in gizmoMap ) {
1048
+
1049
+ for ( let i = gizmoMap[ name ].length; i --; ) {
1050
+
1051
+ const object = gizmoMap[ name ][ i ][ 0 ].clone();
1052
+ const position = gizmoMap[ name ][ i ][ 1 ];
1053
+ const rotation = gizmoMap[ name ][ i ][ 2 ];
1054
+ const scale = gizmoMap[ name ][ i ][ 3 ];
1055
+ const tag = gizmoMap[ name ][ i ][ 4 ];
1056
+
1057
+ // name and tag properties are essential for picking and updating logic.
1058
+ object.name = name;
1059
+ object.tag = tag;
1060
+
1061
+ if ( position ) {
1062
+
1063
+ object.position.set( position[ 0 ], position[ 1 ], position[ 2 ] );
1064
+
1065
+ }
1066
+
1067
+ if ( rotation ) {
1068
+
1069
+ object.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ] );
1070
+
1071
+ }
1072
+
1073
+ if ( scale ) {
1074
+
1075
+ object.scale.set( scale[ 0 ], scale[ 1 ], scale[ 2 ] );
1076
+
1077
+ }
1078
+
1079
+ object.updateMatrix();
1080
+
1081
+ const tempGeometry = object.geometry.clone();
1082
+ tempGeometry.applyMatrix4( object.matrix );
1083
+ object.geometry = tempGeometry;
1084
+ object.renderOrder = Infinity;
1085
+
1086
+ object.position.set( 0, 0, 0 );
1087
+ object.rotation.set( 0, 0, 0 );
1088
+ object.scale.set( 1, 1, 1 );
1089
+
1090
+ gizmo.add( object );
1091
+
1092
+ }
1093
+
1094
+ }
1095
+
1096
+ return gizmo;
1097
+
1098
+ }
1099
+
1100
+ // Gizmo creation
1101
+
1102
+ this.gizmo = {};
1103
+ this.picker = {};
1104
+ this.helper = {};
1105
+
1106
+ this.add( this.gizmo[ 'translate' ] = setupGizmo( gizmoTranslate ) );
1107
+ this.add( this.gizmo[ 'rotate' ] = setupGizmo( gizmoRotate ) );
1108
+ this.add( this.gizmo[ 'scale' ] = setupGizmo( gizmoScale ) );
1109
+ this.add( this.picker[ 'translate' ] = setupGizmo( pickerTranslate ) );
1110
+ this.add( this.picker[ 'rotate' ] = setupGizmo( pickerRotate ) );
1111
+ this.add( this.picker[ 'scale' ] = setupGizmo( pickerScale ) );
1112
+ this.add( this.helper[ 'translate' ] = setupGizmo( helperTranslate ) );
1113
+ this.add( this.helper[ 'rotate' ] = setupGizmo( helperRotate ) );
1114
+ this.add( this.helper[ 'scale' ] = setupGizmo( helperScale ) );
1115
+
1116
+ // Pickers should be hidden always
1117
+
1118
+ this.picker[ 'translate' ].visible = false;
1119
+ this.picker[ 'rotate' ].visible = false;
1120
+ this.picker[ 'scale' ].visible = false;
1121
+
1122
+ }
1123
+
1124
+ // updateMatrixWorld will update transformations and appearance of individual handles
1125
+
1126
+ updateMatrixWorld( force ) {
1127
+
1128
+ const space = ( this.mode === 'scale' ) ? 'local' : this.space; // scale always oriented to local rotation
1129
+
1130
+ const quaternion = ( space === 'local' ) ? this.worldQuaternion : _identityQuaternion;
1131
+
1132
+ // Show only gizmos for current transform mode
1133
+
1134
+ this.gizmo[ 'translate' ].visible = this.mode === 'translate';
1135
+ this.gizmo[ 'rotate' ].visible = this.mode === 'rotate';
1136
+ this.gizmo[ 'scale' ].visible = this.mode === 'scale';
1137
+
1138
+ this.helper[ 'translate' ].visible = this.mode === 'translate';
1139
+ this.helper[ 'rotate' ].visible = this.mode === 'rotate';
1140
+ this.helper[ 'scale' ].visible = this.mode === 'scale';
1141
+
1142
+
1143
+ let handles = [];
1144
+ handles = handles.concat( this.picker[ this.mode ].children );
1145
+ handles = handles.concat( this.gizmo[ this.mode ].children );
1146
+ handles = handles.concat( this.helper[ this.mode ].children );
1147
+
1148
+ for ( let i = 0; i < handles.length; i ++ ) {
1149
+
1150
+ const handle = handles[ i ];
1151
+
1152
+ // hide aligned to camera
1153
+
1154
+ handle.visible = true;
1155
+ handle.rotation.set( 0, 0, 0 );
1156
+ handle.position.copy( this.worldPosition );
1157
+
1158
+ let factor;
1159
+
1160
+ if ( this.camera.isOrthographicCamera ) {
1161
+
1162
+ factor = ( this.camera.top - this.camera.bottom ) / this.camera.zoom;
1163
+
1164
+ } else {
1165
+
1166
+ factor = this.worldPosition.distanceTo( this.cameraPosition ) * Math.min( 1.9 * Math.tan( Math.PI * this.camera.fov / 360 ) / this.camera.zoom, 7 );
1167
+
1168
+ }
1169
+
1170
+ handle.scale.set( 1, 1, 1 ).multiplyScalar( factor * this.size / 4 );
1171
+
1172
+ // TODO: simplify helpers and consider decoupling from gizmo
1173
+
1174
+ if ( handle.tag === 'helper' ) {
1175
+
1176
+ handle.visible = false;
1177
+
1178
+ if ( handle.name === 'AXIS' ) {
1179
+
1180
+ handle.visible = !! this.axis;
1181
+
1182
+ if ( this.axis === 'X' ) {
1183
+
1184
+ _tempQuaternion.setFromEuler( _tempEuler.set( 0, 0, 0 ) );
1185
+ handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
1186
+
1187
+ if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
1188
+
1189
+ handle.visible = false;
1190
+
1191
+ }
1192
+
1193
+ }
1194
+
1195
+ if ( this.axis === 'Y' ) {
1196
+
1197
+ _tempQuaternion.setFromEuler( _tempEuler.set( 0, 0, Math.PI / 2 ) );
1198
+ handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
1199
+
1200
+ if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
1201
+
1202
+ handle.visible = false;
1203
+
1204
+ }
1205
+
1206
+ }
1207
+
1208
+ if ( this.axis === 'Z' ) {
1209
+
1210
+ _tempQuaternion.setFromEuler( _tempEuler.set( 0, Math.PI / 2, 0 ) );
1211
+ handle.quaternion.copy( quaternion ).multiply( _tempQuaternion );
1212
+
1213
+ if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
1214
+
1215
+ handle.visible = false;
1216
+
1217
+ }
1218
+
1219
+ }
1220
+
1221
+ if ( this.axis === 'XYZE' ) {
1222
+
1223
+ _tempQuaternion.setFromEuler( _tempEuler.set( 0, Math.PI / 2, 0 ) );
1224
+ _alignVector.copy( this.rotationAxis );
1225
+ handle.quaternion.setFromRotationMatrix( _lookAtMatrix.lookAt( _zeroVector, _alignVector, _unitY ) );
1226
+ handle.quaternion.multiply( _tempQuaternion );
1227
+ handle.visible = this.dragging;
1228
+
1229
+ }
1230
+
1231
+ if ( this.axis === 'E' ) {
1232
+
1233
+ handle.visible = false;
1234
+
1235
+ }
1236
+
1237
+
1238
+ } else if ( handle.name === 'START' ) {
1239
+
1240
+ handle.position.copy( this.worldPositionStart );
1241
+ handle.visible = this.dragging;
1242
+
1243
+ } else if ( handle.name === 'END' ) {
1244
+
1245
+ handle.position.copy( this.worldPosition );
1246
+ handle.visible = this.dragging;
1247
+
1248
+ } else if ( handle.name === 'DELTA' ) {
1249
+
1250
+ handle.position.copy( this.worldPositionStart );
1251
+ handle.quaternion.copy( this.worldQuaternionStart );
1252
+ _tempVector.set( 1e-10, 1e-10, 1e-10 ).add( this.worldPositionStart ).sub( this.worldPosition ).multiplyScalar( - 1 );
1253
+ _tempVector.applyQuaternion( this.worldQuaternionStart.clone().invert() );
1254
+ handle.scale.copy( _tempVector );
1255
+ handle.visible = this.dragging;
1256
+
1257
+ } else {
1258
+
1259
+ handle.quaternion.copy( quaternion );
1260
+
1261
+ if ( this.dragging ) {
1262
+
1263
+ handle.position.copy( this.worldPositionStart );
1264
+
1265
+ } else {
1266
+
1267
+ handle.position.copy( this.worldPosition );
1268
+
1269
+ }
1270
+
1271
+ if ( this.axis ) {
1272
+
1273
+ handle.visible = this.axis.search( handle.name ) !== - 1;
1274
+
1275
+ }
1276
+
1277
+ }
1278
+
1279
+ // If updating helper, skip rest of the loop
1280
+ continue;
1281
+
1282
+ }
1283
+
1284
+ // Align handles to current local or world rotation
1285
+
1286
+ handle.quaternion.copy( quaternion );
1287
+
1288
+ if ( this.mode === 'translate' || this.mode === 'scale' ) {
1289
+
1290
+ // Hide translate and scale axis facing the camera
1291
+
1292
+ const AXIS_HIDE_THRESHOLD = 0.99;
1293
+ const PLANE_HIDE_THRESHOLD = 0.2;
1294
+
1295
+ if ( handle.name === 'X' ) {
1296
+
1297
+ if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
1298
+
1299
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1300
+ handle.visible = false;
1301
+
1302
+ }
1303
+
1304
+ }
1305
+
1306
+ if ( handle.name === 'Y' ) {
1307
+
1308
+ if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
1309
+
1310
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1311
+ handle.visible = false;
1312
+
1313
+ }
1314
+
1315
+ }
1316
+
1317
+ if ( handle.name === 'Z' ) {
1318
+
1319
+ if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
1320
+
1321
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1322
+ handle.visible = false;
1323
+
1324
+ }
1325
+
1326
+ }
1327
+
1328
+ if ( handle.name === 'XY' ) {
1329
+
1330
+ if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
1331
+
1332
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1333
+ handle.visible = false;
1334
+
1335
+ }
1336
+
1337
+ }
1338
+
1339
+ if ( handle.name === 'YZ' ) {
1340
+
1341
+ if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
1342
+
1343
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1344
+ handle.visible = false;
1345
+
1346
+ }
1347
+
1348
+ }
1349
+
1350
+ if ( handle.name === 'XZ' ) {
1351
+
1352
+ if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
1353
+
1354
+ handle.scale.set( 1e-10, 1e-10, 1e-10 );
1355
+ handle.visible = false;
1356
+
1357
+ }
1358
+
1359
+ }
1360
+
1361
+ } else if ( this.mode === 'rotate' ) {
1362
+
1363
+ // Align handles to current local or world rotation
1364
+
1365
+ _tempQuaternion2.copy( quaternion );
1366
+ _alignVector.copy( this.eye ).applyQuaternion( _tempQuaternion.copy( quaternion ).invert() );
1367
+
1368
+ if ( handle.name.search( 'E' ) !== - 1 ) {
1369
+
1370
+ handle.quaternion.setFromRotationMatrix( _lookAtMatrix.lookAt( this.eye, _zeroVector, _unitY ) );
1371
+
1372
+ }
1373
+
1374
+ if ( handle.name === 'X' ) {
1375
+
1376
+ _tempQuaternion.setFromAxisAngle( _unitX, Math.atan2( - _alignVector.y, _alignVector.z ) );
1377
+ _tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
1378
+ handle.quaternion.copy( _tempQuaternion );
1379
+
1380
+ }
1381
+
1382
+ if ( handle.name === 'Y' ) {
1383
+
1384
+ _tempQuaternion.setFromAxisAngle( _unitY, Math.atan2( _alignVector.x, _alignVector.z ) );
1385
+ _tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
1386
+ handle.quaternion.copy( _tempQuaternion );
1387
+
1388
+ }
1389
+
1390
+ if ( handle.name === 'Z' ) {
1391
+
1392
+ _tempQuaternion.setFromAxisAngle( _unitZ, Math.atan2( _alignVector.y, _alignVector.x ) );
1393
+ _tempQuaternion.multiplyQuaternions( _tempQuaternion2, _tempQuaternion );
1394
+ handle.quaternion.copy( _tempQuaternion );
1395
+
1396
+ }
1397
+
1398
+ }
1399
+
1400
+ // Hide disabled axes
1401
+ handle.visible = handle.visible && ( handle.name.indexOf( 'X' ) === - 1 || this.showX );
1402
+ handle.visible = handle.visible && ( handle.name.indexOf( 'Y' ) === - 1 || this.showY );
1403
+ handle.visible = handle.visible && ( handle.name.indexOf( 'Z' ) === - 1 || this.showZ );
1404
+ handle.visible = handle.visible && ( handle.name.indexOf( 'E' ) === - 1 || ( this.showX && this.showY && this.showZ ) );
1405
+
1406
+ // highlight selected axis
1407
+
1408
+ handle.material._color = handle.material._color || handle.material.color.clone();
1409
+ handle.material._opacity = handle.material._opacity || handle.material.opacity;
1410
+
1411
+ handle.material.color.copy( handle.material._color );
1412
+ handle.material.opacity = handle.material._opacity;
1413
+
1414
+ if ( this.enabled && this.axis ) {
1415
+
1416
+ if ( handle.name === this.axis ) {
1417
+
1418
+ handle.material.color.setHex( 0xffff00 );
1419
+ handle.material.opacity = 1.0;
1420
+
1421
+ } else if ( this.axis.split( '' ).some( function ( a ) {
1422
+
1423
+ return handle.name === a;
1424
+
1425
+ } ) ) {
1426
+
1427
+ handle.material.color.setHex( 0xffff00 );
1428
+ handle.material.opacity = 1.0;
1429
+
1430
+ }
1431
+
1432
+ }
1433
+
1434
+ }
1435
+
1436
+ super.updateMatrixWorld( force );
1437
+
1438
+ }
1439
+
1440
+ }
1441
+
1442
+ //
1443
+
1444
+ class TransformControlsPlane extends Mesh {
1445
+
1446
+ constructor() {
1447
+
1448
+ super(
1449
+ new PlaneGeometry( 100000, 100000, 2, 2 ),
1450
+ new MeshBasicMaterial( { visible: false, wireframe: true, side: DoubleSide, transparent: true, opacity: 0.1, toneMapped: false } )
1451
+ );
1452
+
1453
+ this.isTransformControlsPlane = true;
1454
+
1455
+ this.type = 'TransformControlsPlane';
1456
+
1457
+ }
1458
+
1459
+ updateMatrixWorld( force ) {
1460
+
1461
+ let space = this.space;
1462
+
1463
+ this.position.copy( this.worldPosition );
1464
+
1465
+ if ( this.mode === 'scale' ) space = 'local'; // scale always oriented to local rotation
1466
+
1467
+ _v1.copy( _unitX ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
1468
+ _v2.copy( _unitY ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
1469
+ _v3.copy( _unitZ ).applyQuaternion( space === 'local' ? this.worldQuaternion : _identityQuaternion );
1470
+
1471
+ // Align the plane for current transform mode, axis and space.
1472
+
1473
+ _alignVector.copy( _v2 );
1474
+
1475
+ switch ( this.mode ) {
1476
+
1477
+ case 'translate':
1478
+ case 'scale':
1479
+ switch ( this.axis ) {
1480
+
1481
+ case 'X':
1482
+ _alignVector.copy( this.eye ).cross( _v1 );
1483
+ _dirVector.copy( _v1 ).cross( _alignVector );
1484
+ break;
1485
+ case 'Y':
1486
+ _alignVector.copy( this.eye ).cross( _v2 );
1487
+ _dirVector.copy( _v2 ).cross( _alignVector );
1488
+ break;
1489
+ case 'Z':
1490
+ _alignVector.copy( this.eye ).cross( _v3 );
1491
+ _dirVector.copy( _v3 ).cross( _alignVector );
1492
+ break;
1493
+ case 'XY':
1494
+ _dirVector.copy( _v3 );
1495
+ break;
1496
+ case 'YZ':
1497
+ _dirVector.copy( _v1 );
1498
+ break;
1499
+ case 'XZ':
1500
+ _alignVector.copy( _v3 );
1501
+ _dirVector.copy( _v2 );
1502
+ break;
1503
+ case 'XYZ':
1504
+ case 'E':
1505
+ _dirVector.set( 0, 0, 0 );
1506
+ break;
1507
+
1508
+ }
1509
+
1510
+ break;
1511
+ case 'rotate':
1512
+ default:
1513
+ // special case for rotate
1514
+ _dirVector.set( 0, 0, 0 );
1515
+
1516
+ }
1517
+
1518
+ if ( _dirVector.length() === 0 ) {
1519
+
1520
+ // If in rotate mode, make the plane parallel to camera
1521
+ this.quaternion.copy( this.cameraQuaternion );
1522
+
1523
+ } else {
1524
+
1525
+ _tempMatrix.lookAt( _tempVector.set( 0, 0, 0 ), _dirVector, _alignVector );
1526
+
1527
+ this.quaternion.setFromRotationMatrix( _tempMatrix );
1528
+
1529
+ }
1530
+
1531
+ super.updateMatrixWorld( force );
1532
+
1533
+ }
1534
+
1535
+ }
1536
+
1537
+ export { TransformControls, TransformControlsGizmo, TransformControlsPlane };