diff --git a/src/Renderer/Camera.js b/src/Renderer/Camera.js index defaeaf3be..705e745e2b 100644 --- a/src/Renderer/Camera.js +++ b/src/Renderer/Camera.js @@ -29,12 +29,8 @@ function Camera(width, height, debug) { this.frustum = new THREE.Frustum(); this.width = width; this.height = height; - this.Hypotenuse = Math.sqrt(this.width * this.width + this.height * this.height); - var radAngle = this.FOV * Math.PI / 180; - this.HFOV = 2.0 * Math.atan(Math.tan(radAngle * 0.5) / this.ratio); // TODO surement faux - this.HYFOV = 2.0 * Math.atan(Math.tan(radAngle * 0.5) * this.Hypotenuse / this.width); - this.preSSE = this.Hypotenuse * (2.0 * Math.tan(this.HYFOV * 0.5)); + this.updatePreSSE(); this.cameraHelper = debug ? new THREE.CameraHelper(this.camera3D) : undefined; } @@ -57,10 +53,42 @@ Camera.prototype.camHelper = function() { }; +Camera.prototype.updatePreSSE = function() { + + this.Hypotenuse = Math.sqrt(this.width * this.width + this.height * this.height); + var radAngle = this.FOV * Math.PI / 180; + + this.HFOV = 2.0 * Math.atan(Math.tan(radAngle * 0.5) / this.ratio); // TODO: not correct -> see new preSSE + this.HYFOV = 2.0 * Math.atan(Math.tan(radAngle * 0.5) * this.Hypotenuse / this.width); + this.preSSE = this.Hypotenuse * (2.0 * Math.tan(this.HYFOV * 0.5)); + + /* TODO: New preSSE but problem on Windows + var d = this.height / (2*Math.tan(radAngle/2)); + + //TODO: Verify with arrow helper + this.HFOV = 2*Math.atan((this.width/2)/d); + this.HYFOV = 2*Math.atan((this.Hypotenuse/2)/d); + + this.preSSE = this.Hypotenuse * (2.0 * Math.tan(this.HYFOV * 0.5)); + */ +}; + Camera.prototype.createCamHelper = function() { this.cameraHelper = new THREE.CameraHelper(this.camera3D); + var dir = new THREE.Vector3( 0, 0, -1 ); + var quaternion = new THREE.Quaternion(); + + quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), this.HFOV/2); + dir.applyQuaternion( quaternion ); + var origin = new THREE.Vector3(); + var length = 100000000; + var hex = 0xffff00; + + this.arrowHelper = new THREE.ArrowHelper( dir, origin, length, hex ); + this.cameraHelper.add(this.arrowHelper); + }; Camera.prototype.matrixWorldInverse = function() { @@ -74,18 +102,22 @@ Camera.prototype.resize = function(width, height) { this.height = height; this.ratio = width / height; - this.Hypotenuse = Math.sqrt(this.width * this.width + this.height * this.height); - - var radAngle = this.FOV * Math.PI / 180; - - this.HYFOV = 2.0 * Math.atan(Math.tan(radAngle * 0.5) * this.Hypotenuse / this.width); - - this.preSSE = this.Hypotenuse * (2.0 * Math.tan(this.HYFOV * 0.5)); + this.updatePreSSE(); this.camera3D.aspect = this.ratio; - this.camera3D.updateProjectionMatrix(); + if(this.cameraHelper) + { + var dir = new THREE.Vector3( 0, 0, -1 ); + var quaternion = new THREE.Quaternion(); + quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), this.HFOV/2); + dir.applyQuaternion( quaternion ); + + this.arrowHelper.setDirection(dir); + this.cameraHelper.update(); + } + }; Camera.prototype.computeNodeSSE = function(node) { diff --git a/src/Renderer/ThreeExtented/GlobeControls.js b/src/Renderer/ThreeExtented/GlobeControls.js index 0198a7596c..fb908622c7 100644 --- a/src/Renderer/ThreeExtented/GlobeControls.js +++ b/src/Renderer/ThreeExtented/GlobeControls.js @@ -12,6 +12,14 @@ import CustomEvent from 'custom-event'; var selectClick = new CustomEvent('selectClick'); +//TODO: +// Recast touch for globe +// Fix target problem with pan and panoramic (when target isn't on globe) +// Fix problem with space +// Add damping mouve +// Add real collision +// Animate move camera + var CONTROL_STATE = { NONE: -1, ORBIT: 0, @@ -37,16 +45,17 @@ var CONTROL_KEYS = { }; -//////////// -// internals +// private members var space = false; var EPS = 0.000001; +// Orbit var rotateStart = new THREE.Vector2(); var rotateEnd = new THREE.Vector2(); var rotateDelta = new THREE.Vector2(); +// Pan var panStart = new THREE.Vector2(); var panEnd = new THREE.Vector2(); var panDelta = new THREE.Vector2(); @@ -54,9 +63,11 @@ var panOffset = new THREE.Vector3(); var offset = new THREE.Vector3(); +// Dolly var dollyStart = new THREE.Vector2(); var dollyEnd = new THREE.Vector2(); var dollyDelta = new THREE.Vector2(); +var scale = 1; // Orbit move var spherical = new THREE.Spherical(1.0,0.01,0); @@ -64,32 +75,33 @@ var sphericalDelta = new THREE.Spherical(1.0,0,0); // Globe move var quatGlobe = new THREE.Quaternion(); +var globeTarget = new THREE.Object3D(); +var movingGlobeTarget = new THREE.Vector3(); -var scale = 1; +// Pan Move var panVector = new THREE.Vector3(); +// Save last transformation var lastPosition = new THREE.Vector3(); var lastQuaternion = new THREE.Quaternion(); +// State control var state = CONTROL_STATE.NONE; -///////////////////////// - +// Initial transformation var initialTarget; var initialPosition; var initialZoom; -///////////////////////// - +// picking var ptScreenClick = new THREE.Vector2(); var sizeRendering = new THREE.Vector2(); -var globeTarget = new THREE.Object3D(); -var movingGlobeTarget = new THREE.Vector3(); -// tangent sphere to ellispoid +// Tangent sphere to ellispoid var tSphere = new Sphere(); tSphere.picking = {position : new THREE.Vector3(),normal:new THREE.Vector3()}; +// Special key var keyCtrl = false; var keyShift = false; var keyS = false; @@ -97,13 +109,16 @@ var keyS = false; // Set to true to enable target helper var enableTargetHelper = false; +// Handle Mouse var _handlerMouseMove; var _handlerMouseUp; -//// - +// Pseudo collision var radiusCollision = 50; + +// SnapCamera saves transformation's camera +// It's use to globe move function SnapCamera(camera) { camera.updateMatrixWorld(); @@ -163,7 +178,6 @@ function GlobeControls(camera, domElement, engine) { snapShotCamera = new SnapCamera(camera); this.domElement = (domElement !== undefined) ? domElement : document; - // API // Set to false to disable this control this.enabled = true; @@ -195,7 +209,7 @@ function GlobeControls(camera, domElement, engine) { // How far you can orbit vertically, upper and lower limits. // Range is 0 to Math.PI radians. - // TODO ATTENTION trick pas correct minPolarAngle = 0.01 + // TODO Warning minPolarAngle = 0.01 -> it isn't possible to be perpendicular on Globe this.minPolarAngle = 0.01; // radians this.maxPolarAngle = Math.PI; // radians @@ -219,18 +233,18 @@ function GlobeControls(camera, domElement, engine) { PAN: THREE.MOUSE.RIGHT }; - // radius tSphere + // Radius tangent sphere tSphere.setRadius(engine.size); spherical.radius = tSphere.radius; sizeRendering.set(engine.width,engine.height); + // TODO: test before remove test code // so camera.up is the orbit axis //var quat = new THREE.Quaternion().setFromUnitVectors(camera.up, new THREE.Vector3(0, 1, 0)); //var quatInverse = quat.clone().inverse(); // events - this.changeEvent = { type: 'change' }; @@ -241,7 +255,9 @@ function GlobeControls(camera, domElement, engine) { type: 'end' }; - this.updateObject = function(camera) { + + // + this.updateCamera = function(camera) { snapShotCamera.init(camera.camera3D); sizeRendering.width = camera.width; @@ -435,6 +451,12 @@ function GlobeControls(camera, domElement, engine) { var quaterAxis = new THREE.Quaternion(); var axisX = new THREE.Vector3(1, 0, 0); + /////////////////////////////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + var update = function() { if (state === CONTROL_STATE.MOVE_GLOBE) { @@ -485,7 +507,8 @@ function GlobeControls(camera, domElement, engine) { spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, spherical.radius)); // move target to panned location - globeTarget.position.add( panVector ); + if(state === CONTROL_STATE.PAN) + globeTarget.position.add( panVector ); offset.setFromSpherical( spherical ); @@ -494,6 +517,11 @@ function GlobeControls(camera, domElement, engine) { this.camera.position.copy(collision(globeTarget.localToWorld(offset.clone()))); + // TODO: there's problem when the cameran looks at perpendicular + // --> + // if(state === CONTROL_STATE.PAN) + // this.camera.up.copy(this.camera.position.clone().normalize()); + // <-- } if (state === CONTROL_STATE.PANORAMIC) { @@ -534,6 +562,12 @@ function GlobeControls(camera, domElement, engine) { return space; }; + + this.getSphericalDelta = function() { + return sphericalDelta; + }; + + // Position object on globe var positionObject = function() { var quaterionX = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 2); @@ -546,12 +580,14 @@ function GlobeControls(camera, domElement, engine) { } }(); + // set new globe target var setGlobleTarget = function(newPosition) { // Compute the new target center position positionObject(newPosition,globeTarget); }; + // update globe target var updateGlobeTarget = function() { // Get distance camera DME @@ -571,6 +607,7 @@ function GlobeControls(camera, domElement, engine) { }; + // Update helper var updateHelper = enableTargetHelper ? function(position,helper){ positionObject(position,helper); @@ -583,6 +620,8 @@ function GlobeControls(camera, domElement, engine) { return tSphere.picking.position; }; + // Update radius's sphere : the sphere must cross the point + // Return intersection with mouse and sphere var updateSpherePicking = function() { var mouse = new THREE.Vector2(); @@ -685,10 +724,8 @@ function GlobeControls(camera, domElement, engine) { } if (state !== CONTROL_STATE.NONE) - { update(); - //console.log(coord.longitude(UNIT.DEGREE),coord.latitude(UNIT.DEGREE),coord.altitude()); - } + } }(); @@ -698,7 +735,6 @@ function GlobeControls(camera, domElement, engine) { if (this.enabled === false) return; event.preventDefault(); - //quatGlobe.set(0, 0, 0, 1); snapShotCamera.shot(this.camera); if (event.button === this.mouseButtons.PANORAMIC) { @@ -762,6 +798,14 @@ function GlobeControls(camera, domElement, engine) { } + var onDblClick = function() + { + state = CONTROL_STATE.ORBIT; + scale = 0.3333; + update(); + state = CONTROL_STATE.NONE; + } + var onMouseUp = function( /* event */ ) { if (this.enabled === false) return; @@ -881,7 +925,7 @@ function GlobeControls(camera, domElement, engine) { } } - var touchstart = function(event) { + var onTouchStart = function(event) { if (this.enabled === false) return; @@ -927,7 +971,7 @@ function GlobeControls(camera, domElement, engine) { } - var touchmove= function(event) { + var onTouchMove = function(event) { if (this.enabled === false) return; @@ -1006,7 +1050,7 @@ function GlobeControls(camera, domElement, engine) { } - var touchend= function( /* event */ ) { + var onTouchEnd= function( /* event */ ) { if (this.enabled === false) return; @@ -1018,7 +1062,8 @@ function GlobeControls(camera, domElement, engine) { } - this.updateControls = function(controlState) + // update object camera position + this.updateCameraTransformation = function(controlState) { state = controlState || CONTROL_STATE.ORBIT; update(); @@ -1026,18 +1071,43 @@ function GlobeControls(camera, domElement, engine) { updateGlobeTarget.bind(this)(); }; + this.dispose = function() { + + //this.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); + this.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox + + this.domElement.removeEventListener( 'touchstart', onTouchStart, false ); + this.domElement.removeEventListener( 'touchend', onTouchEnd, false ); + this.domElement.removeEventListener( 'touchmove', onTouchMove, false ); + + this.domElement.removeEventListener( 'mousemove', onMouseMove, false ); + this.domElement.removeEventListener( 'mouseup', onMouseUp, false ); + + window.removeEventListener( 'keydown', onKeyDown, false ); + + //this.dispatchEvent( { type: 'dispose' } ); // should this be added here? + + }; + + // Instance all this.domElement.addEventListener('contextmenu', function(event) { event.preventDefault(); }, false); this.domElement.addEventListener('mousedown', onMouseDown.bind(this), false); this.domElement.addEventListener('mousewheel', onMouseWheel.bind(this), false); - this.domElement.addEventListener('DOMMouseScroll', onMouseWheel.bind(this), false); // firefox + this.domElement.addEventListener("dblclick", onDblClick.bind(this), false); + + //TODO:Verify the right event + //this.domElement.addEventListener('DOMMouseScroll', onMouseWheel.bind(this), false); // firefox + this.domElement.addEventListener('MozMousePixelScroll', onMouseWheel, false ); // firefox - this.domElement.addEventListener('touchstart', touchstart.bind(this), false); - this.domElement.addEventListener('touchend', touchend.bind(this), false); - this.domElement.addEventListener('touchmove', touchmove.bind(this), false); + this.domElement.addEventListener('touchstart', onTouchStart.bind(this), false); + this.domElement.addEventListener('touchend', onTouchEnd.bind(this), false); + this.domElement.addEventListener('touchmove', onTouchMove.bind(this), false); - // TODO Why windows + // TODO: Why windows window.addEventListener('keydown', onKeyDown.bind(this), false); window.addEventListener('keyup', onKeyUp.bind(this), false); @@ -1075,12 +1145,12 @@ GlobeControls.prototype.constructor = GlobeControls; GlobeControls.prototype.setTilt = function(tilt) { sphericalDelta.phi = (tilt * Math.PI / 180 - this.getTiltRad()); - this.updateControls(); + this.updateCameraTransformation(); }; GlobeControls.prototype.setHeading = function(heading) { sphericalDelta.theta = (heading * Math.PI / 180 - this.getHeadingRad()); - this.updateControls(); + this.updateCameraTransformation(); }; GlobeControls.prototype.setCenter = function(position) { @@ -1096,14 +1166,14 @@ GlobeControls.prototype.setCenter = function(position) { var vTo = position.normalize(); quatGlobe.setFromUnitVectors(vFrom, vTo); - this.updateControls(CONTROL_STATE.MOVE_GLOBE); + this.updateCameraTransformation(CONTROL_STATE.MOVE_GLOBE); }; GlobeControls.prototype.setRange = function(pRange) { scale = pRange / globeTarget.position.distanceTo(this.camera.position); - this.updateControls(); + this.updateCameraTransformation(); }; @@ -1174,7 +1244,7 @@ GlobeControls.prototype.reset = function() { this.camera.updateProjectionMatrix(); this.dispatchEvent(this.changeEvent); - this.updateControls(); + this.updateCameraTransformation(); }; diff --git a/src/Renderer/c3DEngine.js b/src/Renderer/c3DEngine.js index 4e091dd14c..24edd79508 100644 --- a/src/Renderer/c3DEngine.js +++ b/src/Renderer/c3DEngine.js @@ -77,6 +77,8 @@ function c3DEngine(scene, positionCamera, viewerDiv, debugMode, gLDebug) { this.camDebug.position.copy(posDebug); this.camDebug.lookAt(target); + this.camDebug.translateX(posDebug.length()/2); + this.camDebug.lookAt(target); this.renderer.setViewport(this.width, 0, this.width, this.height); this.renderer.render(this.scene3D, this.camDebug); @@ -100,7 +102,7 @@ function c3DEngine(scene, positionCamera, viewerDiv, debugMode, gLDebug) { this.height = this.viewerDiv.clientHeight; this.camera.resize(this.width, this.height); this.scene.updateCamera(); - this.controls.updateObject(this.camera); + this.controls.updateCamera(this.camera); if (this.camDebug) { this.camDebug.aspect = this.camera.ratio;