| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 | import Credit from "./Credit.js";import defaultValue from "./defaultValue.js";import defer from "./defer.js";import defined from "./defined.js";import DeveloperError from "./DeveloperError.js";import Ellipsoid from "./Ellipsoid.js";import Event from "./Event.js";import GeographicTilingScheme from "./GeographicTilingScheme.js";import getImagePixels from "./getImagePixels.js";import HeightmapTerrainData from "./HeightmapTerrainData.js";import CesiumMath from "./Math.js";import Rectangle from "./Rectangle.js";import Resource from "./Resource.js";import TerrainProvider from "./TerrainProvider.js";import TileProviderError from "./TileProviderError.js";function DataRectangle(rectangle, maxLevel) {  this.rectangle = rectangle;  this.maxLevel = maxLevel;}/** * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps * retrieved from a {@link http://vr-theworld.com/|VT MÄK VR-TheWorld server}. * * @alias VRTheWorldTerrainProvider * @constructor * * @param {Object} options Object with the following properties: * @param {Resource|String} options.url The URL of the VR-TheWorld TileMap. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid.  If this parameter is not *                    specified, the WGS84 ellipsoid is used. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas. * * * @example * const terrainProvider = new Cesium.VRTheWorldTerrainProvider({ *   url : 'https://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/' * }); * viewer.terrainProvider = terrainProvider; * * @see TerrainProvider */function VRTheWorldTerrainProvider(options) {  options = defaultValue(options, defaultValue.EMPTY_OBJECT);  //>>includeStart('debug', pragmas.debug);  if (!defined(options.url)) {    throw new DeveloperError("options.url is required.");  }  //>>includeEnd('debug');  const resource = Resource.createIfNeeded(options.url);  this._resource = resource;  this._errorEvent = new Event();  this._ready = false;  this._readyPromise = defer();  this._terrainDataStructure = {    heightScale: 1.0 / 1000.0,    heightOffset: -1000.0,    elementsPerHeight: 3,    stride: 4,    elementMultiplier: 256.0,    isBigEndian: true,    lowestEncodedHeight: 0,    highestEncodedHeight: 256 * 256 * 256 - 1,  };  let credit = options.credit;  if (typeof credit === "string") {    credit = new Credit(credit);  }  this._credit = credit;  this._tilingScheme = undefined;  this._rectangles = [];  const that = this;  let metadataError;  const ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);  function metadataSuccess(xml) {    const srs = xml.getElementsByTagName("SRS")[0].textContent;    if (srs === "EPSG:4326") {      that._tilingScheme = new GeographicTilingScheme({ ellipsoid: ellipsoid });    } else {      metadataFailure(`SRS ${srs} is not supported.`);      return;    }    const tileFormat = xml.getElementsByTagName("TileFormat")[0];    that._heightmapWidth = parseInt(tileFormat.getAttribute("width"), 10);    that._heightmapHeight = parseInt(tileFormat.getAttribute("height"), 10);    that._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(      ellipsoid,      Math.min(that._heightmapWidth, that._heightmapHeight),      that._tilingScheme.getNumberOfXTilesAtLevel(0)    );    const dataRectangles = xml.getElementsByTagName("DataExtent");    for (let i = 0; i < dataRectangles.length; ++i) {      const dataRectangle = dataRectangles[i];      const west = CesiumMath.toRadians(        parseFloat(dataRectangle.getAttribute("minx"))      );      const south = CesiumMath.toRadians(        parseFloat(dataRectangle.getAttribute("miny"))      );      const east = CesiumMath.toRadians(        parseFloat(dataRectangle.getAttribute("maxx"))      );      const north = CesiumMath.toRadians(        parseFloat(dataRectangle.getAttribute("maxy"))      );      const maxLevel = parseInt(dataRectangle.getAttribute("maxlevel"), 10);      that._rectangles.push(        new DataRectangle(new Rectangle(west, south, east, north), maxLevel)      );    }    that._ready = true;    that._readyPromise.resolve(true);  }  function metadataFailure(e) {    const message = defaultValue(      e,      `An error occurred while accessing ${that._resource.url}.`    );    metadataError = TileProviderError.handleError(      metadataError,      that,      that._errorEvent,      message,      undefined,      undefined,      undefined,      requestMetadata    );  }  function requestMetadata() {    that._resource.fetchXML().then(metadataSuccess).catch(metadataFailure);  }  requestMetadata();}Object.defineProperties(VRTheWorldTerrainProvider.prototype, {  /**   * Gets an event that is raised when the terrain provider encounters an asynchronous error.  By subscribing   * to the event, you will be notified of the error and can potentially recover from it.  Event listeners   * are passed an instance of {@link TileProviderError}.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Event}   * @readonly   */  errorEvent: {    get: function () {      return this._errorEvent;    },  },  /**   * Gets the credit to display when this terrain provider is active.  Typically this is used to credit   * the source of the terrain.  This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Credit}   * @readonly   */  credit: {    get: function () {      return this._credit;    },  },  /**   * Gets the tiling scheme used by this provider.  This function should   * not be called before {@link VRTheWorldTerrainProvider#ready} returns true.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {GeographicTilingScheme}   * @readonly   */  tilingScheme: {    get: function () {      //>>includeStart('debug', pragmas.debug);      if (!this.ready) {        throw new DeveloperError(          "requestTileGeometry must not be called before ready returns true."        );      }      //>>includeEnd('debug');      return this._tilingScheme;    },  },  /**   * Gets a value indicating whether or not the provider is ready for use.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Boolean}   * @readonly   */  ready: {    get: function () {      return this._ready;    },  },  /**   * Gets a promise that resolves to true when the provider is ready for use.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Promise.<Boolean>}   * @readonly   */  readyPromise: {    get: function () {      return this._readyPromise.promise;    },  },  /**   * Gets a value indicating whether or not the provider includes a water mask.  The water mask   * indicates which areas of the globe are water rather than land, so they can be rendered   * as a reflective surface with animated waves.  This function should not be   * called before {@link VRTheWorldTerrainProvider#ready} returns true.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Boolean}   * @readonly   */  hasWaterMask: {    get: function () {      return false;    },  },  /**   * Gets a value indicating whether or not the requested tiles include vertex normals.   * This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {Boolean}   * @readonly   */  hasVertexNormals: {    get: function () {      return false;    },  },  /**   * Gets an object that can be used to determine availability of terrain from this provider, such as   * at points and in rectangles.  This function should not be called before   * {@link TerrainProvider#ready} returns true.  This property may be undefined if availability   * information is not available.   * @memberof VRTheWorldTerrainProvider.prototype   * @type {TileAvailability}   * @readonly   */  availability: {    get: function () {      return undefined;    },  },});/** * Requests the geometry for a given tile.  This function should not be called before * {@link VRTheWorldTerrainProvider#ready} returns true.  The result includes terrain * data and indicates that all child tiles are available. * * @param {Number} x The X coordinate of the tile for which to request geometry. * @param {Number} y The Y coordinate of the tile for which to request geometry. * @param {Number} level The level of the tile for which to request geometry. * @param {Request} [request] The request object. Intended for internal use only. * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry.  If this method *          returns undefined instead of a promise, it is an indication that too many requests are already *          pending and the request will be retried later. */VRTheWorldTerrainProvider.prototype.requestTileGeometry = function (  x,  y,  level,  request) {  //>>includeStart('debug', pragmas.debug);  if (!this.ready) {    throw new DeveloperError(      "requestTileGeometry must not be called before ready returns true."    );  }  //>>includeEnd('debug');  const yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);  const resource = this._resource.getDerivedResource({    url: `${level}/${x}/${yTiles - y - 1}.tif`,    queryParameters: {      cesium: true,    },    request: request,  });  const promise = resource.fetchImage({    preferImageBitmap: true,  });  if (!defined(promise)) {    return undefined;  }  const that = this;  return Promise.resolve(promise).then(function (image) {    return new HeightmapTerrainData({      buffer: getImagePixels(image),      width: that._heightmapWidth,      height: that._heightmapHeight,      childTileMask: getChildMask(that, x, y, level),      structure: that._terrainDataStructure,    });  });};/** * Gets the maximum geometric error allowed in a tile at a given level. * * @param {Number} level The tile level for which to get the maximum geometric error. * @returns {Number} The maximum geometric error. */VRTheWorldTerrainProvider.prototype.getLevelMaximumGeometricError = function (  level) {  //>>includeStart('debug', pragmas.debug);  if (!this.ready) {    throw new DeveloperError(      "requestTileGeometry must not be called before ready returns true."    );  }  //>>includeEnd('debug');  return this._levelZeroMaximumGeometricError / (1 << level);};const rectangleScratch = new Rectangle();function getChildMask(provider, x, y, level) {  const tilingScheme = provider._tilingScheme;  const rectangles = provider._rectangles;  const parentRectangle = tilingScheme.tileXYToRectangle(x, y, level);  let childMask = 0;  for (let i = 0; i < rectangles.length && childMask !== 15; ++i) {    const rectangle = rectangles[i];    if (rectangle.maxLevel <= level) {      continue;    }    const testRectangle = rectangle.rectangle;    const intersection = Rectangle.intersection(      testRectangle,      parentRectangle,      rectangleScratch    );    if (defined(intersection)) {      // Parent tile is inside this rectangle, so at least one child is, too.      if (        isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2, level + 1)      ) {        childMask |= 4; // northwest      }      if (        isTileInRectangle(          tilingScheme,          testRectangle,          x * 2 + 1,          y * 2,          level + 1        )      ) {        childMask |= 8; // northeast      }      if (        isTileInRectangle(          tilingScheme,          testRectangle,          x * 2,          y * 2 + 1,          level + 1        )      ) {        childMask |= 1; // southwest      }      if (        isTileInRectangle(          tilingScheme,          testRectangle,          x * 2 + 1,          y * 2 + 1,          level + 1        )      ) {        childMask |= 2; // southeast      }    }  }  return childMask;}function isTileInRectangle(tilingScheme, rectangle, x, y, level) {  const tileRectangle = tilingScheme.tileXYToRectangle(x, y, level);  return defined(    Rectangle.intersection(tileRectangle, rectangle, rectangleScratch)  );}/** * Determines whether data for a tile is available to be loaded. * * @param {Number} x The X coordinate of the tile for which to request geometry. * @param {Number} y The Y coordinate of the tile for which to request geometry. * @param {Number} level The level of the tile for which to request geometry. * @returns {Boolean|undefined} Undefined if not supported, otherwise true or false. */VRTheWorldTerrainProvider.prototype.getTileDataAvailable = function (  x,  y,  level) {  return undefined;};/** * Makes sure we load availability data for a tile * * @param {Number} x The X coordinate of the tile for which to request geometry. * @param {Number} y The Y coordinate of the tile for which to request geometry. * @param {Number} level The level of the tile for which to request geometry. * @returns {undefined|Promise<void>} Undefined if nothing need to be loaded or a Promise that resolves when all required tiles are loaded */VRTheWorldTerrainProvider.prototype.loadTileDataAvailability = function (  x,  y,  level) {  return undefined;};export default VRTheWorldTerrainProvider;
 |