diff --git a/web/lib/three/TrackballControls.js b/modules/scene/controls/TrackballControls.js similarity index 91% rename from web/lib/three/TrackballControls.js rename to modules/scene/controls/TrackballControls.js index e60940a0..b1feb3bf 100644 --- a/web/lib/three/TrackballControls.js +++ b/modules/scene/controls/TrackballControls.js @@ -1,4 +1,7 @@ + /** + * Added support of orthographic camera to original implementation + * * @author Eberhard Graether / http://egraether.com/ * @author Mark Lundin / http://mark-lundin.com * @author Simone Manini / http://daron1337.github.io @@ -39,6 +42,9 @@ THREE.TrackballControls = function ( object, domElement ) { this.target = new THREE.Vector3(); + this.projectionChanged = false; + this.projectionZoomSpeed = 0.5; + var EPS = 0.000001; var lastPosition = new THREE.Vector3(); @@ -201,6 +207,11 @@ THREE.TrackballControls = function ( object, domElement ) { }() ); + this.setCameraMode = function(isOrthographic) { + this.noZoom = isOrthographic; + this.projectionZoom = isOrthographic; + }; + this.zoomCamera = function () { var factor; @@ -321,8 +332,10 @@ THREE.TrackballControls = function ( object, domElement ) { _this.object.lookAt( _this.target ); - if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { + if ( lastPosition.distanceToSquared( _this.object.position ) > EPS || this.projectionChanged) { + this.projectionChanged = false; + _this.dispatchEvent( changeEvent ); lastPosition.copy( _this.object.position ); @@ -473,28 +486,52 @@ THREE.TrackballControls = function ( object, domElement ) { event.preventDefault(); event.stopPropagation(); - switch ( event.deltaMode ) { + if (_this.projectionZoom) { + let speed = _this.projectionZoomSpeed; + switch ( event.deltaMode ) { - case 2: - // Zoom in pages - _zoomStart.y -= event.deltaY * 0.025; - break; + case 2: + // Zoom in pages + speed *= 10; + break; + case 1: + // Zoom in lines + speed *= 3; + break; + } + let step = Math.pow( 0.95, speed); + if (event.deltaY < 0) { + step = 1 / step; + } + _this.object.zoom *= step; + _this.object.updateProjectionMatrix(); + _this.projectionChanged = true; - case 1: - // Zoom in lines - _zoomStart.y -= event.deltaY * 0.01; - break; + } else { - default: - // undefined, 0, assume pixels - _zoomStart.y -= event.deltaY * 0.00025; - break; + switch ( event.deltaMode ) { + case 2: + // Zoom in pages + _zoomStart.y -= event.deltaY * 0.025; + break; + + case 1: + // Zoom in lines + _zoomStart.y -= event.deltaY * 0.01; + break; + + default: + // undefined, 0, assume pixels + _zoomStart.y -= event.deltaY * 0.00025; + break; + + } + + _this.dispatchEvent( startEvent ); + _this.dispatchEvent( endEvent ); } - _this.dispatchEvent( startEvent ); - _this.dispatchEvent( endEvent ); - } function touchstart( event ) { diff --git a/modules/scene/sceneSetup.js b/modules/scene/sceneSetup.js index 4345554e..07f2284c 100644 --- a/modules/scene/sceneSetup.js +++ b/modules/scene/sceneSetup.js @@ -1,6 +1,7 @@ import DPR from 'dpr'; +import './utils/threeLoader' -export default class SceneSetUp{ +export default class SceneSetUp { constructor(container) { @@ -17,13 +18,29 @@ export default class SceneSetUp{ aspect() { return this.container.clientWidth / this.container.clientHeight; } + + createOrthographicCamera() { + let width = this.container.clientWidth; + let height = this.container.clientHeight; + this.oCamera = new THREE.OrthographicCamera( width / - 1, width / 1, height / 1, height / - 1, 0.1, 10000); + this.oCamera.position.z = 1000; + this.oCamera.position.x = -1000; + this.oCamera.position.y = 300; + } + + createPerspectiveCamera() { + this.pCamera = new THREE.PerspectiveCamera( 500*75, this.aspect(), 0.1, 10000 ); + this.pCamera.position.z = 1000; + this.pCamera.position.x = -1000; + this.pCamera.position.y = 300; + } setUpCamerasAndLights() { - this.camera = new THREE.PerspectiveCamera( 500*75, this.aspect(), 0.1, 10000 ); - this.camera.position.z = 1000; - this.camera.position.x = -1000; - this.camera.position.y = 300; + this.createOrthographicCamera(); + this.createPerspectiveCamera(); + this.camera = this.pCamera; + this.light = new THREE.PointLight( 0xffffff); this.light.position.set( 10, 10, 10 ); this.scene.add(this.light); @@ -31,17 +48,39 @@ export default class SceneSetUp{ this.renderer = new THREE.WebGLRenderer(); this.renderer.setPixelRatio(DPR); this.renderer.setClearColor(0x808080, 1); - this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.container.appendChild( this.renderer.domElement ); window.addEventListener( 'resize', () => { - this.camera.aspect = this.aspect(); - this.camera.updateProjectionMatrix(); + this.pCamera.aspect = this.aspect(); + this.pCamera.updateProjectionMatrix(); this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); this.render(); }, false ); } + setCamera(camera) { + let camPosition = new THREE.Vector3(); + let camRotation = new THREE.Euler(); + let tempMatrix = new THREE.Matrix4(); + + camPosition.setFromMatrixPosition( this.camera.matrixWorld ); + camRotation.setFromRotationMatrix( tempMatrix.extractRotation( this.camera.matrixWorld ) ); + let camDistance = camera.position.length(); + + camera.up.copy(this.camera.up); + camera.position.copy(camPosition); + camera.quaternion.copy(camPosition); + this.trackballControls.setCameraMode(camera.isOrthographicCamera); + camera.position.normalize(); + camera.position.multiplyScalar(camDistance); + + this.camera = camera; + this.trackballControls.object = camera; + this.transformControls.camera = camera; + this.updateControlsAndHelpers(); + } + setUpControls() { // controls = new THREE.OrbitControls( camera , renderer.domElement); let trackballControls = new THREE.TrackballControls(this.camera , this.renderer.domElement); diff --git a/modules/scene/utils/threeLoader.js b/modules/scene/utils/threeLoader.js new file mode 100644 index 00000000..c6850fb7 --- /dev/null +++ b/modules/scene/utils/threeLoader.js @@ -0,0 +1,6 @@ +import * as THREE from 'three'; +window.THREE = THREE; +require('scene/controls/TrackballControls'); +require('three/examples/js/controls/OrbitControls'); +require('three/examples/js/controls/TransformControls'); + diff --git a/web/app/3d/actions/core-actions.js b/web/app/3d/actions/core-actions.js index 14b37fe2..e2149a18 100644 --- a/web/app/3d/actions/core-actions.js +++ b/web/app/3d/actions/core-actions.js @@ -38,6 +38,16 @@ export const DeselectAll = { invoke: (app) => app.viewer.selectionMgr.deselectAll() }; +export const ToggleCameraMode = { + cssIcons: ['video-camera'], + label: 'toggle camera', + info: 'switch camera mode between perspective and orthographic', + invoke: (app) => { + app.context.services.viewer.toggleCamera(); + app.context.services.viewer.render(); + } +}; + export const Info = { cssIcons: ['info-circle'], label: 'info', diff --git a/web/app/3d/modeler-app.js b/web/app/3d/modeler-app.js index 9955590f..7f4d2ac8 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/3d/modeler-app.js @@ -1,5 +1,4 @@ import '../../../modules/scene/utils/vectorThreeEnhancement' -import '../utils/three-loader' import Bus from 'bus' import {Viewer} from './scene/viewer' import {UI} from './ui/ctrl' diff --git a/web/app/3d/scene/cadScene.js b/web/app/3d/scene/cadScene.js index 257d5cf5..46d92181 100644 --- a/web/app/3d/scene/cadScene.js +++ b/web/app/3d/scene/cadScene.js @@ -50,6 +50,7 @@ export default class CadScene { SceneGraph.addToGroup(this.basisGroup, xAxis); SceneGraph.addToGroup(this.basisGroup, yAxis); SceneGraph.addToGroup(this.workGroup, this.basisGroup, yAxis); + this.hideBasis(); } updateBasis(basis, depth) { diff --git a/web/app/3d/scene/scenePlugin.js b/web/app/3d/scene/scenePlugin.js index 3eedca7e..b3103328 100644 --- a/web/app/3d/scene/scenePlugin.js +++ b/web/app/3d/scene/scenePlugin.js @@ -4,11 +4,10 @@ import CadScene from "./cadScene"; export function activate(context) { let {dom} = context.services; - let viewer = new Viewer(dom.viewerContainer); + let viewer = new Viewer(context.bus, dom.viewerContainer); context.services.viewer = viewer; context.services.cadScene = new CadScene(viewer.sceneSetup.rootGroup); context.bus.subscribe('scene:update', () => viewer.render()); } - diff --git a/web/app/3d/scene/viewer.js b/web/app/3d/scene/viewer.js index ce02462c..2b649808 100644 --- a/web/app/3d/scene/viewer.js +++ b/web/app/3d/scene/viewer.js @@ -2,7 +2,8 @@ import SceneSetup from 'scene/sceneSetup'; export default class Viewer { - constructor(container) { + constructor(bus, container) { + this.bus = bus; this.sceneSetup = new SceneSetup(container); } @@ -18,9 +19,30 @@ export default class Viewer { return this.sceneSetup.raycast(event, group); } - setCameraMode() { - + setCameraMode(mode) { + if (mode === CAMERA_MODE.PERSPECTIVE) { + + this.sceneSetup.setCamera(this.sceneSetup.pCamera); + } else { + this.sceneSetup.setCamera(this.sceneSetup.oCamera); + } + this.bus.dispatch('scene_cameraMode', this.getCameraMode()); + } + + getCameraMode() { + return this.sceneSetup.camera === this.sceneSetup.pCamera ? CAMERA_MODE.PERSPECTIVE : CAMERA_MODE.ORTHOGRAPHIC; } + toggleCamera() { + if (this.getCameraMode() === CAMERA_MODE.PERSPECTIVE) { + this.setCameraMode(CAMERA_MODE.ORTHOGRAPHIC); + } else { + this.setCameraMode(CAMERA_MODE.PERSPECTIVE); + } + } } +export const CAMERA_MODE = { + ORTHOGRAPHIC: 'ORTHOGRAPHIC', + PERSPECTIVE: 'PERSPECTIVE' +}; diff --git a/web/app/3d/ui/ctrl.js b/web/app/3d/ui/ctrl.js index 0a42a287..1d4bf61c 100644 --- a/web/app/3d/ui/ctrl.js +++ b/web/app/3d/ui/ctrl.js @@ -123,6 +123,7 @@ UI.prototype.fillControlBar = function() { this.app.controlBar.add('RefreshSketches', RIGHT, {'label': null}); this.app.controlBar.add('ShowSketches', RIGHT, {'label': 'sketches'}); this.app.controlBar.add('DeselectAll', RIGHT, {'label': null}); + this.app.controlBar.add('ToggleCameraMode', RIGHT, {'label': null}); this.app.controlBar.add('menu.file', LEFT); this.app.controlBar.add('menu.craft', LEFT); this.app.controlBar.add('menu.boolean', LEFT); diff --git a/web/app/index.js b/web/app/index.js index b3f1dfc1..41e82243 100644 --- a/web/app/index.js +++ b/web/app/index.js @@ -1,5 +1,4 @@ //import './utils/jqueryfy' -//import './utils/three-loader' import App from './3d/modeler-app' window.onload = function() { diff --git a/web/app/utils/three-loader.js b/web/app/utils/three-loader.js deleted file mode 100644 index e71cc593..00000000 --- a/web/app/utils/three-loader.js +++ /dev/null @@ -1,6 +0,0 @@ -import * as THREE from 'three'; -window.THREE = THREE; -require('../../lib/three/TrackballControls'); -require('../../lib/three/OrbitControls'); -require('../../lib/three/TransformControls'); - diff --git a/web/lib/three/OrbitControls.js b/web/lib/three/OrbitControls.js deleted file mode 100644 index 6259b4ae..00000000 --- a/web/lib/three/OrbitControls.js +++ /dev/null @@ -1,1042 +0,0 @@ -/** - * @author qiao / https://github.com/qiao - * @author mrdoob / http://mrdoob.com - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author erich666 / http://erichaines.com - */ - -// This set of controls performs orbiting, dollying (zooming), and panning. -// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). -// -// Orbit - left mouse / touch: one finger move -// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish -// Pan - right mouse, or arrow keys / touch: three finger swipe - -THREE.OrbitControls = function ( object, domElement ) { - - this.object = object; - - this.domElement = ( domElement !== undefined ) ? domElement : document; - - // Set to false to disable this control - this.enabled = true; - - // "target" sets the location of focus, where the object orbits around - this.target = new THREE.Vector3(); - - // How far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0; - this.maxDistance = Infinity; - - // How far you can zoom in and out ( OrthographicCamera only ) - this.minZoom = 0; - this.maxZoom = Infinity; - - // How far you can orbit vertically, upper and lower limits. - // Range is 0 to Math.PI radians. - this.minPolarAngle = 0; // radians - this.maxPolarAngle = Math.PI; // radians - - // How far you can orbit horizontally, upper and lower limits. - // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. - this.minAzimuthAngle = - Infinity; // radians - this.maxAzimuthAngle = Infinity; // radians - - // Set to true to enable damping (inertia) - // If damping is enabled, you must call controls.update() in your animation loop - this.enableDamping = false; - this.dampingFactor = 0.25; - - // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. - // Set to false to disable zooming - this.enableZoom = true; - this.zoomSpeed = 1.0; - - // Set to false to disable rotating - this.enableRotate = true; - this.rotateSpeed = 1.0; - - // Set to false to disable panning - this.enablePan = true; - this.keyPanSpeed = 7.0; // pixels moved per arrow key push - - // Set to true to automatically rotate around the target - // If auto-rotate is enabled, you must call controls.update() in your animation loop - this.autoRotate = false; - this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 - - // Set to false to disable use of the keys - this.enableKeys = true; - - // The four arrow keys - this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; - - // Mouse buttons - this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; - - // for reset - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.zoom0 = this.object.zoom; - - // - // public methods - // - - this.getPolarAngle = function () { - - return spherical.phi; - - }; - - this.getAzimuthalAngle = function () { - - return spherical.theta; - - }; - - this.saveState = function () { - - scope.target0.copy( scope.target ); - scope.position0.copy( scope.object.position ); - scope.zoom0 = scope.object.zoom; - - }; - - this.reset = function () { - - scope.target.copy( scope.target0 ); - scope.object.position.copy( scope.position0 ); - scope.object.zoom = scope.zoom0; - - scope.object.updateProjectionMatrix(); - scope.dispatchEvent( changeEvent ); - - scope.update(); - - state = STATE.NONE; - - }; - - // this method is exposed, but perhaps it would be better if we can make it private... - this.update = function () { - - var offset = new THREE.Vector3(); - - // so camera.up is the orbit axis - var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); - var quatInverse = quat.clone().inverse(); - - var lastPosition = new THREE.Vector3(); - var lastQuaternion = new THREE.Quaternion(); - - return function update() { - - var position = scope.object.position; - - offset.copy( position ).sub( scope.target ); - - // rotate offset to "y-axis-is-up" space - offset.applyQuaternion( quat ); - - // angle from z-axis around y-axis - spherical.setFromVector3( offset ); - - if ( scope.autoRotate && state === STATE.NONE ) { - - rotateLeft( getAutoRotationAngle() ); - - } - - spherical.theta += sphericalDelta.theta; - spherical.phi += sphericalDelta.phi; - - // restrict theta to be between desired limits - spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); - - // restrict phi to be between desired limits - spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); - - spherical.makeSafe(); - - - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - - // move target to panned location - scope.target.add( panOffset ); - - offset.setFromSpherical( spherical ); - - // rotate offset back to "camera-up-vector-is-up" space - offset.applyQuaternion( quatInverse ); - - position.copy( scope.target ).add( offset ); - - scope.object.lookAt( scope.target ); - - if ( scope.enableDamping === true ) { - - sphericalDelta.theta *= ( 1 - scope.dampingFactor ); - sphericalDelta.phi *= ( 1 - scope.dampingFactor ); - - } else { - - sphericalDelta.set( 0, 0, 0 ); - - } - - scale = 1; - panOffset.set( 0, 0, 0 ); - - // update condition is: - // min(camera displacement, camera rotation in radians)^2 > EPS - // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - - if ( zoomChanged || - lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; - - return true; - - } - - return false; - - }; - - }(); - - this.dispose = function () { - - scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); - scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - window.removeEventListener( 'keydown', onKeyDown, false ); - - //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? - - }; - - // - // internals - // - - var scope = this; - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; - - var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 }; - - var state = STATE.NONE; - - var EPS = 0.000001; - - // current position in spherical coordinates - var spherical = new THREE.Spherical(); - var sphericalDelta = new THREE.Spherical(); - - var scale = 1; - var panOffset = new THREE.Vector3(); - var zoomChanged = false; - - var rotateStart = new THREE.Vector2(); - var rotateEnd = new THREE.Vector2(); - var rotateDelta = new THREE.Vector2(); - - var panStart = new THREE.Vector2(); - var panEnd = new THREE.Vector2(); - var panDelta = new THREE.Vector2(); - - var dollyStart = new THREE.Vector2(); - var dollyEnd = new THREE.Vector2(); - var dollyDelta = new THREE.Vector2(); - - function getAutoRotationAngle() { - - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - - } - - function getZoomScale() { - - return Math.pow( 0.95, scope.zoomSpeed ); - - } - - function rotateLeft( angle ) { - - sphericalDelta.theta -= angle; - - } - - function rotateUp( angle ) { - - sphericalDelta.phi -= angle; - - } - - var panLeft = function () { - - var v = new THREE.Vector3(); - - return function panLeft( distance, objectMatrix ) { - - v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix - v.multiplyScalar( - distance ); - - panOffset.add( v ); - - }; - - }(); - - var panUp = function () { - - var v = new THREE.Vector3(); - - return function panUp( distance, objectMatrix ) { - - v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix - v.multiplyScalar( distance ); - - panOffset.add( v ); - - }; - - }(); - - // deltaX and deltaY are in pixels; right and down are positive - var pan = function () { - - var offset = new THREE.Vector3(); - - return function pan( deltaX, deltaY ) { - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - if ( scope.object.isPerspectiveCamera ) { - - // perspective - var position = scope.object.position; - offset.copy( position ).sub( scope.target ); - var targetDistance = offset.length(); - - // half of the fov is center to top of screen - targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); - - // we actually don't use screenWidth, since perspective camera is fixed to screen height - panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); - panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); - - } else if ( scope.object.isOrthographicCamera ) { - - // orthographic - panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); - panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); - - } else { - - // camera neither orthographic nor perspective - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); - scope.enablePan = false; - - } - - }; - - }(); - - function dollyIn( dollyScale ) { - - if ( scope.object.isPerspectiveCamera ) { - - scale /= dollyScale; - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - function dollyOut( dollyScale ) { - - if ( scope.object.isPerspectiveCamera ) { - - scale *= dollyScale; - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - - } else { - - console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); - scope.enableZoom = false; - - } - - } - - // - // event callbacks - update the object state - // - - function handleMouseDownRotate( event ) { - - //console.log( 'handleMouseDownRotate' ); - - rotateStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownDolly( event ) { - - //console.log( 'handleMouseDownDolly' ); - - dollyStart.set( event.clientX, event.clientY ); - - } - - function handleMouseDownPan( event ) { - - //console.log( 'handleMouseDownPan' ); - - panStart.set( event.clientX, event.clientY ); - - } - - function handleMouseMoveRotate( event ) { - - //console.log( 'handleMouseMoveRotate' ); - - rotateEnd.set( event.clientX, event.clientY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleMouseMoveDolly( event ) { - - //console.log( 'handleMouseMoveDolly' ); - - dollyEnd.set( event.clientX, event.clientY ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyIn( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyOut( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleMouseMovePan( event ) { - - //console.log( 'handleMouseMovePan' ); - - panEnd.set( event.clientX, event.clientY ); - - panDelta.subVectors( panEnd, panStart ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleMouseUp( event ) { - - // console.log( 'handleMouseUp' ); - - } - - function handleMouseWheel( event ) { - - // console.log( 'handleMouseWheel' ); - - if ( event.deltaY < 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( event.deltaY > 0 ) { - - dollyIn( getZoomScale() ); - - } - - scope.update(); - - } - - function handleKeyDown( event ) { - - //console.log( 'handleKeyDown' ); - - switch ( event.keyCode ) { - - case scope.keys.UP: - pan( 0, scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.BOTTOM: - pan( 0, - scope.keyPanSpeed ); - scope.update(); - break; - - case scope.keys.LEFT: - pan( scope.keyPanSpeed, 0 ); - scope.update(); - break; - - case scope.keys.RIGHT: - pan( - scope.keyPanSpeed, 0 ); - scope.update(); - break; - - } - - } - - function handleTouchStartRotate( event ) { - - //console.log( 'handleTouchStartRotate' ); - - rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchStartDolly( event ) { - - //console.log( 'handleTouchStartDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyStart.set( 0, distance ); - - } - - function handleTouchStartPan( event ) { - - //console.log( 'handleTouchStartPan' ); - - panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - } - - function handleTouchMoveRotate( event ) { - - //console.log( 'handleTouchMoveRotate' ); - - rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - rotateDelta.subVectors( rotateEnd, rotateStart ); - - var element = scope.domElement === document ? scope.domElement.body : scope.domElement; - - // rotating across whole screen goes 360 degrees around - rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); - - // rotating up and down along whole screen attempts to go 360, but limited to 180 - rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); - - rotateStart.copy( rotateEnd ); - - scope.update(); - - } - - function handleTouchMoveDolly( event ) { - - //console.log( 'handleTouchMoveDolly' ); - - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - - var distance = Math.sqrt( dx * dx + dy * dy ); - - dollyEnd.set( 0, distance ); - - dollyDelta.subVectors( dollyEnd, dollyStart ); - - if ( dollyDelta.y > 0 ) { - - dollyOut( getZoomScale() ); - - } else if ( dollyDelta.y < 0 ) { - - dollyIn( getZoomScale() ); - - } - - dollyStart.copy( dollyEnd ); - - scope.update(); - - } - - function handleTouchMovePan( event ) { - - //console.log( 'handleTouchMovePan' ); - - panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); - - panDelta.subVectors( panEnd, panStart ); - - pan( panDelta.x, panDelta.y ); - - panStart.copy( panEnd ); - - scope.update(); - - } - - function handleTouchEnd( event ) { - - //console.log( 'handleTouchEnd' ); - - } - - // - // event handlers - FSM: listen for events and reset state - // - - function onMouseDown( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - switch ( event.button ) { - - case scope.mouseButtons.ORBIT: - - if ( scope.enableRotate === false ) return; - - handleMouseDownRotate( event ); - - state = STATE.ROTATE; - - break; - - case scope.mouseButtons.ZOOM: - - if ( scope.enableZoom === false ) return; - - handleMouseDownDolly( event ); - - state = STATE.DOLLY; - - break; - - case scope.mouseButtons.PAN: - - if ( scope.enablePan === false ) return; - - handleMouseDownPan( event ); - - state = STATE.PAN; - - break; - - } - - if ( state !== STATE.NONE ) { - - document.addEventListener( 'mousemove', onMouseMove, false ); - document.addEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( startEvent ); - - } - - } - - function onMouseMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - switch ( state ) { - - case STATE.ROTATE: - - if ( scope.enableRotate === false ) return; - - handleMouseMoveRotate( event ); - - break; - - case STATE.DOLLY: - - if ( scope.enableZoom === false ) return; - - handleMouseMoveDolly( event ); - - break; - - case STATE.PAN: - - if ( scope.enablePan === false ) return; - - handleMouseMovePan( event ); - - break; - - } - - } - - function onMouseUp( event ) { - - if ( scope.enabled === false ) return; - - handleMouseUp( event ); - - document.removeEventListener( 'mousemove', onMouseMove, false ); - document.removeEventListener( 'mouseup', onMouseUp, false ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onMouseWheel( event ) { - - if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; - - event.preventDefault(); - event.stopPropagation(); - - handleMouseWheel( event ); - - scope.dispatchEvent( startEvent ); // not sure why these are here... - scope.dispatchEvent( endEvent ); - - } - - function onKeyDown( event ) { - - if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; - - handleKeyDown( event ); - - } - - function onTouchStart( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - - handleTouchStartRotate( event ); - - state = STATE.TOUCH_ROTATE; - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - - handleTouchStartDolly( event ); - - state = STATE.TOUCH_DOLLY; - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - - handleTouchStartPan( event ); - - state = STATE.TOUCH_PAN; - - break; - - default: - - state = STATE.NONE; - - } - - if ( state !== STATE.NONE ) { - - scope.dispatchEvent( startEvent ); - - } - - } - - function onTouchMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.touches.length ) { - - case 1: // one-fingered touch: rotate - - if ( scope.enableRotate === false ) return; - if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?... - - handleTouchMoveRotate( event ); - - break; - - case 2: // two-fingered touch: dolly - - if ( scope.enableZoom === false ) return; - if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?... - - handleTouchMoveDolly( event ); - - break; - - case 3: // three-fingered touch: pan - - if ( scope.enablePan === false ) return; - if ( state !== STATE.TOUCH_PAN ) return; // is this needed?... - - handleTouchMovePan( event ); - - break; - - default: - - state = STATE.NONE; - - } - - } - - function onTouchEnd( event ) { - - if ( scope.enabled === false ) return; - - handleTouchEnd( event ); - - scope.dispatchEvent( endEvent ); - - state = STATE.NONE; - - } - - function onContextMenu( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - } - - // - - scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); - - scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); - scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); - - scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); - scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); - scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); - - window.addEventListener( 'keydown', onKeyDown, false ); - - // force an update at start - - this.update(); - -}; - -THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; - -Object.defineProperties( THREE.OrbitControls.prototype, { - - center: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); - return this.target; - - } - - }, - - // backward compatibility - - noZoom: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - return ! this.enableZoom; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); - this.enableZoom = ! value; - - } - - }, - - noRotate: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - return ! this.enableRotate; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); - this.enableRotate = ! value; - - } - - }, - - noPan: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - return ! this.enablePan; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); - this.enablePan = ! value; - - } - - }, - - noKeys: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - return ! this.enableKeys; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); - this.enableKeys = ! value; - - } - - }, - - staticMoving: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - return ! this.enableDamping; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); - this.enableDamping = ! value; - - } - - }, - - dynamicDampingFactor: { - - get: function () { - - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - return this.dampingFactor; - - }, - - set: function ( value ) { - - console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); - this.dampingFactor = value; - - } - - } - -} ); \ No newline at end of file diff --git a/web/lib/three/TransformControls.js b/web/lib/three/TransformControls.js deleted file mode 100644 index 2e897705..00000000 --- a/web/lib/three/TransformControls.js +++ /dev/null @@ -1,1149 +0,0 @@ -/** - * @author arodic / https://github.com/arodic - */ - -( function () { - - 'use strict'; - - var GizmoMaterial = function ( parameters ) { - - THREE.MeshBasicMaterial.call( this ); - - this.depthTest = false; - this.depthWrite = false; - this.side = THREE.FrontSide; - this.transparent = true; - - this.setValues( parameters ); - - this.oldColor = this.color.clone(); - this.oldOpacity = this.opacity; - - this.highlight = function( highlighted ) { - - if ( highlighted ) { - - this.color.setRGB( 1, 1, 0 ); - this.opacity = 1; - - } else { - - this.color.copy( this.oldColor ); - this.opacity = this.oldOpacity; - - } - - }; - - }; - - GizmoMaterial.prototype = Object.create( THREE.MeshBasicMaterial.prototype ); - GizmoMaterial.prototype.constructor = GizmoMaterial; - - - var GizmoLineMaterial = function ( parameters ) { - - THREE.LineBasicMaterial.call( this ); - - this.depthTest = false; - this.depthWrite = false; - this.transparent = true; - this.linewidth = 1; - - this.setValues( parameters ); - - this.oldColor = this.color.clone(); - this.oldOpacity = this.opacity; - - this.highlight = function( highlighted ) { - - if ( highlighted ) { - - this.color.setRGB( 1, 1, 0 ); - this.opacity = 1; - - } else { - - this.color.copy( this.oldColor ); - this.opacity = this.oldOpacity; - - } - - }; - - }; - - GizmoLineMaterial.prototype = Object.create( THREE.LineBasicMaterial.prototype ); - GizmoLineMaterial.prototype.constructor = GizmoLineMaterial; - - - var pickerMaterial = new GizmoMaterial( { visible: false, transparent: false } ); - - - THREE.TransformGizmo = function () { - - this.init = function () { - - THREE.Object3D.call( this ); - - this.handles = new THREE.Object3D(); - this.pickers = new THREE.Object3D(); - this.planes = new THREE.Object3D(); - - this.add( this.handles ); - this.add( this.pickers ); - this.add( this.planes ); - - //// PLANES - - var planeGeometry = new THREE.PlaneBufferGeometry( 50, 50, 2, 2 ); - var planeMaterial = new THREE.MeshBasicMaterial( { visible: false, side: THREE.DoubleSide } ); - - var planes = { - "XY": new THREE.Mesh( planeGeometry, planeMaterial ), - "YZ": new THREE.Mesh( planeGeometry, planeMaterial ), - "XZ": new THREE.Mesh( planeGeometry, planeMaterial ), - "XYZE": new THREE.Mesh( planeGeometry, planeMaterial ) - }; - - this.activePlane = planes[ "XYZE" ]; - - planes[ "YZ" ].rotation.set( 0, Math.PI / 2, 0 ); - planes[ "XZ" ].rotation.set( - Math.PI / 2, 0, 0 ); - - for ( var i in planes ) { - - planes[ i ].name = i; - this.planes.add( planes[ i ] ); - this.planes[ i ] = planes[ i ]; - - } - - //// HANDLES AND PICKERS - - var setupGizmos = function( gizmoMap, parent ) { - - for ( var name in gizmoMap ) { - - for ( i = gizmoMap[ name ].length; i --; ) { - - var object = gizmoMap[ name ][ i ][ 0 ]; - var position = gizmoMap[ name ][ i ][ 1 ]; - var rotation = gizmoMap[ name ][ i ][ 2 ]; - - object.name = name; - - if ( position ) object.position.set( position[ 0 ], position[ 1 ], position[ 2 ] ); - if ( rotation ) object.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ] ); - - parent.add( object ); - - } - - } - - }; - - setupGizmos( this.handleGizmos, this.handles ); - setupGizmos( this.pickerGizmos, this.pickers ); - - // reset Transformations - - this.traverse( function ( child ) { - - if ( child instanceof THREE.Mesh ) { - - child.updateMatrix(); - - var tempGeometry = child.geometry.clone(); - tempGeometry.applyMatrix( child.matrix ); - child.geometry = tempGeometry; - - child.position.set( 0, 0, 0 ); - child.rotation.set( 0, 0, 0 ); - child.scale.set( 1, 1, 1 ); - - } - - } ); - - }; - - this.highlight = function ( axis ) { - - this.traverse( function( child ) { - - if ( child.material && child.material.highlight ) { - - if ( child.name === axis ) { - - child.material.highlight( true ); - - } else { - - child.material.highlight( false ); - - } - - } - - } ); - - }; - - }; - - THREE.TransformGizmo.prototype = Object.create( THREE.Object3D.prototype ); - THREE.TransformGizmo.prototype.constructor = THREE.TransformGizmo; - - THREE.TransformGizmo.prototype.update = function ( rotation, eye ) { - - var vec1 = new THREE.Vector3( 0, 0, 0 ); - var vec2 = new THREE.Vector3( 0, 1, 0 ); - var lookAtMatrix = new THREE.Matrix4(); - - this.traverse( function( child ) { - - if ( child.name.search( "E" ) !== - 1 ) { - - child.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( eye, vec1, vec2 ) ); - - } else if ( child.name.search( "X" ) !== - 1 || child.name.search( "Y" ) !== - 1 || child.name.search( "Z" ) !== - 1 ) { - - child.quaternion.setFromEuler( rotation ); - - } - - } ); - - }; - - THREE.TransformGizmoTranslate = function () { - - THREE.TransformGizmo.call( this ); - - var arrowGeometry = new THREE.Geometry(); - var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) ); - mesh.position.y = 0.5; - mesh.updateMatrix(); - - arrowGeometry.merge( mesh.geometry, mesh.matrix ); - - var lineXGeometry = new THREE.BufferGeometry(); - lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) ); - - var lineYGeometry = new THREE.BufferGeometry(); - lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - - var lineZGeometry = new THREE.BufferGeometry(); - lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - - this.handleGizmos = { - - X: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ], - [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] - ], - - Y: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], - [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] - ], - - Z: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], - [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] - ], - - XYZ: [ - [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, 0, 0 ] ] - ], - - XY: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.15, 0.15, 0 ] ] - ], - - YZ: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ] ] - ], - - XZ: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ] ] - ] - - }; - - this.pickerGizmos = { - - X: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] - ], - - Y: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ] - ], - - Z: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] - ], - - XYZ: [ - [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.2, 0 ), pickerMaterial ) ] - ], - - XY: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0.2, 0.2, 0 ] ] - ], - - YZ: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0, 0.2, 0.2 ], [ 0, Math.PI / 2, 0 ] ] - ], - - XZ: [ - [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0.2, 0, 0.2 ], [ - Math.PI / 2, 0, 0 ] ] - ] - - }; - - this.setActivePlane = function ( axis, eye ) { - - var tempMatrix = new THREE.Matrix4(); - eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); - - if ( axis === "X" ) { - - this.activePlane = this.planes[ "XY" ]; - - if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ]; - - } - - if ( axis === "Y" ) { - - this.activePlane = this.planes[ "XY" ]; - - if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ]; - - } - - if ( axis === "Z" ) { - - this.activePlane = this.planes[ "XZ" ]; - - if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ]; - - } - - if ( axis === "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; - - if ( axis === "XY" ) this.activePlane = this.planes[ "XY" ]; - - if ( axis === "YZ" ) this.activePlane = this.planes[ "YZ" ]; - - if ( axis === "XZ" ) this.activePlane = this.planes[ "XZ" ]; - - }; - - this.init(); - - }; - - THREE.TransformGizmoTranslate.prototype = Object.create( THREE.TransformGizmo.prototype ); - THREE.TransformGizmoTranslate.prototype.constructor = THREE.TransformGizmoTranslate; - - THREE.TransformGizmoRotate = function () { - - THREE.TransformGizmo.call( this ); - - var CircleGeometry = function ( radius, facing, arc ) { - - var geometry = new THREE.BufferGeometry(); - var vertices = []; - arc = arc ? arc : 1; - - for ( var i = 0; i <= 64 * arc; ++ i ) { - - if ( facing === 'x' ) vertices.push( 0, Math.cos( i / 32 * Math.PI ) * radius, Math.sin( i / 32 * Math.PI ) * radius ); - if ( facing === 'y' ) vertices.push( Math.cos( i / 32 * Math.PI ) * radius, 0, Math.sin( i / 32 * Math.PI ) * radius ); - if ( facing === 'z' ) vertices.push( Math.sin( i / 32 * Math.PI ) * radius, Math.cos( i / 32 * Math.PI ) * radius, 0 ); - - } - - geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) ); - return geometry; - - }; - - this.handleGizmos = { - - X: [ - [ new THREE.Line( new CircleGeometry( 1, 'x', 0.5 ), new GizmoLineMaterial( { color: 0xff0000 } ) ) ] - ], - - Y: [ - [ new THREE.Line( new CircleGeometry( 1, 'y', 0.5 ), new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] - ], - - Z: [ - [ new THREE.Line( new CircleGeometry( 1, 'z', 0.5 ), new GizmoLineMaterial( { color: 0x0000ff } ) ) ] - ], - - E: [ - [ new THREE.Line( new CircleGeometry( 1.25, 'z', 1 ), new GizmoLineMaterial( { color: 0xcccc00 } ) ) ] - ], - - XYZE: [ - [ new THREE.Line( new CircleGeometry( 1, 'z', 1 ), new GizmoLineMaterial( { color: 0x787878 } ) ) ] - ] - - }; - - this.pickerGizmos = { - - X: [ - [ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ] ] - ], - - Y: [ - [ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ] ] - ], - - Z: [ - [ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] - ], - - E: [ - [ new THREE.Mesh( new THREE.TorusBufferGeometry( 1.25, 0.12, 2, 24 ), pickerMaterial ) ] - ], - - XYZE: [ - [ new THREE.Mesh() ]// TODO - ] - - }; - - this.setActivePlane = function ( axis ) { - - if ( axis === "E" ) this.activePlane = this.planes[ "XYZE" ]; - - if ( axis === "X" ) this.activePlane = this.planes[ "YZ" ]; - - if ( axis === "Y" ) this.activePlane = this.planes[ "XZ" ]; - - if ( axis === "Z" ) this.activePlane = this.planes[ "XY" ]; - - }; - - this.update = function ( rotation, eye2 ) { - - THREE.TransformGizmo.prototype.update.apply( this, arguments ); - - var tempMatrix = new THREE.Matrix4(); - var worldRotation = new THREE.Euler( 0, 0, 1 ); - var tempQuaternion = new THREE.Quaternion(); - var unitX = new THREE.Vector3( 1, 0, 0 ); - var unitY = new THREE.Vector3( 0, 1, 0 ); - var unitZ = new THREE.Vector3( 0, 0, 1 ); - var quaternionX = new THREE.Quaternion(); - var quaternionY = new THREE.Quaternion(); - var quaternionZ = new THREE.Quaternion(); - var eye = eye2.clone(); - - worldRotation.copy( this.planes[ "XY" ].rotation ); - tempQuaternion.setFromEuler( worldRotation ); - - tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix ); - eye.applyMatrix4( tempMatrix ); - - this.traverse( function( child ) { - - tempQuaternion.setFromEuler( worldRotation ); - - if ( child.name === "X" ) { - - quaternionX.setFromAxisAngle( unitX, Math.atan2( - eye.y, eye.z ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - child.quaternion.copy( tempQuaternion ); - - } - - if ( child.name === "Y" ) { - - quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); - child.quaternion.copy( tempQuaternion ); - - } - - if ( child.name === "Z" ) { - - quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); - child.quaternion.copy( tempQuaternion ); - - } - - } ); - - }; - - this.init(); - - }; - - THREE.TransformGizmoRotate.prototype = Object.create( THREE.TransformGizmo.prototype ); - THREE.TransformGizmoRotate.prototype.constructor = THREE.TransformGizmoRotate; - - THREE.TransformGizmoScale = function () { - - THREE.TransformGizmo.call( this ); - - var arrowGeometry = new THREE.Geometry(); - var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) ); - mesh.position.y = 0.5; - mesh.updateMatrix(); - - arrowGeometry.merge( mesh.geometry, mesh.matrix ); - - var lineXGeometry = new THREE.BufferGeometry(); - lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) ); - - var lineYGeometry = new THREE.BufferGeometry(); - lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - - var lineZGeometry = new THREE.BufferGeometry(); - lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - - this.handleGizmos = { - - X: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ], - [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] - ], - - Y: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], - [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] - ], - - Z: [ - [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], - [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] - ], - - XYZ: [ - [ new THREE.Mesh( new THREE.BoxBufferGeometry( 0.125, 0.125, 0.125 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ] - ] - - }; - - this.pickerGizmos = { - - X: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] - ], - - Y: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ] - ], - - Z: [ - [ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] - ], - - XYZ: [ - [ new THREE.Mesh( new THREE.BoxBufferGeometry( 0.4, 0.4, 0.4 ), pickerMaterial ) ] - ] - - }; - - this.setActivePlane = function ( axis, eye ) { - - var tempMatrix = new THREE.Matrix4(); - eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); - - if ( axis === "X" ) { - - this.activePlane = this.planes[ "XY" ]; - if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ]; - - } - - if ( axis === "Y" ) { - - this.activePlane = this.planes[ "XY" ]; - if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ]; - - } - - if ( axis === "Z" ) { - - this.activePlane = this.planes[ "XZ" ]; - if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ]; - - } - - if ( axis === "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; - - }; - - this.init(); - - }; - - THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype ); - THREE.TransformGizmoScale.prototype.constructor = THREE.TransformGizmoScale; - - THREE.TransformControls = function ( camera, domElement ) { - - // TODO: Make non-uniform scale and rotate play nice in hierarchies - // TODO: ADD RXYZ contol - - THREE.Object3D.call( this ); - - domElement = ( domElement !== undefined ) ? domElement : document; - - this.object = undefined; - this.visible = false; - this.translationSnap = null; - this.rotationSnap = null; - this.space = "world"; - this.size = 1; - this.axis = null; - - var scope = this; - - var _mode = "translate"; - var _dragging = false; - var _gizmo = { - - "translate": new THREE.TransformGizmoTranslate(), - "rotate": new THREE.TransformGizmoRotate(), - "scale": new THREE.TransformGizmoScale() - }; - - for ( var type in _gizmo ) { - - var gizmoObj = _gizmo[ type ]; - - gizmoObj.visible = ( type === _mode ); - this.add( gizmoObj ); - - } - - var changeEvent = { type: "change" }; - var mouseDownEvent = { type: "mouseDown" }; - var mouseUpEvent = { type: "mouseUp", mode: _mode }; - var objectChangeEvent = { type: "objectChange" }; - - var ray = new THREE.Raycaster(); - var pointerVector = new THREE.Vector2(); - - var point = new THREE.Vector3(); - var offset = new THREE.Vector3(); - - var rotation = new THREE.Vector3(); - var offsetRotation = new THREE.Vector3(); - var scale = 1; - - var lookAtMatrix = new THREE.Matrix4(); - var eye = new THREE.Vector3(); - - var tempMatrix = new THREE.Matrix4(); - var tempVector = new THREE.Vector3(); - var tempQuaternion = new THREE.Quaternion(); - var unitX = new THREE.Vector3( 1, 0, 0 ); - var unitY = new THREE.Vector3( 0, 1, 0 ); - var unitZ = new THREE.Vector3( 0, 0, 1 ); - - var quaternionXYZ = new THREE.Quaternion(); - var quaternionX = new THREE.Quaternion(); - var quaternionY = new THREE.Quaternion(); - var quaternionZ = new THREE.Quaternion(); - var quaternionE = new THREE.Quaternion(); - - var oldPosition = new THREE.Vector3(); - var oldScale = new THREE.Vector3(); - var oldRotationMatrix = new THREE.Matrix4(); - - var parentRotationMatrix = new THREE.Matrix4(); - var parentScale = new THREE.Vector3(); - - var worldPosition = new THREE.Vector3(); - var worldRotation = new THREE.Euler(); - var worldRotationMatrix = new THREE.Matrix4(); - var camPosition = new THREE.Vector3(); - var camRotation = new THREE.Euler(); - - domElement.addEventListener( "mousedown", onPointerDown, false ); - domElement.addEventListener( "touchstart", onPointerDown, false ); - - domElement.addEventListener( "mousemove", onPointerHover, false ); - domElement.addEventListener( "touchmove", onPointerHover, false ); - - domElement.addEventListener( "mousemove", onPointerMove, false ); - domElement.addEventListener( "touchmove", onPointerMove, false ); - - domElement.addEventListener( "mouseup", onPointerUp, false ); - domElement.addEventListener( "mouseout", onPointerUp, false ); - domElement.addEventListener( "touchend", onPointerUp, false ); - domElement.addEventListener( "touchcancel", onPointerUp, false ); - domElement.addEventListener( "touchleave", onPointerUp, false ); - - this.dispose = function () { - - domElement.removeEventListener( "mousedown", onPointerDown ); - domElement.removeEventListener( "touchstart", onPointerDown ); - - domElement.removeEventListener( "mousemove", onPointerHover ); - domElement.removeEventListener( "touchmove", onPointerHover ); - - domElement.removeEventListener( "mousemove", onPointerMove ); - domElement.removeEventListener( "touchmove", onPointerMove ); - - domElement.removeEventListener( "mouseup", onPointerUp ); - domElement.removeEventListener( "mouseout", onPointerUp ); - domElement.removeEventListener( "touchend", onPointerUp ); - domElement.removeEventListener( "touchcancel", onPointerUp ); - domElement.removeEventListener( "touchleave", onPointerUp ); - - }; - - this.attach = function ( object ) { - - this.object = object; - this.visible = true; - this.update(); - - }; - - this.detach = function () { - - this.object = undefined; - this.visible = false; - this.axis = null; - - }; - - this.getMode = function () { - - return _mode; - - }; - - this.setMode = function ( mode ) { - - _mode = mode ? mode : _mode; - - if ( _mode === "scale" ) scope.space = "local"; - - for ( var type in _gizmo ) _gizmo[ type ].visible = ( type === _mode ); - - this.update(); - scope.dispatchEvent( changeEvent ); - - }; - - this.setTranslationSnap = function ( translationSnap ) { - - scope.translationSnap = translationSnap; - - }; - - this.setRotationSnap = function ( rotationSnap ) { - - scope.rotationSnap = rotationSnap; - - }; - - this.setSize = function ( size ) { - - scope.size = size; - this.update(); - scope.dispatchEvent( changeEvent ); - - }; - - this.setSpace = function ( space ) { - - scope.space = space; - this.update(); - scope.dispatchEvent( changeEvent ); - - }; - - this.update = function () { - - if ( scope.object === undefined ) return; - - scope.object.updateMatrixWorld(); - worldPosition.setFromMatrixPosition( scope.object.matrixWorld ); - worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.object.matrixWorld ) ); - - camera.updateMatrixWorld(); - camPosition.setFromMatrixPosition( camera.matrixWorld ); - camRotation.setFromRotationMatrix( tempMatrix.extractRotation( camera.matrixWorld ) ); - - scale = worldPosition.distanceTo( camPosition ) / 6 * scope.size; - this.position.copy( worldPosition ); - this.scale.set( scale, scale, scale ); - - if ( camera instanceof THREE.PerspectiveCamera ) { - - eye.copy( camPosition ).sub( worldPosition ).normalize(); - - } else if ( camera instanceof THREE.OrthographicCamera ) { - - eye.copy( camPosition ).normalize(); - - } - - if ( scope.space === "local" ) { - - _gizmo[ _mode ].update( worldRotation, eye ); - - } else if ( scope.space === "world" ) { - - _gizmo[ _mode ].update( new THREE.Euler(), eye ); - - } - - _gizmo[ _mode ].highlight( scope.axis ); - - }; - - function onPointerHover( event ) { - - if ( scope.object === undefined || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return; - - var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; - - var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children ); - - var axis = null; - - if ( intersect ) { - - axis = intersect.object.name; - - event.preventDefault(); - - } - - if ( scope.axis !== axis ) { - - scope.axis = axis; - scope.update(); - scope.dispatchEvent( changeEvent ); - - } - - } - - function onPointerDown( event ) { - - if ( scope.object === undefined || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return; - - var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; - - if ( pointer.button === 0 || pointer.button === undefined ) { - - var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children ); - - if ( intersect ) { - - event.preventDefault(); - event.stopPropagation(); - - scope.dispatchEvent( mouseDownEvent ); - - scope.axis = intersect.object.name; - - scope.update(); - - eye.copy( camPosition ).sub( worldPosition ).normalize(); - - _gizmo[ _mode ].setActivePlane( scope.axis, eye ); - - var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] ); - - if ( planeIntersect ) { - - oldPosition.copy( scope.object.position ); - oldScale.copy( scope.object.scale ); - - oldRotationMatrix.extractRotation( scope.object.matrix ); - worldRotationMatrix.extractRotation( scope.object.matrixWorld ); - - parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld ); - parentScale.setFromMatrixScale( tempMatrix.getInverse( scope.object.parent.matrixWorld ) ); - - offset.copy( planeIntersect.point ); - - } - - } - - } - - _dragging = true; - - } - - function onPointerMove( event ) { - - if ( scope.object === undefined || scope.axis === null || _dragging === false || ( event.button !== undefined && event.button !== 0 ) ) return; - - var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; - - var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] ); - - if ( planeIntersect === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - point.copy( planeIntersect.point ); - - if ( _mode === "translate" ) { - - point.sub( offset ); - point.multiply( parentScale ); - - if ( scope.space === "local" ) { - - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - - if ( scope.axis.search( "X" ) === - 1 ) point.x = 0; - if ( scope.axis.search( "Y" ) === - 1 ) point.y = 0; - if ( scope.axis.search( "Z" ) === - 1 ) point.z = 0; - - point.applyMatrix4( oldRotationMatrix ); - - scope.object.position.copy( oldPosition ); - scope.object.position.add( point ); - - } - - if ( scope.space === "world" || scope.axis.search( "XYZ" ) !== - 1 ) { - - if ( scope.axis.search( "X" ) === - 1 ) point.x = 0; - if ( scope.axis.search( "Y" ) === - 1 ) point.y = 0; - if ( scope.axis.search( "Z" ) === - 1 ) point.z = 0; - - point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) ); - - scope.object.position.copy( oldPosition ); - scope.object.position.add( point ); - - } - - if ( scope.translationSnap !== null ) { - - if ( scope.space === "local" ) { - - scope.object.position.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - - } - - if ( scope.axis.search( "X" ) !== - 1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.translationSnap ) * scope.translationSnap; - if ( scope.axis.search( "Y" ) !== - 1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.translationSnap ) * scope.translationSnap; - if ( scope.axis.search( "Z" ) !== - 1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.translationSnap ) * scope.translationSnap; - - if ( scope.space === "local" ) { - - scope.object.position.applyMatrix4( worldRotationMatrix ); - - } - - } - - } else if ( _mode === "scale" ) { - - point.sub( offset ); - point.multiply( parentScale ); - - if ( scope.space === "local" ) { - - if ( scope.axis === "XYZ" ) { - - scale = 1 + ( ( point.y ) / Math.max( oldScale.x, oldScale.y, oldScale.z ) ); - - scope.object.scale.x = oldScale.x * scale; - scope.object.scale.y = oldScale.y * scale; - scope.object.scale.z = oldScale.z * scale; - - } else { - - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - - if ( scope.axis === "X" ) scope.object.scale.x = oldScale.x * ( 1 + point.x / oldScale.x ); - if ( scope.axis === "Y" ) scope.object.scale.y = oldScale.y * ( 1 + point.y / oldScale.y ); - if ( scope.axis === "Z" ) scope.object.scale.z = oldScale.z * ( 1 + point.z / oldScale.z ); - - } - - } - - } else if ( _mode === "rotate" ) { - - point.sub( worldPosition ); - point.multiply( parentScale ); - tempVector.copy( offset ).sub( worldPosition ); - tempVector.multiply( parentScale ); - - if ( scope.axis === "E" ) { - - point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); - tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); - - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - - quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z ); - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - - scope.object.quaternion.copy( tempQuaternion ); - - } else if ( scope.axis === "XYZE" ) { - - quaternionE.setFromEuler( point.clone().cross( tempVector ).normalize() ); // rotation axis - - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo( tempVector ) ); - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - - scope.object.quaternion.copy( tempQuaternion ); - - } else if ( scope.space === "local" ) { - - point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - - tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); - - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - - quaternionXYZ.setFromRotationMatrix( oldRotationMatrix ); - - if ( scope.rotationSnap !== null ) { - - quaternionX.setFromAxisAngle( unitX, Math.round( ( rotation.x - offsetRotation.x ) / scope.rotationSnap ) * scope.rotationSnap ); - quaternionY.setFromAxisAngle( unitY, Math.round( ( rotation.y - offsetRotation.y ) / scope.rotationSnap ) * scope.rotationSnap ); - quaternionZ.setFromAxisAngle( unitZ, Math.round( ( rotation.z - offsetRotation.z ) / scope.rotationSnap ) * scope.rotationSnap ); - - } else { - - quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); - quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); - quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); - - } - - if ( scope.axis === "X" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX ); - if ( scope.axis === "Y" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY ); - if ( scope.axis === "Z" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ ); - - scope.object.quaternion.copy( quaternionXYZ ); - - } else if ( scope.space === "world" ) { - - rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); - offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); - - tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); - - if ( scope.rotationSnap !== null ) { - - quaternionX.setFromAxisAngle( unitX, Math.round( ( rotation.x - offsetRotation.x ) / scope.rotationSnap ) * scope.rotationSnap ); - quaternionY.setFromAxisAngle( unitY, Math.round( ( rotation.y - offsetRotation.y ) / scope.rotationSnap ) * scope.rotationSnap ); - quaternionZ.setFromAxisAngle( unitZ, Math.round( ( rotation.z - offsetRotation.z ) / scope.rotationSnap ) * scope.rotationSnap ); - - } else { - - quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); - quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); - quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); - - } - - quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); - - if ( scope.axis === "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); - if ( scope.axis === "Y" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); - if ( scope.axis === "Z" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); - - tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); - - scope.object.quaternion.copy( tempQuaternion ); - - } - - } - - scope.update(); - scope.dispatchEvent( changeEvent ); - scope.dispatchEvent( objectChangeEvent ); - - } - - function onPointerUp( event ) { - - event.preventDefault(); // Prevent MouseEvent on mobile - - if ( event.button !== undefined && event.button !== 0 ) return; - - if ( _dragging && ( scope.axis !== null ) ) { - - mouseUpEvent.mode = _mode; - scope.dispatchEvent( mouseUpEvent ); - - } - - _dragging = false; - - if ( 'TouchEvent' in window && event instanceof TouchEvent ) { - - // Force "rollover" - - scope.axis = null; - scope.update(); - scope.dispatchEvent( changeEvent ); - - } else { - - onPointerHover( event ); - - } - - } - - function intersectObjects( pointer, objects ) { - - var rect = domElement.getBoundingClientRect(); - var x = ( pointer.clientX - rect.left ) / rect.width; - var y = ( pointer.clientY - rect.top ) / rect.height; - - pointerVector.set( ( x * 2 ) - 1, - ( y * 2 ) + 1 ); - ray.setFromCamera( pointerVector, camera ); - - var intersections = ray.intersectObjects( objects, true ); - return intersections[ 0 ] ? intersections[ 0 ] : false; - - } - - }; - - THREE.TransformControls.prototype = Object.create( THREE.Object3D.prototype ); - THREE.TransformControls.prototype.constructor = THREE.TransformControls; - -}() ); \ No newline at end of file