diff --git a/src/Core/Commander/Interfaces/ApiInterface/ApiGlobe.js b/src/Core/Commander/Interfaces/ApiInterface/ApiGlobe.js index f9f862fd66..b238486e34 100644 --- a/src/Core/Commander/Interfaces/ApiInterface/ApiGlobe.js +++ b/src/Core/Commander/Interfaces/ApiInterface/ApiGlobe.js @@ -131,7 +131,6 @@ ApiGlobe.prototype.removeImageryLayer = function(id) { return false; }; - /** * Add an elevation layer to the map. Elevations layers are used to build the terrain. * Only one elevation layer is used, so if multiple layers cover the same area, the one @@ -220,7 +219,7 @@ ApiGlobe.prototype.createSceneGlobe = function(coordCarto, viewerDiv) { var debugMode = false; //gLDebug = true; // true to support GLInspector addon - debugMode = true; + //debugMode = true; var ellipsoid = new Ellipsoid({ x: 6378137, @@ -530,8 +529,7 @@ ApiGlobe.prototype.computeDistance = function(p1, p2) { */ ApiGlobe.prototype.setCenter = function(coordinates) { - - var position3D = this.scene.getEllipsoid().cartographicToCartesian(new GeoCoordinate().copyFromDegree(coordinates)); + var position3D = this.scene.getEllipsoid().cartographicToCartesian(new GeoCoordinate(coordinates.longitude,coordinates.latitude,0,UNIT.DEGREE)); this.scene.currentControls().setCenter(position3D); }; diff --git a/src/Core/Commander/Providers/TileProvider.js b/src/Core/Commander/Providers/TileProvider.js index 80dec840f4..78acf1799e 100644 --- a/src/Core/Commander/Providers/TileProvider.js +++ b/src/Core/Commander/Providers/TileProvider.js @@ -13,8 +13,6 @@ * */ - - import Provider from 'Core/Commander/Providers/Provider'; import Projection from 'Core/Geographic/Projection'; import TileGeometry from 'Globe/TileGeometry'; @@ -41,10 +39,10 @@ TileProvider.prototype.constructor = TileProvider; TileProvider.prototype.preprocessLayer = function( /*layer*/ ) { /* no-op */ -} +}; TileProvider.prototype.getGeometry = function(bbox, cooWMTS) { - var geometry = undefined; + var geometry; var n = Math.pow(2, cooWMTS.zoom + 1); var part = Math.PI * 2.0 / n; @@ -75,7 +73,7 @@ TileProvider.prototype.executeCommand = function(command) { var parent = command.requester; // build tile - var geometry = undefined; //getGeometry(bbox,tileCoord); + var geometry; //getGeometry(bbox,tileCoord); var params = { bbox: bbox, @@ -83,7 +81,7 @@ TileProvider.prototype.executeCommand = function(command) { segment: 16, center: null, projected: null - } + }; var tile = new command.type(params, this.builder); diff --git a/src/Core/Geographic/GeoCoordinate.js b/src/Core/Geographic/GeoCoordinate.js index 99ac45d482..686895866b 100644 --- a/src/Core/Geographic/GeoCoordinate.js +++ b/src/Core/Geographic/GeoCoordinate.js @@ -35,7 +35,7 @@ var getCoordinateValue = function(unit,coord,id) return mE.radToDeg(coord[id]); -} +}; var setCoordinateValue = function(unit,coord,id,value) { @@ -49,7 +49,7 @@ var setCoordinateValue = function(unit,coord,id,value) return coord[id] = mE.degToRad(value); -} +}; var setCoordinate = function(coordinate,longitude, latitude, altitude,unit) { diff --git a/src/Core/Math/MathExtented.js b/src/Core/Math/MathExtented.js index be902f6686..1cdd636a35 100644 --- a/src/Core/Math/MathExtented.js +++ b/src/Core/Math/MathExtented.js @@ -48,30 +48,28 @@ MathExt.RADTODEG = 180.0 / MathExt.PI; MathExt.DEGTORAD = MathExt.PI / 180.0; -MathExt.radToDeg = function(rad) -{ +MathExt.radToDeg = function(rad) { + return rad * MathExt.RADTODEG; }; -MathExt.degToRad = function(deg) -{ +MathExt.degToRad = function(deg) { + return deg * MathExt.DEGTORAD; }; -MathExt.arrayDegToRad = function(arrayDeg) -{ - if(arrayDeg) - { +MathExt.arrayDegToRad = function(arrayDeg) { + + if(arrayDeg) { for (var i = 0; i < arrayDeg.length; i++) { arrayDeg[i]= MathExt.degToRad(arrayDeg[i]); } } }; -MathExt.arrayRadToDeg = function(arrayDeg) -{ - if(arrayDeg) - { +MathExt.arrayRadToDeg = function(arrayDeg) { + + if(arrayDeg) { for (var i = 0; i < arrayDeg.length; i++) { arrayDeg[i]= MathExt.radToDeg(arrayDeg[i]); } @@ -79,51 +77,23 @@ MathExt.arrayRadToDeg = function(arrayDeg) }; // TODO: Function in test : -MathExt.step = function(val,stepVal) -{ - if(val=0; i -= 1) { - if (str.charCodeAt(i)>255) { - //console.log('Wrong string parametr'); - return false; - } - int += str.charCodeAt(i) * multi; - multi *= 256; - } } - sign = (int>>>31)?-1:1; - exp = (int >>> 23 & 0xff) - 127; - mantissa = ((int & 0x7fffff) + 0x800000).toString(2); - for (i=0; i this.radius) { + // mirror point is symetric of pc + // The mirror ray must pass through the point mirrorPoint + let mirrorPoint = pc.clone().setLength(this.radius*2 - a); - var pc = ray.closestPointToPoint(this.center); - var a = pc.length(); + // Compute the new direction + d = ray.direction.subVectors(mirrorPoint,ray.origin).normalize(); - if (a > this.radius) - return undefined; // new THREE.Vector3(); + // Classic intersection with the new ray + pc = ray.closestPointToPoint(this.center); + a = pc.length(); - if (ray.origin.length() > this.radius) { - var d = ray.direction.clone(); - var b = Math.sqrt(this.radius * this.radius - a * a); + b = Math.sqrt(this.radius * this.radius - a * a); d.setLength(b); - return vector.subVectors(pc, d); - } else - return undefined; + return vector.addVectors(pc, d); + } -} + // TODO: check all intersections : if (ray.origin.length() > this.radius) + d = ray.direction.clone(); + b = Math.sqrt(this.radius * this.radius - a * a); + d.setLength(b); + + return vector.subVectors(pc, d); + +}; export default Sphere; diff --git a/src/Globe/Globe.js b/src/Globe/Globe.js index 2971bdc637..778d94818f 100644 --- a/src/Globe/Globe.js +++ b/src/Globe/Globe.js @@ -110,7 +110,7 @@ Globe.prototype = Object.create(Layer.prototype); Globe.prototype.constructor = Globe; /** - * @documentation: Rafrachi les mat�riaux en fonction du quadTree ORTHO + * @documentation: Rafrachi les materiaux en fonction du quadTree ORTHO * */ Globe.prototype.QuadTreeToMaterial = function() { @@ -223,6 +223,10 @@ Globe.prototype.getZoomLevel = function( /*id*/ ) { return cO(); }; +Globe.prototype.getTile = function(coordinate) { + return this.tiles.getTile(coordinate); +}; + Globe.prototype.setRealisticLightingOn = function(bool) { this.atmosphere.setRealisticOn(bool); diff --git a/src/Globe/TileMesh.js b/src/Globe/TileMesh.js index 2776f23291..675654eb2d 100644 --- a/src/Globe/TileMesh.js +++ b/src/Globe/TileMesh.js @@ -121,7 +121,7 @@ TileMesh.prototype.setUuid = function(uuid) { TileMesh.prototype.getUuid = function(uuid) { return this.materials[RendererConstant.ID].getUuid(uuid); -} +}; TileMesh.prototype.setColorLayerParameters = function(paramsTextureColor) { this.materials[RendererConstant.FINAL].setParam(paramsTextureColor); @@ -190,8 +190,7 @@ TileMesh.prototype.setTextureElevation = function(elevation) { return; } - var texture = undefined; - var pitScale; + var texture, pitScale; if (elevation) { texture = elevation.texture; diff --git a/src/Renderer/Camera.js b/src/Renderer/Camera.js index 226ae36ae9..60470fa1de 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,21 @@ 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/LayeredMaterial.js b/src/Renderer/LayeredMaterial.js index 6279af3404..a3a78de0a8 100644 --- a/src/Renderer/LayeredMaterial.js +++ b/src/Renderer/LayeredMaterial.js @@ -39,7 +39,7 @@ var getColorAtIdUv = function(nbTex) { } return fooTexture; -} +}; var LayeredMaterial = function(id) { @@ -142,12 +142,11 @@ var LayeredMaterial = function(id) { this.uniforms.lightingOn = { type: "i", value: gfxEngine().lightingOn - }, - this.uniforms.lightPosition = { - type: "v3", - value: new THREE.Vector3(-0.5, 0.0, 1.0) }; - + this.uniforms.lightPosition = { + type: "v3", + value: new THREE.Vector3(-0.5, 0.0, 1.0) + }; this.setUuid(id || 0); this.wireframe = false; //this.wireframe = true; diff --git a/src/Renderer/ThreeExtented/GlobeControls.js b/src/Renderer/ThreeExtented/GlobeControls.js index 545beedd5c..2cba2e2847 100644 --- a/src/Renderer/ThreeExtented/GlobeControls.js +++ b/src/Renderer/ThreeExtented/GlobeControls.js @@ -6,12 +6,22 @@ // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish // Pan - right mouse, or arrow keys / touch: three finter swipe +/* global document,window*/ + import THREE from 'three'; -import Sphere from 'Core/Math/Sphere' +import Sphere from 'Core/Math/Sphere'; 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 +47,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 +65,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,47 +77,58 @@ var sphericalDelta = new THREE.Spherical(1.0,0,0); // Globe move var quatGlobe = new THREE.Quaternion(); +var globeTarget = new THREE.Object3D(); +// Replace matrix float by matrix double +globeTarget.matrixWorld.elements = new Float64Array(16); +globeTarget.matrixWorldInverse = new THREE.Matrix4(); +globeTarget.matrixWorldInverse.elements = new Float64Array(16); -var scale = 1; +var movingGlobeTarget = new THREE.Vector3(); + +// 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; // Set to true to enable target helper -var enableTargetHelper = true; +var enableTargetHelper = false; +// Handle Mouse var _handlerMouseMove; var _handlerMouseUp; -//// +// Pseudo collision +var radiusCollision = 50; + -function SnapCamera(object) { +// SnapCamera saves transformation's camera +// It's use to globe move +function SnapCamera(camera) { - object.updateMatrixWorld(); + camera.updateMatrixWorld(); this.matrixWorld = new THREE.Matrix4(); this.projectionMatrix = new THREE.Matrix4(); @@ -115,16 +139,16 @@ function SnapCamera(object) { this.projectionMatrix.elements = new Float64Array(16); this.invProjectionMatrix.elements = new Float64Array(16); - this.init = function(object) + this.init = function(camera) { - this.matrixWorld.elements.set(object.matrixWorld.elements); - this.projectionMatrix.elements.set(object.projectionMatrix.elements); - this.position.copy(object.position); + this.matrixWorld.elements.set(camera.matrixWorld.elements); + this.projectionMatrix.elements.set(camera.projectionMatrix.elements); + this.position.copy(camera.position); this.invProjectionMatrix.getInverse( this.projectionMatrix ); }; - this.init(object); + this.init(camera); this.shot = function(objectToSnap) { @@ -153,13 +177,14 @@ var snapShotCamera; ///////////////////////// -function GlobeControls(object, domElement, engine) { +function GlobeControls(camera, domElement, engine) { - this.object = object; - snapShotCamera = new SnapCamera(object); + var scene = engine.scene; + + this.camera = camera; + snapShotCamera = new SnapCamera(camera); this.domElement = (domElement !== undefined) ? domElement : document; - // API // Set to false to disable this control this.enabled = true; @@ -170,7 +195,7 @@ function GlobeControls(object, domElement, engine) { this.zoomSpeed = 1.0; // Limits to how far you can dolly in and out ( PerspectiveCamera only ) - this.minDistance = 0; + this.minDistance = radiusCollision; this.maxDistance = Infinity; // Limits to how far you can zoom in and out ( OrthographicCamera only ) @@ -191,7 +216,7 @@ function GlobeControls(object, 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 @@ -215,18 +240,18 @@ function GlobeControls(object, 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(object.up, new THREE.Vector3(0, 1, 0)); + //var quat = new THREE.Quaternion().setFromUnitVectors(camera.up, new THREE.Vector3(0, 1, 0)); //var quatInverse = quat.clone().inverse(); // events - this.changeEvent = { type: 'change' }; @@ -237,7 +262,9 @@ function GlobeControls(object, domElement, engine) { type: 'end' }; - this.updateObject = function(camera) { + + // + this.updateCamera = function(camera) { snapShotCamera.init(camera.camera3D); sizeRendering.width = camera.width; @@ -249,13 +276,13 @@ function GlobeControls(object, domElement, engine) { return 2 * Math.PI / 60 / 60 * this.autoRotateSpeed; - } + }; this.getZoomScale = function () { return Math.pow(0.95, this.zoomSpeed); - } + }; this.rotateLeft = function(angle) { @@ -282,7 +309,7 @@ function GlobeControls(object, domElement, engine) { // pass in distance in world space to move left this.panLeft = function(distance) { - var te = this.object.matrix.elements; + var te = this.camera.matrix.elements; // get X column of matrix panOffset.set(te[0], te[1], te[2]); @@ -295,7 +322,7 @@ function GlobeControls(object, domElement, engine) { // pass in distance in world space to move up this.panUp = function(distance) { - var te = this.object.matrix.elements; + var te = this.camera.matrix.elements; // get Y column of matrix panOffset.set(te[4], te[5], te[6]); @@ -311,10 +338,10 @@ function GlobeControls(object, domElement, engine) { var element = this.domElement === document ? this.domElement.body : this.domElement; - if (this.object instanceof THREE.PerspectiveCamera) { + if (this.camera instanceof THREE.PerspectiveCamera) { // perspective - var position = this.object.position; + var position = this.camera.position; //var offset = position.clone().sub(this.target); var offset = position.clone().sub(globeTarget.position); @@ -322,18 +349,18 @@ function GlobeControls(object, domElement, engine) { var targetDistance = offset.length(); // half of the fov is center to top of screen - targetDistance *= Math.tan((this.object.fov / 2) * Math.PI / 180.0); + targetDistance *= Math.tan((this.camera.fov / 2) * Math.PI / 180.0); // we actually don't use screenWidth, since perspective camera is fixed to screen height this.panLeft(2 * deltaX * targetDistance / element.clientHeight); this.panUp(2 * deltaY * targetDistance / element.clientHeight); - } else if (this.object instanceof THREE.OrthographicCamera) { + } else if (this.camera instanceof THREE.OrthographicCamera) { // orthographic - this.panLeft(deltaX * (this.object.right - this.object.left) / element.clientWidth); - this.panUp(deltaY * (this.object.top - this.object.bottom) / element.clientHeight); + this.panLeft(deltaX * (this.camera.right - this.camera.left) / element.clientWidth); + this.panUp(deltaY * (this.camera.top - this.camera.bottom) / element.clientHeight); } else { @@ -352,14 +379,14 @@ function GlobeControls(object, domElement, engine) { } - if (this.object instanceof THREE.PerspectiveCamera) { + if (this.camera instanceof THREE.PerspectiveCamera) { scale /= dollyScale; - } else if (this.object instanceof THREE.OrthographicCamera) { + } else if (this.camera instanceof THREE.OrthographicCamera) { - this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom * dollyScale)); - this.object.updateProjectionMatrix(); + this.camera.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.camera.zoom * dollyScale)); + this.camera.updateProjectionMatrix(); this.dispatchEvent(this.changeEvent); } else { @@ -378,14 +405,14 @@ function GlobeControls(object, domElement, engine) { } - if (this.object instanceof THREE.PerspectiveCamera) { + if (this.camera instanceof THREE.PerspectiveCamera) { scale *= dollyScale; - } else if (this.object instanceof THREE.OrthographicCamera) { + } else if (this.camera instanceof THREE.OrthographicCamera) { - this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom / dollyScale)); - this.object.updateProjectionMatrix(); + this.camera.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.camera.zoom / dollyScale)); + this.camera.updateProjectionMatrix(); this.dispatchEvent(this.changeEvent); } else { @@ -411,28 +438,65 @@ function GlobeControls(object, domElement, engine) { }(); + // introduction collision + // Not use for the moment + // eslint-disable-next-line + var collision = function(position) + { + if(scene.getMap()) + { + var coord = scene.getMap().projection.cartesianToGeo(position); + var bbox = scene.getMap().getTile(coord).bbox; + var delta = coord.altitude() - (bbox.top() + radiusCollision); + + if(delta<0) + position.setLength(position.length()-delta); + } + + return position; + }; + var offGT = new THREE.Vector3(); var quaterPano = new THREE.Quaternion(); var quaterAxis = new THREE.Quaternion(); var axisX = new THREE.Vector3(1, 0, 0); + /////////////////////////////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + var update = function() { if (state === CONTROL_STATE.MOVE_GLOBE) { offset.copy(snapShotCamera.position); } else { - offset.copy(globeTarget.worldToLocal(this.object.position.clone())); + // get camera position + offset.copy(this.camera.position); + // transform to local globeTarget + offset.applyMatrix4( globeTarget.matrixWorldInverse ); } offGT.copy(globeTarget.position); if (state === CONTROL_STATE.MOVE_GLOBE) { + offGT.applyQuaternion(quatGlobe); movingGlobeTarget.copy(offGT); - this.object.position.copy(offset.applyQuaternion(quatGlobe)); - this.object.up.copy(offGT.clone().normalize()); + this.camera.position.copy(offset.applyQuaternion(quatGlobe)); + this.camera.up.copy(offGT.clone().normalize()); - } else if (state !== CONTROL_STATE.PANORAMIC) { + } + else if(state === CONTROL_STATE.PAN) + { + this.camera.position.add( panVector ); + globeTarget.position.add( panVector ); + globeTarget.updateMatrixWorld(); + globeTarget.matrixWorldInverse.getInverse(globeTarget.matrixWorld); + offGT.copy(globeTarget.position); + } + else if (state !== CONTROL_STATE.PANORAMIC) { // State ZOOM/ORBIT @@ -465,33 +529,37 @@ function GlobeControls(object, domElement, engine) { // restrict radius to be between desired limits spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, spherical.radius)); - // move target to panned location - globeTarget.position.add( panVector ); - offset.setFromSpherical( spherical ); //rotate point back to "camera-up-vector-is-up" space //offset.applyQuaternion( quatInverse ); - this.object.position.copy(globeTarget.localToWorld(offset.clone())); + var newPosition = globeTarget.localToWorld(offset.clone()); + this.camera.position.copy(newPosition); + + // 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) { - this.object.worldToLocal(movingGlobeTarget); - var normal = this.object.position.clone().normalize().applyQuaternion(this.object.quaternion.clone().inverse()); + this.camera.worldToLocal(movingGlobeTarget); + var normal = this.camera.position.clone().normalize().applyQuaternion(this.camera.quaternion.clone().inverse()); quaterPano.setFromAxisAngle(normal, sphericalDelta.theta).multiply(quaterAxis.setFromAxisAngle(axisX, sphericalDelta.phi)); movingGlobeTarget.applyQuaternion(quaterPano); - this.object.localToWorld(movingGlobeTarget); - this.object.up.copy(movingGlobeTarget.clone().normalize()); - this.object.lookAt(movingGlobeTarget); + this.camera.localToWorld(movingGlobeTarget); + this.camera.up.copy(movingGlobeTarget.clone().normalize()); + this.camera.lookAt(movingGlobeTarget); } else { - this.object.lookAt(offGT); // Usual CASE (not rotating around camera axe) + this.camera.lookAt(offGT); // Usual CASE (not rotating around camera axe) } - // quatGlobe.set(0, 0, 0, 1); + quatGlobe.set(0, 0, 0, 1); sphericalDelta.theta = 0; sphericalDelta.phi = 0; scale = 1; @@ -501,12 +569,12 @@ function GlobeControls(object, domElement, engine) { // min(camera displacement, camera rotation in radians)^2 > EPS // using small-angle approximation cos(x/2) = 1 - x^2 / 8 - if (lastPosition.distanceToSquared(this.object.position) > EPS || 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS) { + if (lastPosition.distanceToSquared(this.camera.position) > EPS || 8 * (1 - lastQuaternion.dot(this.camera.quaternion)) > EPS) { this.dispatchEvent(this.changeEvent); - lastPosition.copy(this.object.position); - lastQuaternion.copy(this.object.quaternion); + lastPosition.copy(this.camera.position); + lastQuaternion.copy(this.camera.quaternion); } }.bind(this); @@ -515,43 +583,62 @@ function GlobeControls(object, 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); return function(newPosition,object) { object.position.copy(newPosition); - object.lookAt(newPosition.clone().multiplyScalar(2)); + object.lookAt(newPosition.clone().multiplyScalar(1.1)); object.quaternion.multiply(quaterionX); object.updateMatrixWorld(); - } + }; }(); + // set new globe target var setGlobleTarget = function(newPosition) { // Compute the new target center position positionObject(newPosition,globeTarget); + globeTarget.matrixWorldInverse.getInverse(globeTarget.matrixWorld); + }; + var cT = new THREE.Vector3(); + // update globe target var updateGlobeTarget = function() { // Get distance camera DME - var distanceTarget = getPickingPosition().distanceTo(this.object.position); + var distanceTarget = Math.floor(getPickingPosition().distanceTo(this.camera.position)); // Position movingGlobeTarget on DME - this.object.worldToLocal(movingGlobeTarget); - movingGlobeTarget.setLength(distanceTarget); - this.object.localToWorld(movingGlobeTarget); + + // TODO: error accuracy with this old method : why? : matrix world inverse + // this.camera.worldToLocal(movingGlobeTarget); + // movingGlobeTarget.setLength(distanceTarget); + // this.camera.localToWorld(movingGlobeTarget); + + cT.subVectors(movingGlobeTarget,this.camera.position); + cT.setLength(distanceTarget); + movingGlobeTarget.addVectors(this.camera.position,cT); // set new globe target setGlobleTarget(movingGlobeTarget); // update spherical from target - offset.copy(globeTarget.worldToLocal(this.object.position.clone())); + offset.copy(this.camera.position); + offset.applyMatrix4(globeTarget.matrixWorldInverse); spherical.setFromVector3(offset); }; + // Update helper var updateHelper = enableTargetHelper ? function(position,helper){ positionObject(position,helper); @@ -564,6 +651,8 @@ function GlobeControls(object, 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(); @@ -573,16 +662,12 @@ function GlobeControls(object, domElement, engine) { tSphere.setRadius(point.length()); - // mouse.x = (screenCoord.x / this.domElement.clientWidth) * 2 - 1; - // mouse.y = -(screenCoord.y / this.domElement.clientHeight) * 2 + 1; - - mouse.x = (screenCoord.x / sizeRendering.width) * 2 - 1; mouse.y = -(screenCoord.y / sizeRendering.height) * 2 + 1; snapShotCamera.updateRay(ray,mouse); // pick position on tSphere - tSphere.picking.position.copy(tSphere.intersectWithRay(ray)); + tSphere.picking.position.copy(tSphere.intersectWithRayNoMiss(ray)); tSphere.picking.normal = tSphere.picking.position.clone().normalize(); updateHelper.bind(this)(tSphere.picking.position,this.pickingHelper); @@ -590,94 +675,100 @@ function GlobeControls(object, domElement, engine) { }.bind(this)(); - var onMouseMove = function(event) { + var onMouseMove = function() { - if (this.enabled === false) return; + var ray = new THREE.Ray(); + var mouse = new THREE.Vector2(); - event.preventDefault(); + return function(event) + { - if (state === CONTROL_STATE.ORBIT || state === CONTROL_STATE.PANORAMIC) { + if (this.enabled === false) return; - if (this.enableRotate === false) return; + event.preventDefault(); - rotateEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); - rotateDelta.subVectors(rotateEnd, rotateStart); + if (state === CONTROL_STATE.ORBIT || state === CONTROL_STATE.PANORAMIC) { - // rotating across whole screen goes 360 degrees around - if (!space) { - this.rotateLeft(2 * Math.PI * rotateDelta.x / sizeRendering.width * this.rotateSpeed); + if (this.enableRotate === false) return; - // rotating up and down along whole screen attempts to go 360, but limited to 180 - this.rotateUp(2 * Math.PI * rotateDelta.y / sizeRendering.height * this.rotateSpeed); + rotateEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); + rotateDelta.subVectors(rotateEnd, rotateStart); - } else { + // rotating across whole screen goes 360 degrees around + if (!space) { + this.rotateLeft(2 * Math.PI * rotateDelta.x / sizeRendering.width * this.rotateSpeed); - this.rotateLeft(rotateDelta.x); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + this.rotateUp(2 * Math.PI * rotateDelta.y / sizeRendering.height * this.rotateSpeed); - // rotating up and down along whole screen attempts to go 360, but limited to 180 - this.rotateUp(rotateDelta.y); - } + } else { - rotateStart.copy(rotateEnd); + this.rotateLeft(rotateDelta.x); - } else if (state === CONTROL_STATE.DOLLY) { + // rotating up and down along whole screen attempts to go 360, but limited to 180 + this.rotateUp(rotateDelta.y); + } - if (this.enableZoom === false) return; + rotateStart.copy(rotateEnd); - dollyEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); - dollyDelta.subVectors(dollyEnd, dollyStart); + } else if (state === CONTROL_STATE.DOLLY) { - if (dollyDelta.y > 0) { + if (this.enableZoom === false) return; - this.dollyIn(); + dollyEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); + dollyDelta.subVectors(dollyEnd, dollyStart); - } else if (dollyDelta.y < 0) { + if (dollyDelta.y > 0) { - this.dollyOut(); + this.dollyIn(); - } + } else if (dollyDelta.y < 0) { - dollyStart.copy(dollyEnd); + this.dollyOut(); - } else if (state === CONTROL_STATE.PAN) { + } - if (this.enablePan === false) return; + dollyStart.copy(dollyEnd); - panEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); - panDelta.subVectors(panEnd, panStart); + } else if (state === CONTROL_STATE.PAN) { - this.pan(panDelta.x, panDelta.y); + if (this.enablePan === false) return; - panStart.copy(panEnd); + panEnd.set(event.clientX - event.target.offsetLeft, event.clientY - event.target.offsetTop); + panDelta.subVectors(panEnd, panStart); - } else if (state === CONTROL_STATE.MOVE_GLOBE) { + this.pan(panDelta.x, panDelta.y); - var mouse = new THREE.Vector2(); + panStart.copy(panEnd); - mouse.x = ((event.clientX - event.target.offsetLeft) / sizeRendering.width) * 2 - 1; - mouse.y = -((event.clientY - event.target.offsetTop) / sizeRendering.height) * 2 + 1; + } else if (state === CONTROL_STATE.MOVE_GLOBE) { - var ray = new THREE.Ray(); + mouse.x = ((event.clientX - event.target.offsetLeft) / sizeRendering.width) * 2 - 1; + mouse.y = -((event.clientY - event.target.offsetTop) / sizeRendering.height) * 2 + 1; - snapShotCamera.updateRay(ray,mouse); + snapShotCamera.updateRay(ray,mouse); - var intersection = tSphere.intersectWithRay(ray); + var intersection = tSphere.intersectWithRayNoMiss(ray); - if (intersection) - quatGlobe.setFromUnitVectors(intersection.normalize(), tSphere.picking.normal); - } + if (intersection) + quatGlobe.setFromUnitVectors(intersection.normalize(), tSphere.picking.normal); + } - if (state !== CONTROL_STATE.NONE) update(); + if (state !== CONTROL_STATE.NONE) + update(); - } + }; + + }(); var onMouseDown = function(event) { if (this.enabled === false) return; event.preventDefault(); - //quatGlobe.set(0, 0, 0, 1); - snapShotCamera.shot(this.object); + quatGlobe.set(0, 0, 0, 1); + + snapShotCamera.shot(this.camera); if (event.button === this.mouseButtons.PANORAMIC) { if (this.enableRotate === false) return; @@ -700,7 +791,7 @@ function GlobeControls(object, domElement, engine) { state = CONTROL_STATE.MOVE_GLOBE; - snapShotCamera.shot(this.object); + snapShotCamera.shot(this.camera); ptScreenClick.x = event.clientX - event.target.offsetLeft; ptScreenClick.y = event.clientY - event.target.offsetTop; @@ -738,7 +829,15 @@ function GlobeControls(object, domElement, engine) { this.dispatchEvent(this.startEvent); } - } + }; + + var onDblClick = function() + { + // state = CONTROL_STATE.ORBIT; + // scale = 0.3333; + // update(); + // state = CONTROL_STATE.NONE; + }; var onMouseUp = function( /* event */ ) { @@ -753,7 +852,7 @@ function GlobeControls(object, domElement, engine) { updateGlobeTarget.bind(this)(); state = CONTROL_STATE.NONE; - } + }; var onMouseWheel = function(event) { @@ -789,7 +888,7 @@ function GlobeControls(object, domElement, engine) { this.dispatchEvent(this.startEvent); this.dispatchEvent(this.endEvent); - } + }; var onKeyUp = function ( /*event*/ ) { @@ -800,13 +899,19 @@ function GlobeControls(object, domElement, engine) { { movingGlobeTarget.copy(globeTarget.position); updateGlobeTarget.bind(this)(); + state = CONTROL_STATE.NONE; } keyCtrl = false; keyShift = false; keyS = false; + }; - } + var panUpdate = function(deltaX,deltaY) { + this.pan(deltaX,deltaY); + state = CONTROL_STATE.PAN; + update(); + }; var onKeyDown = function(event) { @@ -814,30 +919,18 @@ function GlobeControls(object, domElement, engine) { keyCtrl = false; keyShift = false; - this.keyPanSpeed = 7.0; - - // console.log(); - switch (event.keyCode) { - case CONTROL_KEYS.UP: - this.pan(0, this.keyPanSpeed); - update(); + panUpdate.bind(this)(0, this.keyPanSpeed); break; - case CONTROL_KEYS.BOTTOM: - this.pan(0, -this.keyPanSpeed); - update(); + panUpdate.bind(this)(0, -this.keyPanSpeed); break; - case CONTROL_KEYS.LEFT: - this.pan(this.keyPanSpeed, 0); - update(); + panUpdate.bind(this)(this.keyPanSpeed, 0); break; - case CONTROL_KEYS.RIGHT: - this.pan(-this.keyPanSpeed, 0); - update(); + panUpdate.bind(this)(-this.keyPanSpeed, 0); break; // TODO Why space key, looking for movement case CONTROL_KEYS.SPACE: @@ -859,9 +952,9 @@ function GlobeControls(object, domElement, engine) { break; } - } + }; - var touchstart = function(event) { + var onTouchStart = function(event) { if (this.enabled === false) return; @@ -905,9 +998,9 @@ function GlobeControls(object, domElement, engine) { if (state !== CONTROL_STATE.NONE) this.dispatchEvent(this.startEvent); - } + }; - var touchmove= function(event) { + var onTouchMove = function(event) { if (this.enabled === false) return; @@ -984,9 +1077,9 @@ function GlobeControls(object, domElement, engine) { } - } + }; - var touchend= function( /* event */ ) { + var onTouchEnd= function( /* event */ ) { if (this.enabled === false) return; @@ -996,9 +1089,10 @@ function GlobeControls(object, domElement, engine) { keyShift = false; keyS = false; - } + }; - this.updateControls = function(controlState) + // update object camera position + this.updateCameraTransformation = function(controlState) { state = controlState || CONTROL_STATE.ORBIT; update(); @@ -1006,26 +1100,51 @@ function GlobeControls(object, 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); // Initialisation Globe Target and movingGlobeTarget - var positionTarget = new THREE.Vector3().copy(object.position).setLength(tSphere.radius); + var positionTarget = new THREE.Vector3().copy(camera.position).setLength(tSphere.radius); setGlobleTarget(positionTarget); movingGlobeTarget.copy(positionTarget); - this.object.up.copy(positionTarget.normalize()); + this.camera.up.copy(positionTarget.normalize()); update(); @@ -1039,8 +1158,8 @@ function GlobeControls(object, domElement, engine) { // Start position initialTarget = globeTarget.clone(); - initialPosition = this.object.position.clone(); - initialZoom = this.object.zoom; + initialPosition = this.camera.position.clone(); + initialZoom = this.camera.zoom; _handlerMouseMove = onMouseMove.bind(this); _handlerMouseUp = onMouseUp.bind(this); @@ -1055,19 +1174,19 @@ 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) { var center = globeTarget.position; - snapShotCamera.shot(this.object); + snapShotCamera.shot(this.camera); ptScreenClick.x = this.domElement.width / 2; ptScreenClick.y = this.domElement.height / 2; @@ -1076,14 +1195,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.object.position); - this.updateControls(); + scale = pRange / globeTarget.position.distanceTo(this.camera.position); + this.updateCameraTransformation(); }; @@ -1092,11 +1211,11 @@ GlobeControls.prototype.setRange = function(pRange) { GlobeControls.prototype.getRay = function() { var direction = new THREE.Vector3(0, 0, 1); - this.object.localToWorld(direction); - direction.sub(this.object.position).negate().normalize(); + this.camera.localToWorld(direction); + direction.sub(this.camera.position).negate().normalize(); return { - origin: this.object.position, + origin: this.camera.position, direction: direction }; @@ -1148,13 +1267,13 @@ GlobeControls.prototype.reset = function() { state = CONTROL_STATE.NONE; this.target.copy(initialTarget); - this.object.position.copy(initialPosition); - this.object.zoom = initialZoom; + this.camera.position.copy(initialPosition); + this.camera.zoom = initialZoom; - this.object.updateProjectionMatrix(); + this.camera.updateProjectionMatrix(); this.dispatchEvent(this.changeEvent); - this.updateControls(); + this.updateCameraTransformation(); }; diff --git a/src/Renderer/c3DEngine.js b/src/Renderer/c3DEngine.js index bafad8c126..2db8f4e3db 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); @@ -99,7 +101,7 @@ function c3DEngine(scene, positionCamera, viewerDiv, debugMode, gLDebug) { this.width = this.viewerDiv.clientWidth * (this.debug ? 0.5 : 1); this.height = this.viewerDiv.clientHeight; this.camera.resize(this.width, this.height); - this.controls.updateObject(this.camera); + this.controls.updateCamera(this.camera); if (this.camDebug) { this.camDebug.aspect = this.camera.ratio; @@ -236,7 +238,6 @@ c3DEngine.prototype.enableRTC = function(enable) { }; - /** * change state all visible nodes * @param {type} state new state to apply diff --git a/src/Scene/Quadtree.js b/src/Scene/Quadtree.js index 8649d75176..df6a1de809 100644 --- a/src/Scene/Quadtree.js +++ b/src/Scene/Quadtree.js @@ -73,7 +73,7 @@ Quadtree.prototype.init = function(geometryLayer) { for (var i = 0; i < this.schemeTile.rootCount(); i++) { this.requestNewTile(geometryLayer, this.schemeTile.getRoot(i), rootNode); } -} +}; Quadtree.prototype.northWest = function(node) { return node.children[0]; @@ -120,4 +120,37 @@ Quadtree.prototype.subdivideNode = function(node) { return [quad.northWest, quad.northEast, quad.southWest, quad.southEast]; }; +Quadtree.prototype.traverse = function(foo,node) +{ + if(foo(node)) + for (var i = 0; i < node.children.length; i++) + this.traverse(foo,node.children[i]); +}; + +Quadtree.prototype.getTile = function(coordinate) { + + var point = {x:coordinate.longitude(),y:coordinate.latitude()}; + + var gT = function(tile) + { + var inside = tile.bbox ? tile.bbox.isInside(point) : true; + + if(tile.children.length === 0 && inside) + point.tile = tile; + + //TODO: Fix error verify if this is correct + if(inside) + point.parent = tile.parent; + + return inside; + }; + + this.traverse(gT,this.children[0]); + + if(point.tile === undefined) + return point.parent; + else + return point.tile; +}; + export default Quadtree; diff --git a/src/Scene/Scene.js b/src/Scene/Scene.js index 4b4385d5e5..bbf054afa1 100644 --- a/src/Scene/Scene.js +++ b/src/Scene/Scene.js @@ -87,7 +87,7 @@ Scene.prototype.getPickPosition = function(mouse) { Scene.prototype.getEllipsoid = function() { return this.ellipsoid; -} +}; // Scene.prototype.getZoomLevel = function(){ // return this.selectNodes;