import { Feature as GeoJsonFeature } from "geojson"; import { IReactionPublic, isObservableArray, reaction, runInAction } from "mobx"; import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3"; import createGuid from "terriajs-cesium/Source/Core/createGuid"; import Ellipsoid from "terriajs-cesium/Source/Core/Ellipsoid"; import CesiumMath from "terriajs-cesium/Source/Core/Math"; import filterOutUndefined from "../../Core/filterOutUndefined"; import flatten from "../../Core/flatten"; import { FeatureCollectionWithCrs } from "../../Core/GeoJson"; import isDefined from "../../Core/isDefined"; import Result from "../../Core/Result"; import featureDataToGeoJson from "../../Map/PickedFeatures/featureDataToGeoJson"; import GeoJsonCatalogItem from "../../Models/Catalog/CatalogItems/GeoJsonCatalogItem"; import CommonStrata from "../../Models/Definition/CommonStrata"; import GeoJsonParameter from "../../Models/FunctionParameters/GeoJsonParameter"; import MapInteractionMode from "../../Models/MapInteractionMode"; import Terria from "../../Models/Terria"; import ViewState from "../../ReactViewModels/ViewState"; /** * Prompts the user to select a point on the map. */ export function selectOnMap( terria: Terria, viewState: ViewState, parameter: GeoJsonParameter ) { // Cancel any feature picking already in progress. terria.pickedFeatures = undefined; let pickedFeaturesSubscription: IReactionPublic; const pickPolygonMode = new MapInteractionMode({ message: '
Select existing polygon

If there are no polygons to select, add a layer that provides polygons.

', onCancel: function () { terria.mapInteractionModeStack.pop(); viewState.openAddData(); if (pickedFeaturesSubscription) { pickedFeaturesSubscription.dispose(); } } }); terria.mapInteractionModeStack.push(pickPolygonMode); reaction( () => pickPolygonMode.pickedFeatures, async (pickedFeatures, _previousValue, reaction) => { pickedFeaturesSubscription = reaction; if (pickedFeatures?.allFeaturesAvailablePromise) { await pickedFeatures.allFeaturesAvailablePromise; } if (!isDefined(pickedFeatures?.pickPosition)) { return []; } const catalogItems = (pickedFeatures?.features .map(function (feature) { let geojson: FeatureCollectionWithCrs | GeoJsonFeature | undefined; if (feature.data) { geojson = featureDataToGeoJson(feature.data); // Note featureDataToGeoJson will only ever have a single feature // Add an id to it const firstFeature = geojson?.features[0]; if ( isDefined(firstFeature) && !isDefined(firstFeature.id) && isDefined(feature.id) ) { firstFeature.id = feature.id; } } else if (isDefined(feature.polygon)) { const positions = feature.polygon.hierarchy ?.getValue(terria.timelineClock.currentTime) .positions.map((position: Cartesian3) => { const cartographic = Ellipsoid.WGS84.cartesianToCartographic(position); return [ CesiumMath.toDegrees(cartographic.longitude), CesiumMath.toDegrees(cartographic.latitude) ]; }); geojson = { id: feature.id, type: "Feature", properties: feature.properties ? feature.properties.getValue(terria.timelineClock.currentTime) : undefined, geometry: { coordinates: [[positions]], type: "MultiPolygon" } }; } if (isDefined(geojson)) { const catalogItem = new GeoJsonCatalogItem(createGuid(), terria); catalogItem.setTrait( CommonStrata.user, "geoJsonData", geojson as any ); return catalogItem; } }) .filter((item) => isDefined(item)) ?? []) as GeoJsonCatalogItem[]; const result = Result.combine( await Promise.all(catalogItems.map((model) => model.loadMapItems())), "Failed to load picked polygons" ); if (result.error) { terria.raiseErrorToUser(result.error, "Failed to select polygons"); terria.mapInteractionModeStack.pop(); } else { const features = flatten( filterOutUndefined( catalogItems.map((item) => item.readyData?.features) ) ).filter( (f) => f.geometry.type === "Polygon" || f.geometry.type === "MultiPolygon" ) as any; runInAction(() => { parameter.setValue(CommonStrata.user, features); terria.mapInteractionModeStack.pop(); viewState.openAddData(); }); } if (pickedFeaturesSubscription) { pickedFeaturesSubscription.dispose(); } } ); viewState.explorerPanelIsVisible = false; } export function getDisplayValue(value: GeoJsonFeature[]) { if (!isDefined(value) || !isObservableArray(value)) { return ""; } return value .map(function (featureData) { return featureData.id; }) .join(", "); }