QuantizedMeshTerrainData.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. import when from "../ThirdParty/when.js";
  2. import BoundingSphere from "./BoundingSphere.js";
  3. import Cartesian2 from "./Cartesian2.js";
  4. import Cartesian3 from "./Cartesian3.js";
  5. import defaultValue from "./defaultValue.js";
  6. import defined from "./defined.js";
  7. import DeveloperError from "./DeveloperError.js";
  8. import IndexDatatype from "./IndexDatatype.js";
  9. import Intersections2D from "./Intersections2D.js";
  10. import CesiumMath from "./Math.js";
  11. import OrientedBoundingBox from "./OrientedBoundingBox.js";
  12. import TaskProcessor from "./TaskProcessor.js";
  13. import TerrainEncoding from "./TerrainEncoding.js";
  14. import TerrainMesh from "./TerrainMesh.js";
  15. /**
  16. * Terrain data for a single tile where the terrain data is represented as a quantized mesh. A quantized
  17. * mesh consists of three vertex attributes, longitude, latitude, and height. All attributes are expressed
  18. * as 16-bit values in the range 0 to 32767. Longitude and latitude are zero at the southwest corner
  19. * of the tile and 32767 at the northeast corner. Height is zero at the minimum height in the tile
  20. * and 32767 at the maximum height in the tile.
  21. *
  22. * @alias QuantizedMeshTerrainData
  23. * @constructor
  24. *
  25. * @param {Object} options Object with the following properties:
  26. * @param {Uint16Array} options.quantizedVertices The buffer containing the quantized mesh.
  27. * @param {Uint16Array|Uint32Array} options.indices The indices specifying how the quantized vertices are linked
  28. * together into triangles. Each three indices specifies one triangle.
  29. * @param {Number} options.minimumHeight The minimum terrain height within the tile, in meters above the ellipsoid.
  30. * @param {Number} options.maximumHeight The maximum terrain height within the tile, in meters above the ellipsoid.
  31. * @param {BoundingSphere} options.boundingSphere A sphere bounding all of the vertices in the mesh.
  32. * @param {OrientedBoundingBox} [options.orientedBoundingBox] An OrientedBoundingBox bounding all of the vertices in the mesh.
  33. * @param {Cartesian3} options.horizonOcclusionPoint The horizon occlusion point of the mesh. If this point
  34. * is below the horizon, the entire tile is assumed to be below the horizon as well.
  35. * The point is expressed in ellipsoid-scaled coordinates.
  36. * @param {Number[]} options.westIndices The indices of the vertices on the western edge of the tile.
  37. * @param {Number[]} options.southIndices The indices of the vertices on the southern edge of the tile.
  38. * @param {Number[]} options.eastIndices The indices of the vertices on the eastern edge of the tile.
  39. * @param {Number[]} options.northIndices The indices of the vertices on the northern edge of the tile.
  40. * @param {Number} options.westSkirtHeight The height of the skirt to add on the western edge of the tile.
  41. * @param {Number} options.southSkirtHeight The height of the skirt to add on the southern edge of the tile.
  42. * @param {Number} options.eastSkirtHeight The height of the skirt to add on the eastern edge of the tile.
  43. * @param {Number} options.northSkirtHeight The height of the skirt to add on the northern edge of the tile.
  44. * @param {Number} [options.childTileMask=15] A bit mask indicating which of this tile's four children exist.
  45. * If a child's bit is set, geometry will be requested for that tile as well when it
  46. * is needed. If the bit is cleared, the child tile is not requested and geometry is
  47. * instead upsampled from the parent. The bit values are as follows:
  48. * <table>
  49. * <tr><th>Bit Position</th><th>Bit Value</th><th>Child Tile</th></tr>
  50. * <tr><td>0</td><td>1</td><td>Southwest</td></tr>
  51. * <tr><td>1</td><td>2</td><td>Southeast</td></tr>
  52. * <tr><td>2</td><td>4</td><td>Northwest</td></tr>
  53. * <tr><td>3</td><td>8</td><td>Northeast</td></tr>
  54. * </table>
  55. * @param {Boolean} [options.createdByUpsampling=false] True if this instance was created by upsampling another instance;
  56. * otherwise, false.
  57. * @param {Uint8Array} [options.encodedNormals] The buffer containing per vertex normals, encoded using 'oct' encoding
  58. * @param {Uint8Array} [options.waterMask] The buffer containing the watermask.
  59. * @param {Credit[]} [options.credits] Array of credits for this tile.
  60. *
  61. *
  62. * @example
  63. * var data = new Cesium.QuantizedMeshTerrainData({
  64. * minimumHeight : -100,
  65. * maximumHeight : 2101,
  66. * quantizedVertices : new Uint16Array([// order is SW NW SE NE
  67. * // longitude
  68. * 0, 0, 32767, 32767,
  69. * // latitude
  70. * 0, 32767, 0, 32767,
  71. * // heights
  72. * 16384, 0, 32767, 16384]),
  73. * indices : new Uint16Array([0, 3, 1,
  74. * 0, 2, 3]),
  75. * boundingSphere : new Cesium.BoundingSphere(new Cesium.Cartesian3(1.0, 2.0, 3.0), 10000),
  76. * orientedBoundingBox : new Cesium.OrientedBoundingBox(new Cesium.Cartesian3(1.0, 2.0, 3.0), Cesium.Matrix3.fromRotationX(Cesium.Math.PI, new Cesium.Matrix3())),
  77. * horizonOcclusionPoint : new Cesium.Cartesian3(3.0, 2.0, 1.0),
  78. * westIndices : [0, 1],
  79. * southIndices : [0, 1],
  80. * eastIndices : [2, 3],
  81. * northIndices : [1, 3],
  82. * westSkirtHeight : 1.0,
  83. * southSkirtHeight : 1.0,
  84. * eastSkirtHeight : 1.0,
  85. * northSkirtHeight : 1.0
  86. * });
  87. *
  88. * @see TerrainData
  89. * @see HeightmapTerrainData
  90. * @see GoogleEarthEnterpriseTerrainData
  91. */
  92. function QuantizedMeshTerrainData(options) {
  93. //>>includeStart('debug', pragmas.debug)
  94. if (!defined(options) || !defined(options.quantizedVertices)) {
  95. throw new DeveloperError("options.quantizedVertices is required.");
  96. }
  97. if (!defined(options.indices)) {
  98. throw new DeveloperError("options.indices is required.");
  99. }
  100. if (!defined(options.minimumHeight)) {
  101. throw new DeveloperError("options.minimumHeight is required.");
  102. }
  103. if (!defined(options.maximumHeight)) {
  104. throw new DeveloperError("options.maximumHeight is required.");
  105. }
  106. if (!defined(options.maximumHeight)) {
  107. throw new DeveloperError("options.maximumHeight is required.");
  108. }
  109. if (!defined(options.boundingSphere)) {
  110. throw new DeveloperError("options.boundingSphere is required.");
  111. }
  112. if (!defined(options.horizonOcclusionPoint)) {
  113. throw new DeveloperError("options.horizonOcclusionPoint is required.");
  114. }
  115. if (!defined(options.westIndices)) {
  116. throw new DeveloperError("options.westIndices is required.");
  117. }
  118. if (!defined(options.southIndices)) {
  119. throw new DeveloperError("options.southIndices is required.");
  120. }
  121. if (!defined(options.eastIndices)) {
  122. throw new DeveloperError("options.eastIndices is required.");
  123. }
  124. if (!defined(options.northIndices)) {
  125. throw new DeveloperError("options.northIndices is required.");
  126. }
  127. if (!defined(options.westSkirtHeight)) {
  128. throw new DeveloperError("options.westSkirtHeight is required.");
  129. }
  130. if (!defined(options.southSkirtHeight)) {
  131. throw new DeveloperError("options.southSkirtHeight is required.");
  132. }
  133. if (!defined(options.eastSkirtHeight)) {
  134. throw new DeveloperError("options.eastSkirtHeight is required.");
  135. }
  136. if (!defined(options.northSkirtHeight)) {
  137. throw new DeveloperError("options.northSkirtHeight is required.");
  138. }
  139. //>>includeEnd('debug');
  140. this._quantizedVertices = options.quantizedVertices;
  141. this._encodedNormals = options.encodedNormals;
  142. this._indices = options.indices;
  143. this._minimumHeight = options.minimumHeight;
  144. this._maximumHeight = options.maximumHeight;
  145. this._boundingSphere = options.boundingSphere;
  146. this._orientedBoundingBox = options.orientedBoundingBox;
  147. this._horizonOcclusionPoint = options.horizonOcclusionPoint;
  148. this._credits = options.credits;
  149. var vertexCount = this._quantizedVertices.length / 3;
  150. var uValues = (this._uValues = this._quantizedVertices.subarray(
  151. 0,
  152. vertexCount
  153. ));
  154. var vValues = (this._vValues = this._quantizedVertices.subarray(
  155. vertexCount,
  156. 2 * vertexCount
  157. ));
  158. this._heightValues = this._quantizedVertices.subarray(
  159. 2 * vertexCount,
  160. 3 * vertexCount
  161. );
  162. // We don't assume that we can count on the edge vertices being sorted by u or v.
  163. function sortByV(a, b) {
  164. return vValues[a] - vValues[b];
  165. }
  166. function sortByU(a, b) {
  167. return uValues[a] - uValues[b];
  168. }
  169. this._westIndices = sortIndicesIfNecessary(
  170. options.westIndices,
  171. sortByV,
  172. vertexCount
  173. );
  174. this._southIndices = sortIndicesIfNecessary(
  175. options.southIndices,
  176. sortByU,
  177. vertexCount
  178. );
  179. this._eastIndices = sortIndicesIfNecessary(
  180. options.eastIndices,
  181. sortByV,
  182. vertexCount
  183. );
  184. this._northIndices = sortIndicesIfNecessary(
  185. options.northIndices,
  186. sortByU,
  187. vertexCount
  188. );
  189. this._westSkirtHeight = options.westSkirtHeight;
  190. this._southSkirtHeight = options.southSkirtHeight;
  191. this._eastSkirtHeight = options.eastSkirtHeight;
  192. this._northSkirtHeight = options.northSkirtHeight;
  193. this._childTileMask = defaultValue(options.childTileMask, 15);
  194. this._createdByUpsampling = defaultValue(options.createdByUpsampling, false);
  195. this._waterMask = options.waterMask;
  196. this._mesh = undefined;
  197. }
  198. Object.defineProperties(QuantizedMeshTerrainData.prototype, {
  199. /**
  200. * An array of credits for this tile.
  201. * @memberof QuantizedMeshTerrainData.prototype
  202. * @type {Credit[]}
  203. */
  204. credits: {
  205. get: function () {
  206. return this._credits;
  207. },
  208. },
  209. /**
  210. * The water mask included in this terrain data, if any. A water mask is a rectangular
  211. * Uint8Array or image where a value of 255 indicates water and a value of 0 indicates land.
  212. * Values in between 0 and 255 are allowed as well to smoothly blend between land and water.
  213. * @memberof QuantizedMeshTerrainData.prototype
  214. * @type {Uint8Array|HTMLImageElement|HTMLCanvasElement}
  215. */
  216. waterMask: {
  217. get: function () {
  218. return this._waterMask;
  219. },
  220. },
  221. childTileMask: {
  222. get: function () {
  223. return this._childTileMask;
  224. },
  225. },
  226. canUpsample: {
  227. get: function () {
  228. return defined(this._mesh);
  229. },
  230. },
  231. });
  232. var arrayScratch = [];
  233. function sortIndicesIfNecessary(indices, sortFunction, vertexCount) {
  234. arrayScratch.length = indices.length;
  235. var needsSort = false;
  236. for (var i = 0, len = indices.length; i < len; ++i) {
  237. arrayScratch[i] = indices[i];
  238. needsSort =
  239. needsSort || (i > 0 && sortFunction(indices[i - 1], indices[i]) > 0);
  240. }
  241. if (needsSort) {
  242. arrayScratch.sort(sortFunction);
  243. return IndexDatatype.createTypedArray(vertexCount, arrayScratch);
  244. }
  245. return indices;
  246. }
  247. var createMeshTaskProcessor = new TaskProcessor(
  248. "createVerticesFromQuantizedTerrainMesh"
  249. );
  250. /**
  251. * Creates a {@link TerrainMesh} from this terrain data.
  252. *
  253. * @private
  254. *
  255. * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
  256. * @param {Number} x The X coordinate of the tile for which to create the terrain data.
  257. * @param {Number} y The Y coordinate of the tile for which to create the terrain data.
  258. * @param {Number} level The level of the tile for which to create the terrain data.
  259. * @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
  260. * @returns {Promise.<TerrainMesh>|undefined} A promise for the terrain mesh, or undefined if too many
  261. * asynchronous mesh creations are already in progress and the operation should
  262. * be retried later.
  263. */
  264. QuantizedMeshTerrainData.prototype.createMesh = function (
  265. tilingScheme,
  266. x,
  267. y,
  268. level,
  269. exaggeration
  270. ) {
  271. //>>includeStart('debug', pragmas.debug);
  272. if (!defined(tilingScheme)) {
  273. throw new DeveloperError("tilingScheme is required.");
  274. }
  275. if (!defined(x)) {
  276. throw new DeveloperError("x is required.");
  277. }
  278. if (!defined(y)) {
  279. throw new DeveloperError("y is required.");
  280. }
  281. if (!defined(level)) {
  282. throw new DeveloperError("level is required.");
  283. }
  284. //>>includeEnd('debug');
  285. var ellipsoid = tilingScheme.ellipsoid;
  286. var rectangle = tilingScheme.tileXYToRectangle(x, y, level);
  287. exaggeration = defaultValue(exaggeration, 1.0);
  288. var verticesPromise = createMeshTaskProcessor.scheduleTask({
  289. minimumHeight: this._minimumHeight,
  290. maximumHeight: this._maximumHeight,
  291. quantizedVertices: this._quantizedVertices,
  292. octEncodedNormals: this._encodedNormals,
  293. includeWebMercatorT: true,
  294. indices: this._indices,
  295. westIndices: this._westIndices,
  296. southIndices: this._southIndices,
  297. eastIndices: this._eastIndices,
  298. northIndices: this._northIndices,
  299. westSkirtHeight: this._westSkirtHeight,
  300. southSkirtHeight: this._southSkirtHeight,
  301. eastSkirtHeight: this._eastSkirtHeight,
  302. northSkirtHeight: this._northSkirtHeight,
  303. rectangle: rectangle,
  304. relativeToCenter: this._boundingSphere.center,
  305. ellipsoid: ellipsoid,
  306. exaggeration: exaggeration,
  307. });
  308. if (!defined(verticesPromise)) {
  309. // Postponed
  310. return undefined;
  311. }
  312. var that = this;
  313. return when(verticesPromise, function (result) {
  314. var vertexCountWithoutSkirts = that._quantizedVertices.length / 3;
  315. var vertexCount =
  316. vertexCountWithoutSkirts +
  317. that._westIndices.length +
  318. that._southIndices.length +
  319. that._eastIndices.length +
  320. that._northIndices.length;
  321. var indicesTypedArray = IndexDatatype.createTypedArray(
  322. vertexCount,
  323. result.indices
  324. );
  325. var vertices = new Float32Array(result.vertices);
  326. var rtc = result.center;
  327. var minimumHeight = result.minimumHeight;
  328. var maximumHeight = result.maximumHeight;
  329. var boundingSphere = defaultValue(
  330. BoundingSphere.clone(result.boundingSphere),
  331. that._boundingSphere
  332. );
  333. var obb = defaultValue(
  334. OrientedBoundingBox.clone(result.orientedBoundingBox),
  335. that._orientedBoundingBox
  336. );
  337. var occludeePointInScaledSpace = defaultValue(
  338. Cartesian3.clone(result.occludeePointInScaledSpace),
  339. that._horizonOcclusionPoint
  340. );
  341. var stride = result.vertexStride;
  342. var terrainEncoding = TerrainEncoding.clone(result.encoding);
  343. // Clone complex result objects because the transfer from the web worker
  344. // has stripped them down to JSON-style objects.
  345. that._mesh = new TerrainMesh(
  346. rtc,
  347. vertices,
  348. indicesTypedArray,
  349. result.indexCountWithoutSkirts,
  350. vertexCountWithoutSkirts,
  351. minimumHeight,
  352. maximumHeight,
  353. boundingSphere,
  354. occludeePointInScaledSpace,
  355. stride,
  356. obb,
  357. terrainEncoding,
  358. exaggeration,
  359. result.westIndicesSouthToNorth,
  360. result.southIndicesEastToWest,
  361. result.eastIndicesNorthToSouth,
  362. result.northIndicesWestToEast
  363. );
  364. // Free memory received from server after mesh is created.
  365. that._quantizedVertices = undefined;
  366. that._encodedNormals = undefined;
  367. that._indices = undefined;
  368. that._uValues = undefined;
  369. that._vValues = undefined;
  370. that._heightValues = undefined;
  371. that._westIndices = undefined;
  372. that._southIndices = undefined;
  373. that._eastIndices = undefined;
  374. that._northIndices = undefined;
  375. return that._mesh;
  376. });
  377. };
  378. var upsampleTaskProcessor = new TaskProcessor("upsampleQuantizedTerrainMesh");
  379. /**
  380. * Upsamples this terrain data for use by a descendant tile. The resulting instance will contain a subset of the
  381. * vertices in this instance, interpolated if necessary.
  382. *
  383. * @param {TilingScheme} tilingScheme The tiling scheme of this terrain data.
  384. * @param {Number} thisX The X coordinate of this tile in the tiling scheme.
  385. * @param {Number} thisY The Y coordinate of this tile in the tiling scheme.
  386. * @param {Number} thisLevel The level of this tile in the tiling scheme.
  387. * @param {Number} descendantX The X coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  388. * @param {Number} descendantY The Y coordinate within the tiling scheme of the descendant tile for which we are upsampling.
  389. * @param {Number} descendantLevel The level within the tiling scheme of the descendant tile for which we are upsampling.
  390. * @returns {Promise.<QuantizedMeshTerrainData>|undefined} A promise for upsampled heightmap terrain data for the descendant tile,
  391. * or undefined if too many asynchronous upsample operations are in progress and the request has been
  392. * deferred.
  393. */
  394. QuantizedMeshTerrainData.prototype.upsample = function (
  395. tilingScheme,
  396. thisX,
  397. thisY,
  398. thisLevel,
  399. descendantX,
  400. descendantY,
  401. descendantLevel
  402. ) {
  403. //>>includeStart('debug', pragmas.debug);
  404. if (!defined(tilingScheme)) {
  405. throw new DeveloperError("tilingScheme is required.");
  406. }
  407. if (!defined(thisX)) {
  408. throw new DeveloperError("thisX is required.");
  409. }
  410. if (!defined(thisY)) {
  411. throw new DeveloperError("thisY is required.");
  412. }
  413. if (!defined(thisLevel)) {
  414. throw new DeveloperError("thisLevel is required.");
  415. }
  416. if (!defined(descendantX)) {
  417. throw new DeveloperError("descendantX is required.");
  418. }
  419. if (!defined(descendantY)) {
  420. throw new DeveloperError("descendantY is required.");
  421. }
  422. if (!defined(descendantLevel)) {
  423. throw new DeveloperError("descendantLevel is required.");
  424. }
  425. var levelDifference = descendantLevel - thisLevel;
  426. if (levelDifference > 1) {
  427. throw new DeveloperError(
  428. "Upsampling through more than one level at a time is not currently supported."
  429. );
  430. }
  431. //>>includeEnd('debug');
  432. var mesh = this._mesh;
  433. if (!defined(this._mesh)) {
  434. return undefined;
  435. }
  436. var isEastChild = thisX * 2 !== descendantX;
  437. var isNorthChild = thisY * 2 === descendantY;
  438. var ellipsoid = tilingScheme.ellipsoid;
  439. var childRectangle = tilingScheme.tileXYToRectangle(
  440. descendantX,
  441. descendantY,
  442. descendantLevel
  443. );
  444. var upsamplePromise = upsampleTaskProcessor.scheduleTask({
  445. vertices: mesh.vertices,
  446. vertexCountWithoutSkirts: mesh.vertexCountWithoutSkirts,
  447. indices: mesh.indices,
  448. indexCountWithoutSkirts: mesh.indexCountWithoutSkirts,
  449. encoding: mesh.encoding,
  450. minimumHeight: this._minimumHeight,
  451. maximumHeight: this._maximumHeight,
  452. isEastChild: isEastChild,
  453. isNorthChild: isNorthChild,
  454. childRectangle: childRectangle,
  455. ellipsoid: ellipsoid,
  456. exaggeration: mesh.exaggeration,
  457. });
  458. if (!defined(upsamplePromise)) {
  459. // Postponed
  460. return undefined;
  461. }
  462. var shortestSkirt = Math.min(this._westSkirtHeight, this._eastSkirtHeight);
  463. shortestSkirt = Math.min(shortestSkirt, this._southSkirtHeight);
  464. shortestSkirt = Math.min(shortestSkirt, this._northSkirtHeight);
  465. var westSkirtHeight = isEastChild
  466. ? shortestSkirt * 0.5
  467. : this._westSkirtHeight;
  468. var southSkirtHeight = isNorthChild
  469. ? shortestSkirt * 0.5
  470. : this._southSkirtHeight;
  471. var eastSkirtHeight = isEastChild
  472. ? this._eastSkirtHeight
  473. : shortestSkirt * 0.5;
  474. var northSkirtHeight = isNorthChild
  475. ? this._northSkirtHeight
  476. : shortestSkirt * 0.5;
  477. var credits = this._credits;
  478. return when(upsamplePromise).then(function (result) {
  479. var quantizedVertices = new Uint16Array(result.vertices);
  480. var indicesTypedArray = IndexDatatype.createTypedArray(
  481. quantizedVertices.length / 3,
  482. result.indices
  483. );
  484. var encodedNormals;
  485. if (defined(result.encodedNormals)) {
  486. encodedNormals = new Uint8Array(result.encodedNormals);
  487. }
  488. return new QuantizedMeshTerrainData({
  489. quantizedVertices: quantizedVertices,
  490. indices: indicesTypedArray,
  491. encodedNormals: encodedNormals,
  492. minimumHeight: result.minimumHeight,
  493. maximumHeight: result.maximumHeight,
  494. boundingSphere: BoundingSphere.clone(result.boundingSphere),
  495. orientedBoundingBox: OrientedBoundingBox.clone(
  496. result.orientedBoundingBox
  497. ),
  498. horizonOcclusionPoint: Cartesian3.clone(result.horizonOcclusionPoint),
  499. westIndices: result.westIndices,
  500. southIndices: result.southIndices,
  501. eastIndices: result.eastIndices,
  502. northIndices: result.northIndices,
  503. westSkirtHeight: westSkirtHeight,
  504. southSkirtHeight: southSkirtHeight,
  505. eastSkirtHeight: eastSkirtHeight,
  506. northSkirtHeight: northSkirtHeight,
  507. childTileMask: 0,
  508. credits: credits,
  509. createdByUpsampling: true,
  510. });
  511. });
  512. };
  513. var maxShort = 32767;
  514. var barycentricCoordinateScratch = new Cartesian3();
  515. /**
  516. * Computes the terrain height at a specified longitude and latitude.
  517. *
  518. * @param {Rectangle} rectangle The rectangle covered by this terrain data.
  519. * @param {Number} longitude The longitude in radians.
  520. * @param {Number} latitude The latitude in radians.
  521. * @returns {Number} The terrain height at the specified position. The position is clamped to
  522. * the rectangle, so expect incorrect results for positions far outside the rectangle.
  523. */
  524. QuantizedMeshTerrainData.prototype.interpolateHeight = function (
  525. rectangle,
  526. longitude,
  527. latitude
  528. ) {
  529. var u = CesiumMath.clamp(
  530. (longitude - rectangle.west) / rectangle.width,
  531. 0.0,
  532. 1.0
  533. );
  534. u *= maxShort;
  535. var v = CesiumMath.clamp(
  536. (latitude - rectangle.south) / rectangle.height,
  537. 0.0,
  538. 1.0
  539. );
  540. v *= maxShort;
  541. if (!defined(this._mesh)) {
  542. return interpolateHeight(this, u, v);
  543. }
  544. return interpolateMeshHeight(this, u, v);
  545. };
  546. function pointInBoundingBox(u, v, u0, v0, u1, v1, u2, v2) {
  547. var minU = Math.min(u0, u1, u2);
  548. var maxU = Math.max(u0, u1, u2);
  549. var minV = Math.min(v0, v1, v2);
  550. var maxV = Math.max(v0, v1, v2);
  551. return u >= minU && u <= maxU && v >= minV && v <= maxV;
  552. }
  553. var texCoordScratch0 = new Cartesian2();
  554. var texCoordScratch1 = new Cartesian2();
  555. var texCoordScratch2 = new Cartesian2();
  556. function interpolateMeshHeight(terrainData, u, v) {
  557. var mesh = terrainData._mesh;
  558. var vertices = mesh.vertices;
  559. var encoding = mesh.encoding;
  560. var indices = mesh.indices;
  561. for (var i = 0, len = indices.length; i < len; i += 3) {
  562. var i0 = indices[i];
  563. var i1 = indices[i + 1];
  564. var i2 = indices[i + 2];
  565. var uv0 = encoding.decodeTextureCoordinates(vertices, i0, texCoordScratch0);
  566. var uv1 = encoding.decodeTextureCoordinates(vertices, i1, texCoordScratch1);
  567. var uv2 = encoding.decodeTextureCoordinates(vertices, i2, texCoordScratch2);
  568. if (pointInBoundingBox(u, v, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y)) {
  569. var barycentric = Intersections2D.computeBarycentricCoordinates(
  570. u,
  571. v,
  572. uv0.x,
  573. uv0.y,
  574. uv1.x,
  575. uv1.y,
  576. uv2.x,
  577. uv2.y,
  578. barycentricCoordinateScratch
  579. );
  580. if (
  581. barycentric.x >= -1e-15 &&
  582. barycentric.y >= -1e-15 &&
  583. barycentric.z >= -1e-15
  584. ) {
  585. var h0 = encoding.decodeHeight(vertices, i0);
  586. var h1 = encoding.decodeHeight(vertices, i1);
  587. var h2 = encoding.decodeHeight(vertices, i2);
  588. return barycentric.x * h0 + barycentric.y * h1 + barycentric.z * h2;
  589. }
  590. }
  591. }
  592. // Position does not lie in any triangle in this mesh.
  593. return undefined;
  594. }
  595. function interpolateHeight(terrainData, u, v) {
  596. var uBuffer = terrainData._uValues;
  597. var vBuffer = terrainData._vValues;
  598. var heightBuffer = terrainData._heightValues;
  599. var indices = terrainData._indices;
  600. for (var i = 0, len = indices.length; i < len; i += 3) {
  601. var i0 = indices[i];
  602. var i1 = indices[i + 1];
  603. var i2 = indices[i + 2];
  604. var u0 = uBuffer[i0];
  605. var u1 = uBuffer[i1];
  606. var u2 = uBuffer[i2];
  607. var v0 = vBuffer[i0];
  608. var v1 = vBuffer[i1];
  609. var v2 = vBuffer[i2];
  610. if (pointInBoundingBox(u, v, u0, v0, u1, v1, u2, v2)) {
  611. var barycentric = Intersections2D.computeBarycentricCoordinates(
  612. u,
  613. v,
  614. u0,
  615. v0,
  616. u1,
  617. v1,
  618. u2,
  619. v2,
  620. barycentricCoordinateScratch
  621. );
  622. if (
  623. barycentric.x >= -1e-15 &&
  624. barycentric.y >= -1e-15 &&
  625. barycentric.z >= -1e-15
  626. ) {
  627. var quantizedHeight =
  628. barycentric.x * heightBuffer[i0] +
  629. barycentric.y * heightBuffer[i1] +
  630. barycentric.z * heightBuffer[i2];
  631. return CesiumMath.lerp(
  632. terrainData._minimumHeight,
  633. terrainData._maximumHeight,
  634. quantizedHeight / maxShort
  635. );
  636. }
  637. }
  638. }
  639. // Position does not lie in any triangle in this mesh.
  640. return undefined;
  641. }
  642. /**
  643. * Determines if a given child tile is available, based on the
  644. * {@link HeightmapTerrainData.childTileMask}. The given child tile coordinates are assumed
  645. * to be one of the four children of this tile. If non-child tile coordinates are
  646. * given, the availability of the southeast child tile is returned.
  647. *
  648. * @param {Number} thisX The tile X coordinate of this (the parent) tile.
  649. * @param {Number} thisY The tile Y coordinate of this (the parent) tile.
  650. * @param {Number} childX The tile X coordinate of the child tile to check for availability.
  651. * @param {Number} childY The tile Y coordinate of the child tile to check for availability.
  652. * @returns {Boolean} True if the child tile is available; otherwise, false.
  653. */
  654. QuantizedMeshTerrainData.prototype.isChildAvailable = function (
  655. thisX,
  656. thisY,
  657. childX,
  658. childY
  659. ) {
  660. //>>includeStart('debug', pragmas.debug);
  661. if (!defined(thisX)) {
  662. throw new DeveloperError("thisX is required.");
  663. }
  664. if (!defined(thisY)) {
  665. throw new DeveloperError("thisY is required.");
  666. }
  667. if (!defined(childX)) {
  668. throw new DeveloperError("childX is required.");
  669. }
  670. if (!defined(childY)) {
  671. throw new DeveloperError("childY is required.");
  672. }
  673. //>>includeEnd('debug');
  674. var bitNumber = 2; // northwest child
  675. if (childX !== thisX * 2) {
  676. ++bitNumber; // east child
  677. }
  678. if (childY !== thisY * 2) {
  679. bitNumber -= 2; // south child
  680. }
  681. return (this._childTileMask & (1 << bitNumber)) !== 0;
  682. };
  683. /**
  684. * Gets a value indicating whether or not this terrain data was created by upsampling lower resolution
  685. * terrain data. If this value is false, the data was obtained from some other source, such
  686. * as by downloading it from a remote server. This method should return true for instances
  687. * returned from a call to {@link HeightmapTerrainData#upsample}.
  688. *
  689. * @returns {Boolean} True if this instance was created by upsampling; otherwise, false.
  690. */
  691. QuantizedMeshTerrainData.prototype.wasCreatedByUpsampling = function () {
  692. return this._createdByUpsampling;
  693. };
  694. export default QuantizedMeshTerrainData;