sampleTerrain.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import when from "../ThirdParty/when.js";
  2. import Check from "./Check.js";
  3. /**
  4. * Initiates a terrain height query for an array of {@link Cartographic} positions by
  5. * requesting tiles from a terrain provider, sampling, and interpolating. The interpolation
  6. * matches the triangles used to render the terrain at the specified level. The query
  7. * happens asynchronously, so this function returns a promise that is resolved when
  8. * the query completes. Each point height is modified in place. If a height can not be
  9. * determined because no terrain data is available for the specified level at that location,
  10. * or another error occurs, the height is set to undefined. As is typical of the
  11. * {@link Cartographic} type, the supplied height is a height above the reference ellipsoid
  12. * (such as {@link Ellipsoid.WGS84}) rather than an altitude above mean sea level. In other
  13. * words, it will not necessarily be 0.0 if sampled in the ocean. This function needs the
  14. * terrain level of detail as input, if you need to get the altitude of the terrain as precisely
  15. * as possible (i.e. with maximum level of detail) use {@link sampleTerrainMostDetailed}.
  16. *
  17. * @function sampleTerrain
  18. *
  19. * @param {TerrainProvider} terrainProvider The terrain provider from which to query heights.
  20. * @param {Number} level The terrain level-of-detail from which to query terrain heights.
  21. * @param {Cartographic[]} positions The positions to update with terrain heights.
  22. * @returns {Promise.<Cartographic[]>} A promise that resolves to the provided list of positions when terrain the query has completed.
  23. *
  24. * @see sampleTerrainMostDetailed
  25. *
  26. * @example
  27. * // Query the terrain height of two Cartographic positions
  28. * var terrainProvider = Cesium.createWorldTerrain();
  29. * var positions = [
  30. * Cesium.Cartographic.fromDegrees(86.925145, 27.988257),
  31. * Cesium.Cartographic.fromDegrees(87.0, 28.0)
  32. * ];
  33. * var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);
  34. * Cesium.when(promise, function(updatedPositions) {
  35. * // positions[0].height and positions[1].height have been updated.
  36. * // updatedPositions is just a reference to positions.
  37. * });
  38. */
  39. function sampleTerrain(terrainProvider, level, positions) {
  40. //>>includeStart('debug', pragmas.debug);
  41. Check.typeOf.object("terrainProvider", terrainProvider);
  42. Check.typeOf.number("level", level);
  43. Check.defined("positions", positions);
  44. //>>includeEnd('debug');
  45. return terrainProvider.readyPromise.then(function () {
  46. return doSampling(terrainProvider, level, positions);
  47. });
  48. }
  49. function doSampling(terrainProvider, level, positions) {
  50. var tilingScheme = terrainProvider.tilingScheme;
  51. var i;
  52. // Sort points into a set of tiles
  53. var tileRequests = []; // Result will be an Array as it's easier to work with
  54. var tileRequestSet = {}; // A unique set
  55. for (i = 0; i < positions.length; ++i) {
  56. var xy = tilingScheme.positionToTileXY(positions[i], level);
  57. var key = xy.toString();
  58. if (!tileRequestSet.hasOwnProperty(key)) {
  59. // When tile is requested for the first time
  60. var value = {
  61. x: xy.x,
  62. y: xy.y,
  63. level: level,
  64. tilingScheme: tilingScheme,
  65. terrainProvider: terrainProvider,
  66. positions: [],
  67. };
  68. tileRequestSet[key] = value;
  69. tileRequests.push(value);
  70. }
  71. // Now append to array of points for the tile
  72. tileRequestSet[key].positions.push(positions[i]);
  73. }
  74. // Send request for each required tile
  75. var tilePromises = [];
  76. for (i = 0; i < tileRequests.length; ++i) {
  77. var tileRequest = tileRequests[i];
  78. var requestPromise = tileRequest.terrainProvider.requestTileGeometry(
  79. tileRequest.x,
  80. tileRequest.y,
  81. tileRequest.level
  82. );
  83. var tilePromise = requestPromise
  84. .then(createInterpolateFunction(tileRequest))
  85. .otherwise(createMarkFailedFunction(tileRequest));
  86. tilePromises.push(tilePromise);
  87. }
  88. return when.all(tilePromises, function () {
  89. return positions;
  90. });
  91. }
  92. function createInterpolateFunction(tileRequest) {
  93. var tilePositions = tileRequest.positions;
  94. var rectangle = tileRequest.tilingScheme.tileXYToRectangle(
  95. tileRequest.x,
  96. tileRequest.y,
  97. tileRequest.level
  98. );
  99. return function (terrainData) {
  100. for (var i = 0; i < tilePositions.length; ++i) {
  101. var position = tilePositions[i];
  102. position.height = terrainData.interpolateHeight(
  103. rectangle,
  104. position.longitude,
  105. position.latitude
  106. );
  107. }
  108. };
  109. }
  110. function createMarkFailedFunction(tileRequest) {
  111. var tilePositions = tileRequest.positions;
  112. return function () {
  113. for (var i = 0; i < tilePositions.length; ++i) {
  114. var position = tilePositions[i];
  115. position.height = undefined;
  116. }
  117. };
  118. }
  119. export default sampleTerrain;