UNPKG

terriajs

Version:

Geospatial data visualization platform.

221 lines (189 loc) 5.91 kB
import BoundingSphere from "terriajs-cesium/Source/Core/BoundingSphere"; import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3"; import Cartographic from "terriajs-cesium/Source/Core/Cartographic"; import IntersectionTests from "terriajs-cesium/Source/Core/IntersectionTests"; import MapProjection from "terriajs-cesium/Source/Core/MapProjection"; import Ray from "terriajs-cesium/Source/Core/Ray"; import defined from "terriajs-cesium/Source/Core/defined"; import Scene from "terriajs-cesium/Source/Scene/Scene"; import SceneMode from "terriajs-cesium/Source/Scene/SceneMode"; type Tile = any; type GlobeSurfaceTile = any; type TerrainEncoding = any; export interface PickTriangleResult extends PickTriangleFromGlobeSurfaceTileResult { tile: Tile; } const scratchArray: Tile[] = []; const scratchSphereIntersectionResult = { start: 0.0, stop: 0.0 }; // This is adapted from CesiumJS's `Globe.pick` function, but extended // to return more information. export default function pickTriangle( ray: Ray, scene: Scene, cullBackFaces: boolean, result: PickTriangleResult ): PickTriangleResult | undefined { const mode = scene.mode; const projection = scene.mapProjection; const sphereIntersections = scratchArray; sphereIntersections.length = 0; const globeAny: any = scene.globe; const surface = globeAny._surface; const tilesToRender = surface._tilesToRender; let length = tilesToRender.length; let tile; let i; for (i = 0; i < length; ++i) { tile = tilesToRender[i]; const surfaceTile = tile.data; if (!defined(surfaceTile)) { continue; } let boundingVolume = surfaceTile.pickBoundingSphere; if (mode !== SceneMode.SCENE3D) { surfaceTile.pickBoundingSphere = boundingVolume = BoundingSphere.fromRectangleWithHeights2D( tile.rectangle, projection, surfaceTile.tileBoundingRegion.minimumHeight, surfaceTile.tileBoundingRegion.maximumHeight, boundingVolume ); Cartesian3.fromElements( boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center ); } else if (defined(surfaceTile.renderedMesh)) { BoundingSphere.clone( surfaceTile.tileBoundingRegion.boundingSphere, boundingVolume ); } else { // So wait how did we render this thing then? It shouldn't be possible to get here. continue; } const boundingSphereIntersection = IntersectionTests.raySphere( ray, boundingVolume, scratchSphereIntersectionResult ); if (defined(boundingSphereIntersection)) { sphereIntersections.push(tile); } } sphereIntersections.sort(createComparePickTileFunction(ray.origin)); let intersection; length = sphereIntersections.length; for (i = 0; i < length; ++i) { intersection = pickTriangleFromGlobeSurfaceTile( sphereIntersections[i].data, ray, scene.mode, scene.mapProjection, cullBackFaces, result ); if (intersection !== undefined) { result.tile = sphereIntersections[i]; break; } } return intersection === undefined ? undefined : result; } function createComparePickTileFunction(rayOrigin: Cartesian3) { return function (a: Tile, b: Tile) { const aDist = BoundingSphere.distanceSquaredTo( a.data.pickBoundingSphere, rayOrigin ); const bDist = BoundingSphere.distanceSquaredTo( b.data.pickBoundingSphere, rayOrigin ); return aDist - bDist; }; } const scratchCartographic = new Cartographic(); function getPosition( encoding: TerrainEncoding, mode: SceneMode, projection: MapProjection, vertices: any, index: number, result: Cartesian3 ) { let position = encoding.getExaggeratedPosition(vertices, index, result); if (defined(mode) && mode !== SceneMode.SCENE3D) { const ellipsoid = projection.ellipsoid; const positionCartographic = ellipsoid.cartesianToCartographic( position, scratchCartographic ); position = projection.project(positionCartographic, result); position = Cartesian3.fromElements( position.z, position.x, position.y, result ); } return position; } const scratchV0 = new Cartesian3(); const scratchV1 = new Cartesian3(); const scratchV2 = new Cartesian3(); export interface PickTriangleFromGlobeSurfaceTileResult { intersection: Cartesian3; v0: Cartesian3; v1: Cartesian3; v2: Cartesian3; } function pickTriangleFromGlobeSurfaceTile( globeSurfaceTile: GlobeSurfaceTile, ray: Ray, mode: SceneMode, projection: MapProjection, cullBackFaces: boolean, result: PickTriangleFromGlobeSurfaceTileResult ): PickTriangleFromGlobeSurfaceTileResult | undefined { const mesh = globeSurfaceTile.renderedMesh; if (!defined(mesh)) { return undefined; } const vertices = mesh.vertices; const indices = mesh.indices; const encoding = mesh.encoding; const indicesLength = indices.length; let minT = Number.MAX_VALUE; for (let i = 0; i < indicesLength; i += 3) { const i0 = indices[i]; const i1 = indices[i + 1]; const i2 = indices[i + 2]; const v0 = getPosition(encoding, mode, projection, vertices, i0, scratchV0); const v1 = getPosition(encoding, mode, projection, vertices, i1, scratchV1); const v2 = getPosition(encoding, mode, projection, vertices, i2, scratchV2); const t = IntersectionTests.rayTriangleParametric( ray, v0, v1, v2, cullBackFaces ); if (defined(t) && t < minT && t >= 0.0) { minT = t; Cartesian3.clone(v0, result.v0); Cartesian3.clone(v1, result.v1); Cartesian3.clone(v2, result.v2); } } if (minT === Number.MAX_VALUE) { return undefined; } Ray.getPoint(ray, minT, result.intersection); return result; }