TerrainFillMesh.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183
  1. import AttributeCompression from "../Core/AttributeCompression.js";
  2. import binarySearch from "../Core/binarySearch.js";
  3. import BoundingSphere from "../Core/BoundingSphere.js";
  4. import Cartesian2 from "../Core/Cartesian2.js";
  5. import Cartesian3 from "../Core/Cartesian3.js";
  6. import Cartesian4 from "../Core/Cartesian4.js";
  7. import Cartographic from "../Core/Cartographic.js";
  8. import defined from "../Core/defined.js";
  9. import DeveloperError from "../Core/DeveloperError.js";
  10. import HeightmapTerrainData from "../Core/HeightmapTerrainData.js";
  11. import CesiumMath from "../Core/Math.js";
  12. import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";
  13. import Queue from "../Core/Queue.js";
  14. import Rectangle from "../Core/Rectangle.js";
  15. import TerrainEncoding from "../Core/TerrainEncoding.js";
  16. import TerrainMesh from "../Core/TerrainMesh.js";
  17. import TileEdge from "../Core/TileEdge.js";
  18. import WebMercatorProjection from "../Core/WebMercatorProjection.js";
  19. import GlobeSurfaceTile from "./GlobeSurfaceTile.js";
  20. import TileSelectionResult from "./TileSelectionResult.js";
  21. function TerrainFillMesh(tile) {
  22. this.tile = tile;
  23. this.frameLastUpdated = undefined;
  24. this.westMeshes = []; // north to south (CCW)
  25. this.westTiles = [];
  26. this.southMeshes = []; // west to east (CCW)
  27. this.southTiles = [];
  28. this.eastMeshes = []; // south to north (CCW)
  29. this.eastTiles = [];
  30. this.northMeshes = []; // east to west (CCW)
  31. this.northTiles = [];
  32. this.southwestMesh = undefined;
  33. this.southwestTile = undefined;
  34. this.southeastMesh = undefined;
  35. this.southeastTile = undefined;
  36. this.northwestMesh = undefined;
  37. this.northwestTile = undefined;
  38. this.northeastMesh = undefined;
  39. this.northeastTile = undefined;
  40. this.changedThisFrame = true;
  41. this.visitedFrame = undefined;
  42. this.enqueuedFrame = undefined;
  43. this.mesh = undefined;
  44. this.vertexArray = undefined;
  45. this.waterMaskTexture = undefined;
  46. this.waterMaskTranslationAndScale = new Cartesian4();
  47. }
  48. TerrainFillMesh.prototype.update = function (
  49. tileProvider,
  50. frameState,
  51. vertexArraysToDestroy
  52. ) {
  53. if (this.changedThisFrame) {
  54. createFillMesh(tileProvider, frameState, this.tile, vertexArraysToDestroy);
  55. this.changedThisFrame = false;
  56. }
  57. };
  58. TerrainFillMesh.prototype.destroy = function (vertexArraysToDestroy) {
  59. if (defined(this.vertexArray)) {
  60. if (defined(vertexArraysToDestroy)) {
  61. vertexArraysToDestroy.push(this.vertexArray);
  62. } else {
  63. GlobeSurfaceTile._freeVertexArray(
  64. this.vertexArray,
  65. vertexArraysToDestroy
  66. );
  67. }
  68. this.vertexArray = undefined;
  69. }
  70. if (defined(this.waterMaskTexture)) {
  71. --this.waterMaskTexture.referenceCount;
  72. if (this.waterMaskTexture.referenceCount === 0) {
  73. this.waterMaskTexture.destroy();
  74. }
  75. this.waterMaskTexture = undefined;
  76. }
  77. return undefined;
  78. };
  79. var traversalQueueScratch = new Queue();
  80. TerrainFillMesh.updateFillTiles = function (
  81. tileProvider,
  82. renderedTiles,
  83. frameState,
  84. vertexArraysToDestroy
  85. ) {
  86. // We want our fill tiles to look natural, which means they should align perfectly with
  87. // adjacent loaded tiles, and their edges that are not adjacent to loaded tiles should have
  88. // sensible heights (e.g. the average of the heights of loaded edges). Some fill tiles may
  89. // be adjacent only to other fill tiles, and in that case heights should be assigned fanning
  90. // outward from the loaded tiles so that there are no sudden changes in height.
  91. // We do this with a breadth-first traversal of the rendered tiles, starting with the loaded
  92. // ones. Graph nodes are tiles and graph edges connect to other rendered tiles that are spatially adjacent
  93. // to those tiles. As we visit each node, we propagate tile edges to adjacent tiles. If there's no data
  94. // for a tile edge, we create an edge with an average height and then propagate it. If an edge is partially defined
  95. // (e.g. an edge is adjacent to multiple more-detailed tiles and only some of them are loaded), we
  96. // fill in the rest of the edge with the same height.
  97. var quadtree = tileProvider._quadtree;
  98. var levelZeroTiles = quadtree._levelZeroTiles;
  99. var lastSelectionFrameNumber = quadtree._lastSelectionFrameNumber;
  100. var traversalQueue = traversalQueueScratch;
  101. traversalQueue.clear();
  102. // Add the tiles with real geometry to the traversal queue.
  103. for (var i = 0; i < renderedTiles.length; ++i) {
  104. var renderedTile = renderedTiles[i];
  105. if (defined(renderedTile.data.vertexArray)) {
  106. traversalQueue.enqueue(renderedTiles[i]);
  107. }
  108. }
  109. var tile = traversalQueue.dequeue();
  110. while (tile !== undefined) {
  111. var tileToWest = tile.findTileToWest(levelZeroTiles);
  112. var tileToSouth = tile.findTileToSouth(levelZeroTiles);
  113. var tileToEast = tile.findTileToEast(levelZeroTiles);
  114. var tileToNorth = tile.findTileToNorth(levelZeroTiles);
  115. visitRenderedTiles(
  116. tileProvider,
  117. frameState,
  118. tile,
  119. tileToWest,
  120. lastSelectionFrameNumber,
  121. TileEdge.EAST,
  122. false,
  123. traversalQueue,
  124. vertexArraysToDestroy
  125. );
  126. visitRenderedTiles(
  127. tileProvider,
  128. frameState,
  129. tile,
  130. tileToSouth,
  131. lastSelectionFrameNumber,
  132. TileEdge.NORTH,
  133. false,
  134. traversalQueue,
  135. vertexArraysToDestroy
  136. );
  137. visitRenderedTiles(
  138. tileProvider,
  139. frameState,
  140. tile,
  141. tileToEast,
  142. lastSelectionFrameNumber,
  143. TileEdge.WEST,
  144. false,
  145. traversalQueue,
  146. vertexArraysToDestroy
  147. );
  148. visitRenderedTiles(
  149. tileProvider,
  150. frameState,
  151. tile,
  152. tileToNorth,
  153. lastSelectionFrameNumber,
  154. TileEdge.SOUTH,
  155. false,
  156. traversalQueue,
  157. vertexArraysToDestroy
  158. );
  159. var tileToNorthwest = tileToWest.findTileToNorth(levelZeroTiles);
  160. var tileToSouthwest = tileToWest.findTileToSouth(levelZeroTiles);
  161. var tileToNortheast = tileToEast.findTileToNorth(levelZeroTiles);
  162. var tileToSoutheast = tileToEast.findTileToSouth(levelZeroTiles);
  163. visitRenderedTiles(
  164. tileProvider,
  165. frameState,
  166. tile,
  167. tileToNorthwest,
  168. lastSelectionFrameNumber,
  169. TileEdge.SOUTHEAST,
  170. false,
  171. traversalQueue,
  172. vertexArraysToDestroy
  173. );
  174. visitRenderedTiles(
  175. tileProvider,
  176. frameState,
  177. tile,
  178. tileToNortheast,
  179. lastSelectionFrameNumber,
  180. TileEdge.SOUTHWEST,
  181. false,
  182. traversalQueue,
  183. vertexArraysToDestroy
  184. );
  185. visitRenderedTiles(
  186. tileProvider,
  187. frameState,
  188. tile,
  189. tileToSouthwest,
  190. lastSelectionFrameNumber,
  191. TileEdge.NORTHEAST,
  192. false,
  193. traversalQueue,
  194. vertexArraysToDestroy
  195. );
  196. visitRenderedTiles(
  197. tileProvider,
  198. frameState,
  199. tile,
  200. tileToSoutheast,
  201. lastSelectionFrameNumber,
  202. TileEdge.NORTHWEST,
  203. false,
  204. traversalQueue,
  205. vertexArraysToDestroy
  206. );
  207. tile = traversalQueue.dequeue();
  208. }
  209. };
  210. function visitRenderedTiles(
  211. tileProvider,
  212. frameState,
  213. sourceTile,
  214. startTile,
  215. currentFrameNumber,
  216. tileEdge,
  217. downOnly,
  218. traversalQueue,
  219. vertexArraysToDestroy
  220. ) {
  221. if (startTile === undefined) {
  222. // There are no tiles North or South of the poles.
  223. return;
  224. }
  225. var tile = startTile;
  226. while (
  227. tile &&
  228. (tile._lastSelectionResultFrame !== currentFrameNumber ||
  229. TileSelectionResult.wasKicked(tile._lastSelectionResult) ||
  230. TileSelectionResult.originalResult(tile._lastSelectionResult) ===
  231. TileSelectionResult.CULLED)
  232. ) {
  233. // This tile wasn't visited or it was visited and then kicked, so walk up to find the closest ancestor that was rendered.
  234. // We also walk up if the tile was culled, because if siblings were kicked an ancestor may have been rendered.
  235. if (downOnly) {
  236. return;
  237. }
  238. var parent = tile.parent;
  239. if (tileEdge >= TileEdge.NORTHWEST && parent !== undefined) {
  240. // When we're looking for a corner, verify that the parent tile is still relevant.
  241. // That is, the parent and child must share the corner in question.
  242. switch (tileEdge) {
  243. case TileEdge.NORTHWEST:
  244. tile = tile === parent.northwestChild ? parent : undefined;
  245. break;
  246. case TileEdge.NORTHEAST:
  247. tile = tile === parent.northeastChild ? parent : undefined;
  248. break;
  249. case TileEdge.SOUTHWEST:
  250. tile = tile === parent.southwestChild ? parent : undefined;
  251. break;
  252. case TileEdge.SOUTHEAST:
  253. tile = tile === parent.southeastChild ? parent : undefined;
  254. break;
  255. }
  256. } else {
  257. tile = parent;
  258. }
  259. }
  260. if (tile === undefined) {
  261. return;
  262. }
  263. if (tile._lastSelectionResult === TileSelectionResult.RENDERED) {
  264. if (defined(tile.data.vertexArray)) {
  265. // No further processing necessary for renderable tiles.
  266. return;
  267. }
  268. visitTile(
  269. tileProvider,
  270. frameState,
  271. sourceTile,
  272. tile,
  273. tileEdge,
  274. currentFrameNumber,
  275. traversalQueue,
  276. vertexArraysToDestroy
  277. );
  278. return;
  279. }
  280. if (
  281. TileSelectionResult.originalResult(startTile._lastSelectionResult) ===
  282. TileSelectionResult.CULLED
  283. ) {
  284. return;
  285. }
  286. // This tile was refined, so find rendered children, if any.
  287. // Visit the tiles in counter-clockwise order.
  288. switch (tileEdge) {
  289. case TileEdge.WEST:
  290. visitRenderedTiles(
  291. tileProvider,
  292. frameState,
  293. sourceTile,
  294. startTile.northwestChild,
  295. currentFrameNumber,
  296. tileEdge,
  297. true,
  298. traversalQueue,
  299. vertexArraysToDestroy
  300. );
  301. visitRenderedTiles(
  302. tileProvider,
  303. frameState,
  304. sourceTile,
  305. startTile.southwestChild,
  306. currentFrameNumber,
  307. tileEdge,
  308. true,
  309. traversalQueue,
  310. vertexArraysToDestroy
  311. );
  312. break;
  313. case TileEdge.EAST:
  314. visitRenderedTiles(
  315. tileProvider,
  316. frameState,
  317. sourceTile,
  318. startTile.southeastChild,
  319. currentFrameNumber,
  320. tileEdge,
  321. true,
  322. traversalQueue,
  323. vertexArraysToDestroy
  324. );
  325. visitRenderedTiles(
  326. tileProvider,
  327. frameState,
  328. sourceTile,
  329. startTile.northeastChild,
  330. currentFrameNumber,
  331. tileEdge,
  332. true,
  333. traversalQueue,
  334. vertexArraysToDestroy
  335. );
  336. break;
  337. case TileEdge.SOUTH:
  338. visitRenderedTiles(
  339. tileProvider,
  340. frameState,
  341. sourceTile,
  342. startTile.southwestChild,
  343. currentFrameNumber,
  344. tileEdge,
  345. true,
  346. traversalQueue,
  347. vertexArraysToDestroy
  348. );
  349. visitRenderedTiles(
  350. tileProvider,
  351. frameState,
  352. sourceTile,
  353. startTile.southeastChild,
  354. currentFrameNumber,
  355. tileEdge,
  356. true,
  357. traversalQueue,
  358. vertexArraysToDestroy
  359. );
  360. break;
  361. case TileEdge.NORTH:
  362. visitRenderedTiles(
  363. tileProvider,
  364. frameState,
  365. sourceTile,
  366. startTile.northeastChild,
  367. currentFrameNumber,
  368. tileEdge,
  369. true,
  370. traversalQueue,
  371. vertexArraysToDestroy
  372. );
  373. visitRenderedTiles(
  374. tileProvider,
  375. frameState,
  376. sourceTile,
  377. startTile.northwestChild,
  378. currentFrameNumber,
  379. tileEdge,
  380. true,
  381. traversalQueue,
  382. vertexArraysToDestroy
  383. );
  384. break;
  385. case TileEdge.NORTHWEST:
  386. visitRenderedTiles(
  387. tileProvider,
  388. frameState,
  389. sourceTile,
  390. startTile.northwestChild,
  391. currentFrameNumber,
  392. tileEdge,
  393. true,
  394. traversalQueue,
  395. vertexArraysToDestroy
  396. );
  397. break;
  398. case TileEdge.NORTHEAST:
  399. visitRenderedTiles(
  400. tileProvider,
  401. frameState,
  402. sourceTile,
  403. startTile.northeastChild,
  404. currentFrameNumber,
  405. tileEdge,
  406. true,
  407. traversalQueue,
  408. vertexArraysToDestroy
  409. );
  410. break;
  411. case TileEdge.SOUTHWEST:
  412. visitRenderedTiles(
  413. tileProvider,
  414. frameState,
  415. sourceTile,
  416. startTile.southwestChild,
  417. currentFrameNumber,
  418. tileEdge,
  419. true,
  420. traversalQueue,
  421. vertexArraysToDestroy
  422. );
  423. break;
  424. case TileEdge.SOUTHEAST:
  425. visitRenderedTiles(
  426. tileProvider,
  427. frameState,
  428. sourceTile,
  429. startTile.southeastChild,
  430. currentFrameNumber,
  431. tileEdge,
  432. true,
  433. traversalQueue,
  434. vertexArraysToDestroy
  435. );
  436. break;
  437. default:
  438. throw new DeveloperError("Invalid edge");
  439. }
  440. }
  441. function visitTile(
  442. tileProvider,
  443. frameState,
  444. sourceTile,
  445. destinationTile,
  446. tileEdge,
  447. frameNumber,
  448. traversalQueue,
  449. vertexArraysToDestroy
  450. ) {
  451. var destinationSurfaceTile = destinationTile.data;
  452. if (destinationSurfaceTile.fill === undefined) {
  453. destinationSurfaceTile.fill = new TerrainFillMesh(destinationTile);
  454. } else if (destinationSurfaceTile.fill.visitedFrame === frameNumber) {
  455. // Don't propagate edges to tiles that have already been visited this frame.
  456. return;
  457. }
  458. if (destinationSurfaceTile.fill.enqueuedFrame !== frameNumber) {
  459. // First time visiting this tile this frame, add it to the traversal queue.
  460. destinationSurfaceTile.fill.enqueuedFrame = frameNumber;
  461. destinationSurfaceTile.fill.changedThisFrame = false;
  462. traversalQueue.enqueue(destinationTile);
  463. }
  464. propagateEdge(
  465. tileProvider,
  466. frameState,
  467. sourceTile,
  468. destinationTile,
  469. tileEdge,
  470. vertexArraysToDestroy
  471. );
  472. }
  473. function propagateEdge(
  474. tileProvider,
  475. frameState,
  476. sourceTile,
  477. destinationTile,
  478. tileEdge,
  479. vertexArraysToDestroy
  480. ) {
  481. var destinationFill = destinationTile.data.fill;
  482. var sourceMesh;
  483. var sourceFill = sourceTile.data.fill;
  484. if (defined(sourceFill)) {
  485. sourceFill.visitedFrame = frameState.frameNumber;
  486. // Source is a fill, create/update it if necessary.
  487. if (sourceFill.changedThisFrame) {
  488. createFillMesh(
  489. tileProvider,
  490. frameState,
  491. sourceTile,
  492. vertexArraysToDestroy
  493. );
  494. sourceFill.changedThisFrame = false;
  495. }
  496. sourceMesh = sourceTile.data.fill.mesh;
  497. } else {
  498. sourceMesh = sourceTile.data.mesh;
  499. }
  500. var edgeMeshes;
  501. var edgeTiles;
  502. switch (tileEdge) {
  503. case TileEdge.WEST:
  504. edgeMeshes = destinationFill.westMeshes;
  505. edgeTiles = destinationFill.westTiles;
  506. break;
  507. case TileEdge.SOUTH:
  508. edgeMeshes = destinationFill.southMeshes;
  509. edgeTiles = destinationFill.southTiles;
  510. break;
  511. case TileEdge.EAST:
  512. edgeMeshes = destinationFill.eastMeshes;
  513. edgeTiles = destinationFill.eastTiles;
  514. break;
  515. case TileEdge.NORTH:
  516. edgeMeshes = destinationFill.northMeshes;
  517. edgeTiles = destinationFill.northTiles;
  518. break;
  519. // Corners are simpler.
  520. case TileEdge.NORTHWEST:
  521. destinationFill.changedThisFrame =
  522. destinationFill.changedThisFrame ||
  523. destinationFill.northwestMesh !== sourceMesh;
  524. destinationFill.northwestMesh = sourceMesh;
  525. destinationFill.northwestTile = sourceTile;
  526. return;
  527. case TileEdge.NORTHEAST:
  528. destinationFill.changedThisFrame =
  529. destinationFill.changedThisFrame ||
  530. destinationFill.northeastMesh !== sourceMesh;
  531. destinationFill.northeastMesh = sourceMesh;
  532. destinationFill.northeastTile = sourceTile;
  533. return;
  534. case TileEdge.SOUTHWEST:
  535. destinationFill.changedThisFrame =
  536. destinationFill.changedThisFrame ||
  537. destinationFill.southwestMesh !== sourceMesh;
  538. destinationFill.southwestMesh = sourceMesh;
  539. destinationFill.southwestTile = sourceTile;
  540. return;
  541. case TileEdge.SOUTHEAST:
  542. destinationFill.changedThisFrame =
  543. destinationFill.changedThisFrame ||
  544. destinationFill.southeastMesh !== sourceMesh;
  545. destinationFill.southeastMesh = sourceMesh;
  546. destinationFill.southeastTile = sourceTile;
  547. return;
  548. }
  549. if (sourceTile.level <= destinationTile.level) {
  550. // Source edge completely spans the destination edge.
  551. destinationFill.changedThisFrame =
  552. destinationFill.changedThisFrame ||
  553. edgeMeshes[0] !== sourceMesh ||
  554. edgeMeshes.length !== 1;
  555. edgeMeshes[0] = sourceMesh;
  556. edgeTiles[0] = sourceTile;
  557. edgeMeshes.length = 1;
  558. edgeTiles.length = 1;
  559. return;
  560. }
  561. // Source edge is a subset of the destination edge.
  562. // Figure out the range of meshes we're replacing.
  563. var startIndex, endIndex, existingTile, existingRectangle;
  564. var sourceRectangle = sourceTile.rectangle;
  565. var epsilon;
  566. var destinationRectangle = destinationTile.rectangle;
  567. switch (tileEdge) {
  568. case TileEdge.WEST:
  569. epsilon =
  570. (destinationRectangle.north - destinationRectangle.south) *
  571. CesiumMath.EPSILON5;
  572. for (startIndex = 0; startIndex < edgeTiles.length; ++startIndex) {
  573. existingTile = edgeTiles[startIndex];
  574. existingRectangle = existingTile.rectangle;
  575. if (
  576. CesiumMath.greaterThan(
  577. sourceRectangle.north,
  578. existingRectangle.south,
  579. epsilon
  580. )
  581. ) {
  582. break;
  583. }
  584. }
  585. for (endIndex = startIndex; endIndex < edgeTiles.length; ++endIndex) {
  586. existingTile = edgeTiles[endIndex];
  587. existingRectangle = existingTile.rectangle;
  588. if (
  589. CesiumMath.greaterThanOrEquals(
  590. sourceRectangle.south,
  591. existingRectangle.north,
  592. epsilon
  593. )
  594. ) {
  595. break;
  596. }
  597. }
  598. break;
  599. case TileEdge.SOUTH:
  600. epsilon =
  601. (destinationRectangle.east - destinationRectangle.west) *
  602. CesiumMath.EPSILON5;
  603. for (startIndex = 0; startIndex < edgeTiles.length; ++startIndex) {
  604. existingTile = edgeTiles[startIndex];
  605. existingRectangle = existingTile.rectangle;
  606. if (
  607. CesiumMath.lessThan(
  608. sourceRectangle.west,
  609. existingRectangle.east,
  610. epsilon
  611. )
  612. ) {
  613. break;
  614. }
  615. }
  616. for (endIndex = startIndex; endIndex < edgeTiles.length; ++endIndex) {
  617. existingTile = edgeTiles[endIndex];
  618. existingRectangle = existingTile.rectangle;
  619. if (
  620. CesiumMath.lessThanOrEquals(
  621. sourceRectangle.east,
  622. existingRectangle.west,
  623. epsilon
  624. )
  625. ) {
  626. break;
  627. }
  628. }
  629. break;
  630. case TileEdge.EAST:
  631. epsilon =
  632. (destinationRectangle.north - destinationRectangle.south) *
  633. CesiumMath.EPSILON5;
  634. for (startIndex = 0; startIndex < edgeTiles.length; ++startIndex) {
  635. existingTile = edgeTiles[startIndex];
  636. existingRectangle = existingTile.rectangle;
  637. if (
  638. CesiumMath.lessThan(
  639. sourceRectangle.south,
  640. existingRectangle.north,
  641. epsilon
  642. )
  643. ) {
  644. break;
  645. }
  646. }
  647. for (endIndex = startIndex; endIndex < edgeTiles.length; ++endIndex) {
  648. existingTile = edgeTiles[endIndex];
  649. existingRectangle = existingTile.rectangle;
  650. if (
  651. CesiumMath.lessThanOrEquals(
  652. sourceRectangle.north,
  653. existingRectangle.south,
  654. epsilon
  655. )
  656. ) {
  657. break;
  658. }
  659. }
  660. break;
  661. case TileEdge.NORTH:
  662. epsilon =
  663. (destinationRectangle.east - destinationRectangle.west) *
  664. CesiumMath.EPSILON5;
  665. for (startIndex = 0; startIndex < edgeTiles.length; ++startIndex) {
  666. existingTile = edgeTiles[startIndex];
  667. existingRectangle = existingTile.rectangle;
  668. if (
  669. CesiumMath.greaterThan(
  670. sourceRectangle.east,
  671. existingRectangle.west,
  672. epsilon
  673. )
  674. ) {
  675. break;
  676. }
  677. }
  678. for (endIndex = startIndex; endIndex < edgeTiles.length; ++endIndex) {
  679. existingTile = edgeTiles[endIndex];
  680. existingRectangle = existingTile.rectangle;
  681. if (
  682. CesiumMath.greaterThanOrEquals(
  683. sourceRectangle.west,
  684. existingRectangle.east,
  685. epsilon
  686. )
  687. ) {
  688. break;
  689. }
  690. }
  691. break;
  692. }
  693. if (endIndex - startIndex === 1) {
  694. destinationFill.changedThisFrame =
  695. destinationFill.changedThisFrame || edgeMeshes[startIndex] !== sourceMesh;
  696. edgeMeshes[startIndex] = sourceMesh;
  697. edgeTiles[startIndex] = sourceTile;
  698. } else {
  699. destinationFill.changedThisFrame = true;
  700. edgeMeshes.splice(startIndex, endIndex - startIndex, sourceMesh);
  701. edgeTiles.splice(startIndex, endIndex - startIndex, sourceTile);
  702. }
  703. }
  704. var cartographicScratch = new Cartographic();
  705. var centerCartographicScratch = new Cartographic();
  706. var cartesianScratch = new Cartesian3();
  707. var normalScratch = new Cartesian3();
  708. var octEncodedNormalScratch = new Cartesian2();
  709. var uvScratch2 = new Cartesian2();
  710. var uvScratch = new Cartesian2();
  711. function HeightAndNormal() {
  712. this.height = 0.0;
  713. this.encodedNormal = new Cartesian2();
  714. }
  715. function fillMissingCorner(
  716. fill,
  717. ellipsoid,
  718. u,
  719. v,
  720. corner,
  721. adjacentCorner1,
  722. adjacentCorner2,
  723. oppositeCorner,
  724. vertex
  725. ) {
  726. if (defined(corner)) {
  727. return corner;
  728. }
  729. var height;
  730. if (defined(adjacentCorner1) && defined(adjacentCorner2)) {
  731. height = (adjacentCorner1.height + adjacentCorner2.height) * 0.5;
  732. } else if (defined(adjacentCorner1)) {
  733. height = adjacentCorner1.height;
  734. } else if (defined(adjacentCorner2)) {
  735. height = adjacentCorner2.height;
  736. } else if (defined(oppositeCorner)) {
  737. height = oppositeCorner.height;
  738. } else {
  739. var surfaceTile = fill.tile.data;
  740. var tileBoundingRegion = surfaceTile.tileBoundingRegion;
  741. var minimumHeight = 0.0;
  742. var maximumHeight = 0.0;
  743. if (defined(tileBoundingRegion)) {
  744. minimumHeight = tileBoundingRegion.minimumHeight;
  745. maximumHeight = tileBoundingRegion.maximumHeight;
  746. }
  747. height = (minimumHeight + maximumHeight) * 0.5;
  748. }
  749. getVertexWithHeightAtCorner(fill, ellipsoid, u, v, height, vertex);
  750. return vertex;
  751. }
  752. var heightRangeScratch = {
  753. minimumHeight: 0.0,
  754. maximumHeight: 0.0,
  755. };
  756. var swVertexScratch = new HeightAndNormal();
  757. var seVertexScratch = new HeightAndNormal();
  758. var nwVertexScratch = new HeightAndNormal();
  759. var neVertexScratch = new HeightAndNormal();
  760. var heightmapBuffer =
  761. typeof Uint8Array !== "undefined" ? new Uint8Array(9 * 9) : undefined;
  762. function createFillMesh(tileProvider, frameState, tile, vertexArraysToDestroy) {
  763. GlobeSurfaceTile.initialize(
  764. tile,
  765. tileProvider.terrainProvider,
  766. tileProvider._imageryLayers
  767. );
  768. var surfaceTile = tile.data;
  769. var fill = surfaceTile.fill;
  770. var rectangle = tile.rectangle;
  771. var ellipsoid = tile.tilingScheme.ellipsoid;
  772. var nwCorner = getCorner(
  773. fill,
  774. ellipsoid,
  775. 0.0,
  776. 1.0,
  777. fill.northwestTile,
  778. fill.northwestMesh,
  779. fill.northTiles,
  780. fill.northMeshes,
  781. fill.westTiles,
  782. fill.westMeshes,
  783. nwVertexScratch
  784. );
  785. var swCorner = getCorner(
  786. fill,
  787. ellipsoid,
  788. 0.0,
  789. 0.0,
  790. fill.southwestTile,
  791. fill.southwestMesh,
  792. fill.westTiles,
  793. fill.westMeshes,
  794. fill.southTiles,
  795. fill.southMeshes,
  796. swVertexScratch
  797. );
  798. var seCorner = getCorner(
  799. fill,
  800. ellipsoid,
  801. 1.0,
  802. 0.0,
  803. fill.southeastTile,
  804. fill.southeastMesh,
  805. fill.southTiles,
  806. fill.southMeshes,
  807. fill.eastTiles,
  808. fill.eastMeshes,
  809. seVertexScratch
  810. );
  811. var neCorner = getCorner(
  812. fill,
  813. ellipsoid,
  814. 1.0,
  815. 1.0,
  816. fill.northeastTile,
  817. fill.northeastMesh,
  818. fill.eastTiles,
  819. fill.eastMeshes,
  820. fill.northTiles,
  821. fill.northMeshes,
  822. neVertexScratch
  823. );
  824. nwCorner = fillMissingCorner(
  825. fill,
  826. ellipsoid,
  827. 0.0,
  828. 1.0,
  829. nwCorner,
  830. swCorner,
  831. neCorner,
  832. seCorner,
  833. nwVertexScratch
  834. );
  835. swCorner = fillMissingCorner(
  836. fill,
  837. ellipsoid,
  838. 0.0,
  839. 0.0,
  840. swCorner,
  841. nwCorner,
  842. seCorner,
  843. neCorner,
  844. swVertexScratch
  845. );
  846. seCorner = fillMissingCorner(
  847. fill,
  848. ellipsoid,
  849. 1.0,
  850. 1.0,
  851. seCorner,
  852. swCorner,
  853. neCorner,
  854. nwCorner,
  855. seVertexScratch
  856. );
  857. neCorner = fillMissingCorner(
  858. fill,
  859. ellipsoid,
  860. 1.0,
  861. 1.0,
  862. neCorner,
  863. seCorner,
  864. nwCorner,
  865. swCorner,
  866. neVertexScratch
  867. );
  868. var southwestHeight = swCorner.height;
  869. var southeastHeight = seCorner.height;
  870. var northwestHeight = nwCorner.height;
  871. var northeastHeight = neCorner.height;
  872. var minimumHeight = Math.min(
  873. southwestHeight,
  874. southeastHeight,
  875. northwestHeight,
  876. northeastHeight
  877. );
  878. var maximumHeight = Math.max(
  879. southwestHeight,
  880. southeastHeight,
  881. northwestHeight,
  882. northeastHeight
  883. );
  884. var middleHeight = (minimumHeight + maximumHeight) * 0.5;
  885. var i;
  886. var len;
  887. // For low-detail tiles, our usual fill tile approach will create tiles that
  888. // look really blocky because they don't have enough vertices to account for the
  889. // Earth's curvature. But the height range will also typically be well within
  890. // the allowed geometric error for those levels. So fill such tiles with a
  891. // constant-height heightmap.
  892. var geometricError = tileProvider.getLevelMaximumGeometricError(tile.level);
  893. var minCutThroughRadius = ellipsoid.maximumRadius - geometricError;
  894. var maxTileWidth =
  895. Math.acos(minCutThroughRadius / ellipsoid.maximumRadius) * 4.0;
  896. // When the tile width is greater than maxTileWidth as computed above, the error
  897. // of a normal fill tile from globe curvature alone will exceed the allowed geometric
  898. // error. Terrain won't change that much. However, we can allow more error than that.
  899. // A little blockiness during load is acceptable. For the WGS84 ellipsoid and
  900. // standard geometric error setup, the value here will have us use a heightmap
  901. // at levels 1, 2, and 3.
  902. maxTileWidth *= 1.5;
  903. if (
  904. rectangle.width > maxTileWidth &&
  905. maximumHeight - minimumHeight <= geometricError
  906. ) {
  907. var terrainData = new HeightmapTerrainData({
  908. width: 9,
  909. height: 9,
  910. buffer: heightmapBuffer,
  911. structure: {
  912. // Use the maximum as the constant height so that this tile's skirt
  913. // covers any cracks with adjacent tiles.
  914. heightOffset: maximumHeight,
  915. },
  916. });
  917. fill.mesh = terrainData._createMeshSync(
  918. tile.tilingScheme,
  919. tile.x,
  920. tile.y,
  921. tile.level,
  922. 1.0
  923. );
  924. } else {
  925. var encoding = new TerrainEncoding(
  926. undefined,
  927. undefined,
  928. undefined,
  929. undefined,
  930. true,
  931. true
  932. );
  933. var centerCartographic = centerCartographicScratch;
  934. centerCartographic.longitude = (rectangle.east + rectangle.west) * 0.5;
  935. centerCartographic.latitude = (rectangle.north + rectangle.south) * 0.5;
  936. centerCartographic.height = middleHeight;
  937. encoding.center = ellipsoid.cartographicToCartesian(
  938. centerCartographic,
  939. encoding.center
  940. );
  941. // At _most_, we have vertices for the 4 corners, plus 1 center, plus every adjacent edge vertex.
  942. // In reality there will be less most of the time, but close enough; better
  943. // to overestimate than to re-allocate/copy/traverse the vertices twice.
  944. // Also, we'll often be able to squeeze the index data into the extra space in the buffer.
  945. var maxVertexCount = 5;
  946. var meshes;
  947. meshes = fill.westMeshes;
  948. for (i = 0, len = meshes.length; i < len; ++i) {
  949. maxVertexCount += meshes[i].eastIndicesNorthToSouth.length;
  950. }
  951. meshes = fill.southMeshes;
  952. for (i = 0, len = meshes.length; i < len; ++i) {
  953. maxVertexCount += meshes[i].northIndicesWestToEast.length;
  954. }
  955. meshes = fill.eastMeshes;
  956. for (i = 0, len = meshes.length; i < len; ++i) {
  957. maxVertexCount += meshes[i].westIndicesSouthToNorth.length;
  958. }
  959. meshes = fill.northMeshes;
  960. for (i = 0, len = meshes.length; i < len; ++i) {
  961. maxVertexCount += meshes[i].southIndicesEastToWest.length;
  962. }
  963. var heightRange = heightRangeScratch;
  964. heightRange.minimumHeight = minimumHeight;
  965. heightRange.maximumHeight = maximumHeight;
  966. var stride = encoding.getStride();
  967. var typedArray = new Float32Array(maxVertexCount * stride);
  968. var nextIndex = 0;
  969. var northwestIndex = nextIndex;
  970. nextIndex = addVertexWithComputedPosition(
  971. ellipsoid,
  972. rectangle,
  973. encoding,
  974. typedArray,
  975. nextIndex,
  976. 0.0,
  977. 1.0,
  978. nwCorner.height,
  979. nwCorner.encodedNormal,
  980. 1.0,
  981. heightRange
  982. );
  983. nextIndex = addEdge(
  984. fill,
  985. ellipsoid,
  986. encoding,
  987. typedArray,
  988. nextIndex,
  989. fill.westTiles,
  990. fill.westMeshes,
  991. TileEdge.EAST,
  992. heightRange
  993. );
  994. var southwestIndex = nextIndex;
  995. nextIndex = addVertexWithComputedPosition(
  996. ellipsoid,
  997. rectangle,
  998. encoding,
  999. typedArray,
  1000. nextIndex,
  1001. 0.0,
  1002. 0.0,
  1003. swCorner.height,
  1004. swCorner.encodedNormal,
  1005. 0.0,
  1006. heightRange
  1007. );
  1008. nextIndex = addEdge(
  1009. fill,
  1010. ellipsoid,
  1011. encoding,
  1012. typedArray,
  1013. nextIndex,
  1014. fill.southTiles,
  1015. fill.southMeshes,
  1016. TileEdge.NORTH,
  1017. heightRange
  1018. );
  1019. var southeastIndex = nextIndex;
  1020. nextIndex = addVertexWithComputedPosition(
  1021. ellipsoid,
  1022. rectangle,
  1023. encoding,
  1024. typedArray,
  1025. nextIndex,
  1026. 1.0,
  1027. 0.0,
  1028. seCorner.height,
  1029. seCorner.encodedNormal,
  1030. 0.0,
  1031. heightRange
  1032. );
  1033. nextIndex = addEdge(
  1034. fill,
  1035. ellipsoid,
  1036. encoding,
  1037. typedArray,
  1038. nextIndex,
  1039. fill.eastTiles,
  1040. fill.eastMeshes,
  1041. TileEdge.WEST,
  1042. heightRange
  1043. );
  1044. var northeastIndex = nextIndex;
  1045. nextIndex = addVertexWithComputedPosition(
  1046. ellipsoid,
  1047. rectangle,
  1048. encoding,
  1049. typedArray,
  1050. nextIndex,
  1051. 1.0,
  1052. 1.0,
  1053. neCorner.height,
  1054. neCorner.encodedNormal,
  1055. 1.0,
  1056. heightRange
  1057. );
  1058. nextIndex = addEdge(
  1059. fill,
  1060. ellipsoid,
  1061. encoding,
  1062. typedArray,
  1063. nextIndex,
  1064. fill.northTiles,
  1065. fill.northMeshes,
  1066. TileEdge.SOUTH,
  1067. heightRange
  1068. );
  1069. minimumHeight = heightRange.minimumHeight;
  1070. maximumHeight = heightRange.maximumHeight;
  1071. var obb = OrientedBoundingBox.fromRectangle(
  1072. rectangle,
  1073. minimumHeight,
  1074. maximumHeight,
  1075. tile.tilingScheme.ellipsoid
  1076. );
  1077. // Add a single vertex at the center of the tile.
  1078. var southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  1079. rectangle.south
  1080. );
  1081. var oneOverMercatorHeight =
  1082. 1.0 /
  1083. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(rectangle.north) -
  1084. southMercatorY);
  1085. var centerWebMercatorT =
  1086. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  1087. centerCartographic.latitude
  1088. ) -
  1089. southMercatorY) *
  1090. oneOverMercatorHeight;
  1091. ellipsoid.geodeticSurfaceNormalCartographic(
  1092. cartographicScratch,
  1093. normalScratch
  1094. );
  1095. var centerEncodedNormal = AttributeCompression.octEncode(
  1096. normalScratch,
  1097. octEncodedNormalScratch
  1098. );
  1099. var centerIndex = nextIndex;
  1100. encoding.encode(
  1101. typedArray,
  1102. nextIndex * stride,
  1103. obb.center,
  1104. Cartesian2.fromElements(0.5, 0.5, uvScratch),
  1105. middleHeight,
  1106. centerEncodedNormal,
  1107. centerWebMercatorT
  1108. );
  1109. ++nextIndex;
  1110. var vertexCount = nextIndex;
  1111. var bytesPerIndex = vertexCount < 256 ? 1 : 2;
  1112. var indexCount = (vertexCount - 1) * 3; // one triangle per edge vertex
  1113. var indexDataBytes = indexCount * bytesPerIndex;
  1114. var availableBytesInBuffer =
  1115. (typedArray.length - vertexCount * stride) *
  1116. Float32Array.BYTES_PER_ELEMENT;
  1117. var indices;
  1118. if (availableBytesInBuffer >= indexDataBytes) {
  1119. // Store the index data in the same buffer as the vertex data.
  1120. var startIndex = vertexCount * stride * Float32Array.BYTES_PER_ELEMENT;
  1121. indices =
  1122. vertexCount < 256
  1123. ? new Uint8Array(typedArray.buffer, startIndex, indexCount)
  1124. : new Uint16Array(typedArray.buffer, startIndex, indexCount);
  1125. } else {
  1126. // Allocate a new buffer for the index data.
  1127. indices =
  1128. vertexCount < 256
  1129. ? new Uint8Array(indexCount)
  1130. : new Uint16Array(indexCount);
  1131. }
  1132. typedArray = new Float32Array(typedArray.buffer, 0, vertexCount * stride);
  1133. var indexOut = 0;
  1134. for (i = 0; i < vertexCount - 2; ++i) {
  1135. indices[indexOut++] = centerIndex;
  1136. indices[indexOut++] = i;
  1137. indices[indexOut++] = i + 1;
  1138. }
  1139. indices[indexOut++] = centerIndex;
  1140. indices[indexOut++] = i;
  1141. indices[indexOut++] = 0;
  1142. var westIndicesSouthToNorth = [];
  1143. for (i = southwestIndex; i >= northwestIndex; --i) {
  1144. westIndicesSouthToNorth.push(i);
  1145. }
  1146. var southIndicesEastToWest = [];
  1147. for (i = southeastIndex; i >= southwestIndex; --i) {
  1148. southIndicesEastToWest.push(i);
  1149. }
  1150. var eastIndicesNorthToSouth = [];
  1151. for (i = northeastIndex; i >= southeastIndex; --i) {
  1152. eastIndicesNorthToSouth.push(i);
  1153. }
  1154. var northIndicesWestToEast = [];
  1155. northIndicesWestToEast.push(0);
  1156. for (i = centerIndex - 1; i >= northeastIndex; --i) {
  1157. northIndicesWestToEast.push(i);
  1158. }
  1159. fill.mesh = new TerrainMesh(
  1160. encoding.center,
  1161. typedArray,
  1162. indices,
  1163. indexCount,
  1164. vertexCount,
  1165. minimumHeight,
  1166. maximumHeight,
  1167. BoundingSphere.fromOrientedBoundingBox(obb),
  1168. computeOccludeePoint(
  1169. tileProvider,
  1170. obb.center,
  1171. rectangle,
  1172. minimumHeight,
  1173. maximumHeight
  1174. ),
  1175. encoding.getStride(),
  1176. obb,
  1177. encoding,
  1178. frameState.terrainExaggeration,
  1179. westIndicesSouthToNorth,
  1180. southIndicesEastToWest,
  1181. eastIndicesNorthToSouth,
  1182. northIndicesWestToEast
  1183. );
  1184. }
  1185. var context = frameState.context;
  1186. if (defined(fill.vertexArray)) {
  1187. if (defined(vertexArraysToDestroy)) {
  1188. vertexArraysToDestroy.push(fill.vertexArray);
  1189. } else {
  1190. GlobeSurfaceTile._freeVertexArray(fill.vertexArray);
  1191. }
  1192. }
  1193. fill.vertexArray = GlobeSurfaceTile._createVertexArrayForMesh(
  1194. context,
  1195. fill.mesh
  1196. );
  1197. surfaceTile.processImagery(
  1198. tile,
  1199. tileProvider.terrainProvider,
  1200. frameState,
  1201. true
  1202. );
  1203. var oldTexture = fill.waterMaskTexture;
  1204. fill.waterMaskTexture = undefined;
  1205. if (tileProvider.terrainProvider.hasWaterMask) {
  1206. var waterSourceTile = surfaceTile._findAncestorTileWithTerrainData(tile);
  1207. if (
  1208. defined(waterSourceTile) &&
  1209. defined(waterSourceTile.data.waterMaskTexture)
  1210. ) {
  1211. fill.waterMaskTexture = waterSourceTile.data.waterMaskTexture;
  1212. ++fill.waterMaskTexture.referenceCount;
  1213. surfaceTile._computeWaterMaskTranslationAndScale(
  1214. tile,
  1215. waterSourceTile,
  1216. fill.waterMaskTranslationAndScale
  1217. );
  1218. }
  1219. }
  1220. if (defined(oldTexture)) {
  1221. --oldTexture.referenceCount;
  1222. if (oldTexture.referenceCount === 0) {
  1223. oldTexture.destroy();
  1224. }
  1225. }
  1226. }
  1227. function addVertexWithComputedPosition(
  1228. ellipsoid,
  1229. rectangle,
  1230. encoding,
  1231. buffer,
  1232. index,
  1233. u,
  1234. v,
  1235. height,
  1236. encodedNormal,
  1237. webMercatorT,
  1238. heightRange
  1239. ) {
  1240. var cartographic = cartographicScratch;
  1241. cartographic.longitude = CesiumMath.lerp(rectangle.west, rectangle.east, u);
  1242. cartographic.latitude = CesiumMath.lerp(rectangle.south, rectangle.north, v);
  1243. cartographic.height = height;
  1244. var position = ellipsoid.cartographicToCartesian(
  1245. cartographic,
  1246. cartesianScratch
  1247. );
  1248. var uv = uvScratch2;
  1249. uv.x = u;
  1250. uv.y = v;
  1251. encoding.encode(
  1252. buffer,
  1253. index * encoding.getStride(),
  1254. position,
  1255. uv,
  1256. height,
  1257. encodedNormal,
  1258. webMercatorT
  1259. );
  1260. heightRange.minimumHeight = Math.min(heightRange.minimumHeight, height);
  1261. heightRange.maximumHeight = Math.max(heightRange.maximumHeight, height);
  1262. return index + 1;
  1263. }
  1264. var sourceRectangleScratch = new Rectangle();
  1265. function transformTextureCoordinates(
  1266. sourceTile,
  1267. targetTile,
  1268. coordinates,
  1269. result
  1270. ) {
  1271. var sourceRectangle = sourceTile.rectangle;
  1272. var targetRectangle = targetTile.rectangle;
  1273. // Handle transforming across the anti-meridian.
  1274. if (
  1275. targetTile.x === 0 &&
  1276. coordinates.x === 1.0 &&
  1277. sourceTile.x ===
  1278. sourceTile.tilingScheme.getNumberOfXTilesAtLevel(sourceTile.level) - 1
  1279. ) {
  1280. sourceRectangle = Rectangle.clone(
  1281. sourceTile.rectangle,
  1282. sourceRectangleScratch
  1283. );
  1284. sourceRectangle.west -= CesiumMath.TWO_PI;
  1285. sourceRectangle.east -= CesiumMath.TWO_PI;
  1286. } else if (
  1287. sourceTile.x === 0 &&
  1288. coordinates.x === 0.0 &&
  1289. targetTile.x ===
  1290. targetTile.tilingScheme.getNumberOfXTilesAtLevel(targetTile.level) - 1
  1291. ) {
  1292. sourceRectangle = Rectangle.clone(
  1293. sourceTile.rectangle,
  1294. sourceRectangleScratch
  1295. );
  1296. sourceRectangle.west += CesiumMath.TWO_PI;
  1297. sourceRectangle.east += CesiumMath.TWO_PI;
  1298. }
  1299. var sourceWidth = sourceRectangle.east - sourceRectangle.west;
  1300. var umin = (targetRectangle.west - sourceRectangle.west) / sourceWidth;
  1301. var umax = (targetRectangle.east - sourceRectangle.west) / sourceWidth;
  1302. var sourceHeight = sourceRectangle.north - sourceRectangle.south;
  1303. var vmin = (targetRectangle.south - sourceRectangle.south) / sourceHeight;
  1304. var vmax = (targetRectangle.north - sourceRectangle.south) / sourceHeight;
  1305. var u = (coordinates.x - umin) / (umax - umin);
  1306. var v = (coordinates.y - vmin) / (vmax - vmin);
  1307. // Ensure that coordinates very near the corners are at the corners.
  1308. if (Math.abs(u) < Math.EPSILON5) {
  1309. u = 0.0;
  1310. } else if (Math.abs(u - 1.0) < Math.EPSILON5) {
  1311. u = 1.0;
  1312. }
  1313. if (Math.abs(v) < Math.EPSILON5) {
  1314. v = 0.0;
  1315. } else if (Math.abs(v - 1.0) < Math.EPSILON5) {
  1316. v = 1.0;
  1317. }
  1318. result.x = u;
  1319. result.y = v;
  1320. return result;
  1321. }
  1322. var encodedNormalScratch = new Cartesian2();
  1323. function getVertexFromTileAtCorner(sourceMesh, sourceIndex, u, v, vertex) {
  1324. var sourceEncoding = sourceMesh.encoding;
  1325. var sourceVertices = sourceMesh.vertices;
  1326. vertex.height = sourceEncoding.decodeHeight(sourceVertices, sourceIndex);
  1327. if (sourceEncoding.hasVertexNormals) {
  1328. sourceEncoding.getOctEncodedNormal(
  1329. sourceVertices,
  1330. sourceIndex,
  1331. vertex.encodedNormal
  1332. );
  1333. } else {
  1334. var normal = vertex.encodedNormal;
  1335. normal.x = 0.0;
  1336. normal.y = 0.0;
  1337. }
  1338. }
  1339. var encodedNormalScratch2 = new Cartesian2();
  1340. var cartesianScratch2 = new Cartesian3();
  1341. function getInterpolatedVertexAtCorner(
  1342. ellipsoid,
  1343. sourceTile,
  1344. targetTile,
  1345. sourceMesh,
  1346. previousIndex,
  1347. nextIndex,
  1348. u,
  1349. v,
  1350. interpolateU,
  1351. vertex
  1352. ) {
  1353. var sourceEncoding = sourceMesh.encoding;
  1354. var sourceVertices = sourceMesh.vertices;
  1355. var previousUv = transformTextureCoordinates(
  1356. sourceTile,
  1357. targetTile,
  1358. sourceEncoding.decodeTextureCoordinates(
  1359. sourceVertices,
  1360. previousIndex,
  1361. uvScratch
  1362. ),
  1363. uvScratch
  1364. );
  1365. var nextUv = transformTextureCoordinates(
  1366. sourceTile,
  1367. targetTile,
  1368. sourceEncoding.decodeTextureCoordinates(
  1369. sourceVertices,
  1370. nextIndex,
  1371. uvScratch2
  1372. ),
  1373. uvScratch2
  1374. );
  1375. var ratio;
  1376. if (interpolateU) {
  1377. ratio = (u - previousUv.x) / (nextUv.x - previousUv.x);
  1378. } else {
  1379. ratio = (v - previousUv.y) / (nextUv.y - previousUv.y);
  1380. }
  1381. var height1 = sourceEncoding.decodeHeight(sourceVertices, previousIndex);
  1382. var height2 = sourceEncoding.decodeHeight(sourceVertices, nextIndex);
  1383. var targetRectangle = targetTile.rectangle;
  1384. cartographicScratch.longitude = CesiumMath.lerp(
  1385. targetRectangle.west,
  1386. targetRectangle.east,
  1387. u
  1388. );
  1389. cartographicScratch.latitude = CesiumMath.lerp(
  1390. targetRectangle.south,
  1391. targetRectangle.north,
  1392. v
  1393. );
  1394. vertex.height = cartographicScratch.height = CesiumMath.lerp(
  1395. height1,
  1396. height2,
  1397. ratio
  1398. );
  1399. var normal;
  1400. if (sourceEncoding.hasVertexNormals) {
  1401. var encodedNormal1 = sourceEncoding.getOctEncodedNormal(
  1402. sourceVertices,
  1403. previousIndex,
  1404. encodedNormalScratch
  1405. );
  1406. var encodedNormal2 = sourceEncoding.getOctEncodedNormal(
  1407. sourceVertices,
  1408. nextIndex,
  1409. encodedNormalScratch2
  1410. );
  1411. var normal1 = AttributeCompression.octDecode(
  1412. encodedNormal1.x,
  1413. encodedNormal1.y,
  1414. cartesianScratch
  1415. );
  1416. var normal2 = AttributeCompression.octDecode(
  1417. encodedNormal2.x,
  1418. encodedNormal2.y,
  1419. cartesianScratch2
  1420. );
  1421. normal = Cartesian3.lerp(normal1, normal2, ratio, cartesianScratch);
  1422. Cartesian3.normalize(normal, normal);
  1423. AttributeCompression.octEncode(normal, vertex.encodedNormal);
  1424. } else {
  1425. normal = ellipsoid.geodeticSurfaceNormalCartographic(
  1426. cartographicScratch,
  1427. cartesianScratch
  1428. );
  1429. AttributeCompression.octEncode(normal, vertex.encodedNormal);
  1430. }
  1431. }
  1432. function getVertexWithHeightAtCorner(
  1433. terrainFillMesh,
  1434. ellipsoid,
  1435. u,
  1436. v,
  1437. height,
  1438. vertex
  1439. ) {
  1440. vertex.height = height;
  1441. var normal = ellipsoid.geodeticSurfaceNormalCartographic(
  1442. cartographicScratch,
  1443. cartesianScratch
  1444. );
  1445. AttributeCompression.octEncode(normal, vertex.encodedNormal);
  1446. }
  1447. function getCorner(
  1448. terrainFillMesh,
  1449. ellipsoid,
  1450. u,
  1451. v,
  1452. cornerTile,
  1453. cornerMesh,
  1454. previousEdgeTiles,
  1455. previousEdgeMeshes,
  1456. nextEdgeTiles,
  1457. nextEdgeMeshes,
  1458. vertex
  1459. ) {
  1460. var gotCorner =
  1461. getCornerFromEdge(
  1462. terrainFillMesh,
  1463. ellipsoid,
  1464. previousEdgeMeshes,
  1465. previousEdgeTiles,
  1466. false,
  1467. u,
  1468. v,
  1469. vertex
  1470. ) ||
  1471. getCornerFromEdge(
  1472. terrainFillMesh,
  1473. ellipsoid,
  1474. nextEdgeMeshes,
  1475. nextEdgeTiles,
  1476. true,
  1477. u,
  1478. v,
  1479. vertex
  1480. );
  1481. if (gotCorner) {
  1482. return vertex;
  1483. }
  1484. var vertexIndex;
  1485. if (meshIsUsable(cornerTile, cornerMesh)) {
  1486. // Corner mesh is valid, copy its corner vertex to this mesh.
  1487. if (u === 0.0) {
  1488. if (v === 0.0) {
  1489. // southwest destination, northeast source
  1490. vertexIndex = cornerMesh.eastIndicesNorthToSouth[0];
  1491. } else {
  1492. // northwest destination, southeast source
  1493. vertexIndex = cornerMesh.southIndicesEastToWest[0];
  1494. }
  1495. } else if (v === 0.0) {
  1496. // southeast destination, northwest source
  1497. vertexIndex = cornerMesh.northIndicesWestToEast[0];
  1498. } else {
  1499. // northeast destination, southwest source
  1500. vertexIndex = cornerMesh.westIndicesSouthToNorth[0];
  1501. }
  1502. getVertexFromTileAtCorner(cornerMesh, vertexIndex, u, v, vertex);
  1503. return vertex;
  1504. }
  1505. // There is no precise vertex available from the corner or from either adjacent edge.
  1506. // This is either because there are no tiles at all at the edges and corner, or
  1507. // because the tiles at the edge are higher-level-number and don't extend all the way
  1508. // to the corner.
  1509. // Try to grab a height from the adjacent edges.
  1510. var height;
  1511. if (u === 0.0) {
  1512. if (v === 0.0) {
  1513. // southwest
  1514. height = getClosestHeightToCorner(
  1515. terrainFillMesh.westMeshes,
  1516. terrainFillMesh.westTiles,
  1517. TileEdge.EAST,
  1518. terrainFillMesh.southMeshes,
  1519. terrainFillMesh.southTiles,
  1520. TileEdge.NORTH,
  1521. u,
  1522. v
  1523. );
  1524. } else {
  1525. // northwest
  1526. height = getClosestHeightToCorner(
  1527. terrainFillMesh.northMeshes,
  1528. terrainFillMesh.northTiles,
  1529. TileEdge.SOUTH,
  1530. terrainFillMesh.westMeshes,
  1531. terrainFillMesh.westTiles,
  1532. TileEdge.EAST,
  1533. u,
  1534. v
  1535. );
  1536. }
  1537. } else if (v === 0.0) {
  1538. // southeast
  1539. height = getClosestHeightToCorner(
  1540. terrainFillMesh.southMeshes,
  1541. terrainFillMesh.southTiles,
  1542. TileEdge.NORTH,
  1543. terrainFillMesh.eastMeshes,
  1544. terrainFillMesh.eastTiles,
  1545. TileEdge.WEST,
  1546. u,
  1547. v
  1548. );
  1549. } else {
  1550. // northeast
  1551. height = getClosestHeightToCorner(
  1552. terrainFillMesh.eastMeshes,
  1553. terrainFillMesh.eastTiles,
  1554. TileEdge.WEST,
  1555. terrainFillMesh.northMeshes,
  1556. terrainFillMesh.northTiles,
  1557. TileEdge.SOUTH,
  1558. u,
  1559. v
  1560. );
  1561. }
  1562. if (defined(height)) {
  1563. getVertexWithHeightAtCorner(
  1564. terrainFillMesh,
  1565. ellipsoid,
  1566. u,
  1567. v,
  1568. height,
  1569. vertex
  1570. );
  1571. return vertex;
  1572. }
  1573. // No heights available that are closer than the adjacent corners.
  1574. return undefined;
  1575. }
  1576. function getClosestHeightToCorner(
  1577. previousMeshes,
  1578. previousTiles,
  1579. previousEdge,
  1580. nextMeshes,
  1581. nextTiles,
  1582. nextEdge,
  1583. u,
  1584. v
  1585. ) {
  1586. var height1 = getNearestHeightOnEdge(
  1587. previousMeshes,
  1588. previousTiles,
  1589. false,
  1590. previousEdge,
  1591. u,
  1592. v
  1593. );
  1594. var height2 = getNearestHeightOnEdge(
  1595. nextMeshes,
  1596. nextTiles,
  1597. true,
  1598. nextEdge,
  1599. u,
  1600. v
  1601. );
  1602. if (defined(height1) && defined(height2)) {
  1603. // It would be slightly better to do a weighted average of the two heights
  1604. // based on their distance from the corner, but it shouldn't matter much in practice.
  1605. return (height1 + height2) * 0.5;
  1606. } else if (defined(height1)) {
  1607. return height1;
  1608. }
  1609. return height2;
  1610. }
  1611. function addEdge(
  1612. terrainFillMesh,
  1613. ellipsoid,
  1614. encoding,
  1615. typedArray,
  1616. nextIndex,
  1617. edgeTiles,
  1618. edgeMeshes,
  1619. tileEdge,
  1620. heightRange
  1621. ) {
  1622. for (var i = 0; i < edgeTiles.length; ++i) {
  1623. nextIndex = addEdgeMesh(
  1624. terrainFillMesh,
  1625. ellipsoid,
  1626. encoding,
  1627. typedArray,
  1628. nextIndex,
  1629. edgeTiles[i],
  1630. edgeMeshes[i],
  1631. tileEdge,
  1632. heightRange
  1633. );
  1634. }
  1635. return nextIndex;
  1636. }
  1637. function addEdgeMesh(
  1638. terrainFillMesh,
  1639. ellipsoid,
  1640. encoding,
  1641. typedArray,
  1642. nextIndex,
  1643. edgeTile,
  1644. edgeMesh,
  1645. tileEdge,
  1646. heightRange
  1647. ) {
  1648. // Handle copying edges across the anti-meridian.
  1649. var sourceRectangle = edgeTile.rectangle;
  1650. if (tileEdge === TileEdge.EAST && terrainFillMesh.tile.x === 0) {
  1651. sourceRectangle = Rectangle.clone(
  1652. edgeTile.rectangle,
  1653. sourceRectangleScratch
  1654. );
  1655. sourceRectangle.west -= CesiumMath.TWO_PI;
  1656. sourceRectangle.east -= CesiumMath.TWO_PI;
  1657. } else if (tileEdge === TileEdge.WEST && edgeTile.x === 0) {
  1658. sourceRectangle = Rectangle.clone(
  1659. edgeTile.rectangle,
  1660. sourceRectangleScratch
  1661. );
  1662. sourceRectangle.west += CesiumMath.TWO_PI;
  1663. sourceRectangle.east += CesiumMath.TWO_PI;
  1664. }
  1665. var targetRectangle = terrainFillMesh.tile.rectangle;
  1666. var lastU;
  1667. var lastV;
  1668. if (nextIndex > 0) {
  1669. encoding.decodeTextureCoordinates(typedArray, nextIndex - 1, uvScratch);
  1670. lastU = uvScratch.x;
  1671. lastV = uvScratch.y;
  1672. }
  1673. var indices;
  1674. var compareU;
  1675. switch (tileEdge) {
  1676. case TileEdge.WEST:
  1677. indices = edgeMesh.westIndicesSouthToNorth;
  1678. compareU = false;
  1679. break;
  1680. case TileEdge.NORTH:
  1681. indices = edgeMesh.northIndicesWestToEast;
  1682. compareU = true;
  1683. break;
  1684. case TileEdge.EAST:
  1685. indices = edgeMesh.eastIndicesNorthToSouth;
  1686. compareU = false;
  1687. break;
  1688. case TileEdge.SOUTH:
  1689. indices = edgeMesh.southIndicesEastToWest;
  1690. compareU = true;
  1691. break;
  1692. }
  1693. var sourceTile = edgeTile;
  1694. var targetTile = terrainFillMesh.tile;
  1695. var sourceEncoding = edgeMesh.encoding;
  1696. var sourceVertices = edgeMesh.vertices;
  1697. var targetStride = encoding.getStride();
  1698. var southMercatorY;
  1699. var oneOverMercatorHeight;
  1700. if (sourceEncoding.hasWebMercatorT) {
  1701. southMercatorY = WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  1702. targetRectangle.south
  1703. );
  1704. oneOverMercatorHeight =
  1705. 1.0 /
  1706. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  1707. targetRectangle.north
  1708. ) -
  1709. southMercatorY);
  1710. }
  1711. for (var i = 0; i < indices.length; ++i) {
  1712. var index = indices[i];
  1713. var uv = sourceEncoding.decodeTextureCoordinates(
  1714. sourceVertices,
  1715. index,
  1716. uvScratch
  1717. );
  1718. transformTextureCoordinates(sourceTile, targetTile, uv, uv);
  1719. var u = uv.x;
  1720. var v = uv.y;
  1721. var uOrV = compareU ? u : v;
  1722. if (uOrV < 0.0 || uOrV > 1.0) {
  1723. // Vertex is outside the target tile - skip it.
  1724. continue;
  1725. }
  1726. if (
  1727. Math.abs(u - lastU) < CesiumMath.EPSILON5 &&
  1728. Math.abs(v - lastV) < CesiumMath.EPSILON5
  1729. ) {
  1730. // Vertex is very close to the previous one - skip it.
  1731. continue;
  1732. }
  1733. var nearlyEdgeU =
  1734. Math.abs(u) < CesiumMath.EPSILON5 ||
  1735. Math.abs(u - 1.0) < CesiumMath.EPSILON5;
  1736. var nearlyEdgeV =
  1737. Math.abs(v) < CesiumMath.EPSILON5 ||
  1738. Math.abs(v - 1.0) < CesiumMath.EPSILON5;
  1739. if (nearlyEdgeU && nearlyEdgeV) {
  1740. // Corner vertex - skip it.
  1741. continue;
  1742. }
  1743. var position = sourceEncoding.decodePosition(
  1744. sourceVertices,
  1745. index,
  1746. cartesianScratch
  1747. );
  1748. var height = sourceEncoding.decodeHeight(sourceVertices, index);
  1749. var normal;
  1750. if (sourceEncoding.hasVertexNormals) {
  1751. normal = sourceEncoding.getOctEncodedNormal(
  1752. sourceVertices,
  1753. index,
  1754. octEncodedNormalScratch
  1755. );
  1756. } else {
  1757. normal = octEncodedNormalScratch;
  1758. normal.x = 0.0;
  1759. normal.y = 0.0;
  1760. }
  1761. var webMercatorT = v;
  1762. if (sourceEncoding.hasWebMercatorT) {
  1763. var latitude = CesiumMath.lerp(
  1764. targetRectangle.south,
  1765. targetRectangle.north,
  1766. v
  1767. );
  1768. webMercatorT =
  1769. (WebMercatorProjection.geodeticLatitudeToMercatorAngle(latitude) -
  1770. southMercatorY) *
  1771. oneOverMercatorHeight;
  1772. }
  1773. encoding.encode(
  1774. typedArray,
  1775. nextIndex * targetStride,
  1776. position,
  1777. uv,
  1778. height,
  1779. normal,
  1780. webMercatorT
  1781. );
  1782. heightRange.minimumHeight = Math.min(heightRange.minimumHeight, height);
  1783. heightRange.maximumHeight = Math.max(heightRange.maximumHeight, height);
  1784. ++nextIndex;
  1785. }
  1786. return nextIndex;
  1787. }
  1788. function getNearestHeightOnEdge(meshes, tiles, isNext, edge, u, v) {
  1789. var meshStart;
  1790. var meshEnd;
  1791. var meshStep;
  1792. if (isNext) {
  1793. meshStart = 0;
  1794. meshEnd = meshes.length;
  1795. meshStep = 1;
  1796. } else {
  1797. meshStart = meshes.length - 1;
  1798. meshEnd = -1;
  1799. meshStep = -1;
  1800. }
  1801. for (
  1802. var meshIndex = meshStart;
  1803. meshIndex !== meshEnd;
  1804. meshIndex += meshStep
  1805. ) {
  1806. var mesh = meshes[meshIndex];
  1807. var tile = tiles[meshIndex];
  1808. if (!meshIsUsable(tile, mesh)) {
  1809. continue;
  1810. }
  1811. var indices;
  1812. switch (edge) {
  1813. case TileEdge.WEST:
  1814. indices = mesh.westIndicesSouthToNorth;
  1815. break;
  1816. case TileEdge.SOUTH:
  1817. indices = mesh.southIndicesEastToWest;
  1818. break;
  1819. case TileEdge.EAST:
  1820. indices = mesh.eastIndicesNorthToSouth;
  1821. break;
  1822. case TileEdge.NORTH:
  1823. indices = mesh.northIndicesWestToEast;
  1824. break;
  1825. }
  1826. var index = indices[isNext ? 0 : indices.length - 1];
  1827. if (defined(index)) {
  1828. return mesh.encoding.decodeHeight(mesh.vertices, index);
  1829. }
  1830. }
  1831. return undefined;
  1832. }
  1833. function meshIsUsable(tile, mesh) {
  1834. return (
  1835. defined(mesh) &&
  1836. (!defined(tile.data.fill) || !tile.data.fill.changedThisFrame)
  1837. );
  1838. }
  1839. function getCornerFromEdge(
  1840. terrainFillMesh,
  1841. ellipsoid,
  1842. edgeMeshes,
  1843. edgeTiles,
  1844. isNext,
  1845. u,
  1846. v,
  1847. vertex
  1848. ) {
  1849. var edgeVertices;
  1850. var compareU;
  1851. var increasing;
  1852. var vertexIndexIndex;
  1853. var vertexIndex;
  1854. var sourceTile = edgeTiles[isNext ? 0 : edgeMeshes.length - 1];
  1855. var sourceMesh = edgeMeshes[isNext ? 0 : edgeMeshes.length - 1];
  1856. if (meshIsUsable(sourceTile, sourceMesh)) {
  1857. // Previous mesh is valid, but we don't know yet if it covers this corner.
  1858. if (u === 0.0) {
  1859. if (v === 0.0) {
  1860. // southwest
  1861. edgeVertices = isNext
  1862. ? sourceMesh.northIndicesWestToEast
  1863. : sourceMesh.eastIndicesNorthToSouth;
  1864. compareU = isNext;
  1865. increasing = isNext;
  1866. } else {
  1867. // northwest
  1868. edgeVertices = isNext
  1869. ? sourceMesh.eastIndicesNorthToSouth
  1870. : sourceMesh.southIndicesEastToWest;
  1871. compareU = !isNext;
  1872. increasing = false;
  1873. }
  1874. } else if (v === 0.0) {
  1875. // southeast
  1876. edgeVertices = isNext
  1877. ? sourceMesh.westIndicesSouthToNorth
  1878. : sourceMesh.northIndicesWestToEast;
  1879. compareU = !isNext;
  1880. increasing = true;
  1881. } else {
  1882. // northeast
  1883. edgeVertices = isNext
  1884. ? sourceMesh.southIndicesEastToWest
  1885. : sourceMesh.westIndicesSouthToNorth;
  1886. compareU = isNext;
  1887. increasing = !isNext;
  1888. }
  1889. if (edgeVertices.length > 0) {
  1890. // The vertex we want will very often be the first/last vertex so check that first.
  1891. vertexIndexIndex = isNext ? 0 : edgeVertices.length - 1;
  1892. vertexIndex = edgeVertices[vertexIndexIndex];
  1893. sourceMesh.encoding.decodeTextureCoordinates(
  1894. sourceMesh.vertices,
  1895. vertexIndex,
  1896. uvScratch
  1897. );
  1898. var targetUv = transformTextureCoordinates(
  1899. sourceTile,
  1900. terrainFillMesh.tile,
  1901. uvScratch,
  1902. uvScratch
  1903. );
  1904. if (targetUv.x === u && targetUv.y === v) {
  1905. // Vertex is good!
  1906. getVertexFromTileAtCorner(sourceMesh, vertexIndex, u, v, vertex);
  1907. return true;
  1908. }
  1909. // The last vertex is not the one we need, try binary searching for the right one.
  1910. vertexIndexIndex = binarySearch(edgeVertices, compareU ? u : v, function (
  1911. vertexIndex,
  1912. textureCoordinate
  1913. ) {
  1914. sourceMesh.encoding.decodeTextureCoordinates(
  1915. sourceMesh.vertices,
  1916. vertexIndex,
  1917. uvScratch
  1918. );
  1919. var targetUv = transformTextureCoordinates(
  1920. sourceTile,
  1921. terrainFillMesh.tile,
  1922. uvScratch,
  1923. uvScratch
  1924. );
  1925. if (increasing) {
  1926. if (compareU) {
  1927. return targetUv.x - u;
  1928. }
  1929. return targetUv.y - v;
  1930. } else if (compareU) {
  1931. return u - targetUv.x;
  1932. }
  1933. return v - targetUv.y;
  1934. });
  1935. if (vertexIndexIndex < 0) {
  1936. vertexIndexIndex = ~vertexIndexIndex;
  1937. if (vertexIndexIndex > 0 && vertexIndexIndex < edgeVertices.length) {
  1938. // The corner falls between two vertices, so interpolate between them.
  1939. getInterpolatedVertexAtCorner(
  1940. ellipsoid,
  1941. sourceTile,
  1942. terrainFillMesh.tile,
  1943. sourceMesh,
  1944. edgeVertices[vertexIndexIndex - 1],
  1945. edgeVertices[vertexIndexIndex],
  1946. u,
  1947. v,
  1948. compareU,
  1949. vertex
  1950. );
  1951. return true;
  1952. }
  1953. } else {
  1954. // Found a vertex that fits in the corner exactly.
  1955. getVertexFromTileAtCorner(
  1956. sourceMesh,
  1957. edgeVertices[vertexIndexIndex],
  1958. u,
  1959. v,
  1960. vertex
  1961. );
  1962. return true;
  1963. }
  1964. }
  1965. }
  1966. return false;
  1967. }
  1968. var cornerPositionsScratch = [
  1969. new Cartesian3(),
  1970. new Cartesian3(),
  1971. new Cartesian3(),
  1972. new Cartesian3(),
  1973. ];
  1974. function computeOccludeePoint(
  1975. tileProvider,
  1976. center,
  1977. rectangle,
  1978. minimumHeight,
  1979. maximumHeight,
  1980. result
  1981. ) {
  1982. var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
  1983. var ellipsoid = ellipsoidalOccluder.ellipsoid;
  1984. var cornerPositions = cornerPositionsScratch;
  1985. Cartesian3.fromRadians(
  1986. rectangle.west,
  1987. rectangle.south,
  1988. maximumHeight,
  1989. ellipsoid,
  1990. cornerPositions[0]
  1991. );
  1992. Cartesian3.fromRadians(
  1993. rectangle.east,
  1994. rectangle.south,
  1995. maximumHeight,
  1996. ellipsoid,
  1997. cornerPositions[1]
  1998. );
  1999. Cartesian3.fromRadians(
  2000. rectangle.west,
  2001. rectangle.north,
  2002. maximumHeight,
  2003. ellipsoid,
  2004. cornerPositions[2]
  2005. );
  2006. Cartesian3.fromRadians(
  2007. rectangle.east,
  2008. rectangle.north,
  2009. maximumHeight,
  2010. ellipsoid,
  2011. cornerPositions[3]
  2012. );
  2013. return ellipsoidalOccluder.computeHorizonCullingPointPossiblyUnderEllipsoid(
  2014. center,
  2015. cornerPositions,
  2016. minimumHeight,
  2017. result
  2018. );
  2019. }
  2020. export default TerrainFillMesh;