From a6e08c62bcedabf6eea6ca6a814b2236fbd230da Mon Sep 17 00:00:00 2001 From: Mm24 <50300669+Mm24@users.noreply.github.com> Date: Wed, 16 Jun 2021 10:23:03 +0200 Subject: [PATCH 01/31] Revert "Depth map dev" --- src/js/viewer/ViewerPanoAPI.js | 187 ++------------------------------- starter.html | 2 +- 2 files changed, 7 insertions(+), 182 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 80477a4..405ccfb 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -21,27 +21,16 @@ export class ViewerPanoAPI { //initialize the eventLayer this.eventLayer = new EventLayer(); - - - // properties needed for display and depthAtPointer method + // property needed for display method this.loadedMesh = null; - this.depthCanvas = document.createElement("canvas"); - // Two new event listeneres are called to handle *how far* the user drags this.oPM = (event) => this.onPointerMove(event); this.oPU = () => this.onPointerUp(); - - document.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); - document.addEventListener('pointerdown', (event) => this.onPointerDown(event)); - document.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - this.panoViewer=document.getElementById('pano-viewer'); this.panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); this.panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); this.panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - - $('#pano-viewer').mousedown((event) => this.onRightClick(event)); this.display(this.viewerImageAPI.currentImageId); @@ -67,21 +56,6 @@ export class ViewerPanoAPI { 'r3.jpg'); texturePano.mapping = THREE.EquirectangularReflectionMapping; // not sure if this line matters - - // also load depth-map for panorama - const image = new Image(); - - //image.crossOrigin = "use-credentials"; - image.src = this.viewerAPI.baseURL + - Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + - this.viewerImageAPI.currentImage.id + 'd.png'; - - image.addEventListener('load', () => { - this.depthCanvas.getContext("2d").drawImage(image, 0, 0); - }, false); - - - // put the texture on the spehere and add it to the scene const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); @@ -110,14 +84,6 @@ export class ViewerPanoAPI { // Set the panorama view characteristics. view(lonov, latov, fov) { - - const normalizedViewingDirection = lonLatToLocal(lonov, latov); - - // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - - this.camera.lookAt(localCoord.add(normalizedViewingDirection)); - let phi = THREE.MathUtils.degToRad(90 - latov); let theta = THREE.MathUtils.degToRad(lonov); @@ -130,7 +96,6 @@ export class ViewerPanoAPI { this.camera.lookAt(x + localCoord.x, y + localCoord.y, z + localCoord.z); - this.camera.fov = THREE.MathUtils.clamp(fov, MIN_FOV, MAX_FOV); this.camera.updateProjectionMatrix(); @@ -142,14 +107,9 @@ export class ViewerPanoAPI { this.lastMousePos = [event.clientX, event.clientY]; this.lastViewState = [this.viewerViewState.lonov, this.viewerViewState.latov]; - - document.addEventListener('pointermove', this.oPM); document.addEventListener('pointerup', this.oPU); - this.visualTest(event); - - } // handles continues update of the distance mouse moved @@ -158,7 +118,6 @@ export class ViewerPanoAPI { this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); - this.initMap(this.viewerAPI.map).show_direction(); } @@ -181,9 +140,6 @@ export class ViewerPanoAPI { } onDoubleClick(event) { - - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const halfWidth = window.innerWidth / 2; const halfHeight = window.innerHeight / 2; @@ -193,7 +149,6 @@ export class ViewerPanoAPI { const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov)) + 360) % 360; const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov - (verticalOffset * this.viewerViewState.fov / 2))); - const MEDIAN_WALKING_DISTANCE = 5; // in meter // distance to be walked along adjustedHorizontalAngle from current location const distance = MEDIAN_WALKING_DISTANCE + ((adjustedLatov / 85) * MEDIAN_WALKING_DISTANCE); @@ -216,9 +171,8 @@ export class ViewerPanoAPI { //get the current pointer position: const xy = new EventPosition(event); - - //get the position of pointer in scene: - const location = this.getCursorLocation(event); + //get the viewing direction: + const location = this.camera.getWorldDirection(); //Set up the context menu: $.contextMenu({ @@ -227,101 +181,15 @@ export class ViewerPanoAPI { }); } } -} - - // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) - depthAtPointer(event) { - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - - // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first - const localPos = lonLatToLocal(adjustedLonov, adjustedLatov); - const adjustedQuaternion = localPos.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - const [realLonov, realLatov] = localToLonLat(adjustedQuaternion); - - // pixel offsets in depth map at current curser position - const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); - const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); - - const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; - const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; - - // convert pixel value to depth information - const use5pixelAvg = false; - let imgData; - if (use5pixelAvg) { - imgData = this.depthCanvas.getContext("2d").getImageData(offsetX, offsetY, 5, 5); - } else { - imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); - } - const [red, green, blue, alpha] = averagePixelValues(imgData.data); - - // LSB red -> green -> blue MSB (ignore alpha) - const distanceMM = red | (green << 8) | (blue << 16); - - // convert from millimeter to meter - return distanceMM / 1000; - } - - // returns the current location of the cursor in the three js scene (Vector3) - getCursorLocation(event) { - // param: event.x event.y current cursor position on screen - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); - - // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - - // get distance und extend viewing direction vector by distance - const dist = this.depthAtPointer(event); - - localCoord.addScaledVector(normalizedLocalViewingDir, dist) - - return localCoord; - } - - // returns [lonov, latov] at the current cursor position - getAdjustedViewstate(event) { - // find correct pixel position on equilateral projected depth map - const halfWidth = window.innerWidth / 2; - const halfHeight = window.innerHeight / 2; - - // horizontal (lonov) : image left -> 0, image right -> 360 - // vertical (latov) : image top -> 85, image bottom -> -85 - const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen - const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - - const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; - const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); - - return [adjustedLonov, adjustedLatov]; - } - - visualTest(event) { - // visual test, spawn in white sphere at cursor position in scene - const direction = this.getCursorLocation(event); - const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); - const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); - mesh.position.set(direction.x, direction.y, direction.z); - - if (this.testMesh != null) { - this.scene.remove(this.testMesh); - } - - this.scene.add(mesh); - - this.testMesh = mesh; - } - initMap(map){ var viewerMapAPI = map; - return viewerMapAPI; + return viewerMapAPI } } - // takes in a location (in lot/lat), a direction (as a *angle*[rad, in birds eye view), and a distance (in meters) to move in the direction -const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { +function newLocationFromPointAngle(lon1, lat1, angle, distance) { // angle: +-0 -> west, +pi/2 -> south, +-pi -> east, -pi/2 -> north let lon2, lat2; @@ -332,47 +200,4 @@ const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { lat2 = lat1 - (dy / 111.3); return [lon2, lat2]; -} - -const averagePixelValues = (data) => { - const pixels = data.length / 4; - let [red, green, blue, alpha] = [0, 0, 0, 0]; // sum of all pixel values - - for (let i = 0; i < data.length; i = i + 4) { - red = red + data[i]; - green = green + data[i + 1]; - blue = blue + data[i + 2]; - alpha = alpha + data[i + 3]; - } - - // get average by dividing - red = red / pixels; - green = green / pixels; - blue = blue / pixels; - alpha = alpha / pixels; - - return [red, green, blue, alpha]; -} - -// returns a normalized Vector3 pointing in the direction specified by lonov latov -const lonLatToLocal = (lonov, latov) => { - const phi = THREE.MathUtils.degToRad(90 - latov); - const theta = THREE.MathUtils.degToRad(lonov); - - const x = Math.sin(phi) * Math.cos(theta); - const y = Math.cos(phi); - const z = Math.sin(phi) * Math.sin(theta); - - return new THREE.Vector3(x, y, z); -} - -// inverse operation to above -const localToLonLat = (vec) => { - const phi = Math.acos(vec.y); - const theta = Math.atan2(vec.z, vec.x); - - let latov = THREE.MathUtils.radToDeg(phi); - const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; - - return [lonov, 90 - latov]; -} +} \ No newline at end of file diff --git a/starter.html b/starter.html index aac4d38..e81a752 100644 --- a/starter.html +++ b/starter.html @@ -26,7 +26,7 @@ window.parent = { callback: function(viewerWindow, viewerAsync) { console.info("initial callback called:", viewerWindow, viewerAsync); - viewerAsync("../assets/", (api) => { + viewerAsync("https://bora.bup-nbg.de/amos2floors/", (api) => { console.info("loaded callback called with API:", api); }); } From 4a1a4f8dcd5448114a033562d2a9287ddb740323 Mon Sep 17 00:00:00 2001 From: clairebb1005 Date: Thu, 17 Jun 2021 16:26:39 +0200 Subject: [PATCH 02/31] click to navigation + set view to middle done --- src/js/viewer/ViewerMapAPI.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index fd15762..00d22f7 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -29,6 +29,10 @@ export class ViewerMapAPI { this.lastLayerDirection = []; this.redraw(); + + this.viewerAPI = viewerAPI; + let map = document.getElementById('map'); + map.addEventListener('dblclick', (event) => this.onDoubleClick(event)); } // Method: Add an event layer to the map (2D) view. @@ -70,7 +74,7 @@ export class ViewerMapAPI { new ol.control.FullScreen(), ]), //Disable Zoom Control on MAP - interactions: ol.interaction.defaults({ mouseWheelZoom: false }), + interactions: ol.interaction.defaults({doubleClickZoom :false}), }); // create image layers for each floors @@ -179,6 +183,9 @@ export class ViewerMapAPI { this.map.addLayer(vectorLayerRed); + // set view to middle + this.setMiddle(this.posLon,this.posLan); + // save last vector layers for deleting next time this.lastVectorLayer = currentVectorLayer; this.lastVectorLayerRed = vectorLayerRed; @@ -263,5 +270,31 @@ export class ViewerMapAPI { let lan = 111000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); return [lon, lan]; } + + onDoubleClick(event) { + + var coord = []; + var mousePosition = []; + var mapdata = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].mapData; + var floor = this.viewerFloorAPI; + var z = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].z; + var viewerAPI = this.viewerAPI; + // this.map.getView().setZoom(1); + + this.map.on('dblclick', function(event){ + + coord = event.coordinate; + mousePosition.push(((coord[0] - (mapdata.x / mapdata.density)) / 87000 ) + floor.origin[0]); + mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / 111000 ) + floor.origin[1]); + + // move + viewerAPI.move(mousePosition[0],mousePosition[1],z); + + }) + } + + setMiddle(poslon, poslan){ + this.map.getView().setCenter([poslon,poslan]); + } } From 27d49c02a403c8f136f80ce8689af957d185e947 Mon Sep 17 00:00:00 2001 From: Mm24 Date: Fri, 18 Jun 2021 14:48:04 +0200 Subject: [PATCH 03/31] peer reviewed code: working successfully --- starter.html => index.html | 0 src/js/viewer/ViewerMapAPI.js | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename starter.html => index.html (100%) diff --git a/starter.html b/index.html similarity index 100% rename from starter.html rename to index.html diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 00d22f7..2838717 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -190,7 +190,6 @@ export class ViewerMapAPI { this.lastVectorLayer = currentVectorLayer; this.lastVectorLayerRed = vectorLayerRed; - // disable init this.show_direction(); this.init = false; } @@ -235,7 +234,6 @@ export class ViewerMapAPI { }); this.lastLayerDirection = vectorLayerTriangleVertex; - // this.addLayer(this.lastLayerDirection); // Draw Triangle Polygon let styleTriangle = new ol.style.Style({ @@ -272,9 +270,11 @@ export class ViewerMapAPI { } onDoubleClick(event) { - + + // Function to trigger the position change var coord = []; var mousePosition = []; + // Update location metadata var mapdata = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].mapData; var floor = this.viewerFloorAPI; var z = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].z; From fc36df53e0a4a98979f8cd6a64b90a5b4c9a4b4d Mon Sep 17 00:00:00 2001 From: Mm24 Date: Fri, 18 Jun 2021 15:45:32 +0200 Subject: [PATCH 04/31] peer review and samll bug fix --- src/js/viewer/ViewerMapAPI.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 2838717..0c20313 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -264,11 +264,18 @@ export class ViewerMapAPI { getLonLanCoordinates(position, mapdata){ // Compute the latitude and longitude in reference to the origin in WGS84 and aff offset of the map - let lon = 87000 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); - let lan = 111000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); + let lon = 71500 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); + let lan = 113000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); return [lon, lan]; } + getCoordinatesLonLan(position, mapdata){ + // Compute the coordinate in reference to the origin from WGS84 Longitude Latitude + let x = (position[0] -(mapdata.x / mapdata.density) )/71500 + this.viewerFloorAPI.origin[0]; + let y = (position[1] -(mapdata.x / mapdata.density) )/113000 + this.viewerFloorAPI.origin[1]; + return [x, y]; + } + onDoubleClick(event) { // Function to trigger the position change @@ -279,13 +286,13 @@ export class ViewerMapAPI { var floor = this.viewerFloorAPI; var z = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].z; var viewerAPI = this.viewerAPI; - // this.map.getView().setZoom(1); + this.map.on('dblclick', function(event){ coord = event.coordinate; - mousePosition.push(((coord[0] - (mapdata.x / mapdata.density)) / 87000 ) + floor.origin[0]); - mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / 111000 ) + floor.origin[1]); + mousePosition.push( ((coord[0] - (mapdata.x / mapdata.density)) / 71500 ) + floor.origin[0] ); + mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / 113000 ) + floor.origin[1]); // move viewerAPI.move(mousePosition[0],mousePosition[1],z); From 4122727f1747244bf9b1f2f5e9e51ae14ff84408 Mon Sep 17 00:00:00 2001 From: Mm24 Date: Fri, 18 Jun 2021 16:11:20 +0200 Subject: [PATCH 05/31] merge current advances --- .../2021-06-16-Kanban-board-Sprint-9.PNG | Bin 0 -> 131711 bytes .../2021-06-16-Planning-Document-Sprint-9.pdf | Bin 0 -> 123485 bytes starter.html => index.html | 0 src/js/viewer/ViewerAPI.js | 31 +--- src/js/viewer/ViewerMapAPI.js | 59 +++++-- src/js/viewer/ViewerPanoAPI.js | 156 ++++++++++++++---- 6 files changed, 178 insertions(+), 68 deletions(-) create mode 100644 Deliverables/2021-06-16-Kanban-board-Sprint-9.PNG create mode 100644 Deliverables/2021-06-16-Planning-Document-Sprint-9.pdf rename starter.html => index.html (100%) diff --git a/Deliverables/2021-06-16-Kanban-board-Sprint-9.PNG b/Deliverables/2021-06-16-Kanban-board-Sprint-9.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f50b8fc07ed6ba74b7e2f43f2e911b81d1b399a4 GIT binary patch literal 131711 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

Ji>ZpA%9vu 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 literal 0 HcmV?d00001 diff --git a/Deliverables/2021-06-16-Planning-Document-Sprint-9.pdf b/Deliverables/2021-06-16-Planning-Document-Sprint-9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ca570a9b8b8dc97d40ef6efe757fe04d512e80dd GIT binary patch literal 123485 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 +~HH3KK+?x^#{2*+47*y%AlH7 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 { // the only html element we work with (the pano-viewer div) - const container = document.getElementById('pano-viewer'); - - console.log("init") - this.pano.initMap(this.map); + const panoDiv = document.getElementById('pano-viewer'); // create the renderer, and embed the attributed dom element in the html page this.renderer = new THREE.WebGLRenderer(); @@ -56,14 +53,11 @@ export class ViewerAPI { this.renderer.autoClear = false; // To allow render overlay on top of panorama scene this.renderer.sortObjects = false; - container.appendChild(this.renderer.domElement); + panoDiv.appendChild(this.renderer.domElement); // start animation loop this.animate(); }); - - console.log(this.getMap()); - } animate() { @@ -71,8 +65,6 @@ export class ViewerAPI { this.pano.view(this.pano.viewerViewState.lonov, this.pano.viewerViewState.latov, this.pano.viewerViewState.fov); this.renderer.clear(); this.renderer.render(this.pano.scene, this.pano.camera); - this.renderer.clearDepth(); - this.renderer.render(this.map.scene, this.map.camera); } //Move the view to the nearest (euclidian distance) panorama to the given position. (ignore z value because only called on same floor) @@ -96,7 +88,6 @@ export class ViewerAPI { // avoid duplication if (bestImg != this.image.currentImage) { this.pano.display(bestImg.id); - console.log("move") this.map.redraw(); return bestImg; } @@ -145,12 +136,12 @@ export class ViewerAPI { // Convert the local metric three.js coordinates used by the viewer to WGS 84 coordinates [longitude, latitude, z]. toGlobal(localCoords) { // localCoords : THREE.Vector3 // Local coordinates used by the viewer - const globalX = this.floor.origin[0] - (localCoords.x / 71.5); - const globalY = this.floor.origin[1] - (localCoords.y / 111.3); - const globalZ = localCoords.z - this.floor.currentFloor.z; + const globalX = this.floor.origin[0] - ((localCoords.x / 1000) / 71.5); + const globalY = this.floor.origin[1] - ((-localCoords.z / 1000) / 111.3); + const globalZ = localCoords.y - this.floor.currentFloor.z; // the three js scene sees the y axis as the up-down axis so we have to swap with z - return [globalX, globalZ, globalY]; + return [globalX, globalY, globalZ]; // Returns: [Number] : WGS 84 coordinates [longitude, latitude, z] (z value is floorZ + panoZ, where localCoords is just the panoZ) } @@ -160,18 +151,14 @@ export class ViewerAPI { // Distance calculation math taken from here https://www.mkompf.com/gps/distcalc.html // The more accurate calculation breaks the pixel offset on the pre-created maps const dx = 71.5 * (this.floor.origin[0] - globalCoords[0]); - const dy = 111.3 * (this.floor.origin[1] - globalCoords[1]); + const dz = 111.3 * (this.floor.origin[1] - globalCoords[1]); return new this.THREE.Vector3( dx * 1000, globalCoords[2] + this.floor.currentFloor.z, - dy * 1000); + -dz * 1000); } // TODO: swap() and big(wanted) - getMap(){ - return this.map - } - } diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 56a34c9..0c20313 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -14,15 +14,6 @@ export class ViewerMapAPI { viewerAPI.floor.viewerMapAPI = this; // set reference to mapAPI in floorAPI - this.scene = new THREE.Scene(); // scene THREE.Scene scene overlayed over the map (2D) view - this.camera = new THREE.OrthographicCamera( - - window.innerWidth / 2, // frustum left plane - window.innerWidth / 2, // frustum right plane - window.innerHeight / 2, // frustum top plane - - window.innerHeight / 2, // frustum bottom plane - 1, // frustum near plane - 10); // frustum far plane - this.baseURL = viewerAPI.baseURL; // create Map and Layers @@ -38,6 +29,10 @@ export class ViewerMapAPI { this.lastLayerDirection = []; this.redraw(); + + this.viewerAPI = viewerAPI; + let map = document.getElementById('map'); + map.addEventListener('dblclick', (event) => this.onDoubleClick(event)); } // Method: Add an event layer to the map (2D) view. @@ -79,7 +74,7 @@ export class ViewerMapAPI { new ol.control.FullScreen(), ]), //Disable Zoom Control on MAP - interactions: ol.interaction.defaults({ mouseWheelZoom: false }), + interactions: ol.interaction.defaults({doubleClickZoom :false}), }); // create image layers for each floors @@ -188,11 +183,13 @@ export class ViewerMapAPI { this.map.addLayer(vectorLayerRed); + // set view to middle + this.setMiddle(this.posLon,this.posLan); + // save last vector layers for deleting next time this.lastVectorLayer = currentVectorLayer; this.lastVectorLayerRed = vectorLayerRed; - // disable init this.show_direction(); this.init = false; } @@ -237,7 +234,6 @@ export class ViewerMapAPI { }); this.lastLayerDirection = vectorLayerTriangleVertex; - // this.addLayer(this.lastLayerDirection); // Draw Triangle Polygon let styleTriangle = new ol.style.Style({ @@ -268,9 +264,44 @@ export class ViewerMapAPI { getLonLanCoordinates(position, mapdata){ // Compute the latitude and longitude in reference to the origin in WGS84 and aff offset of the map - let lon = 87000 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); - let lan = 111000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); + let lon = 71500 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); + let lan = 113000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); return [lon, lan]; } + + getCoordinatesLonLan(position, mapdata){ + // Compute the coordinate in reference to the origin from WGS84 Longitude Latitude + let x = (position[0] -(mapdata.x / mapdata.density) )/71500 + this.viewerFloorAPI.origin[0]; + let y = (position[1] -(mapdata.x / mapdata.density) )/113000 + this.viewerFloorAPI.origin[1]; + return [x, y]; + } + + onDoubleClick(event) { + + // Function to trigger the position change + var coord = []; + var mousePosition = []; + // Update location metadata + var mapdata = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].mapData; + var floor = this.viewerFloorAPI; + var z = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].z; + var viewerAPI = this.viewerAPI; + + + this.map.on('dblclick', function(event){ + + coord = event.coordinate; + mousePosition.push( ((coord[0] - (mapdata.x / mapdata.density)) / 71500 ) + floor.origin[0] ); + mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / 113000 ) + floor.origin[1]); + + // move + viewerAPI.move(mousePosition[0],mousePosition[1],z); + + }) + } + + setMiddle(poslon, poslan){ + this.map.getView().setCenter([poslon,poslan]); + } } diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 405ccfb..82bdd45 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -12,7 +12,7 @@ export class ViewerPanoAPI { this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); this.viewerImageAPI = viewerAPI.image; this.viewerAPI = viewerAPI; - this.sphereRadius = 10; + this.sphereRadius = 5; this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); this.lastViewState; @@ -20,22 +20,23 @@ export class ViewerPanoAPI { //initialize the eventLayer this.eventLayer = new EventLayer(); - - // property needed for display method + + // properties needed for display and depthAtPointer method this.loadedMesh = null; + this.depthCanvas = document.createElement("canvas"); // Two new event listeneres are called to handle *how far* the user drags this.oPM = (event) => this.onPointerMove(event); this.oPU = () => this.onPointerUp(); - this.panoViewer=document.getElementById('pano-viewer'); - this.panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); - this.panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); - this.panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); + + const panoViewer = document.getElementById('pano-viewer'); + panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); + panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); + panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); + $('#pano-viewer').mousedown((event) => this.onRightClick(event)); this.display(this.viewerImageAPI.currentImageId); - - this.viewerMapAPI; } // displays the panorama with idx *ImageNum* in the model @@ -56,6 +57,18 @@ export class ViewerPanoAPI { 'r3.jpg'); texturePano.mapping = THREE.EquirectangularReflectionMapping; // not sure if this line matters + // --- load depth-map for panorama --- + const image = new Image(); + //image.crossOrigin = "use-credentials"; + image.src = this.viewerAPI.baseURL + + Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + + this.viewerImageAPI.currentImage.id + 'd.png'; + + image.addEventListener('load', () => { + this.depthCanvas.getContext("2d").drawImage(image, 0, 0); + }, false); + // ----- + // put the texture on the spehere and add it to the scene const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); @@ -84,17 +97,12 @@ export class ViewerPanoAPI { // Set the panorama view characteristics. view(lonov, latov, fov) { - let phi = THREE.MathUtils.degToRad(90 - latov); - let theta = THREE.MathUtils.degToRad(lonov); + const normalizedViewingDirection = lonLatToLocal(lonov, latov); - const x = this.sphereRadius * Math.sin(phi) * Math.cos(theta); - const y = this.sphereRadius * Math.cos(phi); - const z = this.sphereRadius * Math.sin(phi) * Math.sin(theta); - // adjust looking direction for offset of current mesh in scene const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - this.camera.lookAt(x + localCoord.x, y + localCoord.y, z + localCoord.z); + this.camera.lookAt(localCoord.add(normalizedViewingDirection)); this.camera.fov = THREE.MathUtils.clamp(fov, MIN_FOV, MAX_FOV); @@ -107,18 +115,19 @@ export class ViewerPanoAPI { this.lastMousePos = [event.clientX, event.clientY]; this.lastViewState = [this.viewerViewState.lonov, this.viewerViewState.latov]; + document.addEventListener('pointermove', this.oPM); document.addEventListener('pointerup', this.oPU); - } // handles continues update of the distance mouse moved onPointerMove(event) { - let scalingFactor = this.camera.fov / MAX_FOV; + const scalingFactor = this.camera.fov / MAX_FOV; this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); - this.initMap(this.viewerAPI.map).show_direction(); + + this.viewerAPI.map.show_direction(); } // this event listener is called when the user *ends* moving the picture @@ -136,19 +145,11 @@ export class ViewerPanoAPI { this.camera.updateProjectionMatrix(); this.viewerAPI.propagateEvent("viewed", this.viewerViewState, true); - this.initMap(this.viewerAPI.map).show_direction(); + this.viewerAPI.map.show_direction(); } onDoubleClick(event) { - const halfWidth = window.innerWidth / 2; - const halfHeight = window.innerHeight / 2; - - const horizontalOffset = (event.x - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen - const verticalOffset = (event.y - halfHeight) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - - const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov)) + 360) % 360; - const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov - (verticalOffset * this.viewerViewState.fov / 2))); - + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); const MEDIAN_WALKING_DISTANCE = 5; // in meter // distance to be walked along adjustedHorizontalAngle from current location const distance = MEDIAN_WALKING_DISTANCE + ((adjustedLatov / 85) * MEDIAN_WALKING_DISTANCE); @@ -182,9 +183,100 @@ export class ViewerPanoAPI { } } - initMap(map){ - var viewerMapAPI = map; - return viewerMapAPI + + // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) + depthAtPointer(event) { + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); + + // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first + const localPos = lonLatToLocal(adjustedLonov, adjustedLatov); + const adjustedQuaternion = localPos.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + const [realLonov, realLatov] = localToLonLat(adjustedQuaternion); + + // pixel offsets in depth map at current curser position + const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); + const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); + + const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; + const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; + + // convert pixel value to depth information + const use5pixelAvg = false; + let imgData; + if (use5pixelAvg) { + imgData = this.depthCanvas.getContext("2d").getImageData(offsetX, offsetY, 5, 5); + } else { + imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); + } + const [red, green, blue, alpha] = averagePixelValues(imgData.data); + + // LSB red -> green -> blue MSB (ignore alpha) + const distanceMM = red | (green << 8) | (blue << 16); + + // convert from millimeter to meter + return distanceMM / 1000; + } + + // returns the current location of the cursor in the three js scene (Vector3) + getCursorLocation(event) { + // param: event.x event.y current cursor position on screen + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); + const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); + + // adjust looking direction for offset of current mesh in scene + const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + + // get distance und extend viewing direction vector by distance + const dist = this.depthAtPointer(event); + + localCoord.addScaledVector(normalizedLocalViewingDir, dist) + + return localCoord; + } + + // returns [lonov, latov] at the current cursor position + getAdjustedViewstate(event) { + // find correct pixel position on equilateral projected depth map + const halfWidth = window.innerWidth / 2; + const halfHeight = window.innerHeight / 2; + + // horizontal (lonov) : image left -> 0, image right -> 360 + // vertical (latov) : image top -> 85, image bottom -> -85 + const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen + const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen + + const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; + const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); + + return [adjustedLonov, adjustedLatov]; + } + + visualTest(event) { + console.info(this.viewerViewState); + console.info(this.camera.getWorldDirection()); + console.info("current img original global ", this.viewerImageAPI.currentImage.pos) + const loc = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + console.info("current img pos loc ", loc); + const b = this.viewerAPI.toGlobal(loc); + console.info("back to global ", b); + const bb = this.viewerAPI.toLocal(b); + console.info("and back to loc one more time ", bb); + + // visual test, spawn in white sphere at cursor position in scene + const direction = this.getCursorLocation(event); + const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); + const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); + mesh.position.set(direction.x, direction.y, direction.z); + + if (this.testMesh != null) { + this.scene.remove(this.testMesh); + } + + this.scene.add(mesh); + + this.testMesh = mesh; + + console.info("current sphere pos ", direction); } } From 26c00648296293ed3903eb1e4a5b0c4f0aae34c9 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Fri, 18 Jun 2021 18:23:59 +0200 Subject: [PATCH 06/31] Talking about user story and distributing work --- src/js/viewer/ViewerAPI.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index fef3186..c0281f5 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -43,6 +43,14 @@ export class ViewerAPI { this.pano = new ViewerPanoAPI(this); this.map = new ViewerMapAPI(this); }).then(() => { + // const test = THREE.Mesh(...); + // add the methods to test .vwr_oncontext vwr_... + // pano.addLayer(test) + + // panoDiv.eventListener(onMove, check with raycaster if cursor over sphere, call vwr_onpointerenter or vwr_onpointerleave) + // panoDiv.eventListener(onClick, check with raycaster if cursor over sphere, call vwr_onclick) + // panoDiv.eventListener(onRightClick, check with raycaster if cursor over sphere, call vwr_oncontext ) + // the only html element we work with (the pano-viewer div) const panoDiv = document.getElementById('pano-viewer'); From 9924b1795835270db04acc44a2c65ef73a8b546f Mon Sep 17 00:00:00 2001 From: Tong Yao <51960333+ChillYao@users.noreply.github.com> Date: Sat, 19 Jun 2021 00:36:08 +0200 Subject: [PATCH 07/31] Initial setup of the mesh and method frames --- src/js/viewer/ViewerAPI.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index c0281f5..82280b4 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -27,7 +27,7 @@ export class ViewerAPI { this.baseURL = baseURL; this.listeners = []; - + this.renderer; // Load the metadata only once $.ajax({ @@ -45,8 +45,25 @@ export class ViewerAPI { }).then(() => { // const test = THREE.Mesh(...); // add the methods to test .vwr_oncontext vwr_... - // pano.addLayer(test) + const testMesh = new THREE.Mesh(); + + testMesh.vwr_onclick = function () { + console.log("vwr_onclick is triggered."); + } + + testMesh.vwr_oncontext = function () { + console.log("vwr_oncontext is triggered."); + } + + testMesh.vwr_onpointerenter = function () { + console.log("vwr_onpointerenter is triggered."); + } + testMesh.vwr_onpointerleave = function () { + console.log("vwr_onpointerleave is triggered."); + } + + // pano.addLayer(test) // panoDiv.eventListener(onMove, check with raycaster if cursor over sphere, call vwr_onpointerenter or vwr_onpointerleave) // panoDiv.eventListener(onClick, check with raycaster if cursor over sphere, call vwr_onclick) // panoDiv.eventListener(onRightClick, check with raycaster if cursor over sphere, call vwr_oncontext ) @@ -62,7 +79,7 @@ export class ViewerAPI { this.renderer.sortObjects = false; panoDiv.appendChild(this.renderer.domElement); - + // start animation loop this.animate(); }); @@ -81,12 +98,12 @@ export class ViewerAPI { let minDistance = 1000000000; let bestImg; - + this.floor.currentFloor.viewerImages.forEach(element => { const currLocalPos = this.toLocal(element.pos); const [dx, dz] = [localPos.x - currLocalPos.x, localPos.z - currLocalPos.z]; const currDistance = Math.sqrt(dx * dx + dz * dz); - + if (currDistance < minDistance) { minDistance = currDistance; bestImg = element; @@ -160,7 +177,7 @@ export class ViewerAPI { // The more accurate calculation breaks the pixel offset on the pre-created maps const dx = 71.5 * (this.floor.origin[0] - globalCoords[0]); const dz = 111.3 * (this.floor.origin[1] - globalCoords[1]); - + return new this.THREE.Vector3( dx * 1000, globalCoords[2] + this.floor.currentFloor.z, From 261fde6a46d7de1fcdd9223cb19420c1fc7614b0 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Sat, 19 Jun 2021 19:26:52 +0200 Subject: [PATCH 08/31] Methods for adding/removing meshes to scene --- src/js/viewer/ViewerAPI.js | 13 +++++++++---- src/js/viewer/ViewerPanoAPI.js | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 82280b4..581a1cd 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -43,9 +43,12 @@ export class ViewerAPI { this.pano = new ViewerPanoAPI(this); this.map = new ViewerMapAPI(this); }).then(() => { - // const test = THREE.Mesh(...); - // add the methods to test .vwr_oncontext vwr_... - const testMesh = new THREE.Mesh(); + // --- EventMesh TEST --- + // visual test, spawn in white sphere at first image position in scene + const sphere = new THREE.SphereGeometry(1 / 5, 10, 10); + const testMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); + const startPos = this.toLocal(this.image.currentImage.pos); + testMesh.position.set(startPos.x, startPos.y - 2, startPos.z); testMesh.vwr_onclick = function () { console.log("vwr_onclick is triggered."); @@ -63,11 +66,13 @@ export class ViewerAPI { console.log("vwr_onpointerleave is triggered."); } - // pano.addLayer(test) + this.pano.addLayer(testMesh); // panoDiv.eventListener(onMove, check with raycaster if cursor over sphere, call vwr_onpointerenter or vwr_onpointerleave) // panoDiv.eventListener(onClick, check with raycaster if cursor over sphere, call vwr_onclick) // panoDiv.eventListener(onRightClick, check with raycaster if cursor over sphere, call vwr_oncontext ) + // --- --- + // the only html element we work with (the pano-viewer div) const panoDiv = document.getElementById('pano-viewer'); diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 8b304df..6f8ff14 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -12,7 +12,8 @@ export class ViewerPanoAPI { this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); this.viewerImageAPI = viewerAPI.image; this.viewerAPI = viewerAPI; - this.sphereRadius = 5; + this.sphereRadius = 10; + this.addedLayers = new Set(); // EventMesh and EventLayer objects added via addLayer(); this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); this.lastViewState; @@ -109,6 +110,23 @@ export class ViewerPanoAPI { this.camera.updateProjectionMatrix(); } + // Add an event layer to the panorama (3D) viewer. + // param: EventLayer (or EventMesh) to add + addLayer(layer) { + if (!layer) return; + if (this.addedLayers.has(layer)) return; + + this.scene.add(layer); + this.addedLayers.add(layer); + } + + removeLayer(layer) { + if (!layer) return; + if (!this.addedLayers.has(layer)) return; + + this.scene.remove(layer); + this.addedLayers.delete(layer); + } // ----- Event handling functions for panning, zooming and moving ----- onPointerDown(event) { From d4f3c1b521aaade56cc386dbc364eb575d53291c Mon Sep 17 00:00:00 2001 From: Tong Yao <51960333+ChillYao@users.noreply.github.com> Date: Sat, 19 Jun 2021 22:40:58 +0200 Subject: [PATCH 09/31] add argument xy and position. --- src/js/viewer/ViewerAPI.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 581a1cd..41494cf 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -7,6 +7,7 @@ import { ViewerMapAPI } from "./ViewerMapAPI.js" import { ViewerState } from "./ViewerState.js"; import { libraryInfo } from "./LibraryInfo.js"; import { ViewerVersionAPI } from "./ViewerVersionAPI.js"; +import { ViewerContextItem } from "./ViewerContextItem.js"; // API provided by the viewer @@ -50,12 +51,30 @@ export class ViewerAPI { const startPos = this.toLocal(this.image.currentImage.pos); testMesh.position.set(startPos.x, startPos.y - 2, startPos.z); - testMesh.vwr_onclick = function () { + testMesh.vwr_onclick = function (xy, position) { console.log("vwr_onclick is triggered."); + console.log("Pointer position: " + xy); + console.log("Local coordinate for pointer position: " + position); + return true; } - testMesh.vwr_oncontext = function () { + testMesh.vwr_oncontext = function (xy, position) { console.log("vwr_oncontext is triggered."); + console.log("Pointer position: " + xy); + console.log("Local coordinate for pointer position: " + position); + + //Creating callback function for context menu item: + let callback = function (key, options) { + var msg = 'clicked: ' + key; + (window.console && console.log(msg)) || alert(msg); + }; + + //Creating item objects + let itemEdit = new ViewerContextItem(callback, "edit", null, "Edit"); + let itemCut = new ViewerContextItem(callback, "cut", null, "Cut"); + + //Creating list of item objects. + return [itemEdit, itemCut]; } testMesh.vwr_onpointerenter = function () { From 1f7bf248ab532f04b464081a67c81b226cd8472f Mon Sep 17 00:00:00 2001 From: leonopulos Date: Sun, 20 Jun 2021 19:17:54 +0200 Subject: [PATCH 10/31] Add further event listener progress --- src/js/viewer/ViewerPanoAPI.js | 74 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 6f8ff14..3a0e4af 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -14,6 +14,7 @@ export class ViewerPanoAPI { this.viewerAPI = viewerAPI; this.sphereRadius = 10; this.addedLayers = new Set(); // EventMesh and EventLayer objects added via addLayer(); + this.raycaster = new THREE.Raycaster(); this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); this.lastViewState; @@ -35,7 +36,11 @@ export class ViewerPanoAPI { panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - $('#pano-viewer').mousedown((event) => this.onRightClick(event)); + panoViewer.addEventListener('click', (event) => this.meshCheckClick(event)); + panoViewer.addEventListener('contextmenu', (event) => { + event.preventDefault(); + this.meshCheckRightClick(event); + }); this.display(this.viewerImageAPI.currentImageId); } @@ -183,22 +188,65 @@ export class ViewerPanoAPI { this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); } - onRightClick(event) { - //if right mouse is clicked: - if (event.which == 3) { + // ---- event handeling functions for EventMesh / EventLayer API interaction ---- + getIntersectingMeshes(event) { + // calculate mouse position in normalized device coordinates + // (-1 to +1) for both components + const mouse = new THREE.Vector2(); + mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; + + // update the picking ray with the camera and mouse position + this.raycaster.setFromCamera(mouse, this.camera); + + // calculate objects intersecting the picking ray + const intersects = this.raycaster.intersectObjects(this.scene.children); + + // include only objects that are added meshes + const meshes = []; + for (const e in intersects) { + if (this.addedLayers.has(intersects[e].object)) { + meshes.push(intersects[e]); + } + } + + return meshes; + } + + meshCheckClick(event) { + const meshes = this.getIntersectingMeshes(event); + const xy = new EventPosition(event); + const location = this.getCursorLocation(event); + + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i].object; + + if (typeof mesh.vwr_onclick == "function") { + mesh.vwr_onclick(xy, location); + } + + mesh.material.color.set(0xff0000); // as a test set color red + } + } - //get the current pointer position: - const xy = new EventPosition(event); + meshCheckRightClick(event) { + const meshes = this.getIntersectingMeshes(event); + const xy = new EventPosition(event); + const location = this.getCursorLocation(event); + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i].object; - //get the position of pointer in scene: - const location = this.getCursorLocation(event); + if (typeof mesh.vwr_oncontext == "function") { + const callback = mesh.vwr_oncontext(xy, location); + + $.contextMenu({ + selector: '#pano-viewer', + items: callback, + }); + } - //Set up the context menu: - $.contextMenu({ - selector: '#pano-viewer', - items: this.eventLayer.vwr_oncontext(xy, location), - }); + mesh.material.color.set(0x00ff00); // as a test set color green } } From a3baf42513bbbd6c7d9b63843343d0519fd71b17 Mon Sep 17 00:00:00 2001 From: Tong Yao <51960333+ChillYao@users.noreply.github.com> Date: Mon, 21 Jun 2021 00:27:43 +0200 Subject: [PATCH 11/31] the method cannot be triggerd when the pointer leave the mesh. --- src/js/viewer/ViewerPanoAPI.js | 84 ++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 3a0e4af..98eec9b 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -22,7 +22,7 @@ export class ViewerPanoAPI { //initialize the eventLayer this.eventLayer = new EventLayer(); - + // properties needed for display and depthAtPointer method this.loadedMesh = null; this.depthCanvas = document.createElement("canvas"); @@ -41,6 +41,8 @@ export class ViewerPanoAPI { event.preventDefault(); this.meshCheckRightClick(event); }); + panoViewer.addEventListener('pointermove', (event) => this.meshCheckMouseOver(event)); + this.display(this.viewerImageAPI.currentImageId); } @@ -67,9 +69,9 @@ export class ViewerPanoAPI { const image = new Image(); //image.crossOrigin = "use-credentials"; image.src = this.viewerAPI.baseURL + - Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + - this.viewerImageAPI.currentImage.id + 'd.png'; - + Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + + this.viewerImageAPI.currentImage.id + 'd.png'; + image.addEventListener('load', () => { this.depthCanvas.getContext("2d").drawImage(image, 0, 0); }, false); @@ -77,10 +79,10 @@ export class ViewerPanoAPI { // put the texture on the spehere and add it to the scene const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); - + // adjust for orientation offset mesh.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - + // put in the correct position in the scene const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); mesh.position.set(localCoord.x, localCoord.y, localCoord.z); @@ -92,7 +94,7 @@ export class ViewerPanoAPI { this.scene.add(mesh); this.loadedMesh = mesh; - + // put camera inside sphere mesh this.camera.position.set(localCoord.x, localCoord.y, localCoord.z); } @@ -117,10 +119,10 @@ export class ViewerPanoAPI { // Add an event layer to the panorama (3D) viewer. // param: EventLayer (or EventMesh) to add - addLayer(layer) { + addLayer(layer) { if (!layer) return; if (this.addedLayers.has(layer)) return; - + this.scene.add(layer); this.addedLayers.add(layer); } @@ -146,7 +148,7 @@ export class ViewerPanoAPI { // handles continues update of the distance mouse moved onPointerMove(event) { const scalingFactor = this.camera.fov / MAX_FOV; - + this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); @@ -163,7 +165,7 @@ export class ViewerPanoAPI { onDocumentMouseWheel(event) { this.viewerViewState.fov = this.camera.fov + event.deltaY * ZOOM_SPEED; - + this.view(this.viewerViewState.lonov, this.viewerViewState.latov, this.viewerViewState.fov); this.camera.updateProjectionMatrix(); @@ -179,9 +181,9 @@ export class ViewerPanoAPI { // convertedAngle converted to represent directions like specified in newLocationFromPointAngle const convertedAngle = (adjustedLonov < 180) ? -adjustedLonov : 360 - adjustedLonov; - + const currentPos = this.viewerImageAPI.currentImage.pos; - + const newPos = newLocationFromPointAngle(currentPos[0], currentPos[1], THREE.Math.degToRad(convertedAngle), distance); this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); @@ -195,13 +197,13 @@ export class ViewerPanoAPI { const mouse = new THREE.Vector2(); mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; - + // update the picking ray with the camera and mouse position this.raycaster.setFromCamera(mouse, this.camera); // calculate objects intersecting the picking ray const intersects = this.raycaster.intersectObjects(this.scene.children); - + // include only objects that are added meshes const meshes = []; for (const e in intersects) { @@ -212,7 +214,7 @@ export class ViewerPanoAPI { return meshes; } - + meshCheckClick(event) { const meshes = this.getIntersectingMeshes(event); const xy = new EventPosition(event); @@ -239,7 +241,7 @@ export class ViewerPanoAPI { if (typeof mesh.vwr_oncontext == "function") { const callback = mesh.vwr_oncontext(xy, location); - + $.contextMenu({ selector: '#pano-viewer', items: callback, @@ -250,6 +252,40 @@ export class ViewerPanoAPI { } } + meshCheckMouseOver(event) { + const meshes = this.getIntersectingMeshes(event); + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i].object; + + if (typeof mesh.vwr_onpointerenter == "function") { + mesh.vwr_onpointerenter(); + } + + mesh.material.color.set(0xffff00); // as a test set color yellow + } + + document.removeEventListener('pointermove', (event) => this.meshCheckMouseOut(event)); + + } + + meshCheckMouseOut(event) { + const meshes = this.getIntersectingMeshes(event); + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i].object; + + if (typeof mesh.vwr_onpointerleave == "function") { + mesh.vwr_onpointerleave(); + } + + mesh.material.color.set(0x0000FF); // as a test set color blue + } + //document.addEventListener('pointerenter', (event) => this.meshCheckMouseOver(event)); + //document.addEventListener('pointerleave', (event) => this.meshCheckMouseOut(event)); + + } + + + // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) depthAtPointer(event) { @@ -263,7 +299,7 @@ export class ViewerPanoAPI { // pixel offsets in depth map at current curser position const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); - + const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; @@ -289,7 +325,7 @@ export class ViewerPanoAPI { // param: event.x event.y current cursor position on screen const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); - + // adjust looking direction for offset of current mesh in scene const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); @@ -311,10 +347,10 @@ export class ViewerPanoAPI { // vertical (latov) : image top -> 85, image bottom -> -85 const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - + const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); - + return [adjustedLonov, adjustedLatov]; } @@ -334,13 +370,13 @@ export class ViewerPanoAPI { const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); mesh.position.set(direction.x, direction.y, direction.z); - + if (this.testMesh != null) { this.scene.remove(this.testMesh); } this.scene.add(mesh); - + this.testMesh = mesh; console.info("current sphere pos ", direction); @@ -386,7 +422,7 @@ const averagePixelValues = (data) => { const lonLatToLocal = (lonov, latov) => { const phi = THREE.MathUtils.degToRad(90 - latov); const theta = THREE.MathUtils.degToRad(lonov); - + const x = Math.sin(phi) * Math.cos(theta); const y = Math.cos(phi); const z = Math.sin(phi) * Math.sin(theta); From b9f2040e8417c42807b9ff2085f3cb819ad9cd00 Mon Sep 17 00:00:00 2001 From: Tong Yao <51960333+ChillYao@users.noreply.github.com> Date: Mon, 21 Jun 2021 13:38:42 +0200 Subject: [PATCH 12/31] when mouse hovers the mesh, the color can be changed correctly, but methods will be called for many times. --- src/js/viewer/ViewerPanoAPI.js | 54 ++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 98eec9b..5128a7e 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -45,6 +45,7 @@ export class ViewerPanoAPI { this.display(this.viewerImageAPI.currentImageId); + this.preMeshes; } // displays the panorama with idx *ImageNum* in the model @@ -254,35 +255,50 @@ export class ViewerPanoAPI { meshCheckMouseOver(event) { const meshes = this.getIntersectingMeshes(event); - for (let i = 0; i < meshes.length; i++) { - const mesh = meshes[i].object; - - if (typeof mesh.vwr_onpointerenter == "function") { - mesh.vwr_onpointerenter(); + if (meshes.length > 0) { + this.preMeshes = meshes; + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i].object; + if (typeof mesh.vwr_onpointerenter == "function") { + mesh.vwr_onpointerenter(); + } + + mesh.material.color.set(0xffff00); // as a test set color yellow + } + } + else { + if (this.preMeshes) { + for (let i = 0; i < this.preMeshes.length; i++) { + const mesh = this.preMeshes[i].object; + if (typeof mesh.vwr_onpointerleave == "function") { + mesh.vwr_onpointerleave(); + } + + mesh.material.color.set(0x0000FF); // as a test set color blue + } } - mesh.material.color.set(0xffff00); // as a test set color yellow } - document.removeEventListener('pointermove', (event) => this.meshCheckMouseOut(event)); + + + // document.removeEventListener('pointermove', (event) => this.meshCheckMouseOut(event)); } - meshCheckMouseOut(event) { - const meshes = this.getIntersectingMeshes(event); - for (let i = 0; i < meshes.length; i++) { - const mesh = meshes[i].object; + // meshCheckMouseOut(event) { + // const meshes = this.getIntersectingMeshes(event); + // for (let i = 0; i < meshes.length; i++) { + // const mesh = meshes[i].object; - if (typeof mesh.vwr_onpointerleave == "function") { - mesh.vwr_onpointerleave(); - } + // if (typeof mesh.vwr_onpointerleave == "function") { + // mesh.vwr_onpointerleave(); + // } - mesh.material.color.set(0x0000FF); // as a test set color blue - } - //document.addEventListener('pointerenter', (event) => this.meshCheckMouseOver(event)); - //document.addEventListener('pointerleave', (event) => this.meshCheckMouseOut(event)); + // mesh.material.color.set(0x0000FF); // as a test set color blue + // } - } + // } From dea2c15668873ee8ac7e58044e0d406735de3a39 Mon Sep 17 00:00:00 2001 From: Tong Yao <51960333+ChillYao@users.noreply.github.com> Date: Mon, 21 Jun 2021 13:41:01 +0200 Subject: [PATCH 13/31] adding comments --- src/js/viewer/ViewerPanoAPI.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 5128a7e..d992575 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -255,7 +255,9 @@ export class ViewerPanoAPI { meshCheckMouseOver(event) { const meshes = this.getIntersectingMeshes(event); + //if the current mesh exist. if (meshes.length > 0) { + //store the current mesh this.preMeshes = meshes; for (let i = 0; i < meshes.length; i++) { const mesh = meshes[i].object; @@ -267,6 +269,7 @@ export class ViewerPanoAPI { } } else { + //if previous mesh exists if (this.preMeshes) { for (let i = 0; i < this.preMeshes.length; i++) { const mesh = this.preMeshes[i].object; From 858fc7e6b37f19d9fa403fbc29e4a4dfee32a2c8 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Mon, 21 Jun 2021 14:53:14 +0200 Subject: [PATCH 14/31] Update event listeners for mouse leave --- src/js/viewer/ViewerPanoAPI.js | 75 +++++++++++++--------------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index d992575..27d5750 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -14,6 +14,7 @@ export class ViewerPanoAPI { this.viewerAPI = viewerAPI; this.sphereRadius = 10; this.addedLayers = new Set(); // EventMesh and EventLayer objects added via addLayer(); + this.preMeshes = new Set(); // meshes that the mouse pointer is currently over this.raycaster = new THREE.Raycaster(); this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); @@ -45,7 +46,6 @@ export class ViewerPanoAPI { this.display(this.viewerImageAPI.currentImageId); - this.preMeshes; } // displays the panorama with idx *ImageNum* in the model @@ -209,7 +209,7 @@ export class ViewerPanoAPI { const meshes = []; for (const e in intersects) { if (this.addedLayers.has(intersects[e].object)) { - meshes.push(intersects[e]); + meshes.push(intersects[e].object); } } @@ -222,7 +222,7 @@ export class ViewerPanoAPI { const location = this.getCursorLocation(event); for (let i = 0; i < meshes.length; i++) { - const mesh = meshes[i].object; + const mesh = meshes[i]; if (typeof mesh.vwr_onclick == "function") { mesh.vwr_onclick(xy, location); @@ -238,7 +238,7 @@ export class ViewerPanoAPI { const location = this.getCursorLocation(event); for (let i = 0; i < meshes.length; i++) { - const mesh = meshes[i].object; + const mesh = meshes[i]; if (typeof mesh.vwr_oncontext == "function") { const callback = mesh.vwr_oncontext(xy, location); @@ -255,57 +255,40 @@ export class ViewerPanoAPI { meshCheckMouseOver(event) { const meshes = this.getIntersectingMeshes(event); - //if the current mesh exist. - if (meshes.length > 0) { - //store the current mesh - this.preMeshes = meshes; - for (let i = 0; i < meshes.length; i++) { - const mesh = meshes[i].object; + + // check for meshes that mouse pointer is no longer over + this.preMeshes.forEach((preMesh) => { + if (!meshes.includes(preMesh)) { + if (typeof preMesh.vwr_onpointerleave == "function") { + // remove the current mesh + this.preMeshes.delete(preMesh); + + preMesh.vwr_onpointerleave(); + } + + preMesh.material.color.set(0x0000ff); // as a test set color blue + } + }); + + // check for meshes that mouse pointer is newly over + for (let i = 0; i < meshes.length; i++) { + const mesh = meshes[i]; + + //if the current mesh has not been entered before. + if (!this.preMeshes.has(mesh)) { if (typeof mesh.vwr_onpointerenter == "function") { + // store the current mesh + this.preMeshes.add(mesh); + mesh.vwr_onpointerenter(); } mesh.material.color.set(0xffff00); // as a test set color yellow + } } - else { - //if previous mesh exists - if (this.preMeshes) { - for (let i = 0; i < this.preMeshes.length; i++) { - const mesh = this.preMeshes[i].object; - if (typeof mesh.vwr_onpointerleave == "function") { - mesh.vwr_onpointerleave(); - } - - mesh.material.color.set(0x0000FF); // as a test set color blue - } - } - - } - - - - // document.removeEventListener('pointermove', (event) => this.meshCheckMouseOut(event)); - } - // meshCheckMouseOut(event) { - // const meshes = this.getIntersectingMeshes(event); - // for (let i = 0; i < meshes.length; i++) { - // const mesh = meshes[i].object; - - // if (typeof mesh.vwr_onpointerleave == "function") { - // mesh.vwr_onpointerleave(); - // } - - // mesh.material.color.set(0x0000FF); // as a test set color blue - // } - - // } - - - - // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) depthAtPointer(event) { const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); From ccd64ca5d1cfe2e22aeca5ef649e5ac490da4e4c Mon Sep 17 00:00:00 2001 From: leonopulos Date: Mon, 21 Jun 2021 14:59:26 +0200 Subject: [PATCH 15/31] Remove visual test from last sprint --- src/js/viewer/ViewerPanoAPI.js | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 27d5750..fdbc085 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -284,7 +284,6 @@ export class ViewerPanoAPI { } mesh.material.color.set(0xffff00); // as a test set color yellow - } } } @@ -356,33 +355,6 @@ export class ViewerPanoAPI { return [adjustedLonov, adjustedLatov]; } - visualTest(event) { - console.info(this.viewerViewState); - console.info(this.camera.getWorldDirection()); - console.info("current img original global ", this.viewerImageAPI.currentImage.pos) - const loc = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - console.info("current img pos loc ", loc); - const b = this.viewerAPI.toGlobal(loc); - console.info("back to global ", b); - const bb = this.viewerAPI.toLocal(b); - console.info("and back to loc one more time ", bb); - - // visual test, spawn in white sphere at cursor position in scene - const direction = this.getCursorLocation(event); - const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); - const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); - mesh.position.set(direction.x, direction.y, direction.z); - - if (this.testMesh != null) { - this.scene.remove(this.testMesh); - } - - this.scene.add(mesh); - - this.testMesh = mesh; - - console.info("current sphere pos ", direction); - } } From 3002df43ee9811cf9bf7de9ea13a2a8d76cffa79 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Mon, 21 Jun 2021 15:36:15 +0200 Subject: [PATCH 16/31] Minimal changes for better console logging --- src/js/viewer/ViewerAPI.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 41494cf..72c4431 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -53,15 +53,15 @@ export class ViewerAPI { testMesh.vwr_onclick = function (xy, position) { console.log("vwr_onclick is triggered."); - console.log("Pointer position: " + xy); - console.log("Local coordinate for pointer position: " + position); + console.log("Pointer position: " , xy); + console.log("Local coordinate for pointer position: " , position); return true; } testMesh.vwr_oncontext = function (xy, position) { console.log("vwr_oncontext is triggered."); - console.log("Pointer position: " + xy); - console.log("Local coordinate for pointer position: " + position); + console.log("Pointer position: " , xy); + console.log("Local coordinate for pointer position: " , position); //Creating callback function for context menu item: let callback = function (key, options) { From 53140bc7a21c881e62d5740d90e26c9584936871 Mon Sep 17 00:00:00 2001 From: Nes55 <73950780+Nes55@users.noreply.github.com> Date: Mon, 21 Jun 2021 23:30:07 +0200 Subject: [PATCH 17/31] Add files via upload --- ViewerPanoAPI.js | 345 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 ViewerPanoAPI.js diff --git a/ViewerPanoAPI.js b/ViewerPanoAPI.js new file mode 100644 index 0000000..9e58e48 --- /dev/null +++ b/ViewerPanoAPI.js @@ -0,0 +1,345 @@ +"use strict"; + +import { ViewerViewState } from "./ViewerViewState.js"; +import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED } from "./ViewerConfig.js"; +import { EventLayer } from "./EventLayer.js"; +import { EventPosition } from "./EventPosition.js"; + +export class ViewerPanoAPI { + + constructor(viewerAPI) { + this.scene = new THREE.Scene(); // three.js scene used by the panorama (3D) viewer + this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); + this.viewerImageAPI = viewerAPI.image; + this.viewerAPI = viewerAPI; + this.sphereRadius = 5; + + this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); + this.lastViewState; + this.lastMousePos; + + //initialize the eventLayer + this.eventLayer = new EventLayer(); + + // properties needed for display and depthAtPointer method + this.loadedMesh = null; + this.depthCanvas = document.createElement("canvas"); + + // Two new event listeneres are called to handle *how far* the user drags + this.oPM = (event) => this.onPointerMove(event); + this.oPU = () => this.onPointerUp(); + + const panoViewer = document.getElementById('pano-viewer'); + panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); + panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); + panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); + window.addEventListener('resize', () => this.onWindowResize()); + $('#pano-viewer').mousedown((event) => this.onRightClick(event)); + + } + + // displays the panorama with idx *ImageNum* in the model + display(imageNum) { + this.viewerImageAPI.currentImageId = imageNum; + + // create sphere + const sphere = new THREE.SphereGeometry(this.sphereRadius, 60, 40); + // invert the geometry on the x-axis so that we look out from the middle of the sphere + sphere.scale(-1, 1, 1); + + // load the 360-panorama image data (highest resolution hardcoded for now) + const texturePano = this.viewerAPI.textureLoader.load( + this.viewerAPI.baseURL + + Math.trunc(imageNum / 100) + + '/' + + imageNum + + 'r3.jpg'); + texturePano.mapping = THREE.EquirectangularReflectionMapping; // not sure if this line matters + + // --- load depth-map for panorama --- + const image = new Image(); + //image.crossOrigin = "use-credentials"; + image.src = this.viewerAPI.baseURL + + Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + + this.viewerImageAPI.currentImage.id + 'd.png'; + + image.addEventListener('load', () => { + this.depthCanvas.getContext("2d").drawImage(image, 0, 0); + }, false); + // ----- + + // put the texture on the spehere and add it to the scene + const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); + + // adjust for orientation offset + mesh.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + + // put in the correct position in the scene + const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + mesh.position.set(localCoord.x, localCoord.y, localCoord.z); + + // check if other panorama was previously already loaded + if (this.loadedMesh != null) { + this.scene.remove(this.loadedMesh); + } + + this.scene.add(mesh); + this.loadedMesh = mesh; + + // put camera inside sphere mesh + this.camera.position.set(localCoord.x, localCoord.y, localCoord.z); + } + + camera() { + return this.camera; + } + + // Set the panorama view characteristics. + view(lonov, latov, fov) { + const normalizedViewingDirection = lonLatToLocal(lonov, latov); + + // adjust looking direction for offset of current mesh in scene + const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + + this.camera.lookAt(localCoord.add(normalizedViewingDirection)); + + this.camera.fov = THREE.MathUtils.clamp(fov, MIN_FOV, MAX_FOV); + + this.camera.updateProjectionMatrix(); + } + + + // ----- Event handling functions for panning, zooming and moving ----- + onPointerDown(event) { + this.lastMousePos = [event.clientX, event.clientY]; + + this.lastViewState = [this.viewerViewState.lonov, this.viewerViewState.latov]; + + document.addEventListener('pointermove', this.oPM); + document.addEventListener('pointerup', this.oPU); + } + + // handles continues update of the distance mouse moved + onPointerMove(event) { + const scalingFactor = this.camera.fov / MAX_FOV; + + this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); + this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); + + this.viewerAPI.map.show_direction(); + } + + // this event listener is called when the user *ends* moving the picture + onPointerUp() { + document.removeEventListener('pointermove', this.oPM); + document.removeEventListener('pointerup', this.oPU); + + this.viewerAPI.propagateEvent("viewed", this.viewerViewState, true); + } + + onDocumentMouseWheel(event) { + this.viewerViewState.fov = this.camera.fov + event.deltaY * ZOOM_SPEED; + + this.view(this.viewerViewState.lonov, this.viewerViewState.latov, this.viewerViewState.fov); + this.camera.updateProjectionMatrix(); + + this.viewerAPI.propagateEvent("viewed", this.viewerViewState, true); + this.viewerAPI.map.show_direction(); + } + + onDoubleClick(event) { + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); + const MEDIAN_WALKING_DISTANCE = 5; // in meter + // distance to be walked along adjustedHorizontalAngle from current location + const distance = MEDIAN_WALKING_DISTANCE + ((adjustedLatov / 85) * MEDIAN_WALKING_DISTANCE); + + // convertedAngle converted to represent directions like specified in newLocationFromPointAngle + const convertedAngle = (adjustedLonov < 180) ? -adjustedLonov : 360 - adjustedLonov; + + const currentPos = this.viewerImageAPI.currentImage.pos; + + const newPos = newLocationFromPointAngle(currentPos[0], currentPos[1], THREE.Math.degToRad(convertedAngle), distance); + this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); + + this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); + } + onWindowResize() { + + this.camera.aspect = window.innerWidth / window.innerHeight; + this.camera.updateProjectionMatrix(); + + this.renderer.setSize(window.innerWidth, window.innerHeight); + } + onRightClick(event) { + //if right mouse is clicked: + if (event.which == 3) { + + //get the current pointer position: + const xy = new EventPosition(event); + + + //get the position of pointer in scene: + const location = this.getCursorLocation(event); + + //Set up the context menu: + $.contextMenu({ + selector: '#pano-viewer', + items: this.eventLayer.vwr_oncontext(xy, location), + }); + } + } + + + // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) + depthAtPointer(event) { + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); + + // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first + const localPos = lonLatToLocal(adjustedLonov, adjustedLatov); + const adjustedQuaternion = localPos.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + const [realLonov, realLatov] = localToLonLat(adjustedQuaternion); + + // pixel offsets in depth map at current curser position + const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); + const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); + + const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; + const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; + + // convert pixel value to depth information + const use5pixelAvg = false; + let imgData; + if (use5pixelAvg) { + imgData = this.depthCanvas.getContext("2d").getImageData(offsetX, offsetY, 5, 5); + } else { + imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); + } + const [red, green, blue, alpha] = averagePixelValues(imgData.data); + + // LSB red -> green -> blue MSB (ignore alpha) + const distanceMM = red | (green << 8) | (blue << 16); + + // convert from millimeter to meter + return distanceMM / 1000; + } + + // returns the current location of the cursor in the three js scene (Vector3) + getCursorLocation(event) { + // param: event.x event.y current cursor position on screen + const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); + const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); + + // adjust looking direction for offset of current mesh in scene + const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + + // get distance und extend viewing direction vector by distance + const dist = this.depthAtPointer(event); + + localCoord.addScaledVector(normalizedLocalViewingDir, dist) + + return localCoord; + } + + // returns [lonov, latov] at the current cursor position + getAdjustedViewstate(event) { + // find correct pixel position on equilateral projected depth map + const halfWidth = window.innerWidth / 2; + const halfHeight = window.innerHeight / 2; + + // horizontal (lonov) : image left -> 0, image right -> 360 + // vertical (latov) : image top -> 85, image bottom -> -85 + const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen + const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen + + const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; + const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); + + return [adjustedLonov, adjustedLatov]; + } + + visualTest(event) { + console.info(this.viewerViewState); + console.info(this.camera.getWorldDirection()); + console.info("current img original global ", this.viewerImageAPI.currentImage.pos) + const loc = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + console.info("current img pos loc ", loc); + const b = this.viewerAPI.toGlobal(loc); + console.info("back to global ", b); + const bb = this.viewerAPI.toLocal(b); + console.info("and back to loc one more time ", bb); + + // visual test, spawn in white sphere at cursor position in scene + const direction = this.getCursorLocation(event); + const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); + const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); + mesh.position.set(direction.x, direction.y, direction.z); + + if (this.testMesh != null) { + this.scene.remove(this.testMesh); + } + + this.scene.add(mesh); + + this.testMesh = mesh; + + console.info("current sphere pos ", direction); + } +} + + +// takes in a location (in lot/lat), a direction (as a *angle*[rad, in birds eye view), and a distance (in meters) to move in the direction +const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { + // angle: +-0 -> west, +pi/2 -> south, +-pi -> east, -pi/2 -> north + let lon2, lat2; + + const dx = (distance / 1000) * Math.cos(angle); + const dy = (distance / 1000) * Math.sin(angle); + + lon2 = lon1 - (dx / 71.5); + lat2 = lat1 - (dy / 111.3); + + return [lon2, lat2]; +} + +const averagePixelValues = (data) => { + const pixels = data.length / 4; + let [red, green, blue, alpha] = [0, 0, 0, 0]; // sum of all pixel values + + for (let i = 0; i < data.length; i = i + 4) { + red = red + data[i]; + green = green + data[i + 1]; + blue = blue + data[i + 2]; + alpha = alpha + data[i + 3]; + } + + // get average by dividing + red = red / pixels; + green = green / pixels; + blue = blue / pixels; + alpha = alpha / pixels; + + return [red, green, blue, alpha]; +} + +// returns a normalized Vector3 pointing in the direction specified by lonov latov +const lonLatToLocal = (lonov, latov) => { + const phi = THREE.MathUtils.degToRad(90 - latov); + const theta = THREE.MathUtils.degToRad(lonov); + + const x = Math.sin(phi) * Math.cos(theta); + const y = Math.cos(phi); + const z = Math.sin(phi) * Math.sin(theta); + + return new THREE.Vector3(x, y, z); +} + +// inverse operation to above +const localToLonLat = (vec) => { + const phi = Math.acos(vec.y); + const theta = Math.atan2(vec.z, vec.x); + + let latov = THREE.MathUtils.radToDeg(phi); + const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; + + return [lonov, 90 - latov]; +} \ No newline at end of file From 9725da2210674d0c57898234f7d9403a00a33e90 Mon Sep 17 00:00:00 2001 From: clairebb1005 Date: Tue, 22 Jun 2021 15:55:15 +0200 Subject: [PATCH 18/31] creat constant for Lon and Lan parameters --- src/js/viewer/ViewerAPI.js | 9 ++--- src/js/viewer/ViewerConfig.js | 6 ++++ src/js/viewer/ViewerFloorAPI.js | 5 ++- src/js/viewer/ViewerMapAPI.js | 33 +++++++++--------- src/js/viewer/ViewerPanoAPI.js | 59 +++++++++++++++++++++++++++++---- 5 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index fef3186..d92dd91 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -7,6 +7,7 @@ import { ViewerMapAPI } from "./ViewerMapAPI.js" import { ViewerState } from "./ViewerState.js"; import { libraryInfo } from "./LibraryInfo.js"; import { ViewerVersionAPI } from "./ViewerVersionAPI.js"; +import { LON_SCALAR, LAN_SCALAR } from "./ViewerConfig.js"; // API provided by the viewer @@ -136,8 +137,8 @@ export class ViewerAPI { // Convert the local metric three.js coordinates used by the viewer to WGS 84 coordinates [longitude, latitude, z]. toGlobal(localCoords) { // localCoords : THREE.Vector3 // Local coordinates used by the viewer - const globalX = this.floor.origin[0] - ((localCoords.x / 1000) / 71.5); - const globalY = this.floor.origin[1] - ((-localCoords.z / 1000) / 111.3); + const globalX = this.floor.origin[0] - ((localCoords.x / 1000) / LON_SCALAR); + const globalY = this.floor.origin[1] - ((-localCoords.z / 1000) / LAN_SCALAR); const globalZ = localCoords.y - this.floor.currentFloor.z; // the three js scene sees the y axis as the up-down axis so we have to swap with z @@ -150,8 +151,8 @@ export class ViewerAPI { toLocal(globalCoords) { // Distance calculation math taken from here https://www.mkompf.com/gps/distcalc.html // The more accurate calculation breaks the pixel offset on the pre-created maps - const dx = 71.5 * (this.floor.origin[0] - globalCoords[0]); - const dz = 111.3 * (this.floor.origin[1] - globalCoords[1]); + const dx = LON_SCALAR * (this.floor.origin[0] - globalCoords[0]); + const dz = LAN_SCALAR * (this.floor.origin[1] - globalCoords[1]); return new this.THREE.Vector3( dx * 1000, diff --git a/src/js/viewer/ViewerConfig.js b/src/js/viewer/ViewerConfig.js index b75d97e..2e20d45 100644 --- a/src/js/viewer/ViewerConfig.js +++ b/src/js/viewer/ViewerConfig.js @@ -26,3 +26,9 @@ export const SCALING_MAP = 0.2; // Describes the maximum zoom of the map. export const MAP_ZOOM = 4; + +// Scalar for Longitude from degree to km +export const LON_SCALAR = 71.5; + +// Scalar for Langitude from degree to km +export const LAN_SCALAR = 111.3; \ No newline at end of file diff --git a/src/js/viewer/ViewerFloorAPI.js b/src/js/viewer/ViewerFloorAPI.js index 4a261b0..2d2eb7b 100644 --- a/src/js/viewer/ViewerFloorAPI.js +++ b/src/js/viewer/ViewerFloorAPI.js @@ -1,5 +1,8 @@ "use strict"; +import { LON_SCALAR, LAN_SCALAR } from "./ViewerConfig.js"; + + export class ViewerFloorAPI { constructor(data, viewerAPI) { @@ -28,7 +31,7 @@ export class ViewerFloorAPI { if (currentImage.id >= interval[0] && currentImage.id <= interval[1]) { currentImage.floor = key; - const [dx, dy] = [71.5 * (data.lon0 - currentImage.pos[0]), 111.3 * (data.lat0 - currentImage.pos[1])]; + const [dx, dy] = [LON_SCALAR * (data.lon0 - currentImage.pos[0]), LAN_SCALAR * (data.lat0 - currentImage.pos[1])]; const offsetX = currentFloor.mapData.x + currentFloor.mapData.density * (dx * 1000); const offsetY = currentFloor.mapData.y - currentFloor.mapData.density * (dy * 1000); diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 0c20313..64512aa 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -1,6 +1,6 @@ "use strict"; -import { MAX_FOV, SCALING_MAP, MAP_ZOOM } from "./ViewerConfig.js"; +import { MAX_FOV, SCALING_MAP, MAP_ZOOM, LON_SCALAR, LAN_SCALAR } from "./ViewerConfig.js"; // Map (2D) Viewer API // Specific API for the Map View @@ -19,6 +19,7 @@ export class ViewerMapAPI { // create Map and Layers this.map; this.vectorLayer = []; + this.fullscreen = new ol.control.FullScreen(); this.initDisplayMap(); this.init = true; @@ -33,6 +34,10 @@ export class ViewerMapAPI { this.viewerAPI = viewerAPI; let map = document.getElementById('map'); map.addEventListener('dblclick', (event) => this.onDoubleClick(event)); + + this.fullscreen.on('propertychange', function(evt){ + console.log(evt); + }); } // Method: Add an event layer to the map (2D) view. @@ -71,12 +76,14 @@ export class ViewerMapAPI { rotate: false }).extend([ // create fullScreen button - new ol.control.FullScreen(), + this.fullscreen ]), //Disable Zoom Control on MAP interactions: ol.interaction.defaults({doubleClickZoom :false}), }); + + // create image layers for each floors for (var i = 0; i < this.viewerFloorAPI.floors.length; i++) { let mapData = this.viewerFloorAPI.floors[i].mapData @@ -190,6 +197,7 @@ export class ViewerMapAPI { this.lastVectorLayer = currentVectorLayer; this.lastVectorLayerRed = vectorLayerRed; + // disable init this.show_direction(); this.init = false; } @@ -234,6 +242,7 @@ export class ViewerMapAPI { }); this.lastLayerDirection = vectorLayerTriangleVertex; + // this.addLayer(this.lastLayerDirection); // Draw Triangle Polygon let styleTriangle = new ol.style.Style({ @@ -264,35 +273,25 @@ export class ViewerMapAPI { getLonLanCoordinates(position, mapdata){ // Compute the latitude and longitude in reference to the origin in WGS84 and aff offset of the map - let lon = 71500 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); - let lan = 113000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); + let lon = LON_SCALAR * 1000 * (position[0] - this.viewerFloorAPI.origin[0]) + (mapdata.x / mapdata.density); + let lan = LAN_SCALAR * 1000 * (position[1] - this.viewerFloorAPI.origin[1]) + (mapdata.y / mapdata.density); return [lon, lan]; } - getCoordinatesLonLan(position, mapdata){ - // Compute the coordinate in reference to the origin from WGS84 Longitude Latitude - let x = (position[0] -(mapdata.x / mapdata.density) )/71500 + this.viewerFloorAPI.origin[0]; - let y = (position[1] -(mapdata.x / mapdata.density) )/113000 + this.viewerFloorAPI.origin[1]; - return [x, y]; - } - onDoubleClick(event) { - - // Function to trigger the position change + var coord = []; var mousePosition = []; - // Update location metadata var mapdata = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].mapData; var floor = this.viewerFloorAPI; var z = this.viewerFloorAPI.floors[this.viewerFloorAPI.currentFloorId].z; var viewerAPI = this.viewerAPI; - this.map.on('dblclick', function(event){ coord = event.coordinate; - mousePosition.push( ((coord[0] - (mapdata.x / mapdata.density)) / 71500 ) + floor.origin[0] ); - mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / 113000 ) + floor.origin[1]); + mousePosition.push(((coord[0] - (mapdata.x / mapdata.density)) / (LON_SCALAR * 1000) ) + floor.origin[0]); + mousePosition.push(((coord[1] - (mapdata.y / mapdata.density)) / (LAN_SCALAR * 1000) ) + floor.origin[1]); // move viewerAPI.move(mousePosition[0],mousePosition[1],z); diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 82bdd45..7886fa8 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -1,7 +1,7 @@ "use strict"; import { ViewerViewState } from "./ViewerViewState.js"; -import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED } from "./ViewerConfig.js"; +import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED, LON_SCALAR, LAN_SCALAR } from "./ViewerConfig.js"; import { EventLayer } from "./EventLayer.js"; import { EventPosition } from "./EventPosition.js"; @@ -172,8 +172,9 @@ export class ViewerPanoAPI { //get the current pointer position: const xy = new EventPosition(event); - //get the viewing direction: - const location = this.camera.getWorldDirection(); + + //get the position of pointer in scene: + const location = this.getCursorLocation(event); //Set up the context menu: $.contextMenu({ @@ -280,16 +281,60 @@ export class ViewerPanoAPI { } } + // takes in a location (in lot/lat), a direction (as a *angle*[rad, in birds eye view), and a distance (in meters) to move in the direction -function newLocationFromPointAngle(lon1, lat1, angle, distance) { +const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { // angle: +-0 -> west, +pi/2 -> south, +-pi -> east, -pi/2 -> north let lon2, lat2; const dx = (distance / 1000) * Math.cos(angle); const dy = (distance / 1000) * Math.sin(angle); - lon2 = lon1 - (dx / 71.5); - lat2 = lat1 - (dy / 111.3); + lon2 = lon1 - (dx / LON_SCALAR); + lat2 = lat1 - (dy / LAN_SCALAR); return [lon2, lat2]; -} \ No newline at end of file +} + +const averagePixelValues = (data) => { + const pixels = data.length / 4; + let [red, green, blue, alpha] = [0, 0, 0, 0]; // sum of all pixel values + + for (let i = 0; i < data.length; i = i + 4) { + red = red + data[i]; + green = green + data[i + 1]; + blue = blue + data[i + 2]; + alpha = alpha + data[i + 3]; + } + + // get average by dividing + red = red / pixels; + green = green / pixels; + blue = blue / pixels; + alpha = alpha / pixels; + + return [red, green, blue, alpha]; +} + +// returns a normalized Vector3 pointing in the direction specified by lonov latov +const lonLatToLocal = (lonov, latov) => { + const phi = THREE.MathUtils.degToRad(90 - latov); + const theta = THREE.MathUtils.degToRad(lonov); + + const x = Math.sin(phi) * Math.cos(theta); + const y = Math.cos(phi); + const z = Math.sin(phi) * Math.sin(theta); + + return new THREE.Vector3(x, y, z); +} + +// inverse operation to above +const localToLonLat = (vec) => { + const phi = Math.acos(vec.y); + const theta = Math.atan2(vec.z, vec.x); + + let latov = THREE.MathUtils.radToDeg(phi); + const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; + + return [lonov, 90 - latov]; +} From 026a606e45d95944fed982e89d027618549cbe55 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 17:14:13 +0200 Subject: [PATCH 19/31] Move mesh coloring to test mesh --- src/js/viewer/ViewerAPI.js | 8 ++++---- src/js/viewer/ViewerPanoAPI.js | 8 -------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 72c4431..af1777b 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -52,6 +52,7 @@ export class ViewerAPI { testMesh.position.set(startPos.x, startPos.y - 2, startPos.z); testMesh.vwr_onclick = function (xy, position) { + this.material.color.set(0xff0000); // as a test set color red console.log("vwr_onclick is triggered."); console.log("Pointer position: " , xy); console.log("Local coordinate for pointer position: " , position); @@ -59,6 +60,7 @@ export class ViewerAPI { } testMesh.vwr_oncontext = function (xy, position) { + this.material.color.set(0x00ff00); // as a test set color green console.log("vwr_oncontext is triggered."); console.log("Pointer position: " , xy); console.log("Local coordinate for pointer position: " , position); @@ -78,18 +80,16 @@ export class ViewerAPI { } testMesh.vwr_onpointerenter = function () { + this.material.color.set(0xffff00); // as a test set color yellow console.log("vwr_onpointerenter is triggered."); } testMesh.vwr_onpointerleave = function () { + this.material.color.set(0x0000ff); // as a test set color blue console.log("vwr_onpointerleave is triggered."); } this.pano.addLayer(testMesh); - // panoDiv.eventListener(onMove, check with raycaster if cursor over sphere, call vwr_onpointerenter or vwr_onpointerleave) - // panoDiv.eventListener(onClick, check with raycaster if cursor over sphere, call vwr_onclick) - // panoDiv.eventListener(onRightClick, check with raycaster if cursor over sphere, call vwr_oncontext ) - // --- --- // the only html element we work with (the pano-viewer div) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index fdbc085..8f7f8be 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -227,8 +227,6 @@ export class ViewerPanoAPI { if (typeof mesh.vwr_onclick == "function") { mesh.vwr_onclick(xy, location); } - - mesh.material.color.set(0xff0000); // as a test set color red } } @@ -248,8 +246,6 @@ export class ViewerPanoAPI { items: callback, }); } - - mesh.material.color.set(0x00ff00); // as a test set color green } } @@ -265,8 +261,6 @@ export class ViewerPanoAPI { preMesh.vwr_onpointerleave(); } - - preMesh.material.color.set(0x0000ff); // as a test set color blue } }); @@ -282,8 +276,6 @@ export class ViewerPanoAPI { mesh.vwr_onpointerenter(); } - - mesh.material.color.set(0xffff00); // as a test set color yellow } } } From a6ab9b9a42fd3c5eac16ed619be7cbc8e407fc4b Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 17:18:52 +0200 Subject: [PATCH 20/31] Move visual test for EventMesh to seperate function --- src/js/viewer/ViewerAPI.js | 99 ++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index af1777b..45cc1f5 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -44,54 +44,9 @@ export class ViewerAPI { this.pano = new ViewerPanoAPI(this); this.map = new ViewerMapAPI(this); }).then(() => { - // --- EventMesh TEST --- - // visual test, spawn in white sphere at first image position in scene - const sphere = new THREE.SphereGeometry(1 / 5, 10, 10); - const testMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); - const startPos = this.toLocal(this.image.currentImage.pos); - testMesh.position.set(startPos.x, startPos.y - 2, startPos.z); - - testMesh.vwr_onclick = function (xy, position) { - this.material.color.set(0xff0000); // as a test set color red - console.log("vwr_onclick is triggered."); - console.log("Pointer position: " , xy); - console.log("Local coordinate for pointer position: " , position); - return true; - } - - testMesh.vwr_oncontext = function (xy, position) { - this.material.color.set(0x00ff00); // as a test set color green - console.log("vwr_oncontext is triggered."); - console.log("Pointer position: " , xy); - console.log("Local coordinate for pointer position: " , position); - - //Creating callback function for context menu item: - let callback = function (key, options) { - var msg = 'clicked: ' + key; - (window.console && console.log(msg)) || alert(msg); - }; - - //Creating item objects - let itemEdit = new ViewerContextItem(callback, "edit", null, "Edit"); - let itemCut = new ViewerContextItem(callback, "cut", null, "Cut"); - - //Creating list of item objects. - return [itemEdit, itemCut]; - } - - testMesh.vwr_onpointerenter = function () { - this.material.color.set(0xffff00); // as a test set color yellow - console.log("vwr_onpointerenter is triggered."); - } - - testMesh.vwr_onpointerleave = function () { - this.material.color.set(0x0000ff); // as a test set color blue - console.log("vwr_onpointerleave is triggered."); - } - - this.pano.addLayer(testMesh); - // --- --- - + this.eventMeshTest(); + this.eventMeshTest(2); + this.eventMeshTest(-2); // the only html element we work with (the pano-viewer div) const panoDiv = document.getElementById('pano-viewer'); @@ -208,6 +163,54 @@ export class ViewerAPI { -dz * 1000); } + eventMeshTest(x = 0, y = -2, z = 0) { + // visual test, spawn in white sphere at first image position in scene (offset specified by parameters) + const sphere = new THREE.SphereGeometry(1 / 5, 10, 10); + const testMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); + const startPos = this.toLocal(this.image.currentImage.pos); + testMesh.position.set(startPos.x + x, startPos.y + y, startPos.z + z); + + testMesh.vwr_onclick = function (xy, position) { + this.material.color.set(0xff0000); // as a test set color red + console.log("vwr_onclick is triggered."); + console.log("Pointer position: " , xy); + console.log("Local coordinate for pointer position: " , position); + return true; + } + + testMesh.vwr_oncontext = function (xy, position) { + this.material.color.set(0x00ff00); // as a test set color green + console.log("vwr_oncontext is triggered."); + console.log("Pointer position: " , xy); + console.log("Local coordinate for pointer position: " , position); + + //Creating callback function for context menu item: + let callback = function (key, options) { + var msg = 'clicked: ' + key; + (window.console && console.log(msg)) || alert(msg); + }; + + //Creating item objects + let itemEdit = new ViewerContextItem(callback, "edit", null, "Edit"); + let itemCut = new ViewerContextItem(callback, "cut", null, "Cut"); + + //Creating list of item objects. + return [itemEdit, itemCut]; + } + + testMesh.vwr_onpointerenter = function () { + this.material.color.set(0xffff00); // as a test set color yellow + console.log("vwr_onpointerenter is triggered."); + } + + testMesh.vwr_onpointerleave = function () { + this.material.color.set(0x0000ff); // as a test set color blue + console.log("vwr_onpointerleave is triggered."); + } + + this.pano.addLayer(testMesh); + } + // TODO: swap() and big(wanted) } From 3d4f90e51c4742b400db8bbab07f54f1b2c9e365 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 18:27:14 +0200 Subject: [PATCH 21/31] Fixed bug that we found in the meeting Sphere operations were still triggered when spheres were no longer visible --- src/js/viewer/ViewerPanoAPI.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 8f7f8be..ee7c713 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -209,7 +209,11 @@ export class ViewerPanoAPI { const meshes = []; for (const e in intersects) { if (this.addedLayers.has(intersects[e].object)) { - meshes.push(intersects[e].object); + // check if mesh is within sphere radius to camera + const dist = this.camera.position.distanceTo(intersects[e].object.position); + if (dist < this.sphereRadius) { + meshes.push(intersects[e].object); + } } } From fe9f059679ca6bb0f23aeff7afc8e047d2cc82ec Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 18:45:50 +0200 Subject: [PATCH 22/31] Fix some whitespace --- src/js/viewer/ViewerPanoAPI.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index ee7c713..7130e4e 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -261,7 +261,7 @@ export class ViewerPanoAPI { if (!meshes.includes(preMesh)) { if (typeof preMesh.vwr_onpointerleave == "function") { // remove the current mesh - this.preMeshes.delete(preMesh); + this.preMeshes.delete(preMesh); preMesh.vwr_onpointerleave(); } @@ -273,10 +273,10 @@ export class ViewerPanoAPI { const mesh = meshes[i]; //if the current mesh has not been entered before. - if (!this.preMeshes.has(mesh)) { + if (!this.preMeshes.has(mesh)) { if (typeof mesh.vwr_onpointerenter == "function") { // store the current mesh - this.preMeshes.add(mesh); + this.preMeshes.add(mesh); mesh.vwr_onpointerenter(); } From d7e161c034b182f371e06054c1465a3d51d24a04 Mon Sep 17 00:00:00 2001 From: Nes55 <73950780+Nes55@users.noreply.github.com> Date: Tue, 22 Jun 2021 21:36:31 +0200 Subject: [PATCH 23/31] Delete ViewerPanoAPI.js --- ViewerPanoAPI.js | 345 ----------------------------------------------- 1 file changed, 345 deletions(-) delete mode 100644 ViewerPanoAPI.js diff --git a/ViewerPanoAPI.js b/ViewerPanoAPI.js deleted file mode 100644 index 9e58e48..0000000 --- a/ViewerPanoAPI.js +++ /dev/null @@ -1,345 +0,0 @@ -"use strict"; - -import { ViewerViewState } from "./ViewerViewState.js"; -import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED } from "./ViewerConfig.js"; -import { EventLayer } from "./EventLayer.js"; -import { EventPosition } from "./EventPosition.js"; - -export class ViewerPanoAPI { - - constructor(viewerAPI) { - this.scene = new THREE.Scene(); // three.js scene used by the panorama (3D) viewer - this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); - this.viewerImageAPI = viewerAPI.image; - this.viewerAPI = viewerAPI; - this.sphereRadius = 5; - - this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); - this.lastViewState; - this.lastMousePos; - - //initialize the eventLayer - this.eventLayer = new EventLayer(); - - // properties needed for display and depthAtPointer method - this.loadedMesh = null; - this.depthCanvas = document.createElement("canvas"); - - // Two new event listeneres are called to handle *how far* the user drags - this.oPM = (event) => this.onPointerMove(event); - this.oPU = () => this.onPointerUp(); - - const panoViewer = document.getElementById('pano-viewer'); - panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); - panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); - panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - window.addEventListener('resize', () => this.onWindowResize()); - $('#pano-viewer').mousedown((event) => this.onRightClick(event)); - - } - - // displays the panorama with idx *ImageNum* in the model - display(imageNum) { - this.viewerImageAPI.currentImageId = imageNum; - - // create sphere - const sphere = new THREE.SphereGeometry(this.sphereRadius, 60, 40); - // invert the geometry on the x-axis so that we look out from the middle of the sphere - sphere.scale(-1, 1, 1); - - // load the 360-panorama image data (highest resolution hardcoded for now) - const texturePano = this.viewerAPI.textureLoader.load( - this.viewerAPI.baseURL + - Math.trunc(imageNum / 100) + - '/' + - imageNum + - 'r3.jpg'); - texturePano.mapping = THREE.EquirectangularReflectionMapping; // not sure if this line matters - - // --- load depth-map for panorama --- - const image = new Image(); - //image.crossOrigin = "use-credentials"; - image.src = this.viewerAPI.baseURL + - Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + - this.viewerImageAPI.currentImage.id + 'd.png'; - - image.addEventListener('load', () => { - this.depthCanvas.getContext("2d").drawImage(image, 0, 0); - }, false); - // ----- - - // put the texture on the spehere and add it to the scene - const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); - - // adjust for orientation offset - mesh.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - - // put in the correct position in the scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - mesh.position.set(localCoord.x, localCoord.y, localCoord.z); - - // check if other panorama was previously already loaded - if (this.loadedMesh != null) { - this.scene.remove(this.loadedMesh); - } - - this.scene.add(mesh); - this.loadedMesh = mesh; - - // put camera inside sphere mesh - this.camera.position.set(localCoord.x, localCoord.y, localCoord.z); - } - - camera() { - return this.camera; - } - - // Set the panorama view characteristics. - view(lonov, latov, fov) { - const normalizedViewingDirection = lonLatToLocal(lonov, latov); - - // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - - this.camera.lookAt(localCoord.add(normalizedViewingDirection)); - - this.camera.fov = THREE.MathUtils.clamp(fov, MIN_FOV, MAX_FOV); - - this.camera.updateProjectionMatrix(); - } - - - // ----- Event handling functions for panning, zooming and moving ----- - onPointerDown(event) { - this.lastMousePos = [event.clientX, event.clientY]; - - this.lastViewState = [this.viewerViewState.lonov, this.viewerViewState.latov]; - - document.addEventListener('pointermove', this.oPM); - document.addEventListener('pointerup', this.oPU); - } - - // handles continues update of the distance mouse moved - onPointerMove(event) { - const scalingFactor = this.camera.fov / MAX_FOV; - - this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); - this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); - - this.viewerAPI.map.show_direction(); - } - - // this event listener is called when the user *ends* moving the picture - onPointerUp() { - document.removeEventListener('pointermove', this.oPM); - document.removeEventListener('pointerup', this.oPU); - - this.viewerAPI.propagateEvent("viewed", this.viewerViewState, true); - } - - onDocumentMouseWheel(event) { - this.viewerViewState.fov = this.camera.fov + event.deltaY * ZOOM_SPEED; - - this.view(this.viewerViewState.lonov, this.viewerViewState.latov, this.viewerViewState.fov); - this.camera.updateProjectionMatrix(); - - this.viewerAPI.propagateEvent("viewed", this.viewerViewState, true); - this.viewerAPI.map.show_direction(); - } - - onDoubleClick(event) { - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const MEDIAN_WALKING_DISTANCE = 5; // in meter - // distance to be walked along adjustedHorizontalAngle from current location - const distance = MEDIAN_WALKING_DISTANCE + ((adjustedLatov / 85) * MEDIAN_WALKING_DISTANCE); - - // convertedAngle converted to represent directions like specified in newLocationFromPointAngle - const convertedAngle = (adjustedLonov < 180) ? -adjustedLonov : 360 - adjustedLonov; - - const currentPos = this.viewerImageAPI.currentImage.pos; - - const newPos = newLocationFromPointAngle(currentPos[0], currentPos[1], THREE.Math.degToRad(convertedAngle), distance); - this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); - - this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); - } - onWindowResize() { - - this.camera.aspect = window.innerWidth / window.innerHeight; - this.camera.updateProjectionMatrix(); - - this.renderer.setSize(window.innerWidth, window.innerHeight); - } - onRightClick(event) { - //if right mouse is clicked: - if (event.which == 3) { - - //get the current pointer position: - const xy = new EventPosition(event); - - - //get the position of pointer in scene: - const location = this.getCursorLocation(event); - - //Set up the context menu: - $.contextMenu({ - selector: '#pano-viewer', - items: this.eventLayer.vwr_oncontext(xy, location), - }); - } - } - - - // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) - depthAtPointer(event) { - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - - // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first - const localPos = lonLatToLocal(adjustedLonov, adjustedLatov); - const adjustedQuaternion = localPos.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - const [realLonov, realLatov] = localToLonLat(adjustedQuaternion); - - // pixel offsets in depth map at current curser position - const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); - const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); - - const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; - const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; - - // convert pixel value to depth information - const use5pixelAvg = false; - let imgData; - if (use5pixelAvg) { - imgData = this.depthCanvas.getContext("2d").getImageData(offsetX, offsetY, 5, 5); - } else { - imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); - } - const [red, green, blue, alpha] = averagePixelValues(imgData.data); - - // LSB red -> green -> blue MSB (ignore alpha) - const distanceMM = red | (green << 8) | (blue << 16); - - // convert from millimeter to meter - return distanceMM / 1000; - } - - // returns the current location of the cursor in the three js scene (Vector3) - getCursorLocation(event) { - // param: event.x event.y current cursor position on screen - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); - - // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - - // get distance und extend viewing direction vector by distance - const dist = this.depthAtPointer(event); - - localCoord.addScaledVector(normalizedLocalViewingDir, dist) - - return localCoord; - } - - // returns [lonov, latov] at the current cursor position - getAdjustedViewstate(event) { - // find correct pixel position on equilateral projected depth map - const halfWidth = window.innerWidth / 2; - const halfHeight = window.innerHeight / 2; - - // horizontal (lonov) : image left -> 0, image right -> 360 - // vertical (latov) : image top -> 85, image bottom -> -85 - const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen - const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - - const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; - const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); - - return [adjustedLonov, adjustedLatov]; - } - - visualTest(event) { - console.info(this.viewerViewState); - console.info(this.camera.getWorldDirection()); - console.info("current img original global ", this.viewerImageAPI.currentImage.pos) - const loc = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - console.info("current img pos loc ", loc); - const b = this.viewerAPI.toGlobal(loc); - console.info("back to global ", b); - const bb = this.viewerAPI.toLocal(b); - console.info("and back to loc one more time ", bb); - - // visual test, spawn in white sphere at cursor position in scene - const direction = this.getCursorLocation(event); - const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); - const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); - mesh.position.set(direction.x, direction.y, direction.z); - - if (this.testMesh != null) { - this.scene.remove(this.testMesh); - } - - this.scene.add(mesh); - - this.testMesh = mesh; - - console.info("current sphere pos ", direction); - } -} - - -// takes in a location (in lot/lat), a direction (as a *angle*[rad, in birds eye view), and a distance (in meters) to move in the direction -const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { - // angle: +-0 -> west, +pi/2 -> south, +-pi -> east, -pi/2 -> north - let lon2, lat2; - - const dx = (distance / 1000) * Math.cos(angle); - const dy = (distance / 1000) * Math.sin(angle); - - lon2 = lon1 - (dx / 71.5); - lat2 = lat1 - (dy / 111.3); - - return [lon2, lat2]; -} - -const averagePixelValues = (data) => { - const pixels = data.length / 4; - let [red, green, blue, alpha] = [0, 0, 0, 0]; // sum of all pixel values - - for (let i = 0; i < data.length; i = i + 4) { - red = red + data[i]; - green = green + data[i + 1]; - blue = blue + data[i + 2]; - alpha = alpha + data[i + 3]; - } - - // get average by dividing - red = red / pixels; - green = green / pixels; - blue = blue / pixels; - alpha = alpha / pixels; - - return [red, green, blue, alpha]; -} - -// returns a normalized Vector3 pointing in the direction specified by lonov latov -const lonLatToLocal = (lonov, latov) => { - const phi = THREE.MathUtils.degToRad(90 - latov); - const theta = THREE.MathUtils.degToRad(lonov); - - const x = Math.sin(phi) * Math.cos(theta); - const y = Math.cos(phi); - const z = Math.sin(phi) * Math.sin(theta); - - return new THREE.Vector3(x, y, z); -} - -// inverse operation to above -const localToLonLat = (vec) => { - const phi = Math.acos(vec.y); - const theta = Math.atan2(vec.z, vec.x); - - let latov = THREE.MathUtils.radToDeg(phi); - const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; - - return [lonov, 90 - latov]; -} \ No newline at end of file From 53c896e91e081be40067271a83d35169746a72eb Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 22:12:53 +0200 Subject: [PATCH 24/31] Make Z up/down axis and adjust Lonov Also slimming down of ViewerPanoAPI --- src/css/main.css | 8 +- src/js/viewer/ViewerAPI.js | 17 ++-- src/js/viewer/ViewerImage.js | 7 +- src/js/viewer/ViewerMapAPI.js | 2 +- src/js/viewer/ViewerPanoAPI.js | 180 +++++++++++---------------------- 5 files changed, 71 insertions(+), 143 deletions(-) diff --git a/src/css/main.css b/src/css/main.css index 2e7d34e..5aae541 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -25,9 +25,9 @@ body { #map{ position: fixed; bottom: 1%; - right: 3%; + right: 1%; width: 20%; - height:20%; + height: 20%; color: #fff; } @@ -37,8 +37,8 @@ body { .control-OL{ position: fixed; - bottom:20.5%; - right: 3%; + bottom: 22%; + right: 1%; color: #fff; } diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 8e60e1d..2fd7d31 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -81,8 +81,8 @@ export class ViewerAPI { this.floor.currentFloor.viewerImages.forEach(element => { const currLocalPos = this.toLocal(element.pos); - const [dx, dz] = [localPos.x - currLocalPos.x, localPos.z - currLocalPos.z]; - const currDistance = Math.sqrt(dx * dx + dz * dz); + const [dx, dy, dz] = [localPos.x - currLocalPos.x, localPos.y - currLocalPos.y, localPos.z - currLocalPos.z]; + const currDistance = Math.sqrt(dx * dx + dy * dy + dz * dz); if (currDistance < minDistance) { minDistance = currDistance; @@ -142,10 +142,9 @@ export class ViewerAPI { toGlobal(localCoords) { // localCoords : THREE.Vector3 // Local coordinates used by the viewer const globalX = this.floor.origin[0] - ((localCoords.x / 1000) / LON_SCALAR); - const globalY = this.floor.origin[1] - ((-localCoords.z / 1000) / LAN_SCALAR); - const globalZ = localCoords.y - this.floor.currentFloor.z; + const globalY = this.floor.origin[1] - ((localCoords.y / 1000) / LAN_SCALAR); + const globalZ = localCoords.z - this.floor.currentFloor.z; - // the three js scene sees the y axis as the up-down axis so we have to swap with z return [globalX, globalY, globalZ]; // Returns: [Number] : WGS 84 coordinates [longitude, latitude, z] (z value is floorZ + panoZ, where localCoords is just the panoZ) } @@ -156,15 +155,15 @@ export class ViewerAPI { // Distance calculation math taken from here https://www.mkompf.com/gps/distcalc.html // The more accurate calculation breaks the pixel offset on the pre-created maps const dx = LON_SCALAR * (this.floor.origin[0] - globalCoords[0]); - const dz = LAN_SCALAR * (this.floor.origin[1] - globalCoords[1]); + const dy = LAN_SCALAR * (this.floor.origin[1] - globalCoords[1]); return new this.THREE.Vector3( dx * 1000, - globalCoords[2] + this.floor.currentFloor.z, - -dz * 1000); + dy * 1000, + globalCoords[2] + this.floor.currentFloor.z); } - eventMeshTest(x = 0, y = -2, z = 0) { + eventMeshTest(x = 0, y = 0, z = -2) { // visual test, spawn in white sphere at first image position in scene (offset specified by parameters) const sphere = new THREE.SphereGeometry(1 / 5, 10, 10); const testMesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); diff --git a/src/js/viewer/ViewerImage.js b/src/js/viewer/ViewerImage.js index a30fe78..1323122 100644 --- a/src/js/viewer/ViewerImage.js +++ b/src/js/viewer/ViewerImage.js @@ -16,12 +16,7 @@ export class ViewerImage { this.pos = [panoLon, panoLat, panoZ]; // : [Number] // WGS 84 coordinates [longitude, latitude, z] of this image - // The quaternion data available in the json is not quite compatible with the translation we need in our scene - const threeX = y; - const threeY = z; - const threeZ = x; - - this.orientation = new THREE.Quaternion(threeX, threeY, threeZ, w); + this.orientation = new THREE.Quaternion(x, y, z, w); this.mapOffset; // : [offsetX, offsetY] // in pixels, offset from map png diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 64512aa..16ed698 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -207,7 +207,7 @@ export class ViewerMapAPI { var lonov = this.viewerViewState.lonov; // temporary using 170 degree for correcting the starting zero degree of 2D map - var direction = -(lonov + 180) * (Math.PI / 180) % 360; + var direction = lonov * (Math.PI / 180) % 360; // remove prvious vector layers diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index e3e163c..97e9a3b 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -8,35 +8,35 @@ import { EventPosition } from "./EventPosition.js"; export class ViewerPanoAPI { constructor(viewerAPI) { - this.scene = new THREE.Scene(); // three.js scene used by the panorama (3D) viewer - this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); this.viewerImageAPI = viewerAPI.image; this.viewerAPI = viewerAPI; - this.sphereRadius = 10; this.addedLayers = new Set(); // EventMesh and EventLayer objects added via addLayer(); - this.preMeshes = new Set(); // meshes that the mouse pointer is currently over - this.raycaster = new THREE.Raycaster(); - - this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); - this.lastViewState; - this.lastMousePos; - //initialize the eventLayer - this.eventLayer = new EventLayer(); + this.scene = new THREE.Scene(); // three.js scene used by the panorama (3D) viewer + this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); + this.camera.up = new THREE.Vector3(0, 0, 1); + this.sphereRadius = 10; + this.preMeshes = new Set(); // meshes that the mouse pointer is currently over - // properties needed for display and depthAtPointer method + // property needed for display method this.loadedMesh = null; - this.depthCanvas = document.createElement("canvas"); - // Two new event listeneres are called to handle *how far* the user drags - this.oPM = (event) => this.onPointerMove(event); - this.oPU = () => this.onPointerUp(); + // property needed for depthAtPointer method + this.depthCanvas = document.createElement("canvas"); + // handeling zooming / panning / moving const panoViewer = document.getElementById('pano-viewer'); + this.viewerViewState = new ViewerViewState(DEFAULT_FOV, 0, 0); + this.lastViewState; + this.lastMousePos; panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - + // Two new event listeneres are called to handle *how far* the user drags + this.oPM = (event) => this.onPointerMove(event); + this.oPU = () => this.onPointerUp(); + + // handeling EventMesh / EventLayer API integration panoViewer.addEventListener('click', (event) => this.meshCheckClick(event)); panoViewer.addEventListener('contextmenu', (event) => { event.preventDefault(); @@ -56,6 +56,7 @@ export class ViewerPanoAPI { const sphere = new THREE.SphereGeometry(this.sphereRadius, 60, 40); // invert the geometry on the x-axis so that we look out from the middle of the sphere sphere.scale(-1, 1, 1); + sphere.rotateX(Math.PI / 2); // load the 360-panorama image data (highest resolution hardcoded for now) const texturePano = this.viewerAPI.textureLoader.load( @@ -149,8 +150,8 @@ export class ViewerPanoAPI { // handles continues update of the distance mouse moved onPointerMove(event) { const scalingFactor = this.camera.fov / MAX_FOV; - - this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); + + this.viewerViewState.setLonov((event.clientX - this.lastMousePos[0]) * PAN_SPEED * scalingFactor + this.lastViewState[0]); this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); this.viewerAPI.map.show_direction(); @@ -175,17 +176,10 @@ export class ViewerPanoAPI { } onDoubleClick(event) { - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const MEDIAN_WALKING_DISTANCE = 5; // in meter - // distance to be walked along adjustedHorizontalAngle from current location - const distance = MEDIAN_WALKING_DISTANCE + ((adjustedLatov / 85) * MEDIAN_WALKING_DISTANCE); - - // convertedAngle converted to represent directions like specified in newLocationFromPointAngle - const convertedAngle = (adjustedLonov < 180) ? -adjustedLonov : 360 - adjustedLonov; - const currentPos = this.viewerImageAPI.currentImage.pos; + const newLocalPos = this.getCursorLocation(event); + const newPos = this.viewerAPI.toGlobal(newLocalPos); - const newPos = newLocationFromPointAngle(currentPos[0], currentPos[1], THREE.Math.degToRad(convertedAngle), distance); this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); @@ -193,17 +187,10 @@ export class ViewerPanoAPI { // ---- event handeling functions for EventMesh / EventLayer API interaction ---- getIntersectingMeshes(event) { - // calculate mouse position in normalized device coordinates - // (-1 to +1) for both components - const mouse = new THREE.Vector2(); - mouse.x = (event.clientX / window.innerWidth) * 2 - 1; - mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; - - // update the picking ray with the camera and mouse position - this.raycaster.setFromCamera(mouse, this.camera); + const raycaster = this.getRaycaster(event); // calculate objects intersecting the picking ray - const intersects = this.raycaster.intersectObjects(this.scene.children); + const intersects = raycaster.intersectObjects(this.scene.children); // include only objects that are added meshes const meshes = []; @@ -286,29 +273,21 @@ export class ViewerPanoAPI { // returns: the depth information (in meter) of the panorama at the current curser position (event.clientX, event.clientY) depthAtPointer(event) { - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - + const raycaster = this.getRaycaster(event); // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first - const localPos = lonLatToLocal(adjustedLonov, adjustedLatov); - const adjustedQuaternion = localPos.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - const [realLonov, realLatov] = localToLonLat(adjustedQuaternion); + const mappedCursorDirection = raycaster.ray.direction.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + const [cursorLon, cursorLat] = localToLonLat(mappedCursorDirection); + // adjust to calculate pixel offset on image, values in [0;360, -90;90] + const [adjustedLonov, adjustedLatov] = [((180 - cursorLon) + 360) % 360, cursorLat]; + // pixel offsets in depth map at current curser position - const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); - const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); - - const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; - const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; + const pixelX = Math.trunc((adjustedLonov / 360) * this.depthCanvas.width); + const pixelY = Math.trunc((adjustedLatov + 90) / 180 * this.depthCanvas.height); // convert pixel value to depth information - const use5pixelAvg = false; - let imgData; - if (use5pixelAvg) { - imgData = this.depthCanvas.getContext("2d").getImageData(offsetX, offsetY, 5, 5); - } else { - imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); - } - const [red, green, blue, alpha] = averagePixelValues(imgData.data); + const imgData = this.depthCanvas.getContext("2d").getImageData(pixelX, pixelY, 1, 1); + const [red, green, blue, alpha] = imgData.data; // LSB red -> green -> blue MSB (ignore alpha) const distanceMM = red | (green << 8) | (blue << 16); @@ -319,73 +298,28 @@ export class ViewerPanoAPI { // returns the current location of the cursor in the three js scene (Vector3) getCursorLocation(event) { - // param: event.x event.y current cursor position on screen - const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); - const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); - - // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); - - // get distance und extend viewing direction vector by distance - const dist = this.depthAtPointer(event); - - localCoord.addScaledVector(normalizedLocalViewingDir, dist) - - return localCoord; + const raycaster = this.getRaycaster(event); + // formula for position is currentLoc + direction*distance (where the direction is normalized) + const distance = this.depthAtPointer(event); + const cursorLocation = raycaster.ray.origin.addScaledVector(raycaster.ray.direction, distance); + + return cursorLocation; } - // returns [lonov, latov] at the current cursor position - getAdjustedViewstate(event) { - // find correct pixel position on equilateral projected depth map - const halfWidth = window.innerWidth / 2; - const halfHeight = window.innerHeight / 2; - - // horizontal (lonov) : image left -> 0, image right -> 360 - // vertical (latov) : image top -> 85, image bottom -> -85 - const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen - const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - - const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; - const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); - - return [adjustedLonov, adjustedLatov]; - } - -} - - -// takes in a location (in lot/lat), a direction (as a *angle*[rad, in birds eye view), and a distance (in meters) to move in the direction -const newLocationFromPointAngle = (lon1, lat1, angle, distance) => { - // angle: +-0 -> west, +pi/2 -> south, +-pi -> east, -pi/2 -> north - let lon2, lat2; - - const dx = (distance / 1000) * Math.cos(angle); - const dy = (distance / 1000) * Math.sin(angle); - - lon2 = lon1 - (dx / LON_SCALAR); - lat2 = lat1 - (dy / LAN_SCALAR); - - return [lon2, lat2]; -} - -const averagePixelValues = (data) => { - const pixels = data.length / 4; - let [red, green, blue, alpha] = [0, 0, 0, 0]; // sum of all pixel values + getRaycaster(event) { + // calculate mouse position in normalized device coordinates + // (-1 to +1) for both components + const mouse = new THREE.Vector2(); + const raycaster = new THREE.Raycaster(); - for (let i = 0; i < data.length; i = i + 4) { - red = red + data[i]; - green = green + data[i + 1]; - blue = blue + data[i + 2]; - alpha = alpha + data[i + 3]; + mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; + + raycaster.setFromCamera(mouse, this.camera); + + return raycaster; } - - // get average by dividing - red = red / pixels; - green = green / pixels; - blue = blue / pixels; - alpha = alpha / pixels; - - return [red, green, blue, alpha]; + } // returns a normalized Vector3 pointing in the direction specified by lonov latov @@ -394,16 +328,16 @@ const lonLatToLocal = (lonov, latov) => { const theta = THREE.MathUtils.degToRad(lonov); const x = Math.sin(phi) * Math.cos(theta); - const y = Math.cos(phi); - const z = Math.sin(phi) * Math.sin(theta); + const y = Math.sin(phi) * Math.sin(theta); + const z = Math.cos(phi); - return new THREE.Vector3(x, y, z); + return new THREE.Vector3(-x, -y, z); } // inverse operation to above const localToLonLat = (vec) => { - const phi = Math.acos(vec.y); - const theta = Math.atan2(vec.z, vec.x); + const phi = Math.acos(vec.z); + const theta = Math.atan2(-vec.y, -vec.x); let latov = THREE.MathUtils.radToDeg(phi); const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; From 40b00cafb496bfa0d64199c1248210ac6cf72f7f Mon Sep 17 00:00:00 2001 From: Nes55 <73950780+Nes55@users.noreply.github.com> Date: Tue, 22 Jun 2021 22:52:11 +0200 Subject: [PATCH 25/31] commit on browser window resize --- src/js/viewer/ViewerPanoAPI.js | 47 +++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 8b304df..8fba197 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -20,7 +20,7 @@ export class ViewerPanoAPI { //initialize the eventLayer this.eventLayer = new EventLayer(); - + // properties needed for display and depthAtPointer method this.loadedMesh = null; this.depthCanvas = document.createElement("canvas"); @@ -33,7 +33,7 @@ export class ViewerPanoAPI { panoViewer.addEventListener('wheel', (event) => this.onDocumentMouseWheel(event)); panoViewer.addEventListener('pointerdown', (event) => this.onPointerDown(event)); panoViewer.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - + window.addEventListener("resize", () => this.onWindowResize()); $('#pano-viewer').mousedown((event) => this.onRightClick(event)); this.display(this.viewerImageAPI.currentImageId); @@ -61,9 +61,9 @@ export class ViewerPanoAPI { const image = new Image(); //image.crossOrigin = "use-credentials"; image.src = this.viewerAPI.baseURL + - Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + - this.viewerImageAPI.currentImage.id + 'd.png'; - + Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + + this.viewerImageAPI.currentImage.id + 'd.png'; + image.addEventListener('load', () => { this.depthCanvas.getContext("2d").drawImage(image, 0, 0); }, false); @@ -71,10 +71,10 @@ export class ViewerPanoAPI { // put the texture on the spehere and add it to the scene const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); - + // adjust for orientation offset mesh.applyQuaternion(this.viewerImageAPI.currentImage.orientation); - + // put in the correct position in the scene const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); mesh.position.set(localCoord.x, localCoord.y, localCoord.z); @@ -86,7 +86,7 @@ export class ViewerPanoAPI { this.scene.add(mesh); this.loadedMesh = mesh; - + // put camera inside sphere mesh this.camera.position.set(localCoord.x, localCoord.y, localCoord.z); } @@ -123,7 +123,7 @@ export class ViewerPanoAPI { // handles continues update of the distance mouse moved onPointerMove(event) { const scalingFactor = this.camera.fov / MAX_FOV; - + this.viewerViewState.setLonov((this.lastMousePos[0] - event.clientX) * PAN_SPEED * scalingFactor + this.lastViewState[0]); this.viewerViewState.setLatov((event.clientY - this.lastMousePos[1]) * PAN_SPEED * scalingFactor + this.lastViewState[1]); @@ -140,7 +140,7 @@ export class ViewerPanoAPI { onDocumentMouseWheel(event) { this.viewerViewState.fov = this.camera.fov + event.deltaY * ZOOM_SPEED; - + this.view(this.viewerViewState.lonov, this.viewerViewState.latov, this.viewerViewState.fov); this.camera.updateProjectionMatrix(); @@ -156,14 +156,21 @@ export class ViewerPanoAPI { // convertedAngle converted to represent directions like specified in newLocationFromPointAngle const convertedAngle = (adjustedLonov < 180) ? -adjustedLonov : 360 - adjustedLonov; - + const currentPos = this.viewerImageAPI.currentImage.pos; - + const newPos = newLocationFromPointAngle(currentPos[0], currentPos[1], THREE.Math.degToRad(convertedAngle), distance); this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); } + onWindowResize() { + + this.camera.aspect = window.innerWidth / window.innerHeight; + this.camera.updateProjectionMatrix(); + + this.renderer.setSize(window.innerWidth, window.innerHeight); + } onRightClick(event) { //if right mouse is clicked: @@ -197,7 +204,7 @@ export class ViewerPanoAPI { // pixel offsets in depth map at current curser position const pixelX = Math.trunc((realLonov / 360) * this.depthCanvas.width); const pixelY = Math.trunc((realLatov + 90) / 180 * this.depthCanvas.height); - + const offsetX = (pixelX >= 2) ? pixelX - 2 : 0; const offsetY = (pixelY >= 2) ? pixelY - 2 : 0; @@ -223,7 +230,7 @@ export class ViewerPanoAPI { // param: event.x event.y current cursor position on screen const [adjustedLonov, adjustedLatov] = this.getAdjustedViewstate(event); const normalizedLocalViewingDir = lonLatToLocal(adjustedLonov, adjustedLatov); - + // adjust looking direction for offset of current mesh in scene const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); @@ -245,10 +252,10 @@ export class ViewerPanoAPI { // vertical (latov) : image top -> 85, image bottom -> -85 const horizontalOffset = (event.clientX - halfWidth) / halfWidth; // scaled between [-1,1] depending how left-right the mouse click is on the screen const verticalOffset = (halfHeight - event.clientY) / halfHeight; // scaled between [-1,1] depending how up-down the mouse click is on the screen - + const adjustedLonov = ((this.viewerViewState.lonov + (horizontalOffset * this.viewerViewState.fov / 2)) + 360) % 360; const adjustedLatov = Math.max(-85, Math.min(85, this.viewerViewState.latov + (verticalOffset * this.viewerViewState.fov / 2))); - + return [adjustedLonov, adjustedLatov]; } @@ -268,13 +275,13 @@ export class ViewerPanoAPI { const sphere = new THREE.SphereGeometry(1 / this.depthAtPointer(event), 10, 10); const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial()); mesh.position.set(direction.x, direction.y, direction.z); - + if (this.testMesh != null) { this.scene.remove(this.testMesh); } this.scene.add(mesh); - + this.testMesh = mesh; console.info("current sphere pos ", direction); @@ -320,7 +327,7 @@ const averagePixelValues = (data) => { const lonLatToLocal = (lonov, latov) => { const phi = THREE.MathUtils.degToRad(90 - latov); const theta = THREE.MathUtils.degToRad(lonov); - + const x = Math.sin(phi) * Math.cos(theta); const y = Math.cos(phi); const z = Math.sin(phi) * Math.sin(theta); @@ -337,4 +344,4 @@ const localToLonLat = (vec) => { const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; return [lonov, 90 - latov]; -} +} \ No newline at end of file From f29e923ef259f5a982b4c032f8d47635fa282cb7 Mon Sep 17 00:00:00 2001 From: Nes55 <73950780+Nes55@users.noreply.github.com> Date: Tue, 22 Jun 2021 23:02:05 +0200 Subject: [PATCH 26/31] commit on browser window resize --- src/js/viewer/ViewerPanoAPI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index 8fba197..8a65fdb 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -169,7 +169,7 @@ export class ViewerPanoAPI { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); - this.renderer.setSize(window.innerWidth, window.innerHeight); + this.viewerAPI.renderer.setSize(window.innerWidth, window.innerHeight); } onRightClick(event) { From 7e2ed63a2945228d8d9446646ea856710dc33f1f Mon Sep 17 00:00:00 2001 From: leonopulos Date: Tue, 22 Jun 2021 23:32:18 +0200 Subject: [PATCH 27/31] cleanup PanoViewer --- src/js/viewer/ViewerPanoAPI.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/js/viewer/ViewerPanoAPI.js b/src/js/viewer/ViewerPanoAPI.js index d011ac9..10113a0 100644 --- a/src/js/viewer/ViewerPanoAPI.js +++ b/src/js/viewer/ViewerPanoAPI.js @@ -1,14 +1,12 @@ "use strict"; import { ViewerViewState } from "./ViewerViewState.js"; -import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED, LON_SCALAR, LAN_SCALAR } from "./ViewerConfig.js"; -import { EventLayer } from "./EventLayer.js"; +import { DEFAULT_FOV, MAX_FOV, MIN_FOV, ZOOM_SPEED, PAN_SPEED} from "./ViewerConfig.js"; import { EventPosition } from "./EventPosition.js"; export class ViewerPanoAPI { constructor(viewerAPI) { - this.viewerImageAPI = viewerAPI.image; this.viewerAPI = viewerAPI; this.addedLayers = new Set(); // EventMesh and EventLayer objects added via addLayer(); @@ -16,7 +14,6 @@ export class ViewerPanoAPI { this.camera = new THREE.PerspectiveCamera(DEFAULT_FOV, window.innerWidth / window.innerHeight, 1, 1100); this.camera.up = new THREE.Vector3(0, 0, 1); this.sphereRadius = 10; - this.preMeshes = new Set(); // meshes that the mouse pointer is currently over // property needed for display method this.loadedMesh = null; @@ -38,6 +35,7 @@ export class ViewerPanoAPI { this.oPU = () => this.onPointerUp(); // handeling EventMesh / EventLayer API integration + this.preMeshes = new Set(); // meshes that the mouse pointer is currently over panoViewer.addEventListener('click', (event) => this.meshCheckClick(event)); panoViewer.addEventListener('contextmenu', (event) => { event.preventDefault(); @@ -46,12 +44,12 @@ export class ViewerPanoAPI { panoViewer.addEventListener('pointermove', (event) => this.meshCheckMouseOver(event)); - this.display(this.viewerImageAPI.currentImageId); + this.display(this.viewerAPI.image.currentImageId); } // displays the panorama with idx *ImageNum* in the model display(imageNum) { - this.viewerImageAPI.currentImageId = imageNum; + this.viewerAPI.image.currentImageId = imageNum; // create sphere const sphere = new THREE.SphereGeometry(this.sphereRadius, 60, 40); @@ -72,8 +70,8 @@ export class ViewerPanoAPI { const image = new Image(); //image.crossOrigin = "use-credentials"; image.src = this.viewerAPI.baseURL + - Math.trunc(this.viewerImageAPI.currentImage.id / 100) + '/' + - this.viewerImageAPI.currentImage.id + 'd.png'; + Math.trunc(imageNum / 100) + '/' + + imageNum + 'd.png'; image.addEventListener('load', () => { this.depthCanvas.getContext("2d").drawImage(image, 0, 0); @@ -84,10 +82,10 @@ export class ViewerPanoAPI { const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ map: texturePano })); // adjust for orientation offset - mesh.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + mesh.applyQuaternion(this.viewerAPI.image.currentImage.orientation); // put in the correct position in the scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + const localCoord = this.viewerAPI.toLocal(this.viewerAPI.image.currentImage.pos); mesh.position.set(localCoord.x, localCoord.y, localCoord.z); // check if other panorama was previously already loaded @@ -111,7 +109,7 @@ export class ViewerPanoAPI { const normalizedViewingDirection = lonLatToLocal(lonov, latov); // adjust looking direction for offset of current mesh in scene - const localCoord = this.viewerAPI.toLocal(this.viewerImageAPI.currentImage.pos); + const localCoord = this.viewerAPI.toLocal(this.viewerAPI.image.currentImage.pos); this.camera.lookAt(localCoord.add(normalizedViewingDirection)); @@ -177,13 +175,13 @@ export class ViewerPanoAPI { } onDoubleClick(event) { - const currentPos = this.viewerImageAPI.currentImage.pos; + const currentPos = this.viewerAPI.image.currentImage.pos; const newLocalPos = this.getCursorLocation(event); const newPos = this.viewerAPI.toGlobal(newLocalPos); this.viewerAPI.move(newPos[0], newPos[1], currentPos[2]); - this.viewerAPI.propagateEvent("moved", this.viewerImageAPI.currentImage.id, true); + this.viewerAPI.propagateEvent("moved", this.viewerAPI.image.currentImage.id, true); } onWindowResize() { @@ -283,7 +281,7 @@ export class ViewerPanoAPI { depthAtPointer(event) { const raycaster = this.getRaycaster(event); // because depth map is not rotated by quaternion like panorama mesh, the quaternion adjustment need to happen first - const mappedCursorDirection = raycaster.ray.direction.applyQuaternion(this.viewerImageAPI.currentImage.orientation); + const mappedCursorDirection = raycaster.ray.direction.applyQuaternion(this.viewerAPI.image.currentImage.orientation); const [cursorLon, cursorLat] = localToLonLat(mappedCursorDirection); // adjust to calculate pixel offset on image, values in [0;360, -90;90] @@ -347,7 +345,7 @@ const localToLonLat = (vec) => { const phi = Math.acos(vec.z); const theta = Math.atan2(-vec.y, -vec.x); - let latov = THREE.MathUtils.radToDeg(phi); + const latov = THREE.MathUtils.radToDeg(phi); const lonov = (THREE.MathUtils.radToDeg(theta) + 360) % 360; return [lonov, 90 - latov]; From 00782c57f981c94f6abdc81f8dd7ac8ac19176fc Mon Sep 17 00:00:00 2001 From: Mm24 Date: Wed, 23 Jun 2021 11:07:01 +0200 Subject: [PATCH 28/31] hide floor buttons on map full screen mode --- src/js/viewer/ViewerMapAPI.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index 16ed698..ee5a894 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -35,9 +35,10 @@ export class ViewerMapAPI { let map = document.getElementById('map'); map.addEventListener('dblclick', (event) => this.onDoubleClick(event)); - this.fullscreen.on('propertychange', function(evt){ - console.log(evt); - }); + map.addEventListener('fullscreenchange', (event) => { + // If map set to full screen, hide the floor setting buttons + hideButtons( "floorOL"); + }); } // Method: Add an event layer to the map (2D) view. @@ -304,3 +305,15 @@ export class ViewerMapAPI { } } +function hideButtons(divId) { + + //let divId = "floorOL"; + var element = document.getElementById(divId); + + /* Toggle to hide HTML div */ + if (element.style.display === "none") { + element.style.display = "block"; + } else { + element.style.display = "none"; + } + } \ No newline at end of file From cbc5aeda4b7befb0f72cd7d57ad8757a1d2b2191 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Wed, 23 Jun 2021 13:23:21 +0200 Subject: [PATCH 29/31] Remove EventMesh testing spheres --- src/js/viewer/ViewerAPI.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 2fd7d31..1979fcb 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -45,9 +45,6 @@ export class ViewerAPI { this.pano = new ViewerPanoAPI(this); this.map = new ViewerMapAPI(this); }).then(() => { - this.eventMeshTest(); - this.eventMeshTest(2); - this.eventMeshTest(-2); // the only html element we work with (the pano-viewer div) const panoDiv = document.getElementById('pano-viewer'); From ae48f55956b9b8d33e5f0730d3af45b66e1ccd66 Mon Sep 17 00:00:00 2001 From: leonopulos Date: Wed, 23 Jun 2021 14:19:05 +0200 Subject: [PATCH 30/31] Prevent Highlighting of text or other object when interacting Previously the "Current Floor" text was highlighted whenever doubleclicking --- src/js/viewer/ViewerAPI.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/viewer/ViewerAPI.js b/src/js/viewer/ViewerAPI.js index 1979fcb..6827bbf 100644 --- a/src/js/viewer/ViewerAPI.js +++ b/src/js/viewer/ViewerAPI.js @@ -45,6 +45,7 @@ export class ViewerAPI { this.pano = new ViewerPanoAPI(this); this.map = new ViewerMapAPI(this); }).then(() => { + document.addEventListener('mousedown', function (e) { e.preventDefault(); }, false); // the only html element we work with (the pano-viewer div) const panoDiv = document.getElementById('pano-viewer'); From 19988b8ea97d0bcfce8497381421a7df2983ee53 Mon Sep 17 00:00:00 2001 From: clairebb1005 Date: Wed, 23 Jun 2021 18:07:19 +0200 Subject: [PATCH 31/31] change buttons in ViewerMapAPI --- src/css/main.css | 7 +++++++ src/index.html | 5 +++++ src/js/viewer/ViewerMapAPI.js | 36 ++++++++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/css/main.css b/src/css/main.css index 5aae541..4cd5a04 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -42,4 +42,11 @@ body { color: #fff; } +#menu { + float: left; + position: absolute; + top: 0 px; + left: 0%; + z-index: 2000; +} diff --git a/src/index.html b/src/index.html index 19c1b9d..b60dbf5 100644 --- a/src/index.html +++ b/src/index.html @@ -60,6 +60,11 @@

+
diff --git a/src/js/viewer/ViewerMapAPI.js b/src/js/viewer/ViewerMapAPI.js index ee5a894..b52a428 100644 --- a/src/js/viewer/ViewerMapAPI.js +++ b/src/js/viewer/ViewerMapAPI.js @@ -19,7 +19,6 @@ export class ViewerMapAPI { // create Map and Layers this.map; this.vectorLayer = []; - this.fullscreen = new ol.control.FullScreen(); this.initDisplayMap(); this.init = true; @@ -38,7 +37,8 @@ export class ViewerMapAPI { map.addEventListener('fullscreenchange', (event) => { // If map set to full screen, hide the floor setting buttons hideButtons( "floorOL"); - }); + }); + this.control_button(); } // Method: Add an event layer to the map (2D) view. @@ -74,11 +74,9 @@ export class ViewerMapAPI { }), controls: ol.control.defaults({ // Hide Map rotation button - rotate: false - }).extend([ - // create fullScreen button - this.fullscreen - ]), + rotate: false, + zoom: false + }), //Disable Zoom Control on MAP interactions: ol.interaction.defaults({doubleClickZoom :false}), }); @@ -303,6 +301,30 @@ export class ViewerMapAPI { setMiddle(poslon, poslan){ this.map.getView().setCenter([poslon,poslan]); } + + control_button(){ + var zoom_in = document.getElementById('zoom-in'); + var zoom_out = document.getElementById('zoom-out'); + var full_screen = document.getElementById('full-screen'); + var map = this.map; + + zoom_in.addEventListener('click', function () { + var view = map.getView(); + var zoom = view.getZoom(); + view.setZoom(zoom + 1); + }) + + zoom_out.addEventListener('click', function () { + var view = map.getView(); + var zoom = view.getZoom(); + view.setZoom(zoom - 1); + }) + + full_screen.addEventListener('click', function () { + var elem = document.getElementById('map'); + elem.requestFullscreen(); + }) + } } function hideButtons(divId) {