From 62f13057580b39d14d0e952d2e745741b4dc8065 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Patrick=20Sch=C3=B6nberger?= Date: Wed, 3 Feb 2021 08:37:55 +0100 Subject: [PATCH] new files --- Scripts/OrbitControls.js | 1229 +++++++++++++++++++++++++ Textures/neg-x.jpg | Bin 0 -> 72000 bytes Textures/neg-y.jpg | Bin 0 -> 53264 bytes Textures/neg-z.jpg | Bin 0 -> 59501 bytes Textures/pos-x.jpg | Bin 0 -> 64553 bytes Textures/pos-y.jpg | Bin 0 -> 59974 bytes Textures/pos-z.jpg | Bin 0 -> 79825 bytes Textures/tears_of_steel_bridge_2k.jpg | Bin 0 -> 371116 bytes 8 files changed, 1229 insertions(+) create mode 100644 Scripts/OrbitControls.js create mode 100644 Textures/neg-x.jpg create mode 100644 Textures/neg-y.jpg create mode 100644 Textures/neg-z.jpg create mode 100644 Textures/pos-x.jpg create mode 100644 Textures/pos-y.jpg create mode 100644 Textures/pos-z.jpg create mode 100644 Textures/tears_of_steel_bridge_2k.jpg diff --git a/Scripts/OrbitControls.js b/Scripts/OrbitControls.js new file mode 100644 index 0000000..8695c99 --- /dev/null +++ b/Scripts/OrbitControls.js @@ -0,0 +1,1229 @@ +import { + EventDispatcher, + MOUSE, + Quaternion, + Spherical, + TOUCH, + Vector2, + Vector3 +} from './three.module.js'; + +// 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 left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move + +var OrbitControls = function ( object, domElement ) { + + if ( domElement === undefined ) console.warn( 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.' ); + if ( domElement === document ) console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); + + this.object = object; + this.domElement = domElement; + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the object orbits around + this.target = new 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, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 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.05; + + // 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.panSpeed = 1.0; + this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up + 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 + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }; + + // Touch fingers + this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }; + + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // the target DOM element for key events + this._domElementKeyEvents = null; + + // + // public methods + // + + this.getPolarAngle = function () { + + return spherical.phi; + + }; + + this.getAzimuthalAngle = function () { + + return spherical.theta; + + }; + + this.listenToKeyEvents = function ( domElement ) { + + domElement.addEventListener( 'keydown', onKeyDown ); + this._domElementKeyEvents = domElement; + + }; + + 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 Vector3(); + + // so camera.up is the orbit axis + var quat = new Quaternion().setFromUnitVectors( object.up, new Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().invert(); + + var lastPosition = new Vector3(); + var lastQuaternion = new Quaternion(); + + var twoPI = 2 * Math.PI; + + 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() ); + + } + + if ( scope.enableDamping ) { + + spherical.theta += sphericalDelta.theta * scope.dampingFactor; + spherical.phi += sphericalDelta.phi * scope.dampingFactor; + + } else { + + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + + } + + // restrict theta to be between desired limits + + var min = scope.minAzimuthAngle; + var max = scope.maxAzimuthAngle; + + if ( isFinite( min ) && isFinite( max ) ) { + + if ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI; + + if ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI; + + if ( min <= max ) { + + spherical.theta = Math.max( min, Math.min( max, spherical.theta ) ); + + } else { + + spherical.theta = ( spherical.theta > ( min + max ) / 2 ) ? + Math.max( min, spherical.theta ) : + Math.min( max, 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 + + if ( scope.enableDamping === true ) { + + scope.target.addScaledVector( panOffset, scope.dampingFactor ); + + } else { + + 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 ); + + panOffset.multiplyScalar( 1 - scope.dampingFactor ); + + } else { + + sphericalDelta.set( 0, 0, 0 ); + + panOffset.set( 0, 0, 0 ); + + } + + scale = 1; + + // 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 ); + + scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); + scope.domElement.removeEventListener( 'wheel', onMouseWheel ); + + scope.domElement.removeEventListener( 'touchstart', onTouchStart ); + scope.domElement.removeEventListener( 'touchend', onTouchEnd ); + scope.domElement.removeEventListener( 'touchmove', onTouchMove ); + + scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); + + + if ( scope._domElementKeyEvents !== null ) { + + scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + + } + + //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_PAN: 4, + TOUCH_DOLLY_PAN: 5, + TOUCH_DOLLY_ROTATE: 6 + }; + + var state = STATE.NONE; + + var EPS = 0.000001; + + // current position in spherical coordinates + var spherical = new Spherical(); + var sphericalDelta = new Spherical(); + + var scale = 1; + var panOffset = new Vector3(); + var zoomChanged = false; + + var rotateStart = new Vector2(); + var rotateEnd = new Vector2(); + var rotateDelta = new Vector2(); + + var panStart = new Vector2(); + var panEnd = new Vector2(); + var panDelta = new Vector2(); + + var dollyStart = new Vector2(); + var dollyEnd = new Vector2(); + var dollyDelta = new 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 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 Vector3(); + + return function panUp( distance, objectMatrix ) { + + if ( scope.screenSpacePanning === true ) { + + v.setFromMatrixColumn( objectMatrix, 1 ); + + } else { + + v.setFromMatrixColumn( objectMatrix, 0 ); + v.crossVectors( scope.object.up, v ); + + } + + v.multiplyScalar( distance ); + + panOffset.add( v ); + + }; + + }(); + + // deltaX and deltaY are in pixels; right and down are positive + var pan = function () { + + var offset = new Vector3(); + + return function pan( deltaX, deltaY ) { + + var element = 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 use only clientHeight here so aspect ratio does not distort speed + 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 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; + + } + + } + + 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; + + } + + } + + // + // event callbacks - update the object state + // + + function handleMouseDownRotate( event ) { + + rotateStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownDolly( event ) { + + dollyStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownPan( event ) { + + panStart.set( event.clientX, event.clientY ); + + } + + function handleMouseMoveRotate( event ) { + + rotateEnd.set( event.clientX, event.clientY ); + + rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); + + var element = scope.domElement; + + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height + + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + + } + + function handleMouseMoveDolly( event ) { + + dollyEnd.set( event.clientX, event.clientY ); + + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + + } + + function handleMouseMovePan( event ) { + + panEnd.set( event.clientX, event.clientY ); + + panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + + } + + function handleMouseUp( /*event*/ ) { + + // no-op + + } + + function handleMouseWheel( event ) { + + if ( event.deltaY < 0 ) { + + dollyIn( getZoomScale() ); + + } else if ( event.deltaY > 0 ) { + + dollyOut( getZoomScale() ); + + } + + scope.update(); + + } + + function handleKeyDown( event ) { + + var needsUpdate = false; + + switch ( event.keyCode ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + needsUpdate = true; + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + needsUpdate = true; + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + needsUpdate = true; + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + needsUpdate = true; + break; + + } + + if ( needsUpdate ) { + + // prevent the browser from scrolling on cursor keys + event.preventDefault(); + + scope.update(); + + } + + + } + + function handleTouchStartRotate( event ) { + + if ( event.touches.length == 1 ) { + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } else { + + var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); + var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); + + rotateStart.set( x, y ); + + } + + } + + function handleTouchStartPan( event ) { + + if ( event.touches.length == 1 ) { + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } else { + + var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); + var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); + + panStart.set( x, y ); + + } + + } + + function handleTouchStartDolly( event ) { + + 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 handleTouchStartDollyPan( event ) { + + if ( scope.enableZoom ) handleTouchStartDolly( event ); + + if ( scope.enablePan ) handleTouchStartPan( event ); + + } + + function handleTouchStartDollyRotate( event ) { + + if ( scope.enableZoom ) handleTouchStartDolly( event ); + + if ( scope.enableRotate ) handleTouchStartRotate( event ); + + } + + function handleTouchMoveRotate( event ) { + + if ( event.touches.length == 1 ) { + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } else { + + var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); + var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); + + rotateEnd.set( x, y ); + + } + + rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); + + var element = scope.domElement; + + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height + + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); + + rotateStart.copy( rotateEnd ); + + } + + function handleTouchMovePan( event ) { + + if ( event.touches.length == 1 ) { + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + + } else { + + var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); + var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); + + panEnd.set( x, y ); + + } + + panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + } + + function handleTouchMoveDolly( event ) { + + 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.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) ); + + dollyOut( dollyDelta.y ); + + dollyStart.copy( dollyEnd ); + + } + + function handleTouchMoveDollyPan( event ) { + + if ( scope.enableZoom ) handleTouchMoveDolly( event ); + + if ( scope.enablePan ) handleTouchMovePan( event ); + + } + + function handleTouchMoveDollyRotate( event ) { + + if ( scope.enableZoom ) handleTouchMoveDolly( event ); + + if ( scope.enableRotate ) handleTouchMoveRotate( event ); + + } + + function handleTouchEnd( /*event*/ ) { + + // no-op + + } + + // + // event handlers - FSM: listen for events and reset state + // + + function onPointerDown( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.pointerType ) { + + case 'mouse': + case 'pen': + onMouseDown( event ); + break; + + // TODO touch + + } + + } + + function onPointerMove( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.pointerType ) { + + case 'mouse': + case 'pen': + onMouseMove( event ); + break; + + // TODO touch + + } + + } + + function onPointerUp( event ) { + + switch ( event.pointerType ) { + + case 'mouse': + case 'pen': + onMouseUp( event ); + break; + + // TODO touch + + } + + } + + function onMouseDown( event ) { + + // Prevent the browser from scrolling. + event.preventDefault(); + + // Manually set the focus since calling preventDefault above + // prevents the browser from setting it automatically. + + scope.domElement.focus ? scope.domElement.focus() : window.focus(); + + var mouseAction; + + switch ( event.button ) { + + case 0: + + mouseAction = scope.mouseButtons.LEFT; + break; + + case 1: + + mouseAction = scope.mouseButtons.MIDDLE; + break; + + case 2: + + mouseAction = scope.mouseButtons.RIGHT; + break; + + default: + + mouseAction = - 1; + + } + + switch ( mouseAction ) { + + case MOUSE.DOLLY: + + if ( scope.enableZoom === false ) return; + + handleMouseDownDolly( event ); + + state = STATE.DOLLY; + + break; + + case MOUSE.ROTATE: + + if ( event.ctrlKey || event.metaKey || event.shiftKey ) { + + if ( scope.enablePan === false ) return; + + handleMouseDownPan( event ); + + state = STATE.PAN; + + } else { + + if ( scope.enableRotate === false ) return; + + handleMouseDownRotate( event ); + + state = STATE.ROTATE; + + } + + break; + + case MOUSE.PAN: + + if ( event.ctrlKey || event.metaKey || event.shiftKey ) { + + if ( scope.enableRotate === false ) return; + + handleMouseDownRotate( event ); + + state = STATE.ROTATE; + + } else { + + if ( scope.enablePan === false ) return; + + handleMouseDownPan( event ); + + state = STATE.PAN; + + } + + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) { + + scope.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove ); + scope.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp ); + + 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 ) { + + scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); + + if ( scope.enabled === false ) return; + + handleMouseUp( event ); + + 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(); + + scope.dispatchEvent( startEvent ); + + handleMouseWheel( event ); + + scope.dispatchEvent( endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.enablePan === false ) return; + + handleKeyDown( event ); + + } + + function onTouchStart( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); // prevent scrolling + + switch ( event.touches.length ) { + + case 1: + + switch ( scope.touches.ONE ) { + + case TOUCH.ROTATE: + + if ( scope.enableRotate === false ) return; + + handleTouchStartRotate( event ); + + state = STATE.TOUCH_ROTATE; + + break; + + case TOUCH.PAN: + + if ( scope.enablePan === false ) return; + + handleTouchStartPan( event ); + + state = STATE.TOUCH_PAN; + + break; + + default: + + state = STATE.NONE; + + } + + break; + + case 2: + + switch ( scope.touches.TWO ) { + + case TOUCH.DOLLY_PAN: + + if ( scope.enableZoom === false && scope.enablePan === false ) return; + + handleTouchStartDollyPan( event ); + + state = STATE.TOUCH_DOLLY_PAN; + + break; + + case TOUCH.DOLLY_ROTATE: + + if ( scope.enableZoom === false && scope.enableRotate === false ) return; + + handleTouchStartDollyRotate( event ); + + state = STATE.TOUCH_DOLLY_ROTATE; + + break; + + default: + + state = STATE.NONE; + + } + + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) { + + scope.dispatchEvent( startEvent ); + + } + + } + + function onTouchMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); // prevent scrolling + event.stopPropagation(); + + switch ( state ) { + + case STATE.TOUCH_ROTATE: + + if ( scope.enableRotate === false ) return; + + handleTouchMoveRotate( event ); + + scope.update(); + + break; + + case STATE.TOUCH_PAN: + + if ( scope.enablePan === false ) return; + + handleTouchMovePan( event ); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_PAN: + + if ( scope.enableZoom === false && scope.enablePan === false ) return; + + handleTouchMoveDollyPan( event ); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_ROTATE: + + if ( scope.enableZoom === false && scope.enableRotate === false ) return; + + handleTouchMoveDollyRotate( event ); + + scope.update(); + + 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 ); + + scope.domElement.addEventListener( 'pointerdown', onPointerDown ); + scope.domElement.addEventListener( 'wheel', onMouseWheel ); + + scope.domElement.addEventListener( 'touchstart', onTouchStart ); + scope.domElement.addEventListener( 'touchend', onTouchEnd ); + scope.domElement.addEventListener( 'touchmove', onTouchMove ); + + // force an update at start + + this.update(); + +}; + +OrbitControls.prototype = Object.create( EventDispatcher.prototype ); +OrbitControls.prototype.constructor = OrbitControls; + + +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// This is very similar to OrbitControls, another set of touch behavior +// +// Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate +// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish +// Pan - left mouse, or arrow keys / touch: one-finger move + +var MapControls = function ( object, domElement ) { + + OrbitControls.call( this, object, domElement ); + + this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up + + this.mouseButtons.LEFT = MOUSE.PAN; + this.mouseButtons.RIGHT = MOUSE.ROTATE; + + this.touches.ONE = TOUCH.PAN; + this.touches.TWO = TOUCH.DOLLY_ROTATE; + +}; + +MapControls.prototype = Object.create( EventDispatcher.prototype ); +MapControls.prototype.constructor = MapControls; + +export { OrbitControls, MapControls }; \ No newline at end of file diff --git a/Textures/neg-x.jpg b/Textures/neg-x.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82812fc9da970e9c8000e27b0088014d468f8ff0 GIT binary patch literal 72000 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