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(", ");
}