diff --git a/lib/Models/Catalog/CatalogItems/KmlCatalogItem.ts b/lib/Models/Catalog/CatalogItems/KmlCatalogItem.ts index 63417b460b6..e8a58a4444c 100644 --- a/lib/Models/Catalog/CatalogItems/KmlCatalogItem.ts +++ b/lib/Models/Catalog/CatalogItems/KmlCatalogItem.ts @@ -1,25 +1,17 @@ import i18next from "i18next"; import { computed, makeObservable, override } from "mobx"; -import Cartesian3 from "terriajs-cesium/Source/Core/Cartesian3"; -import Cartographic from "terriajs-cesium/Source/Core/Cartographic"; -import Ellipsoid from "terriajs-cesium/Source/Core/Ellipsoid"; -import JulianDate from "terriajs-cesium/Source/Core/JulianDate"; -import PolygonHierarchy from "terriajs-cesium/Source/Core/PolygonHierarchy"; import Resource from "terriajs-cesium/Source/Core/Resource"; -import sampleTerrain from "terriajs-cesium/Source/Core/sampleTerrain"; -import ConstantProperty from "terriajs-cesium/Source/DataSources/ConstantProperty"; import KmlDataSource from "terriajs-cesium/Source/DataSources/KmlDataSource"; -import Property from "terriajs-cesium/Source/DataSources/Property"; +import TerriaError, { networkRequestError } from "../../../Core/TerriaError"; import isDefined from "../../../Core/isDefined"; import readXml from "../../../Core/readXml"; -import TerriaError, { networkRequestError } from "../../../Core/TerriaError"; import CatalogMemberMixin from "../../../ModelMixins/CatalogMemberMixin"; import MappableMixin from "../../../ModelMixins/MappableMixin"; import UrlMixin from "../../../ModelMixins/UrlMixin"; import KmlCatalogItemTraits from "../../../Traits/TraitsClasses/KmlCatalogItemTraits"; import CreateModel from "../../Definition/CreateModel"; -import HasLocalData from "../../HasLocalData"; import { ModelConstructorParameters } from "../../Definition/Model"; +import HasLocalData from "../../HasLocalData"; import proxyCatalogItemUrl from "../proxyCatalogItemUrl"; const kmzRegex = /\.kmz$/i; @@ -62,45 +54,44 @@ class KmlCatalogItem return "1d"; } - protected forceLoadMapItems(): Promise { - return new Promise((resolve) => { - if (isDefined(this.kmlString)) { - const parser = new DOMParser(); - resolve(parser.parseFromString(this.kmlString, "text/xml")); - } else if (isDefined(this._kmlFile)) { - if (this._kmlFile.name && this._kmlFile.name.match(kmzRegex)) { - resolve(this._kmlFile); + protected async forceLoadMapItems(): Promise { + try { + const kmlLoadInput = await new Promise< + string | Resource | Document | Blob + >((resolve) => { + if (isDefined(this.kmlString)) { + const parser = new DOMParser(); + resolve(parser.parseFromString(this.kmlString, "text/xml")); + } else if (isDefined(this._kmlFile)) { + if (this._kmlFile.name && this._kmlFile.name.match(kmzRegex)) { + resolve(this._kmlFile); + } else { + resolve(readXml(this._kmlFile)); + } + } else if (isDefined(this.url)) { + resolve(proxyCatalogItemUrl(this, this.url)); } else { - resolve(readXml(this._kmlFile)); + throw networkRequestError({ + sender: this, + title: i18next.t("models.kml.unableToLoadItemTitle"), + message: i18next.t("models.kml.unableToLoadItemMessage") + }); } - } else if (isDefined(this.url)) { - resolve(proxyCatalogItemUrl(this, this.url)); - } else { - throw networkRequestError({ + }); + this._dataSource = await KmlDataSource.load(kmlLoadInput, { + clampToGround: this.clampToGround + } as any); + } catch (e) { + throw networkRequestError( + TerriaError.from(e, { sender: this, - title: i18next.t("models.kml.unableToLoadItemTitle"), - message: i18next.t("models.kml.unableToLoadItemMessage") - }); - } - }) - .then((kmlLoadInput) => { - return KmlDataSource.load(kmlLoadInput); - }) - .then((dataSource) => { - this._dataSource = dataSource; - this.doneLoading(dataSource); // Unsure if this is necessary - }) - .catch((e) => { - throw networkRequestError( - TerriaError.from(e, { - sender: this, - title: i18next.t("models.kml.errorLoadingTitle"), - message: i18next.t("models.kml.errorLoadingMessage", { - appName: this.terria.appName - }) + title: i18next.t("models.kml.errorLoadingTitle"), + message: i18next.t("models.kml.errorLoadingMessage", { + appName: this.terria.appName }) - ); - }); + }) + ); + } } @computed @@ -115,98 +106,6 @@ class KmlCatalogItem protected forceLoadMetadata(): Promise { return Promise.resolve(); } - - private doneLoading(kmlDataSource: KmlDataSource) { - // Clamp features to terrain. - if (isDefined(this.terria.cesium) && this.clampPolygonsToGround) { - const positionsToSample: Cartographic[] = []; - const correspondingCartesians: Cartesian3[] = []; - - const entities = kmlDataSource.entities.values; - for (let i = 0; i < entities.length; ++i) { - const entity = entities[i]; - - const polygon = entity.polygon; - if (isDefined(polygon)) { - polygon.perPositionHeight = true as unknown as Property; - const polygonHierarchy = getPropertyValue( - polygon.hierarchy - ); - if (polygonHierarchy) { - samplePolygonHierarchyPositions( - polygonHierarchy, - positionsToSample, - correspondingCartesians - ); - } - } - } - const terrainProvider = this.terria.cesium.scene.globe.terrainProvider; - sampleTerrain(terrainProvider, 11, positionsToSample).then(function () { - for (let i = 0; i < positionsToSample.length; ++i) { - const position = positionsToSample[i]; - if (!isDefined(position.height)) { - continue; - } - - Ellipsoid.WGS84.cartographicToCartesian( - position, - correspondingCartesians[i] - ); - } - - // Force the polygons to be rebuilt. - for (let i = 0; i < entities.length; ++i) { - const polygon = entities[i].polygon; - if (!isDefined(polygon)) { - continue; - } - - const existingHierarchy = getPropertyValue( - polygon.hierarchy - ); - if (existingHierarchy) { - polygon.hierarchy = new ConstantProperty( - new PolygonHierarchy( - existingHierarchy.positions, - existingHierarchy.holes - ) - ); - } - } - }); - } - } } export default KmlCatalogItem; - -function getPropertyValue(property: Property | undefined): T | undefined { - if (property === undefined) { - return undefined; - } - return property.getValue(JulianDate.now()); -} - -function samplePolygonHierarchyPositions( - polygonHierarchy: PolygonHierarchy, - positionsToSample: Cartographic[], - correspondingCartesians: Cartesian3[] -) { - const positions = polygonHierarchy.positions; - - for (let i = 0; i < positions.length; ++i) { - const position = positions[i]; - correspondingCartesians.push(position); - positionsToSample.push(Ellipsoid.WGS84.cartesianToCartographic(position)); - } - - const holes = polygonHierarchy.holes; - for (let i = 0; i < holes.length; ++i) { - samplePolygonHierarchyPositions( - holes[i], - positionsToSample, - correspondingCartesians - ); - } -} diff --git a/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts b/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts index f41fb6624b4..858d1364ab1 100644 --- a/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts +++ b/lib/Traits/TraitsClasses/KmlCatalogItemTraits.ts @@ -22,7 +22,7 @@ export default class KmlCatalogItemTraits extends mixTraits( type: "boolean", name: "Clamp to Ground", description: - "Whether the polygon features in this KML should be clamped to the terrain surface." + "true if we want the geometry features (Polygons, LineStrings and LinearRings) clamped to the ground" }) - clampPolygonsToGround: boolean = true; + clampToGround: boolean = true; }