UNPKG

@here/harp-mapview

Version:

Functionality needed to render a map.

195 lines 8.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PlaneViewBounds = void 0; /* * Copyright (C) 2021 HERE Europe B.V. * Licensed under Apache 2.0, see full license in LICENSE * SPDX-License-Identifier: Apache-2.0 */ const harp_geoutils_1 = require("@here/harp-geoutils"); const harp_utils_1 = require("@here/harp-utils"); const three_1 = require("three"); const Utils_1 = require("./Utils"); /** * Generates Bounds for a camera view and a planar projection. * * @internal */ class PlaneViewBounds { constructor(camera, projection, m_options) { this.camera = camera; this.projection = projection; this.m_options = m_options; this.m_groundPlaneNormal = new three_1.Vector3(0, 0, 1); this.m_groundPlane = new three_1.Plane(this.m_groundPlaneNormal.clone()); harp_utils_1.assert(projection.type === harp_geoutils_1.ProjectionType.Planar); } /** * @override */ generate() { //!!!!!!!ALTITUDE IS NOT TAKEN INTO ACCOUNT!!!!!!!!! const coordinates = []; // 1.) Raycast into all four corners of the canvas // => if an intersection is found, add it to the polygon this.addCanvasCornerIntersection(coordinates); // => All 4 corners found an intersection, therefore the screen is covered with the map // and the polygon complete if (coordinates.length === 4) { return this.createPolygon(coordinates); } //2.) Raycast into the two corners of the horizon cutting the canvas sides // => if an intersection is found, add it to the polygon this.addHorizonIntersection(coordinates); //Setup the frustum for further checks const frustum = new three_1.Frustum().setFromProjectionMatrix(new three_1.Matrix4().multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse)); // Setup the world corners for further checks. // Cast to TileCorners as it cannot be undefined here, due to the forced // PlanarProjection above const worldCorners = this.getWorldConers(this.projection); if (!this.m_options.tileWrappingEnabled) { // 3.) If no wrapping, check if any corners of the world plane are inside the view // => if true, add it to the polygon [worldCorners.ne, worldCorners.nw, worldCorners.se, worldCorners.sw].forEach(corner => { this.addPointInFrustum(corner, frustum, coordinates); }); } //4.) Check for any edges of the world plane intersecting with the frustum? // => if true, add to polygon if (!this.m_options.tileWrappingEnabled) { // if no tile wrapping: // check with limited lines around the world edges [ new three_1.Line3(worldCorners.sw, worldCorners.se), new three_1.Line3(worldCorners.ne, worldCorners.nw), new three_1.Line3(worldCorners.se, worldCorners.ne), new three_1.Line3(worldCorners.nw, worldCorners.sw) // west edge ].forEach(edge => { this.addFrustumIntersection(edge, frustum, coordinates); }); } else { // if tile wrapping: // check for intersections with rays along the south and north edges const directionEast = new three_1.Vector3() //west -> east .subVectors(worldCorners.sw, worldCorners.se) .normalize(); const directionWest = new three_1.Vector3() //east -> west .subVectors(worldCorners.se, worldCorners.sw) .normalize(); [ new three_1.Ray(worldCorners.se, directionEast), new three_1.Ray(worldCorners.se, directionWest), new three_1.Ray(worldCorners.ne, directionEast), new three_1.Ray(worldCorners.ne, directionWest) // north west ray ].forEach(ray => { this.addFrustumIntersection(ray, frustum, coordinates); }); } // 5.) Create the Polygon and set needsSort to `true`as we expect it to be convex and // sortable return this.createPolygon(coordinates); } createPolygon(coordinates) { if (coordinates.length > 2) { return new harp_geoutils_1.GeoPolygon(coordinates, true); } return undefined; } getWorldConers(projection) { const worldBox = projection.worldExtent(0, 0); return { sw: worldBox.min, se: new three_1.Vector3(worldBox.max.x, worldBox.min.y, 0), nw: new three_1.Vector3(worldBox.min.x, worldBox.max.y, 0), ne: worldBox.max }; } addNDCRayIntersection(ndcPoints, geoPolygon) { ndcPoints.forEach(corner => { const intersection = Utils_1.MapViewUtils.rayCastWorldCoordinates({ camera: this.camera, projection: this.projection }, corner[0], corner[1]); if (intersection) { this.validateAndAddToGeoPolygon(intersection, geoPolygon); } }); } addHorizonIntersection(geoPolygon) { const verticalHorizonPosition = this.getVerticalHorizonPositionInNDC(); if (!verticalHorizonPosition) { return; } this.addNDCRayIntersection([ [-1, verticalHorizonPosition], [1, verticalHorizonPosition] //horizon right ], geoPolygon); } addCanvasCornerIntersection(geoPolygon) { this.addNDCRayIntersection([ [-1, -1], [1, -1], [1, 1], [-1, 1] //upper left ], geoPolygon); } validateAndAddToGeoPolygon(point, geoPolygon) { if (this.isInVisibleMap(point)) { geoPolygon.push(this.projection.unprojectPoint(point)); } } isInVisibleMap(point) { if (point.y < 0 || point.y > harp_geoutils_1.EarthConstants.EQUATORIAL_CIRCUMFERENCE) { return false; } if (!this.m_options.tileWrappingEnabled && (point.x < 0 || point.x > harp_geoutils_1.EarthConstants.EQUATORIAL_CIRCUMFERENCE)) { return false; } return true; } addPointInFrustum(point, frustum, geoPolygon) { if (frustum.containsPoint(point)) { const geoPoint = this.projection.unprojectPoint(point); geoPoint.altitude = 0; geoPolygon.push(geoPoint); } } addFrustumIntersection(edge, frustum, geoPolygon) { frustum.planes.forEach(plane => { let intersection = null; const target = new three_1.Vector3(); if (edge instanceof three_1.Ray && edge.intersectsPlane(plane)) { intersection = edge.intersectPlane(plane, target); } else if (edge instanceof three_1.Line3 && plane.intersectsLine(edge)) { intersection = plane.intersectLine(edge, target); } if (intersection) { //uses this check to fix inaccuracies if (Utils_1.MapViewUtils.closeToFrustum(intersection, this.camera)) { const geoIntersection = this.projection.unprojectPoint(intersection); //correct altitude caused by inaccuracies, due to large numbers to 0 geoIntersection.altitude = 0; geoPolygon.push(geoIntersection); } } }); } getVerticalHorizonPositionInNDC() { const bottomMidFarPoint = new three_1.Vector3(-1, -1, 1) .unproject(this.camera) .add(new three_1.Vector3(1, -1, 1).unproject(this.camera)) .multiplyScalar(0.5); const topMidFarPoint = new three_1.Vector3(-1, 1, 1) .unproject(this.camera) .add(new three_1.Vector3(1, 1, 1).unproject(this.camera)) .multiplyScalar(0.5); const farPlaneVerticalCenterLine = new three_1.Line3(bottomMidFarPoint, topMidFarPoint); const verticalHorizonPosition = new three_1.Vector3(); if (!this.m_groundPlane.intersectLine(farPlaneVerticalCenterLine, verticalHorizonPosition)) { return undefined; } return verticalHorizonPosition.project(this.camera).y; } } exports.PlaneViewBounds = PlaneViewBounds; //# sourceMappingURL=PlaneViewBounds.js.map