terriajs
Version:
Geospatial data visualization platform.
200 lines • 9.51 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import debounce from "lodash-es/debounce";
import { action, makeObservable, observable, runInAction } from "mobx";
import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3";
import Cartographic from "terriajs-cesium/Source/Core/Cartographic";
import EllipsoidTerrainProvider from "terriajs-cesium/Source/Core/EllipsoidTerrainProvider";
import CesiumEvent from "terriajs-cesium/Source/Core/Event";
import Intersections2D from "terriajs-cesium/Source/Core/Intersections2D";
import CesiumMath from "terriajs-cesium/Source/Core/Math";
import Ray from "terriajs-cesium/Source/Core/Ray";
import sampleTerrainMostDetailed from "terriajs-cesium/Source/Core/sampleTerrainMostDetailed";
import isDefined from "../Core/isDefined";
import pickTriangle from "../Map/Cesium/pickTriangle";
import EarthGravityModel1996 from "../Map/Vector/EarthGravityModel1996";
import prettifyCoordinates from "../Map/Vector/prettifyCoordinates";
import prettifyProjection from "../Map/Vector/prettifyProjection";
import gridFileUrl from "../../wwwroot/data/WW15MGH.DAC";
const scratchRay = new Ray();
const scratchV0 = new Cartographic();
const scratchV1 = new Cartographic();
const scratchV2 = new Cartographic();
const scratchIntersection = new Cartographic();
const scratchBarycentric = new Cartesian3();
const scratchCartographic = new Cartographic();
const pickedTriangleScratch = {
tile: undefined,
intersection: new Cartesian3(),
v0: new Cartesian3(),
v1: new Cartesian3(),
v2: new Cartesian3()
};
export default class MouseCoords {
geoidModel;
proj4Projection;
projectionUnits;
proj4longlat;
accurateSamplingDebounceTime;
debounceSampleAccurateHeight;
tileRequestInFlight;
elevation;
utmZone;
latitude;
longitude;
north;
east;
cartographic;
useProjection = false;
updateEvent = new CesiumEvent();
constructor() {
makeObservable(this);
this.geoidModel = new EarthGravityModel1996(gridFileUrl);
this.proj4Projection = "+proj=utm +ellps=GRS80 +units=m +no_defs";
this.projectionUnits = "m";
this.proj4longlat =
"+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees +no_defs";
this.accurateSamplingDebounceTime = 250;
this.tileRequestInFlight = undefined;
this.debounceSampleAccurateHeight = debounce(this.sampleAccurateHeight, this.accurateSamplingDebounceTime);
}
toggleUseProjection() {
this.useProjection = !this.useProjection;
this.updateEvent.raiseEvent();
}
updateCoordinatesFromCesium(terria, position) {
if (!terria.cesium) {
return;
}
const scene = terria.cesium.scene;
const camera = scene.camera;
const pickRay = camera.getPickRay(position, scratchRay);
const globe = scene.globe;
const pickedTriangle = isDefined(pickRay)
? pickTriangle(pickRay, scene, true, pickedTriangleScratch)
: undefined;
if (isDefined(pickedTriangle)) {
// Get a fast, accurate-ish height every time the mouse moves.
const ellipsoid = globe.ellipsoid;
const v0 = ellipsoid.cartesianToCartographic(pickedTriangle.v0, scratchV0);
const v1 = ellipsoid.cartesianToCartographic(pickedTriangle.v1, scratchV1);
const v2 = ellipsoid.cartesianToCartographic(pickedTriangle.v2, scratchV2);
const intersection = ellipsoid.cartesianToCartographic(pickedTriangle.intersection, scratchIntersection);
let errorBar;
if (globe.terrainProvider instanceof EllipsoidTerrainProvider) {
intersection.height = 0;
}
else {
const barycentric = Intersections2D.computeBarycentricCoordinates(intersection.longitude, intersection.latitude, v0.longitude, v0.latitude, v1.longitude, v1.latitude, v2.longitude, v2.latitude, scratchBarycentric);
if (barycentric.x >= -1e-15 &&
barycentric.y >= -1e-15 &&
barycentric.z >= -1e-15) {
const height = barycentric.x * v0.height +
barycentric.y * v1.height +
barycentric.z * v2.height;
intersection.height = height;
}
const geometricError = globe.terrainProvider.getLevelMaximumGeometricError(pickedTriangle.tile.level);
const approximateHeight = intersection.height;
const minHeight = Math.max(pickedTriangle.tile.data.tileBoundingRegion.minimumHeight, approximateHeight - geometricError);
const maxHeight = Math.min(pickedTriangle.tile.data.tileBoundingRegion.maximumHeight, approximateHeight + geometricError);
const minHeightGeoid = minHeight - (this.geoidModel ? this.geoidModel.minimumHeight : 0.0);
const maxHeightGeoid = maxHeight + (this.geoidModel ? this.geoidModel.maximumHeight : 0.0);
errorBar = Math.max(Math.abs(approximateHeight - minHeightGeoid), Math.abs(maxHeightGeoid - approximateHeight));
}
const terrainProvider = globe.terrainProvider;
this.cartographicToFields(intersection, errorBar);
if (!(terrainProvider instanceof EllipsoidTerrainProvider)) {
this.debounceSampleAccurateHeight(terrainProvider, intersection);
}
}
else {
runInAction(() => {
this.elevation = undefined;
this.utmZone = undefined;
this.latitude = undefined;
this.longitude = undefined;
this.north = undefined;
this.east = undefined;
});
this.updateEvent.raiseEvent();
}
}
updateCoordinatesFromLeaflet(terria, mouseMoveEvent) {
if (!terria.leaflet) {
return;
}
const latLng = terria.leaflet.map.mouseEventToLatLng(mouseMoveEvent);
const coordinates = Cartographic.fromDegrees(latLng.lng, latLng.lat, 0, scratchCartographic);
this.cartographicToFields(coordinates);
}
cartographicToFields(coordinates, errorBar) {
this.cartographic = Cartographic.clone(coordinates, scratchCartographic);
const latitude = CesiumMath.toDegrees(coordinates.latitude);
const longitude = CesiumMath.toDegrees(coordinates.longitude);
if (this.useProjection) {
const prettyProjection = prettifyProjection(longitude, latitude, this.proj4Projection, this.proj4longlat, this.projectionUnits);
this.utmZone = prettyProjection.utmZone;
this.north = prettyProjection.north;
this.east = prettyProjection.east;
}
const prettyCoordinate = prettifyCoordinates(longitude, latitude, {
height: coordinates.height,
errorBar: errorBar
});
this.latitude = prettyCoordinate.latitude;
this.longitude = prettyCoordinate.longitude;
this.elevation = prettyCoordinate.elevation;
this.updateEvent.raiseEvent();
}
sampleAccurateHeight(terrainProvider, position) {
if (this.tileRequestInFlight) {
// A tile request is already in flight, so reschedule for later.
this.debounceSampleAccurateHeight.cancel();
this.debounceSampleAccurateHeight(terrainProvider, position);
return;
}
const positionWithHeight = Cartographic.clone(position);
const geoidHeightPromise = this.geoidModel
? this.geoidModel.getHeight(position.longitude, position.latitude)
: undefined;
const terrainPromise = sampleTerrainMostDetailed(terrainProvider, [
positionWithHeight
]);
this.tileRequestInFlight = Promise.all([geoidHeightPromise, terrainPromise])
.then((result) => {
const geoidHeight = result[0] || 0.0;
this.tileRequestInFlight = undefined;
if (Cartographic.equals(position, this.cartographic)) {
position.height = positionWithHeight.height - geoidHeight;
this.cartographicToFields(position);
}
else {
// Mouse moved since we started this request, so the result isn't useful. Try again next time.
}
})
.catch(() => {
this.tileRequestInFlight = undefined;
});
}
}
__decorate([
observable
], MouseCoords.prototype, "useProjection", void 0);
__decorate([
action.bound
], MouseCoords.prototype, "toggleUseProjection", null);
__decorate([
action
], MouseCoords.prototype, "updateCoordinatesFromCesium", null);
__decorate([
action
], MouseCoords.prototype, "updateCoordinatesFromLeaflet", null);
__decorate([
action
], MouseCoords.prototype, "cartographicToFields", null);
//# sourceMappingURL=MouseCoords.js.map