createVerticesFromHeightmap.js 104 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. define(['./when-e6985d2a', './Check-24cae389', './Math-392d0035', './Cartesian2-a5d6dde9', './Transforms-81680c41', './RuntimeError-61701d3e', './WebGLConstants-34c08bc0', './ComponentDatatype-cb08e294', './AttributeCompression-114c6354', './IntersectionTests-f17c84f0', './Plane-ac6a1d3e', './WebMercatorProjection-a06fbf17', './createTaskProcessorWorker', './EllipsoidTangentPlane-85280670', './OrientedBoundingBox-d8219c10', './TerrainEncoding-a793a9ee'], function (when, Check, _Math, Cartesian2, Transforms, RuntimeError, WebGLConstants, ComponentDatatype, AttributeCompression, IntersectionTests, Plane, WebMercatorProjection, createTaskProcessorWorker, EllipsoidTangentPlane, OrientedBoundingBox, TerrainEncoding) { 'use strict';
  3. /**
  4. * The encoding that is used for a heightmap
  5. *
  6. * @enum {Number}
  7. */
  8. var HeightmapEncoding = {
  9. /**
  10. * No encoding
  11. *
  12. * @type {Number}
  13. * @constant
  14. */
  15. NONE: 0,
  16. /**
  17. * LERC encoding
  18. *
  19. * @type {Number}
  20. * @constant
  21. *
  22. * @see {@link https://github.com/Esri/lerc|The LERC specification}
  23. */
  24. LERC: 1,
  25. };
  26. var HeightmapEncoding$1 = Object.freeze(HeightmapEncoding);
  27. /**
  28. * Contains functions to create a mesh from a heightmap image.
  29. *
  30. * @namespace HeightmapTessellator
  31. *
  32. * @private
  33. */
  34. var HeightmapTessellator = {};
  35. /**
  36. * The default structure of a heightmap, as given to {@link HeightmapTessellator.computeVertices}.
  37. *
  38. * @constant
  39. */
  40. HeightmapTessellator.DEFAULT_STRUCTURE = Object.freeze({
  41. heightScale: 1.0,
  42. heightOffset: 0.0,
  43. elementsPerHeight: 1,
  44. stride: 1,
  45. elementMultiplier: 256.0,
  46. isBigEndian: false,
  47. });
  48. var cartesian3Scratch = new Cartesian2.Cartesian3();
  49. var matrix4Scratch = new Transforms.Matrix4();
  50. var minimumScratch = new Cartesian2.Cartesian3();
  51. var maximumScratch = new Cartesian2.Cartesian3();
  52. /**
  53. * Fills an array of vertices from a heightmap image.
  54. *
  55. * @param {Object} options Object with the following properties:
  56. * @param {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} options.heightmap The heightmap to tessellate.
  57. * @param {Number} options.width The width of the heightmap, in height samples.
  58. * @param {Number} options.height The height of the heightmap, in height samples.
  59. * @param {Number} options.skirtHeight The height of skirts to drape at the edges of the heightmap.
  60. * @param {Rectangle} options.nativeRectangle A rectangle in the native coordinates of the heightmap's projection. For
  61. * a heightmap with a geographic projection, this is degrees. For the web mercator
  62. * projection, this is meters.
  63. * @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
  64. * @param {Rectangle} [options.rectangle] The rectangle covered by the heightmap, in geodetic coordinates with north, south, east and
  65. * west properties in radians. Either rectangle or nativeRectangle must be provided. If both
  66. * are provided, they're assumed to be consistent.
  67. * @param {Boolean} [options.isGeographic=true] True if the heightmap uses a {@link GeographicProjection}, or false if it uses
  68. * a {@link WebMercatorProjection}.
  69. * @param {Cartesian3} [options.relativeToCenter=Cartesian3.ZERO] The positions will be computed as <code>Cartesian3.subtract(worldPosition, relativeToCenter)</code>.
  70. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to which the heightmap applies.
  71. * @param {Object} [options.structure] An object describing the structure of the height data.
  72. * @param {Number} [options.structure.heightScale=1.0] The factor by which to multiply height samples in order to obtain
  73. * the height above the heightOffset, in meters. The heightOffset is added to the resulting
  74. * height after multiplying by the scale.
  75. * @param {Number} [options.structure.heightOffset=0.0] The offset to add to the scaled height to obtain the final
  76. * height in meters. The offset is added after the height sample is multiplied by the
  77. * heightScale.
  78. * @param {Number} [options.structure.elementsPerHeight=1] The number of elements in the buffer that make up a single height
  79. * sample. This is usually 1, indicating that each element is a separate height sample. If
  80. * it is greater than 1, that number of elements together form the height sample, which is
  81. * computed according to the structure.elementMultiplier and structure.isBigEndian properties.
  82. * @param {Number} [options.structure.stride=1] The number of elements to skip to get from the first element of
  83. * one height to the first element of the next height.
  84. * @param {Number} [options.structure.elementMultiplier=256.0] The multiplier used to compute the height value when the
  85. * stride property is greater than 1. For example, if the stride is 4 and the strideMultiplier
  86. * is 256, the height is computed as follows:
  87. * `height = buffer[index] + buffer[index + 1] * 256 + buffer[index + 2] * 256 * 256 + buffer[index + 3] * 256 * 256 * 256`
  88. * This is assuming that the isBigEndian property is false. If it is true, the order of the
  89. * elements is reversed.
  90. * @param {Number} [options.structure.lowestEncodedHeight] The lowest value that can be stored in the height buffer. Any heights that are lower
  91. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  92. * buffer is a `Uint16Array`, this value should be 0 because a `Uint16Array` cannot store negative numbers. If this parameter is
  93. * not specified, no minimum value is enforced.
  94. * @param {Number} [options.structure.highestEncodedHeight] The highest value that can be stored in the height buffer. Any heights that are higher
  95. * than this value after encoding with the `heightScale` and `heightOffset` are clamped to this value. For example, if the height
  96. * buffer is a `Uint16Array`, this value should be `256 * 256 - 1` or 65535 because a `Uint16Array` cannot store numbers larger
  97. * than 65535. If this parameter is not specified, no maximum value is enforced.
  98. * @param {Boolean} [options.structure.isBigEndian=false] Indicates endianness of the elements in the buffer when the
  99. * stride property is greater than 1. If this property is false, the first element is the
  100. * low-order element. If it is true, the first element is the high-order element.
  101. *
  102. * @example
  103. * var width = 5;
  104. * var height = 5;
  105. * var statistics = Cesium.HeightmapTessellator.computeVertices({
  106. * heightmap : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
  107. * width : width,
  108. * height : height,
  109. * skirtHeight : 0.0,
  110. * nativeRectangle : {
  111. * west : 10.0,
  112. * east : 20.0,
  113. * south : 30.0,
  114. * north : 40.0
  115. * }
  116. * });
  117. *
  118. * var encoding = statistics.encoding;
  119. * var position = encoding.decodePosition(statistics.vertices, index * encoding.getStride());
  120. */
  121. HeightmapTessellator.computeVertices = function (options) {
  122. //>>includeStart('debug', pragmas.debug);
  123. if (!when.defined(options) || !when.defined(options.heightmap)) {
  124. throw new Check.DeveloperError("options.heightmap is required.");
  125. }
  126. if (!when.defined(options.width) || !when.defined(options.height)) {
  127. throw new Check.DeveloperError("options.width and options.height are required.");
  128. }
  129. if (!when.defined(options.nativeRectangle)) {
  130. throw new Check.DeveloperError("options.nativeRectangle is required.");
  131. }
  132. if (!when.defined(options.skirtHeight)) {
  133. throw new Check.DeveloperError("options.skirtHeight is required.");
  134. }
  135. //>>includeEnd('debug');
  136. // This function tends to be a performance hotspot for terrain rendering,
  137. // so it employs a lot of inlining and unrolling as an optimization.
  138. // In particular, the functionality of Ellipsoid.cartographicToCartesian
  139. // is inlined.
  140. var cos = Math.cos;
  141. var sin = Math.sin;
  142. var sqrt = Math.sqrt;
  143. var atan = Math.atan;
  144. var exp = Math.exp;
  145. var piOverTwo = _Math.CesiumMath.PI_OVER_TWO;
  146. var toRadians = _Math.CesiumMath.toRadians;
  147. var heightmap = options.heightmap;
  148. var width = options.width;
  149. var height = options.height;
  150. var skirtHeight = options.skirtHeight;
  151. var isGeographic = when.defaultValue(options.isGeographic, true);
  152. var ellipsoid = when.defaultValue(options.ellipsoid, Cartesian2.Ellipsoid.WGS84);
  153. var oneOverGlobeSemimajorAxis = 1.0 / ellipsoid.maximumRadius;
  154. var nativeRectangle = options.nativeRectangle;
  155. var geographicWest;
  156. var geographicSouth;
  157. var geographicEast;
  158. var geographicNorth;
  159. var rectangle = options.rectangle;
  160. if (!when.defined(rectangle)) {
  161. if (isGeographic) {
  162. geographicWest = toRadians(nativeRectangle.west);
  163. geographicSouth = toRadians(nativeRectangle.south);
  164. geographicEast = toRadians(nativeRectangle.east);
  165. geographicNorth = toRadians(nativeRectangle.north);
  166. } else {
  167. geographicWest = nativeRectangle.west * oneOverGlobeSemimajorAxis;
  168. geographicSouth =
  169. piOverTwo -
  170. 2.0 * atan(exp(-nativeRectangle.south * oneOverGlobeSemimajorAxis));
  171. geographicEast = nativeRectangle.east * oneOverGlobeSemimajorAxis;
  172. geographicNorth =
  173. piOverTwo -
  174. 2.0 * atan(exp(-nativeRectangle.north * oneOverGlobeSemimajorAxis));
  175. }
  176. } else {
  177. geographicWest = rectangle.west;
  178. geographicSouth = rectangle.south;
  179. geographicEast = rectangle.east;
  180. geographicNorth = rectangle.north;
  181. }
  182. var relativeToCenter = options.relativeToCenter;
  183. var hasRelativeToCenter = when.defined(relativeToCenter);
  184. relativeToCenter = hasRelativeToCenter ? relativeToCenter : Cartesian2.Cartesian3.ZERO;
  185. var exaggeration = when.defaultValue(options.exaggeration, 1.0);
  186. var includeWebMercatorT = when.defaultValue(options.includeWebMercatorT, false);
  187. var structure = when.defaultValue(
  188. options.structure,
  189. HeightmapTessellator.DEFAULT_STRUCTURE
  190. );
  191. var heightScale = when.defaultValue(
  192. structure.heightScale,
  193. HeightmapTessellator.DEFAULT_STRUCTURE.heightScale
  194. );
  195. var heightOffset = when.defaultValue(
  196. structure.heightOffset,
  197. HeightmapTessellator.DEFAULT_STRUCTURE.heightOffset
  198. );
  199. var elementsPerHeight = when.defaultValue(
  200. structure.elementsPerHeight,
  201. HeightmapTessellator.DEFAULT_STRUCTURE.elementsPerHeight
  202. );
  203. var stride = when.defaultValue(
  204. structure.stride,
  205. HeightmapTessellator.DEFAULT_STRUCTURE.stride
  206. );
  207. var elementMultiplier = when.defaultValue(
  208. structure.elementMultiplier,
  209. HeightmapTessellator.DEFAULT_STRUCTURE.elementMultiplier
  210. );
  211. var isBigEndian = when.defaultValue(
  212. structure.isBigEndian,
  213. HeightmapTessellator.DEFAULT_STRUCTURE.isBigEndian
  214. );
  215. var rectangleWidth = Cartesian2.Rectangle.computeWidth(nativeRectangle);
  216. var rectangleHeight = Cartesian2.Rectangle.computeHeight(nativeRectangle);
  217. var granularityX = rectangleWidth / (width - 1);
  218. var granularityY = rectangleHeight / (height - 1);
  219. if (!isGeographic) {
  220. rectangleWidth *= oneOverGlobeSemimajorAxis;
  221. rectangleHeight *= oneOverGlobeSemimajorAxis;
  222. }
  223. var radiiSquared = ellipsoid.radiiSquared;
  224. var radiiSquaredX = radiiSquared.x;
  225. var radiiSquaredY = radiiSquared.y;
  226. var radiiSquaredZ = radiiSquared.z;
  227. var minimumHeight = 65536.0;
  228. var maximumHeight = -65536.0;
  229. var fromENU = Transforms.Transforms.eastNorthUpToFixedFrame(relativeToCenter, ellipsoid);
  230. var toENU = Transforms.Matrix4.inverseTransformation(fromENU, matrix4Scratch);
  231. var southMercatorY;
  232. var oneOverMercatorHeight;
  233. if (includeWebMercatorT) {
  234. southMercatorY = WebMercatorProjection.WebMercatorProjection.geodeticLatitudeToMercatorAngle(
  235. geographicSouth
  236. );
  237. oneOverMercatorHeight =
  238. 1.0 /
  239. (WebMercatorProjection.WebMercatorProjection.geodeticLatitudeToMercatorAngle(geographicNorth) -
  240. southMercatorY);
  241. }
  242. var minimum = minimumScratch;
  243. minimum.x = Number.POSITIVE_INFINITY;
  244. minimum.y = Number.POSITIVE_INFINITY;
  245. minimum.z = Number.POSITIVE_INFINITY;
  246. var maximum = maximumScratch;
  247. maximum.x = Number.NEGATIVE_INFINITY;
  248. maximum.y = Number.NEGATIVE_INFINITY;
  249. maximum.z = Number.NEGATIVE_INFINITY;
  250. var hMin = Number.POSITIVE_INFINITY;
  251. var gridVertexCount = width * height;
  252. var edgeVertexCount = skirtHeight > 0.0 ? width * 2 + height * 2 : 0;
  253. var vertexCount = gridVertexCount + edgeVertexCount;
  254. var positions = new Array(vertexCount);
  255. var heights = new Array(vertexCount);
  256. var uvs = new Array(vertexCount);
  257. var webMercatorTs = includeWebMercatorT ? new Array(vertexCount) : [];
  258. var startRow = 0;
  259. var endRow = height;
  260. var startCol = 0;
  261. var endCol = width;
  262. if (skirtHeight > 0.0) {
  263. --startRow;
  264. ++endRow;
  265. --startCol;
  266. ++endCol;
  267. }
  268. var skirtOffsetPercentage = 0.00001;
  269. for (var rowIndex = startRow; rowIndex < endRow; ++rowIndex) {
  270. var row = rowIndex;
  271. if (row < 0) {
  272. row = 0;
  273. }
  274. if (row >= height) {
  275. row = height - 1;
  276. }
  277. var latitude = nativeRectangle.north - granularityY * row;
  278. if (!isGeographic) {
  279. latitude =
  280. piOverTwo - 2.0 * atan(exp(-latitude * oneOverGlobeSemimajorAxis));
  281. } else {
  282. latitude = toRadians(latitude);
  283. }
  284. var v = (latitude - geographicSouth) / (geographicNorth - geographicSouth);
  285. v = _Math.CesiumMath.clamp(v, 0.0, 1.0);
  286. var isNorthEdge = rowIndex === startRow;
  287. var isSouthEdge = rowIndex === endRow - 1;
  288. if (skirtHeight > 0.0) {
  289. if (isNorthEdge) {
  290. latitude += skirtOffsetPercentage * rectangleHeight;
  291. } else if (isSouthEdge) {
  292. latitude -= skirtOffsetPercentage * rectangleHeight;
  293. }
  294. }
  295. var cosLatitude = cos(latitude);
  296. var nZ = sin(latitude);
  297. var kZ = radiiSquaredZ * nZ;
  298. var webMercatorT;
  299. if (includeWebMercatorT) {
  300. webMercatorT =
  301. (WebMercatorProjection.WebMercatorProjection.geodeticLatitudeToMercatorAngle(latitude) -
  302. southMercatorY) *
  303. oneOverMercatorHeight;
  304. }
  305. for (var colIndex = startCol; colIndex < endCol; ++colIndex) {
  306. var col = colIndex;
  307. if (col < 0) {
  308. col = 0;
  309. }
  310. if (col >= width) {
  311. col = width - 1;
  312. }
  313. var terrainOffset = row * (width * stride) + col * stride;
  314. var heightSample;
  315. if (elementsPerHeight === 1) {
  316. heightSample = heightmap[terrainOffset];
  317. } else {
  318. heightSample = 0;
  319. var elementOffset;
  320. if (isBigEndian) {
  321. for (
  322. elementOffset = 0;
  323. elementOffset < elementsPerHeight;
  324. ++elementOffset
  325. ) {
  326. heightSample =
  327. heightSample * elementMultiplier +
  328. heightmap[terrainOffset + elementOffset];
  329. }
  330. } else {
  331. for (
  332. elementOffset = elementsPerHeight - 1;
  333. elementOffset >= 0;
  334. --elementOffset
  335. ) {
  336. heightSample =
  337. heightSample * elementMultiplier +
  338. heightmap[terrainOffset + elementOffset];
  339. }
  340. }
  341. }
  342. heightSample = (heightSample * heightScale + heightOffset) * exaggeration;
  343. maximumHeight = Math.max(maximumHeight, heightSample);
  344. minimumHeight = Math.min(minimumHeight, heightSample);
  345. var longitude = nativeRectangle.west + granularityX * col;
  346. if (!isGeographic) {
  347. longitude = longitude * oneOverGlobeSemimajorAxis;
  348. } else {
  349. longitude = toRadians(longitude);
  350. }
  351. var u = (longitude - geographicWest) / (geographicEast - geographicWest);
  352. u = _Math.CesiumMath.clamp(u, 0.0, 1.0);
  353. var index = row * width + col;
  354. if (skirtHeight > 0.0) {
  355. var isWestEdge = colIndex === startCol;
  356. var isEastEdge = colIndex === endCol - 1;
  357. var isEdge = isNorthEdge || isSouthEdge || isWestEdge || isEastEdge;
  358. var isCorner =
  359. (isNorthEdge || isSouthEdge) && (isWestEdge || isEastEdge);
  360. if (isCorner) {
  361. // Don't generate skirts on the corners.
  362. continue;
  363. } else if (isEdge) {
  364. heightSample -= skirtHeight;
  365. if (isWestEdge) {
  366. // The outer loop iterates north to south but the indices are ordered south to north, hence the index flip below
  367. index = gridVertexCount + (height - row - 1);
  368. longitude -= skirtOffsetPercentage * rectangleWidth;
  369. } else if (isSouthEdge) {
  370. // Add after west indices. South indices are ordered east to west.
  371. index = gridVertexCount + height + (width - col - 1);
  372. } else if (isEastEdge) {
  373. // Add after west and south indices. East indices are ordered north to south. The index is flipped like above.
  374. index = gridVertexCount + height + width + row;
  375. longitude += skirtOffsetPercentage * rectangleWidth;
  376. } else if (isNorthEdge) {
  377. // Add after west, south, and east indices. North indices are ordered west to east.
  378. index = gridVertexCount + height + width + height + col;
  379. }
  380. }
  381. }
  382. var nX = cosLatitude * cos(longitude);
  383. var nY = cosLatitude * sin(longitude);
  384. var kX = radiiSquaredX * nX;
  385. var kY = radiiSquaredY * nY;
  386. var gamma = sqrt(kX * nX + kY * nY + kZ * nZ);
  387. var oneOverGamma = 1.0 / gamma;
  388. var rSurfaceX = kX * oneOverGamma;
  389. var rSurfaceY = kY * oneOverGamma;
  390. var rSurfaceZ = kZ * oneOverGamma;
  391. var position = new Cartesian2.Cartesian3();
  392. position.x = rSurfaceX + nX * heightSample;
  393. position.y = rSurfaceY + nY * heightSample;
  394. position.z = rSurfaceZ + nZ * heightSample;
  395. positions[index] = position;
  396. heights[index] = heightSample;
  397. uvs[index] = new Cartesian2.Cartesian2(u, v);
  398. if (includeWebMercatorT) {
  399. webMercatorTs[index] = webMercatorT;
  400. }
  401. Transforms.Matrix4.multiplyByPoint(toENU, position, cartesian3Scratch);
  402. Cartesian2.Cartesian3.minimumByComponent(cartesian3Scratch, minimum, minimum);
  403. Cartesian2.Cartesian3.maximumByComponent(cartesian3Scratch, maximum, maximum);
  404. hMin = Math.min(hMin, heightSample);
  405. }
  406. }
  407. var boundingSphere3D = Transforms.BoundingSphere.fromPoints(positions);
  408. var orientedBoundingBox;
  409. if (when.defined(rectangle)) {
  410. orientedBoundingBox = OrientedBoundingBox.OrientedBoundingBox.fromRectangle(
  411. rectangle,
  412. minimumHeight,
  413. maximumHeight,
  414. ellipsoid
  415. );
  416. }
  417. var occludeePointInScaledSpace;
  418. if (hasRelativeToCenter) {
  419. var occluder = new TerrainEncoding.EllipsoidalOccluder(ellipsoid);
  420. occludeePointInScaledSpace = occluder.computeHorizonCullingPointPossiblyUnderEllipsoid(
  421. relativeToCenter,
  422. positions,
  423. minimumHeight
  424. );
  425. }
  426. var aaBox = new EllipsoidTangentPlane.AxisAlignedBoundingBox(minimum, maximum, relativeToCenter);
  427. var encoding = new TerrainEncoding.TerrainEncoding(
  428. aaBox,
  429. hMin,
  430. maximumHeight,
  431. fromENU,
  432. false,
  433. includeWebMercatorT
  434. );
  435. var vertices = new Float32Array(vertexCount * encoding.getStride());
  436. var bufferIndex = 0;
  437. for (var j = 0; j < vertexCount; ++j) {
  438. bufferIndex = encoding.encode(
  439. vertices,
  440. bufferIndex,
  441. positions[j],
  442. uvs[j],
  443. heights[j],
  444. undefined,
  445. webMercatorTs[j]
  446. );
  447. }
  448. return {
  449. vertices: vertices,
  450. maximumHeight: maximumHeight,
  451. minimumHeight: minimumHeight,
  452. encoding: encoding,
  453. boundingSphere3D: boundingSphere3D,
  454. orientedBoundingBox: orientedBoundingBox,
  455. occludeePointInScaledSpace: occludeePointInScaledSpace,
  456. };
  457. };
  458. /* jshint forin: false, bitwise: false */
  459. /*
  460. Copyright 2015-2018 Esri
  461. Licensed under the Apache License, Version 2.0 (the "License");
  462. you may not use this file except in compliance with the License.
  463. You may obtain a copy of the License at
  464. http://www.apache.org/licenses/LICENSE-2.0
  465. Unless required by applicable law or agreed to in writing, software
  466. distributed under the License is distributed on an "AS IS" BASIS,
  467. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  468. See the License for the specific language governing permissions and
  469. limitations under the License.
  470. A copy of the license and additional notices are located with the
  471. source distribution at:
  472. http://github.com/Esri/lerc/
  473. Contributors: Johannes Schmid, (LERC v1)
  474. Chayanika Khatua, (LERC v1)
  475. Wenxue Ju (LERC v1, v2.x)
  476. */
  477. /* Copyright 2015-2018 Esri. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @preserve */
  478. var tmp = {};
  479. /**
  480. * a module for decoding LERC blobs
  481. * @module Lerc
  482. */
  483. (function() {
  484. //the original LercDecode for Version 1
  485. var LercDecode = (function() {
  486. // WARNING: This decoder version can only read old version 1 Lerc blobs. Use with caution.
  487. // Note: currently, this module only has an implementation for decoding LERC data, not encoding. The name of
  488. // the class was chosen to be future proof.
  489. var CntZImage = {};
  490. CntZImage.defaultNoDataValue = -3.4027999387901484e+38; // smallest Float32 value
  491. /**
  492. * Decode a LERC byte stream and return an object containing the pixel data and some required and optional
  493. * information about it, such as the image's width and height.
  494. *
  495. * @param {ArrayBuffer} input The LERC input byte stream
  496. * @param {object} [options] Decoding options, containing any of the following properties:
  497. * @config {number} [inputOffset = 0]
  498. * Skip the first inputOffset bytes of the input byte stream. A valid LERC file is expected at that position.
  499. * @config {Uint8Array} [encodedMask = null]
  500. * If specified, the decoder will not read mask information from the input and use the specified encoded
  501. * mask data instead. Mask header/data must not be present in the LERC byte stream in this case.
  502. * @config {number} [noDataValue = LercCode.defaultNoDataValue]
  503. * Pixel value to use for masked pixels.
  504. * @config {ArrayBufferView|Array} [pixelType = Float32Array]
  505. * The desired type of the pixelData array in the return value. Note that it is the caller's responsibility to
  506. * provide an appropriate noDataValue if the default pixelType is overridden.
  507. * @config {boolean} [returnMask = false]
  508. * If true, the return value will contain a maskData property of type Uint8Array which has one element per
  509. * pixel, the value of which is 1 or 0 depending on whether that pixel's data is present or masked. If the
  510. * input LERC data does not contain a mask, maskData will not be returned.
  511. * @config {boolean} [returnEncodedMask = false]
  512. * If true, the return value will contain a encodedMaskData property, which can be passed into encode() as
  513. * encodedMask.
  514. * @config {boolean} [returnFileInfo = false]
  515. * If true, the return value will have a fileInfo property that contains metadata obtained from the
  516. * LERC headers and the decoding process.
  517. * @config {boolean} [computeUsedBitDepths = false]
  518. * If true, the fileInfo property in the return value will contain the set of all block bit depths
  519. * encountered during decoding. Will only have an effect if returnFileInfo option is true.
  520. * @returns {{width, height, pixelData, minValue, maxValue, noDataValue, maskData, encodedMaskData, fileInfo}}
  521. */
  522. CntZImage.decode = function(input, options) {
  523. options = options || {};
  524. var skipMask = options.encodedMaskData || (options.encodedMaskData === null);
  525. var parsedData = parse(input, options.inputOffset || 0, skipMask);
  526. var noDataValue = (options.noDataValue !== null) ? options.noDataValue : CntZImage.defaultNoDataValue;
  527. var uncompressedData = uncompressPixelValues(parsedData, options.pixelType || Float32Array,
  528. options.encodedMaskData, noDataValue, options.returnMask);
  529. var result = {
  530. width: parsedData.width,
  531. height: parsedData.height,
  532. pixelData: uncompressedData.resultPixels,
  533. minValue: uncompressedData.minValue,
  534. maxValue: parsedData.pixels.maxValue,
  535. noDataValue: noDataValue
  536. };
  537. if (uncompressedData.resultMask) {
  538. result.maskData = uncompressedData.resultMask;
  539. }
  540. if (options.returnEncodedMask && parsedData.mask) {
  541. result.encodedMaskData = parsedData.mask.bitset ? parsedData.mask.bitset : null;
  542. }
  543. if (options.returnFileInfo) {
  544. result.fileInfo = formatFileInfo(parsedData);
  545. if (options.computeUsedBitDepths) {
  546. result.fileInfo.bitDepths = computeUsedBitDepths(parsedData);
  547. }
  548. }
  549. return result;
  550. };
  551. var uncompressPixelValues = function(data, TypedArrayClass, maskBitset, noDataValue, storeDecodedMask) {
  552. var blockIdx = 0;
  553. var numX = data.pixels.numBlocksX;
  554. var numY = data.pixels.numBlocksY;
  555. var blockWidth = Math.floor(data.width / numX);
  556. var blockHeight = Math.floor(data.height / numY);
  557. var scale = 2 * data.maxZError;
  558. var minValue = Number.MAX_VALUE, currentValue;
  559. maskBitset = maskBitset || ((data.mask) ? data.mask.bitset : null);
  560. var resultPixels, resultMask;
  561. resultPixels = new TypedArrayClass(data.width * data.height);
  562. if (storeDecodedMask && maskBitset) {
  563. resultMask = new Uint8Array(data.width * data.height);
  564. }
  565. var blockDataBuffer = new Float32Array(blockWidth * blockHeight);
  566. var xx, yy;
  567. for (var y = 0; y <= numY; y++) {
  568. var thisBlockHeight = (y !== numY) ? blockHeight : (data.height % numY);
  569. if (thisBlockHeight === 0) {
  570. continue;
  571. }
  572. for (var x = 0; x <= numX; x++) {
  573. var thisBlockWidth = (x !== numX) ? blockWidth : (data.width % numX);
  574. if (thisBlockWidth === 0) {
  575. continue;
  576. }
  577. var outPtr = y * data.width * blockHeight + x * blockWidth;
  578. var outStride = data.width - thisBlockWidth;
  579. var block = data.pixels.blocks[blockIdx];
  580. var blockData, blockPtr, constValue;
  581. if (block.encoding < 2) {
  582. // block is either uncompressed or bit-stuffed (encodings 0 and 1)
  583. if (block.encoding === 0) {
  584. // block is uncompressed
  585. blockData = block.rawData;
  586. } else {
  587. // block is bit-stuffed
  588. unstuff(block.stuffedData, block.bitsPerPixel, block.numValidPixels, block.offset, scale, blockDataBuffer, data.pixels.maxValue);
  589. blockData = blockDataBuffer;
  590. }
  591. blockPtr = 0;
  592. }
  593. else if (block.encoding === 2) {
  594. // block is all 0
  595. constValue = 0;
  596. }
  597. else {
  598. // block has constant value (encoding === 3)
  599. constValue = block.offset;
  600. }
  601. var maskByte;
  602. if (maskBitset) {
  603. for (yy = 0; yy < thisBlockHeight; yy++) {
  604. if (outPtr & 7) {
  605. //
  606. maskByte = maskBitset[outPtr >> 3];
  607. maskByte <<= outPtr & 7;
  608. }
  609. for (xx = 0; xx < thisBlockWidth; xx++) {
  610. if (!(outPtr & 7)) {
  611. // read next byte from mask
  612. maskByte = maskBitset[outPtr >> 3];
  613. }
  614. if (maskByte & 128) {
  615. // pixel data present
  616. if (resultMask) {
  617. resultMask[outPtr] = 1;
  618. }
  619. currentValue = (block.encoding < 2) ? blockData[blockPtr++] : constValue;
  620. minValue = minValue > currentValue ? currentValue : minValue;
  621. resultPixels[outPtr++] = currentValue;
  622. } else {
  623. // pixel data not present
  624. if (resultMask) {
  625. resultMask[outPtr] = 0;
  626. }
  627. resultPixels[outPtr++] = noDataValue;
  628. }
  629. maskByte <<= 1;
  630. }
  631. outPtr += outStride;
  632. }
  633. } else {
  634. // mask not present, simply copy block over
  635. if (block.encoding < 2) {
  636. // duplicating this code block for performance reasons
  637. // blockData case:
  638. for (yy = 0; yy < thisBlockHeight; yy++) {
  639. for (xx = 0; xx < thisBlockWidth; xx++) {
  640. currentValue = blockData[blockPtr++];
  641. minValue = minValue > currentValue ? currentValue : minValue;
  642. resultPixels[outPtr++] = currentValue;
  643. }
  644. outPtr += outStride;
  645. }
  646. }
  647. else {
  648. // constValue case:
  649. minValue = minValue > constValue ? constValue : minValue;
  650. for (yy = 0; yy < thisBlockHeight; yy++) {
  651. for (xx = 0; xx < thisBlockWidth; xx++) {
  652. resultPixels[outPtr++] = constValue;
  653. }
  654. outPtr += outStride;
  655. }
  656. }
  657. }
  658. if ((block.encoding === 1) && (blockPtr !== block.numValidPixels)) {
  659. throw "Block and Mask do not match";
  660. }
  661. blockIdx++;
  662. }
  663. }
  664. return {
  665. resultPixels: resultPixels,
  666. resultMask: resultMask,
  667. minValue: minValue
  668. };
  669. };
  670. var formatFileInfo = function(data) {
  671. return {
  672. "fileIdentifierString": data.fileIdentifierString,
  673. "fileVersion": data.fileVersion,
  674. "imageType": data.imageType,
  675. "height": data.height,
  676. "width": data.width,
  677. "maxZError": data.maxZError,
  678. "eofOffset": data.eofOffset,
  679. "mask": data.mask ? {
  680. "numBlocksX": data.mask.numBlocksX,
  681. "numBlocksY": data.mask.numBlocksY,
  682. "numBytes": data.mask.numBytes,
  683. "maxValue": data.mask.maxValue
  684. } : null,
  685. "pixels": {
  686. "numBlocksX": data.pixels.numBlocksX,
  687. "numBlocksY": data.pixels.numBlocksY,
  688. "numBytes": data.pixels.numBytes,
  689. "maxValue": data.pixels.maxValue,
  690. "noDataValue": data.noDataValue
  691. }
  692. };
  693. };
  694. var computeUsedBitDepths = function(data) {
  695. var numBlocks = data.pixels.numBlocksX * data.pixels.numBlocksY;
  696. var bitDepths = {};
  697. for (var i = 0; i < numBlocks; i++) {
  698. var block = data.pixels.blocks[i];
  699. if (block.encoding === 0) {
  700. bitDepths.float32 = true;
  701. } else if (block.encoding === 1) {
  702. bitDepths[block.bitsPerPixel] = true;
  703. } else {
  704. bitDepths[0] = true;
  705. }
  706. }
  707. return Object.keys(bitDepths);
  708. };
  709. var parse = function(input, fp, skipMask) {
  710. var data = {};
  711. // File header
  712. var fileIdView = new Uint8Array(input, fp, 10);
  713. data.fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  714. if (data.fileIdentifierString.trim() !== "CntZImage") {
  715. throw "Unexpected file identifier string: " + data.fileIdentifierString;
  716. }
  717. fp += 10;
  718. var view = new DataView(input, fp, 24);
  719. data.fileVersion = view.getInt32(0, true);
  720. data.imageType = view.getInt32(4, true);
  721. data.height = view.getUint32(8, true);
  722. data.width = view.getUint32(12, true);
  723. data.maxZError = view.getFloat64(16, true);
  724. fp += 24;
  725. // Mask Header
  726. if (!skipMask) {
  727. view = new DataView(input, fp, 16);
  728. data.mask = {};
  729. data.mask.numBlocksY = view.getUint32(0, true);
  730. data.mask.numBlocksX = view.getUint32(4, true);
  731. data.mask.numBytes = view.getUint32(8, true);
  732. data.mask.maxValue = view.getFloat32(12, true);
  733. fp += 16;
  734. // Mask Data
  735. if (data.mask.numBytes > 0) {
  736. var bitset = new Uint8Array(Math.ceil(data.width * data.height / 8));
  737. view = new DataView(input, fp, data.mask.numBytes);
  738. var cnt = view.getInt16(0, true);
  739. var ip = 2, op = 0;
  740. do {
  741. if (cnt > 0) {
  742. while (cnt--) { bitset[op++] = view.getUint8(ip++); }
  743. } else {
  744. var val = view.getUint8(ip++);
  745. cnt = -cnt;
  746. while (cnt--) { bitset[op++] = val; }
  747. }
  748. cnt = view.getInt16(ip, true);
  749. ip += 2;
  750. } while (ip < data.mask.numBytes);
  751. if ((cnt !== -32768) || (op < bitset.length)) {
  752. throw "Unexpected end of mask RLE encoding";
  753. }
  754. data.mask.bitset = bitset;
  755. fp += data.mask.numBytes;
  756. }
  757. else if ((data.mask.numBytes | data.mask.numBlocksY | data.mask.maxValue) === 0) { // Special case, all nodata
  758. data.mask.bitset = new Uint8Array(Math.ceil(data.width * data.height / 8));
  759. }
  760. }
  761. // Pixel Header
  762. view = new DataView(input, fp, 16);
  763. data.pixels = {};
  764. data.pixels.numBlocksY = view.getUint32(0, true);
  765. data.pixels.numBlocksX = view.getUint32(4, true);
  766. data.pixels.numBytes = view.getUint32(8, true);
  767. data.pixels.maxValue = view.getFloat32(12, true);
  768. fp += 16;
  769. var numBlocksX = data.pixels.numBlocksX;
  770. var numBlocksY = data.pixels.numBlocksY;
  771. // the number of blocks specified in the header does not take into account the blocks at the end of
  772. // each row/column with a special width/height that make the image complete in case the width is not
  773. // evenly divisible by the number of blocks.
  774. var actualNumBlocksX = numBlocksX + ((data.width % numBlocksX) > 0 ? 1 : 0);
  775. var actualNumBlocksY = numBlocksY + ((data.height % numBlocksY) > 0 ? 1 : 0);
  776. data.pixels.blocks = new Array(actualNumBlocksX * actualNumBlocksY);
  777. var blockI = 0;
  778. for (var blockY = 0; blockY < actualNumBlocksY; blockY++) {
  779. for (var blockX = 0; blockX < actualNumBlocksX; blockX++) {
  780. // Block
  781. var size = 0;
  782. var bytesLeft = input.byteLength - fp;
  783. view = new DataView(input, fp, Math.min(10, bytesLeft));
  784. var block = {};
  785. data.pixels.blocks[blockI++] = block;
  786. var headerByte = view.getUint8(0); size++;
  787. block.encoding = headerByte & 63;
  788. if (block.encoding > 3) {
  789. throw "Invalid block encoding (" + block.encoding + ")";
  790. }
  791. if (block.encoding === 2) {
  792. fp++;
  793. continue;
  794. }
  795. if ((headerByte !== 0) && (headerByte !== 2)) {
  796. headerByte >>= 6;
  797. block.offsetType = headerByte;
  798. if (headerByte === 2) {
  799. block.offset = view.getInt8(1); size++;
  800. } else if (headerByte === 1) {
  801. block.offset = view.getInt16(1, true); size += 2;
  802. } else if (headerByte === 0) {
  803. block.offset = view.getFloat32(1, true); size += 4;
  804. } else {
  805. throw "Invalid block offset type";
  806. }
  807. if (block.encoding === 1) {
  808. headerByte = view.getUint8(size); size++;
  809. block.bitsPerPixel = headerByte & 63;
  810. headerByte >>= 6;
  811. block.numValidPixelsType = headerByte;
  812. if (headerByte === 2) {
  813. block.numValidPixels = view.getUint8(size); size++;
  814. } else if (headerByte === 1) {
  815. block.numValidPixels = view.getUint16(size, true); size += 2;
  816. } else if (headerByte === 0) {
  817. block.numValidPixels = view.getUint32(size, true); size += 4;
  818. } else {
  819. throw "Invalid valid pixel count type";
  820. }
  821. }
  822. }
  823. fp += size;
  824. if (block.encoding === 3) {
  825. continue;
  826. }
  827. var arrayBuf, store8;
  828. if (block.encoding === 0) {
  829. var numPixels = (data.pixels.numBytes - 1) / 4;
  830. if (numPixels !== Math.floor(numPixels)) {
  831. throw "uncompressed block has invalid length";
  832. }
  833. arrayBuf = new ArrayBuffer(numPixels * 4);
  834. store8 = new Uint8Array(arrayBuf);
  835. store8.set(new Uint8Array(input, fp, numPixels * 4));
  836. var rawData = new Float32Array(arrayBuf);
  837. block.rawData = rawData;
  838. fp += numPixels * 4;
  839. } else if (block.encoding === 1) {
  840. var dataBytes = Math.ceil(block.numValidPixels * block.bitsPerPixel / 8);
  841. var dataWords = Math.ceil(dataBytes / 4);
  842. arrayBuf = new ArrayBuffer(dataWords * 4);
  843. store8 = new Uint8Array(arrayBuf);
  844. store8.set(new Uint8Array(input, fp, dataBytes));
  845. block.stuffedData = new Uint32Array(arrayBuf);
  846. fp += dataBytes;
  847. }
  848. }
  849. }
  850. data.eofOffset = fp;
  851. return data;
  852. };
  853. var unstuff = function(src, bitsPerPixel, numPixels, offset, scale, dest, maxValue) {
  854. var bitMask = (1 << bitsPerPixel) - 1;
  855. var i = 0, o;
  856. var bitsLeft = 0;
  857. var n, buffer;
  858. var nmax = Math.ceil((maxValue - offset) / scale);
  859. // get rid of trailing bytes that are already part of next block
  860. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  861. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  862. for (o = 0; o < numPixels; o++) {
  863. if (bitsLeft === 0) {
  864. buffer = src[i++];
  865. bitsLeft = 32;
  866. }
  867. if (bitsLeft >= bitsPerPixel) {
  868. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  869. bitsLeft -= bitsPerPixel;
  870. } else {
  871. var missingBits = (bitsPerPixel - bitsLeft);
  872. n = ((buffer & bitMask) << missingBits) & bitMask;
  873. buffer = src[i++];
  874. bitsLeft = 32 - missingBits;
  875. n += (buffer >>> bitsLeft);
  876. }
  877. //pixel values may exceed max due to quantization
  878. dest[o] = n < nmax ? offset + n * scale : maxValue;
  879. }
  880. return dest;
  881. };
  882. return CntZImage;
  883. })();
  884. //version 2. Supports 2.1, 2.2, 2.3
  885. var Lerc2Decode = (function() {
  886. // Note: currently, this module only has an implementation for decoding LERC data, not encoding. The name of
  887. // the class was chosen to be future proof, following LercDecode.
  888. /*****************************************
  889. * private static class bitsutffer used by Lerc2Decode
  890. *******************************************/
  891. var BitStuffer = {
  892. //methods ending with 2 are for the new byte order used by Lerc2.3 and above.
  893. //originalUnstuff is used to unpack Huffman code table. code is duplicated to unstuffx for performance reasons.
  894. unstuff: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) {
  895. var bitMask = (1 << bitsPerPixel) - 1;
  896. var i = 0, o;
  897. var bitsLeft = 0;
  898. var n, buffer, missingBits, nmax;
  899. // get rid of trailing bytes that are already part of next block
  900. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  901. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  902. if (lutArr) {
  903. for (o = 0; o < numPixels; o++) {
  904. if (bitsLeft === 0) {
  905. buffer = src[i++];
  906. bitsLeft = 32;
  907. }
  908. if (bitsLeft >= bitsPerPixel) {
  909. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  910. bitsLeft -= bitsPerPixel;
  911. }
  912. else {
  913. missingBits = (bitsPerPixel - bitsLeft);
  914. n = ((buffer & bitMask) << missingBits) & bitMask;
  915. buffer = src[i++];
  916. bitsLeft = 32 - missingBits;
  917. n += (buffer >>> bitsLeft);
  918. }
  919. dest[o] = lutArr[n];//offset + lutArr[n] * scale;
  920. }
  921. }
  922. else {
  923. nmax = Math.ceil((maxValue - offset) / scale);
  924. for (o = 0; o < numPixels; o++) {
  925. if (bitsLeft === 0) {
  926. buffer = src[i++];
  927. bitsLeft = 32;
  928. }
  929. if (bitsLeft >= bitsPerPixel) {
  930. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  931. bitsLeft -= bitsPerPixel;
  932. }
  933. else {
  934. missingBits = (bitsPerPixel - bitsLeft);
  935. n = ((buffer & bitMask) << missingBits) & bitMask;
  936. buffer = src[i++];
  937. bitsLeft = 32 - missingBits;
  938. n += (buffer >>> bitsLeft);
  939. }
  940. //pixel values may exceed max due to quantization
  941. dest[o] = n < nmax ? offset + n * scale : maxValue;
  942. }
  943. }
  944. },
  945. unstuffLUT: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) {
  946. var bitMask = (1 << bitsPerPixel) - 1;
  947. var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n = 0;
  948. var buffer;
  949. var dest = [];
  950. // get rid of trailing bytes that are already part of next block
  951. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  952. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  953. var nmax = Math.ceil((maxValue - offset) / scale);
  954. for (o = 0; o < numPixels; o++) {
  955. if (bitsLeft === 0) {
  956. buffer = src[i++];
  957. bitsLeft = 32;
  958. }
  959. if (bitsLeft >= bitsPerPixel) {
  960. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  961. bitsLeft -= bitsPerPixel;
  962. } else {
  963. missingBits = (bitsPerPixel - bitsLeft);
  964. n = ((buffer & bitMask) << missingBits) & bitMask;
  965. buffer = src[i++];
  966. bitsLeft = 32 - missingBits;
  967. n += (buffer >>> bitsLeft);
  968. }
  969. //dest.push(n);
  970. dest[o] = n < nmax ? offset + n * scale : maxValue;
  971. }
  972. dest.unshift(offset);//1st one
  973. return dest;
  974. },
  975. unstuff2: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) {
  976. var bitMask = (1 << bitsPerPixel) - 1;
  977. var i = 0, o;
  978. var bitsLeft = 0, bitPos = 0;
  979. var n, buffer, missingBits;
  980. if (lutArr) {
  981. for (o = 0; o < numPixels; o++) {
  982. if (bitsLeft === 0) {
  983. buffer = src[i++];
  984. bitsLeft = 32;
  985. bitPos = 0;
  986. }
  987. if (bitsLeft >= bitsPerPixel) {
  988. n = ((buffer >>> bitPos) & bitMask);
  989. bitsLeft -= bitsPerPixel;
  990. bitPos += bitsPerPixel;
  991. } else {
  992. missingBits = (bitsPerPixel - bitsLeft);
  993. n = (buffer >>> bitPos) & bitMask;
  994. buffer = src[i++];
  995. bitsLeft = 32 - missingBits;
  996. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  997. bitPos = missingBits;
  998. }
  999. dest[o] = lutArr[n];
  1000. }
  1001. }
  1002. else {
  1003. var nmax = Math.ceil((maxValue - offset) / scale);
  1004. for (o = 0; o < numPixels; o++) {
  1005. if (bitsLeft === 0) {
  1006. buffer = src[i++];
  1007. bitsLeft = 32;
  1008. bitPos = 0;
  1009. }
  1010. if (bitsLeft >= bitsPerPixel) {
  1011. //no unsigned left shift
  1012. n = ((buffer >>> bitPos) & bitMask);
  1013. bitsLeft -= bitsPerPixel;
  1014. bitPos += bitsPerPixel;
  1015. } else {
  1016. missingBits = (bitsPerPixel - bitsLeft);
  1017. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  1018. buffer = src[i++];
  1019. bitsLeft = 32 - missingBits;
  1020. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  1021. bitPos = missingBits;
  1022. }
  1023. //pixel values may exceed max due to quantization
  1024. dest[o] = n < nmax ? offset + n * scale : maxValue;
  1025. }
  1026. }
  1027. return dest;
  1028. },
  1029. unstuffLUT2: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) {
  1030. var bitMask = (1 << bitsPerPixel) - 1;
  1031. var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n = 0, bitPos = 0;
  1032. var buffer;
  1033. var dest = [];
  1034. var nmax = Math.ceil((maxValue - offset) / scale);
  1035. for (o = 0; o < numPixels; o++) {
  1036. if (bitsLeft === 0) {
  1037. buffer = src[i++];
  1038. bitsLeft = 32;
  1039. bitPos = 0;
  1040. }
  1041. if (bitsLeft >= bitsPerPixel) {
  1042. //no unsigned left shift
  1043. n = ((buffer >>> bitPos) & bitMask);
  1044. bitsLeft -= bitsPerPixel;
  1045. bitPos += bitsPerPixel;
  1046. } else {
  1047. missingBits = (bitsPerPixel - bitsLeft);
  1048. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  1049. buffer = src[i++];
  1050. bitsLeft = 32 - missingBits;
  1051. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  1052. bitPos = missingBits;
  1053. }
  1054. //dest.push(n);
  1055. dest[o] = n < nmax ? offset + n * scale : maxValue;
  1056. }
  1057. dest.unshift(offset);
  1058. return dest;
  1059. },
  1060. originalUnstuff: function(src, dest, bitsPerPixel, numPixels) {
  1061. var bitMask = (1 << bitsPerPixel) - 1;
  1062. var i = 0, o;
  1063. var bitsLeft = 0;
  1064. var n, buffer, missingBits;
  1065. // get rid of trailing bytes that are already part of next block
  1066. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  1067. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  1068. for (o = 0; o < numPixels; o++) {
  1069. if (bitsLeft === 0) {
  1070. buffer = src[i++];
  1071. bitsLeft = 32;
  1072. }
  1073. if (bitsLeft >= bitsPerPixel) {
  1074. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  1075. bitsLeft -= bitsPerPixel;
  1076. }
  1077. else {
  1078. missingBits = (bitsPerPixel - bitsLeft);
  1079. n = ((buffer & bitMask) << missingBits) & bitMask;
  1080. buffer = src[i++];
  1081. bitsLeft = 32 - missingBits;
  1082. n += (buffer >>> bitsLeft);
  1083. }
  1084. dest[o] = n;
  1085. }
  1086. return dest;
  1087. },
  1088. originalUnstuff2: function(src, dest, bitsPerPixel, numPixels) {
  1089. var bitMask = (1 << bitsPerPixel) - 1;
  1090. var i = 0, o;
  1091. var bitsLeft = 0, bitPos = 0;
  1092. var n, buffer, missingBits;
  1093. //micro-optimizations
  1094. for (o = 0; o < numPixels; o++) {
  1095. if (bitsLeft === 0) {
  1096. buffer = src[i++];
  1097. bitsLeft = 32;
  1098. bitPos = 0;
  1099. }
  1100. if (bitsLeft >= bitsPerPixel) {
  1101. //no unsigned left shift
  1102. n = ((buffer >>> bitPos) & bitMask);
  1103. bitsLeft -= bitsPerPixel;
  1104. bitPos += bitsPerPixel;
  1105. } else {
  1106. missingBits = (bitsPerPixel - bitsLeft);
  1107. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  1108. buffer = src[i++];
  1109. bitsLeft = 32 - missingBits;
  1110. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  1111. bitPos = missingBits;
  1112. }
  1113. dest[o] = n;
  1114. }
  1115. return dest;
  1116. }
  1117. };
  1118. /*****************************************
  1119. *private static class used by Lerc2Decode
  1120. ******************************************/
  1121. var Lerc2Helpers = {
  1122. HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, treat it like constant
  1123. computeChecksumFletcher32: function(input) {
  1124. var sum1 = 0xffff, sum2 = 0xffff;
  1125. var len = input.length;
  1126. var words = Math.floor(len / 2);
  1127. var i = 0;
  1128. while (words) {
  1129. var tlen = (words >= 359) ? 359 : words;
  1130. words -= tlen;
  1131. do {
  1132. sum1 += (input[i++] << 8);
  1133. sum2 += sum1 += input[i++];
  1134. } while (--tlen);
  1135. sum1 = (sum1 & 0xffff) + (sum1 >>> 16);
  1136. sum2 = (sum2 & 0xffff) + (sum2 >>> 16);
  1137. }
  1138. // add the straggler byte if it exists
  1139. if (len & 1) {
  1140. sum2 += sum1 += (input[i] << 8);
  1141. }
  1142. // second reduction step to reduce sums to 16 bits
  1143. sum1 = (sum1 & 0xffff) + (sum1 >>> 16);
  1144. sum2 = (sum2 & 0xffff) + (sum2 >>> 16);
  1145. return (sum2 << 16 | sum1) >>> 0;
  1146. },
  1147. readHeaderInfo: function(input, data) {
  1148. var ptr = data.ptr;
  1149. var fileIdView = new Uint8Array(input, ptr, 6);
  1150. var headerInfo = {};
  1151. headerInfo.fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  1152. if (headerInfo.fileIdentifierString.lastIndexOf("Lerc2", 0) !== 0) {
  1153. throw "Unexpected file identifier string (expect Lerc2 ): " + headerInfo.fileIdentifierString;
  1154. }
  1155. ptr += 6;
  1156. var view = new DataView(input, ptr, 8);
  1157. var fileVersion = view.getInt32(0, true);
  1158. headerInfo.fileVersion = fileVersion;
  1159. ptr += 4;
  1160. if (fileVersion >= 3) {
  1161. headerInfo.checksum = view.getUint32(4, true); //nrows
  1162. ptr += 4;
  1163. }
  1164. //keys start from here
  1165. view = new DataView(input, ptr, 12);
  1166. headerInfo.height = view.getUint32(0, true); //nrows
  1167. headerInfo.width = view.getUint32(4, true); //ncols
  1168. ptr += 8;
  1169. if (fileVersion >= 4) {
  1170. headerInfo.numDims = view.getUint32(8, true);
  1171. ptr += 4;
  1172. }
  1173. else {
  1174. headerInfo.numDims = 1;
  1175. }
  1176. view = new DataView(input, ptr, 40);
  1177. headerInfo.numValidPixel = view.getUint32(0, true);
  1178. headerInfo.microBlockSize = view.getInt32(4, true);
  1179. headerInfo.blobSize = view.getInt32(8, true);
  1180. headerInfo.imageType = view.getInt32(12, true);
  1181. headerInfo.maxZError = view.getFloat64(16, true);
  1182. headerInfo.zMin = view.getFloat64(24, true);
  1183. headerInfo.zMax = view.getFloat64(32, true);
  1184. ptr += 40;
  1185. data.headerInfo = headerInfo;
  1186. data.ptr = ptr;
  1187. var checksum, keyLength;
  1188. if (fileVersion >= 3) {
  1189. keyLength = fileVersion >= 4 ? 52 : 48;
  1190. checksum = this.computeChecksumFletcher32(new Uint8Array(input, ptr - keyLength, headerInfo.blobSize - 14));
  1191. if (checksum !== headerInfo.checksum) {
  1192. throw "Checksum failed.";
  1193. }
  1194. }
  1195. return true;
  1196. },
  1197. checkMinMaxRanges: function(input, data) {
  1198. var headerInfo = data.headerInfo;
  1199. var OutPixelTypeArray = this.getDataTypeArray(headerInfo.imageType);
  1200. var rangeBytes = headerInfo.numDims * this.getDataTypeSize(headerInfo.imageType);
  1201. var minValues = this.readSubArray(input, data.ptr, OutPixelTypeArray, rangeBytes);
  1202. var maxValues = this.readSubArray(input, data.ptr + rangeBytes, OutPixelTypeArray, rangeBytes);
  1203. data.ptr += (2 * rangeBytes);
  1204. var i, equal = true;
  1205. for (i = 0; i < headerInfo.numDims; i++) {
  1206. if (minValues[i] !== maxValues[i]) {
  1207. equal = false;
  1208. break;
  1209. }
  1210. }
  1211. headerInfo.minValues = minValues;
  1212. headerInfo.maxValues = maxValues;
  1213. return equal;
  1214. },
  1215. readSubArray: function(input, ptr, OutPixelTypeArray, numBytes) {
  1216. var rawData;
  1217. if (OutPixelTypeArray === Uint8Array) {
  1218. rawData = new Uint8Array(input, ptr, numBytes);
  1219. }
  1220. else {
  1221. var arrayBuf = new ArrayBuffer(numBytes);
  1222. var store8 = new Uint8Array(arrayBuf);
  1223. store8.set(new Uint8Array(input, ptr, numBytes));
  1224. rawData = new OutPixelTypeArray(arrayBuf);
  1225. }
  1226. return rawData;
  1227. },
  1228. readMask: function(input, data) {
  1229. var ptr = data.ptr;
  1230. var headerInfo = data.headerInfo;
  1231. var numPixels = headerInfo.width * headerInfo.height;
  1232. var numValidPixel = headerInfo.numValidPixel;
  1233. var view = new DataView(input, ptr, 4);
  1234. var mask = {};
  1235. mask.numBytes = view.getUint32(0, true);
  1236. ptr += 4;
  1237. // Mask Data
  1238. if ((0 === numValidPixel || numPixels === numValidPixel) && 0 !== mask.numBytes) {
  1239. throw ("invalid mask");
  1240. }
  1241. var bitset, resultMask;
  1242. if (numValidPixel === 0) {
  1243. bitset = new Uint8Array(Math.ceil(numPixels / 8));
  1244. mask.bitset = bitset;
  1245. resultMask = new Uint8Array(numPixels);
  1246. data.pixels.resultMask = resultMask;
  1247. ptr += mask.numBytes;
  1248. }// ????? else if (data.mask.numBytes > 0 && data.mask.numBytes< data.numValidPixel) {
  1249. else if (mask.numBytes > 0) {
  1250. bitset = new Uint8Array(Math.ceil(numPixels / 8));
  1251. view = new DataView(input, ptr, mask.numBytes);
  1252. var cnt = view.getInt16(0, true);
  1253. var ip = 2, op = 0, val = 0;
  1254. do {
  1255. if (cnt > 0) {
  1256. while (cnt--) { bitset[op++] = view.getUint8(ip++); }
  1257. } else {
  1258. val = view.getUint8(ip++);
  1259. cnt = -cnt;
  1260. while (cnt--) { bitset[op++] = val; }
  1261. }
  1262. cnt = view.getInt16(ip, true);
  1263. ip += 2;
  1264. } while (ip < mask.numBytes);
  1265. if ((cnt !== -32768) || (op < bitset.length)) {
  1266. throw "Unexpected end of mask RLE encoding";
  1267. }
  1268. resultMask = new Uint8Array(numPixels);
  1269. var mb = 0, k = 0;
  1270. for (k = 0; k < numPixels; k++) {
  1271. if (k & 7) {
  1272. mb = bitset[k >> 3];
  1273. mb <<= k & 7;
  1274. }
  1275. else {
  1276. mb = bitset[k >> 3];
  1277. }
  1278. if (mb & 128) {
  1279. resultMask[k] = 1;
  1280. }
  1281. }
  1282. data.pixels.resultMask = resultMask;
  1283. mask.bitset = bitset;
  1284. ptr += mask.numBytes;
  1285. }
  1286. data.ptr = ptr;
  1287. data.mask = mask;
  1288. return true;
  1289. },
  1290. readDataOneSweep: function(input, data, OutPixelTypeArray) {
  1291. var ptr = data.ptr;
  1292. var headerInfo = data.headerInfo;
  1293. var numDims = headerInfo.numDims;
  1294. var numPixels = headerInfo.width * headerInfo.height;
  1295. var imageType = headerInfo.imageType;
  1296. var numBytes = headerInfo.numValidPixel * Lerc2Helpers.getDataTypeSize(imageType) * numDims;
  1297. //data.pixels.numBytes = numBytes;
  1298. var rawData;
  1299. var mask = data.pixels.resultMask;
  1300. if (OutPixelTypeArray === Uint8Array) {
  1301. rawData = new Uint8Array(input, ptr, numBytes);
  1302. }
  1303. else {
  1304. var arrayBuf = new ArrayBuffer(numBytes);
  1305. var store8 = new Uint8Array(arrayBuf);
  1306. store8.set(new Uint8Array(input, ptr, numBytes));
  1307. rawData = new OutPixelTypeArray(arrayBuf);
  1308. }
  1309. if (rawData.length === numPixels * numDims) {
  1310. data.pixels.resultPixels = rawData;
  1311. }
  1312. else //mask
  1313. {
  1314. data.pixels.resultPixels = new OutPixelTypeArray(numPixels * numDims);
  1315. var z = 0, k = 0, i = 0, nStart = 0;
  1316. if (numDims > 1) {
  1317. for (i=0; i < numDims; i++) {
  1318. nStart = i * numPixels;
  1319. for (k = 0; k < numPixels; k++) {
  1320. if (mask[k]) {
  1321. data.pixels.resultPixels[nStart + k] = rawData[z++];
  1322. }
  1323. }
  1324. }
  1325. }
  1326. else {
  1327. for (k = 0; k < numPixels; k++) {
  1328. if (mask[k]) {
  1329. data.pixels.resultPixels[k] = rawData[z++];
  1330. }
  1331. }
  1332. }
  1333. }
  1334. ptr += numBytes;
  1335. data.ptr = ptr; //return data;
  1336. return true;
  1337. },
  1338. readHuffmanTree: function(input, data) {
  1339. var BITS_MAX = this.HUFFMAN_LUT_BITS_MAX; //8 is slow for the large test image
  1340. //var size_max = 1 << BITS_MAX;
  1341. /* ************************
  1342. * reading code table
  1343. *************************/
  1344. var view = new DataView(input, data.ptr, 16);
  1345. data.ptr += 16;
  1346. var version = view.getInt32(0, true);
  1347. if (version < 2) {
  1348. throw "unsupported Huffman version";
  1349. }
  1350. var size = view.getInt32(4, true);
  1351. var i0 = view.getInt32(8, true);
  1352. var i1 = view.getInt32(12, true);
  1353. if (i0 >= i1) {
  1354. return false;
  1355. }
  1356. var blockDataBuffer = new Uint32Array(i1 - i0);
  1357. Lerc2Helpers.decodeBits(input, data, blockDataBuffer);
  1358. var codeTable = []; //size
  1359. var i, j, k, len;
  1360. for (i = i0; i < i1; i++) {
  1361. j = i - (i < size ? 0 : size);//wrap around
  1362. codeTable[j] = { first: blockDataBuffer[i - i0], second: null };
  1363. }
  1364. var dataBytes = input.byteLength - data.ptr;
  1365. var dataWords = Math.ceil(dataBytes / 4);
  1366. var arrayBuf = new ArrayBuffer(dataWords * 4);
  1367. var store8 = new Uint8Array(arrayBuf);
  1368. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1369. var stuffedData = new Uint32Array(arrayBuf); //must start from x*4
  1370. var bitPos = 0, word, srcPtr = 0;
  1371. word = stuffedData[0];
  1372. for (i = i0; i < i1; i++) {
  1373. j = i - (i < size ? 0 : size);//wrap around
  1374. len = codeTable[j].first;
  1375. if (len > 0) {
  1376. codeTable[j].second = (word << bitPos) >>> (32 - len);
  1377. if (32 - bitPos >= len) {
  1378. bitPos += len;
  1379. if (bitPos === 32) {
  1380. bitPos = 0;
  1381. srcPtr++;
  1382. word = stuffedData[srcPtr];
  1383. }
  1384. }
  1385. else {
  1386. bitPos += len - 32;
  1387. srcPtr++;
  1388. word = stuffedData[srcPtr];
  1389. codeTable[j].second |= word >>> (32 - bitPos);
  1390. }
  1391. }
  1392. }
  1393. //finished reading code table
  1394. /* ************************
  1395. * building lut
  1396. *************************/
  1397. var numBitsLUT = 0, numBitsLUTQick = 0;
  1398. var tree = new TreeNode();
  1399. for (i = 0; i < codeTable.length; i++) {
  1400. if (codeTable[i] !== undefined) {
  1401. numBitsLUT = Math.max(numBitsLUT, codeTable[i].first);
  1402. }
  1403. }
  1404. if (numBitsLUT >= BITS_MAX) {
  1405. numBitsLUTQick = BITS_MAX;
  1406. }
  1407. else {
  1408. numBitsLUTQick = numBitsLUT;
  1409. }
  1410. if (numBitsLUT >= 30) {
  1411. console.log("WARning, large NUM LUT BITS IS " + numBitsLUT);
  1412. }
  1413. var decodeLut = [], entry, code, numEntries, jj, currentBit, node;
  1414. for (i = i0; i < i1; i++) {
  1415. j = i - (i < size ? 0 : size);//wrap around
  1416. len = codeTable[j].first;
  1417. if (len > 0) {
  1418. entry = [len, j];
  1419. if (len <= numBitsLUTQick) {
  1420. code = codeTable[j].second << (numBitsLUTQick - len);
  1421. numEntries = 1 << (numBitsLUTQick - len);
  1422. for (k = 0; k < numEntries; k++) {
  1423. decodeLut[code | k] = entry;
  1424. }
  1425. }
  1426. else {
  1427. //build tree
  1428. code = codeTable[j].second;
  1429. node = tree;
  1430. for (jj = len - 1; jj >= 0; jj--) {
  1431. currentBit = code >>> jj & 1; //no left shift as length could be 30,31
  1432. if (currentBit) {
  1433. if (!node.right) {
  1434. node.right = new TreeNode();
  1435. }
  1436. node = node.right;
  1437. }
  1438. else {
  1439. if (!node.left) {
  1440. node.left = new TreeNode();
  1441. }
  1442. node = node.left;
  1443. }
  1444. if (jj === 0 && !node.val) {
  1445. node.val = entry[1];
  1446. }
  1447. }
  1448. }
  1449. }
  1450. }
  1451. return {
  1452. decodeLut: decodeLut,
  1453. numBitsLUTQick: numBitsLUTQick,
  1454. numBitsLUT: numBitsLUT,
  1455. tree: tree,
  1456. stuffedData: stuffedData,
  1457. srcPtr: srcPtr,
  1458. bitPos: bitPos
  1459. };
  1460. },
  1461. readHuffman: function(input, data, OutPixelTypeArray) {
  1462. var headerInfo = data.headerInfo;
  1463. var numDims = headerInfo.numDims;
  1464. var height = data.headerInfo.height;
  1465. var width = data.headerInfo.width;
  1466. var numPixels = width * height;
  1467. //var size_max = 1 << BITS_MAX;
  1468. /* ************************
  1469. * reading huffman structure info
  1470. *************************/
  1471. var huffmanInfo = this.readHuffmanTree(input, data);
  1472. var decodeLut = huffmanInfo.decodeLut;
  1473. var tree = huffmanInfo.tree;
  1474. //stuffedData includes huffman headers
  1475. var stuffedData = huffmanInfo.stuffedData;
  1476. var srcPtr = huffmanInfo.srcPtr;
  1477. var bitPos = huffmanInfo.bitPos;
  1478. var numBitsLUTQick = huffmanInfo.numBitsLUTQick;
  1479. var numBitsLUT = huffmanInfo.numBitsLUT;
  1480. var offset = data.headerInfo.imageType === 0 ? 128 : 0;
  1481. /*************************
  1482. * decode
  1483. ***************************/
  1484. var node, val, delta, mask = data.pixels.resultMask, valTmp, valTmpQuick, currentBit;
  1485. var i, j, k, ii;
  1486. var prevVal = 0;
  1487. if (bitPos > 0) {
  1488. srcPtr++;
  1489. bitPos = 0;
  1490. }
  1491. var word = stuffedData[srcPtr];
  1492. var deltaEncode = data.encodeMode === 1;
  1493. var resultPixelsAllDim = new OutPixelTypeArray(numPixels * numDims);
  1494. var resultPixels = resultPixelsAllDim;
  1495. var iDim;
  1496. for (iDim = 0; iDim < headerInfo.numDims; iDim++) {
  1497. if (numDims > 1) {
  1498. //get the mem block of current dimension
  1499. resultPixels = new OutPixelTypeArray(resultPixelsAllDim.buffer, numPixels * iDim, numPixels);
  1500. prevVal = 0;
  1501. }
  1502. if (data.headerInfo.numValidPixel === width * height) { //all valid
  1503. for (k = 0, i = 0; i < height; i++) {
  1504. for (j = 0; j < width; j++, k++) {
  1505. val = 0;
  1506. valTmp = (word << bitPos) >>> (32 - numBitsLUTQick);
  1507. valTmpQuick = valTmp;// >>> deltaBits;
  1508. if (32 - bitPos < numBitsLUTQick) {
  1509. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUTQick));
  1510. valTmpQuick = valTmp;// >>> deltaBits;
  1511. }
  1512. if (decodeLut[valTmpQuick]) // if there, move the correct number of bits and done
  1513. {
  1514. val = decodeLut[valTmpQuick][1];
  1515. bitPos += decodeLut[valTmpQuick][0];
  1516. }
  1517. else {
  1518. valTmp = (word << bitPos) >>> (32 - numBitsLUT);
  1519. valTmpQuick = valTmp;// >>> deltaBits;
  1520. if (32 - bitPos < numBitsLUT) {
  1521. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUT));
  1522. valTmpQuick = valTmp;// >>> deltaBits;
  1523. }
  1524. node = tree;
  1525. for (ii = 0; ii < numBitsLUT; ii++) {
  1526. currentBit = valTmp >>> (numBitsLUT - ii - 1) & 1;
  1527. node = currentBit ? node.right : node.left;
  1528. if (!(node.left || node.right)) {
  1529. val = node.val;
  1530. bitPos = bitPos + ii + 1;
  1531. break;
  1532. }
  1533. }
  1534. }
  1535. if (bitPos >= 32) {
  1536. bitPos -= 32;
  1537. srcPtr++;
  1538. word = stuffedData[srcPtr];
  1539. }
  1540. delta = val - offset;
  1541. if (deltaEncode) {
  1542. if (j > 0) {
  1543. delta += prevVal; // use overflow
  1544. }
  1545. else if (i > 0) {
  1546. delta += resultPixels[k - width];
  1547. }
  1548. else {
  1549. delta += prevVal;
  1550. }
  1551. delta &= 0xFF; //overflow
  1552. resultPixels[k] = delta;//overflow
  1553. prevVal = delta;
  1554. }
  1555. else {
  1556. resultPixels[k] = delta;
  1557. }
  1558. }
  1559. }
  1560. }
  1561. else { //not all valid, use mask
  1562. for (k = 0, i = 0; i < height; i++) {
  1563. for (j = 0; j < width; j++, k++) {
  1564. if (mask[k]) {
  1565. val = 0;
  1566. valTmp = (word << bitPos) >>> (32 - numBitsLUTQick);
  1567. valTmpQuick = valTmp;// >>> deltaBits;
  1568. if (32 - bitPos < numBitsLUTQick) {
  1569. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUTQick));
  1570. valTmpQuick = valTmp;// >>> deltaBits;
  1571. }
  1572. if (decodeLut[valTmpQuick]) // if there, move the correct number of bits and done
  1573. {
  1574. val = decodeLut[valTmpQuick][1];
  1575. bitPos += decodeLut[valTmpQuick][0];
  1576. }
  1577. else {
  1578. valTmp = (word << bitPos) >>> (32 - numBitsLUT);
  1579. valTmpQuick = valTmp;// >>> deltaBits;
  1580. if (32 - bitPos < numBitsLUT) {
  1581. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUT));
  1582. valTmpQuick = valTmp;// >>> deltaBits;
  1583. }
  1584. node = tree;
  1585. for (ii = 0; ii < numBitsLUT; ii++) {
  1586. currentBit = valTmp >>> (numBitsLUT - ii - 1) & 1;
  1587. node = currentBit ? node.right : node.left;
  1588. if (!(node.left || node.right)) {
  1589. val = node.val;
  1590. bitPos = bitPos + ii + 1;
  1591. break;
  1592. }
  1593. }
  1594. }
  1595. if (bitPos >= 32) {
  1596. bitPos -= 32;
  1597. srcPtr++;
  1598. word = stuffedData[srcPtr];
  1599. }
  1600. delta = val - offset;
  1601. if (deltaEncode) {
  1602. if (j > 0 && mask[k - 1]) {
  1603. delta += prevVal; // use overflow
  1604. }
  1605. else if (i > 0 && mask[k - width]) {
  1606. delta += resultPixels[k - width];
  1607. }
  1608. else {
  1609. delta += prevVal;
  1610. }
  1611. delta &= 0xFF; //overflow
  1612. resultPixels[k] = delta;//overflow
  1613. prevVal = delta;
  1614. }
  1615. else {
  1616. resultPixels[k] = delta;
  1617. }
  1618. }
  1619. }
  1620. }
  1621. }
  1622. data.ptr = data.ptr + (srcPtr + 1) * 4 + (bitPos > 0 ? 4 : 0);
  1623. }
  1624. data.pixels.resultPixels = resultPixelsAllDim;
  1625. },
  1626. decodeBits: function(input, data, blockDataBuffer, offset, iDim) {
  1627. {
  1628. //bitstuff encoding is 3
  1629. var headerInfo = data.headerInfo;
  1630. var fileVersion = headerInfo.fileVersion;
  1631. //var block = {};
  1632. var blockPtr = 0;
  1633. var viewByteLength = ((input.byteLength - data.ptr) >= 5) ? 5 : (input.byteLength - data.ptr);
  1634. var view = new DataView(input, data.ptr, viewByteLength);
  1635. var headerByte = view.getUint8(0);
  1636. blockPtr++;
  1637. var bits67 = headerByte >> 6;
  1638. var n = (bits67 === 0) ? 4 : 3 - bits67;
  1639. var doLut = (headerByte & 32) > 0 ? true : false;//5th bit
  1640. var numBits = headerByte & 31;
  1641. var numElements = 0;
  1642. if (n === 1) {
  1643. numElements = view.getUint8(blockPtr); blockPtr++;
  1644. } else if (n === 2) {
  1645. numElements = view.getUint16(blockPtr, true); blockPtr += 2;
  1646. } else if (n === 4) {
  1647. numElements = view.getUint32(blockPtr, true); blockPtr += 4;
  1648. } else {
  1649. throw "Invalid valid pixel count type";
  1650. }
  1651. //fix: huffman codes are bit stuffed, but not bound by data's max value, so need to use originalUnstuff
  1652. //offset = offset || 0;
  1653. var scale = 2 * headerInfo.maxZError;
  1654. var stuffedData, arrayBuf, store8, dataBytes, dataWords;
  1655. var lutArr, lutData, lutBytes, bitsPerPixel;
  1656. var zMax = headerInfo.numDims > 1 ? headerInfo.maxValues[iDim] : headerInfo.zMax;
  1657. if (doLut) {
  1658. data.counter.lut++;
  1659. lutBytes = view.getUint8(blockPtr);
  1660. blockPtr++;
  1661. dataBytes = Math.ceil((lutBytes - 1) * numBits / 8);
  1662. dataWords = Math.ceil(dataBytes / 4);
  1663. arrayBuf = new ArrayBuffer(dataWords * 4);
  1664. store8 = new Uint8Array(arrayBuf);
  1665. data.ptr += blockPtr;
  1666. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1667. lutData = new Uint32Array(arrayBuf);
  1668. data.ptr += dataBytes;
  1669. bitsPerPixel = 0;
  1670. while ((lutBytes - 1) >>> bitsPerPixel) {
  1671. bitsPerPixel++;
  1672. }
  1673. dataBytes = Math.ceil(numElements * bitsPerPixel / 8);
  1674. dataWords = Math.ceil(dataBytes / 4);
  1675. arrayBuf = new ArrayBuffer(dataWords * 4);
  1676. store8 = new Uint8Array(arrayBuf);
  1677. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1678. stuffedData = new Uint32Array(arrayBuf);
  1679. data.ptr += dataBytes;
  1680. if (fileVersion >= 3) {
  1681. lutArr = BitStuffer.unstuffLUT2(lutData, numBits, lutBytes - 1, offset, scale, zMax);
  1682. }
  1683. else {
  1684. lutArr = BitStuffer.unstuffLUT(lutData, numBits, lutBytes - 1, offset, scale, zMax);
  1685. }
  1686. //lutArr.unshift(0);
  1687. if (fileVersion >= 3) {
  1688. //BitStuffer.unstuff2(block, blockDataBuffer, headerInfo.zMax);
  1689. BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr);
  1690. }
  1691. else {
  1692. BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr);
  1693. }
  1694. }
  1695. else {
  1696. //console.debug("bitstuffer");
  1697. data.counter.bitstuffer++;
  1698. bitsPerPixel = numBits;
  1699. data.ptr += blockPtr;
  1700. if (bitsPerPixel > 0) {
  1701. dataBytes = Math.ceil(numElements * bitsPerPixel / 8);
  1702. dataWords = Math.ceil(dataBytes / 4);
  1703. arrayBuf = new ArrayBuffer(dataWords * 4);
  1704. store8 = new Uint8Array(arrayBuf);
  1705. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1706. stuffedData = new Uint32Array(arrayBuf);
  1707. data.ptr += dataBytes;
  1708. if (fileVersion >= 3) {
  1709. if (offset === null) {
  1710. BitStuffer.originalUnstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements);
  1711. }
  1712. else {
  1713. BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax);
  1714. }
  1715. }
  1716. else {
  1717. if (offset === null) {
  1718. BitStuffer.originalUnstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements);
  1719. }
  1720. else {
  1721. BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax);
  1722. }
  1723. }
  1724. }
  1725. }
  1726. }
  1727. },
  1728. readTiles: function(input, data, OutPixelTypeArray) {
  1729. var headerInfo = data.headerInfo;
  1730. var width = headerInfo.width;
  1731. var height = headerInfo.height;
  1732. var microBlockSize = headerInfo.microBlockSize;
  1733. var imageType = headerInfo.imageType;
  1734. var dataTypeSize = Lerc2Helpers.getDataTypeSize(imageType);
  1735. var numBlocksX = Math.ceil(width / microBlockSize);
  1736. var numBlocksY = Math.ceil(height / microBlockSize);
  1737. data.pixels.numBlocksY = numBlocksY;
  1738. data.pixels.numBlocksX = numBlocksX;
  1739. data.pixels.ptr = 0;
  1740. var row = 0, col = 0, blockY = 0, blockX = 0, thisBlockHeight = 0, thisBlockWidth = 0, bytesLeft = 0, headerByte = 0, bits67 = 0, testCode = 0, outPtr = 0, outStride = 0, numBytes = 0, bytesleft = 0, z = 0, blockPtr = 0;
  1741. var view, block, arrayBuf, store8, rawData;
  1742. var blockEncoding;
  1743. var blockDataBuffer = new OutPixelTypeArray(microBlockSize * microBlockSize);
  1744. var lastBlockHeight = (height % microBlockSize) || microBlockSize;
  1745. var lastBlockWidth = (width % microBlockSize) || microBlockSize;
  1746. var offsetType, offset;
  1747. var numDims = headerInfo.numDims, iDim;
  1748. var mask = data.pixels.resultMask;
  1749. var resultPixels = data.pixels.resultPixels;
  1750. for (blockY = 0; blockY < numBlocksY; blockY++) {
  1751. thisBlockHeight = (blockY !== numBlocksY - 1) ? microBlockSize : lastBlockHeight;
  1752. for (blockX = 0; blockX < numBlocksX; blockX++) {
  1753. //console.debug("y" + blockY + " x" + blockX);
  1754. thisBlockWidth = (blockX !== numBlocksX - 1) ? microBlockSize : lastBlockWidth;
  1755. outPtr = blockY * width * microBlockSize + blockX * microBlockSize;
  1756. outStride = width - thisBlockWidth;
  1757. for (iDim = 0; iDim < numDims; iDim++) {
  1758. if (numDims > 1) {
  1759. resultPixels = new OutPixelTypeArray(data.pixels.resultPixels.buffer, width * height * iDim * dataTypeSize, width * height);
  1760. }
  1761. bytesLeft = input.byteLength - data.ptr;
  1762. view = new DataView(input, data.ptr, Math.min(10, bytesLeft));
  1763. block = {};
  1764. blockPtr = 0;
  1765. headerByte = view.getUint8(0);
  1766. blockPtr++;
  1767. bits67 = (headerByte >> 6) & 0xFF;
  1768. testCode = (headerByte >> 2) & 15; // use bits 2345 for integrity check
  1769. if (testCode !== (((blockX * microBlockSize) >> 3) & 15)) {
  1770. throw "integrity issue";
  1771. //return false;
  1772. }
  1773. blockEncoding = headerByte & 3;
  1774. if (blockEncoding > 3) {
  1775. data.ptr += blockPtr;
  1776. throw "Invalid block encoding (" + blockEncoding + ")";
  1777. }
  1778. else if (blockEncoding === 2) { //constant 0
  1779. data.counter.constant++;
  1780. data.ptr += blockPtr;
  1781. continue;
  1782. }
  1783. else if (blockEncoding === 0) { //uncompressed
  1784. data.counter.uncompressed++;
  1785. data.ptr += blockPtr;
  1786. numBytes = thisBlockHeight * thisBlockWidth * dataTypeSize;
  1787. bytesleft = input.byteLength - data.ptr;
  1788. numBytes = numBytes < bytesleft ? numBytes : bytesleft;
  1789. //bit alignment
  1790. arrayBuf = new ArrayBuffer((numBytes % dataTypeSize) === 0 ? numBytes : (numBytes + dataTypeSize - numBytes % dataTypeSize));
  1791. store8 = new Uint8Array(arrayBuf);
  1792. store8.set(new Uint8Array(input, data.ptr, numBytes));
  1793. rawData = new OutPixelTypeArray(arrayBuf);
  1794. z = 0;
  1795. if (mask) {
  1796. for (row = 0; row < thisBlockHeight; row++) {
  1797. for (col = 0; col < thisBlockWidth; col++) {
  1798. if (mask[outPtr]) {
  1799. resultPixels[outPtr] = rawData[z++];
  1800. }
  1801. outPtr++;
  1802. }
  1803. outPtr += outStride;
  1804. }
  1805. }
  1806. else {//all valid
  1807. for (row = 0; row < thisBlockHeight; row++) {
  1808. for (col = 0; col < thisBlockWidth; col++) {
  1809. resultPixels[outPtr++] = rawData[z++];
  1810. }
  1811. outPtr += outStride;
  1812. }
  1813. }
  1814. data.ptr += z * dataTypeSize;
  1815. }
  1816. else { //1 or 3
  1817. offsetType = Lerc2Helpers.getDataTypeUsed(imageType, bits67);
  1818. offset = Lerc2Helpers.getOnePixel(block, blockPtr, offsetType, view);
  1819. blockPtr += Lerc2Helpers.getDataTypeSize(offsetType);
  1820. if (blockEncoding === 3) //constant offset value
  1821. {
  1822. data.ptr += blockPtr;
  1823. data.counter.constantoffset++;
  1824. //you can delete the following resultMask case in favor of performance because val is constant and users use nodata mask, otherwise nodatavalue post processing handles it too.
  1825. //while the above statement is true, we're not doing it as we want to keep invalid pixel value at 0 rather than arbitrary values
  1826. if (mask) {
  1827. for (row = 0; row < thisBlockHeight; row++) {
  1828. for (col = 0; col < thisBlockWidth; col++) {
  1829. if (mask[outPtr]) {
  1830. resultPixels[outPtr] = offset;
  1831. }
  1832. outPtr++;
  1833. }
  1834. outPtr += outStride;
  1835. }
  1836. }
  1837. else {
  1838. for (row = 0; row < thisBlockHeight; row++) {
  1839. for (col = 0; col < thisBlockWidth; col++) {
  1840. resultPixels[outPtr++] = offset;
  1841. }
  1842. outPtr += outStride;
  1843. }
  1844. }
  1845. }
  1846. else { //bitstuff encoding is 3
  1847. data.ptr += blockPtr;
  1848. //heavy lifting
  1849. Lerc2Helpers.decodeBits(input, data, blockDataBuffer, offset, iDim);
  1850. blockPtr = 0;
  1851. if (mask) {
  1852. for (row = 0; row < thisBlockHeight; row++) {
  1853. for (col = 0; col < thisBlockWidth; col++) {
  1854. if (mask[outPtr]) {
  1855. resultPixels[outPtr] = blockDataBuffer[blockPtr++];
  1856. }
  1857. outPtr++;
  1858. }
  1859. outPtr += outStride;
  1860. }
  1861. }
  1862. else {
  1863. for (row = 0; row < thisBlockHeight; row++) {
  1864. for (col = 0; col < thisBlockWidth; col++) {
  1865. resultPixels[outPtr++] = blockDataBuffer[blockPtr++];
  1866. }
  1867. outPtr += outStride;
  1868. }
  1869. }
  1870. }
  1871. }
  1872. }
  1873. }
  1874. }
  1875. },
  1876. /*****************
  1877. * private methods (helper methods)
  1878. *****************/
  1879. formatFileInfo: function(data) {
  1880. return {
  1881. "fileIdentifierString": data.headerInfo.fileIdentifierString,
  1882. "fileVersion": data.headerInfo.fileVersion,
  1883. "imageType": data.headerInfo.imageType,
  1884. "height": data.headerInfo.height,
  1885. "width": data.headerInfo.width,
  1886. "numValidPixel": data.headerInfo.numValidPixel,
  1887. "microBlockSize": data.headerInfo.microBlockSize,
  1888. "blobSize": data.headerInfo.blobSize,
  1889. "maxZError": data.headerInfo.maxZError,
  1890. "pixelType": Lerc2Helpers.getPixelType(data.headerInfo.imageType),
  1891. "eofOffset": data.eofOffset,
  1892. "mask": data.mask ? {
  1893. "numBytes": data.mask.numBytes
  1894. } : null,
  1895. "pixels": {
  1896. "numBlocksX": data.pixels.numBlocksX,
  1897. "numBlocksY": data.pixels.numBlocksY,
  1898. //"numBytes": data.pixels.numBytes,
  1899. "maxValue": data.headerInfo.zMax,
  1900. "minValue": data.headerInfo.zMin,
  1901. "noDataValue": data.noDataValue
  1902. }
  1903. };
  1904. },
  1905. constructConstantSurface: function(data) {
  1906. var val = data.headerInfo.zMax;
  1907. var numDims = data.headerInfo.numDims;
  1908. var numPixels = data.headerInfo.height * data.headerInfo.width;
  1909. var numPixelAllDims = numPixels * numDims;
  1910. var i=0, k = 0, nStart=0;
  1911. var mask = data.pixels.resultMask;
  1912. if (mask) {
  1913. if (numDims > 1) {
  1914. for (i=0; i < numDims; i++) {
  1915. nStart = i * numPixels;
  1916. for (k = 0; k < numPixels; k++) {
  1917. if (mask[k]) {
  1918. data.pixels.resultPixels[nStart + k] = val;
  1919. }
  1920. }
  1921. }
  1922. }
  1923. else {
  1924. for (k = 0; k < numPixels; k++) {
  1925. if (mask[k]) {
  1926. data.pixels.resultPixels[k] = val;
  1927. }
  1928. }
  1929. }
  1930. }
  1931. else {
  1932. if (data.pixels.resultPixels.fill) {
  1933. data.pixels.resultPixels.fill(val);
  1934. }
  1935. else {
  1936. for (k = 0; k < numPixelAllDims; k++) {
  1937. data.pixels.resultPixels[k] = val;
  1938. }
  1939. }
  1940. }
  1941. return;
  1942. },
  1943. getDataTypeArray: function(t) {
  1944. var tp;
  1945. switch (t) {
  1946. case 0: //char
  1947. tp = Int8Array;
  1948. break;
  1949. case 1: //byte
  1950. tp = Uint8Array;
  1951. break;
  1952. case 2: //short
  1953. tp = Int16Array;
  1954. break;
  1955. case 3: //ushort
  1956. tp = Uint16Array;
  1957. break;
  1958. case 4:
  1959. tp = Int32Array;
  1960. break;
  1961. case 5:
  1962. tp = Uint32Array;
  1963. break;
  1964. case 6:
  1965. tp = Float32Array;
  1966. break;
  1967. case 7:
  1968. tp = Float64Array;
  1969. break;
  1970. default:
  1971. tp = Float32Array;
  1972. }
  1973. return tp;
  1974. },
  1975. getPixelType: function(t) {
  1976. var tp;
  1977. switch (t) {
  1978. case 0: //char
  1979. tp = "S8";
  1980. break;
  1981. case 1: //byte
  1982. tp = "U8";
  1983. break;
  1984. case 2: //short
  1985. tp = "S16";
  1986. break;
  1987. case 3: //ushort
  1988. tp = "U16";
  1989. break;
  1990. case 4:
  1991. tp = "S32";
  1992. break;
  1993. case 5:
  1994. tp = "U32";
  1995. break;
  1996. case 6:
  1997. tp = "F32";
  1998. break;
  1999. case 7:
  2000. tp = "F64"; //not supported
  2001. break;
  2002. default:
  2003. tp = "F32";
  2004. }
  2005. return tp;
  2006. },
  2007. isValidPixelValue: function(t, val) {
  2008. if (val === null) {
  2009. return false;
  2010. }
  2011. var isValid;
  2012. switch (t) {
  2013. case 0: //char
  2014. isValid = val >= -128 && val <= 127;
  2015. break;
  2016. case 1: //byte (unsigned char)
  2017. isValid = val >= 0 && val <= 255;
  2018. break;
  2019. case 2: //short
  2020. isValid = val >= -32768 && val <= 32767;
  2021. break;
  2022. case 3: //ushort
  2023. isValid = val >= 0 && val <= 65536;
  2024. break;
  2025. case 4: //int 32
  2026. isValid = val >= -2147483648 && val <= 2147483647;
  2027. break;
  2028. case 5: //uinit 32
  2029. isValid = val >= 0 && val <= 4294967296;
  2030. break;
  2031. case 6:
  2032. isValid = val >= -3.4027999387901484e+38 && val <= 3.4027999387901484e+38;
  2033. break;
  2034. case 7:
  2035. isValid = val >= 5e-324 && val <= 1.7976931348623157e+308;
  2036. break;
  2037. default:
  2038. isValid = false;
  2039. }
  2040. return isValid;
  2041. },
  2042. getDataTypeSize: function(t) {
  2043. var s = 0;
  2044. switch (t) {
  2045. case 0: //ubyte
  2046. case 1: //byte
  2047. s = 1;
  2048. break;
  2049. case 2: //short
  2050. case 3: //ushort
  2051. s = 2;
  2052. break;
  2053. case 4:
  2054. case 5:
  2055. case 6:
  2056. s = 4;
  2057. break;
  2058. case 7:
  2059. s = 8;
  2060. break;
  2061. default:
  2062. s = t;
  2063. }
  2064. return s;
  2065. },
  2066. getDataTypeUsed: function(dt, tc) {
  2067. var t = dt;
  2068. switch (dt) {
  2069. case 2: //short
  2070. case 4: //long
  2071. t = dt - tc;
  2072. break;
  2073. case 3: //ushort
  2074. case 5: //ulong
  2075. t = dt - 2 * tc;
  2076. break;
  2077. case 6: //float
  2078. if (0 === tc) {
  2079. t = dt;
  2080. }
  2081. else if (1 === tc) {
  2082. t = 2;
  2083. }
  2084. else {
  2085. t = 1;//byte
  2086. }
  2087. break;
  2088. case 7: //double
  2089. if (0 === tc) {
  2090. t = dt;
  2091. }
  2092. else {
  2093. t = dt - 2 * tc + 1;
  2094. }
  2095. break;
  2096. default:
  2097. t = dt;
  2098. break;
  2099. }
  2100. return t;
  2101. },
  2102. getOnePixel: function(block, blockPtr, offsetType, view) {
  2103. var temp = 0;
  2104. switch (offsetType) {
  2105. case 0: //char
  2106. temp = view.getInt8(blockPtr);
  2107. break;
  2108. case 1: //byte
  2109. temp = view.getUint8(blockPtr);
  2110. break;
  2111. case 2:
  2112. temp = view.getInt16(blockPtr, true);
  2113. break;
  2114. case 3:
  2115. temp = view.getUint16(blockPtr, true);
  2116. break;
  2117. case 4:
  2118. temp = view.getInt32(blockPtr, true);
  2119. break;
  2120. case 5:
  2121. temp = view.getUInt32(blockPtr, true);
  2122. break;
  2123. case 6:
  2124. temp = view.getFloat32(blockPtr, true);
  2125. break;
  2126. case 7:
  2127. //temp = view.getFloat64(blockPtr, true);
  2128. //blockPtr += 8;
  2129. //lerc2 encoding doesnt handle float 64, force to float32???
  2130. temp = view.getFloat64(blockPtr, true);
  2131. break;
  2132. default:
  2133. throw ("the decoder does not understand this pixel type");
  2134. }
  2135. return temp;
  2136. }
  2137. };
  2138. /***************************************************
  2139. *private class for a tree node. Huffman code is in Lerc2Helpers
  2140. ****************************************************/
  2141. var TreeNode = function(val, left, right) {
  2142. this.val = val;
  2143. this.left = left;
  2144. this.right = right;
  2145. };
  2146. var Lerc2Decode = {
  2147. /*
  2148. * ********removed options compared to LERC1. We can bring some of them back if needed.
  2149. * removed pixel type. LERC2 is typed and doesn't require user to give pixel type
  2150. * changed encodedMaskData to maskData. LERC2 's js version make it faster to use maskData directly.
  2151. * removed returnMask. mask is used by LERC2 internally and is cost free. In case of user input mask, it's returned as well and has neglible cost.
  2152. * removed nodatavalue. Because LERC2 pixels are typed, nodatavalue will sacrify a useful value for many types (8bit, 16bit) etc,
  2153. * user has to be knowledgable enough about raster and their data to avoid usability issues. so nodata value is simply removed now.
  2154. * We can add it back later if their's a clear requirement.
  2155. * removed encodedMask. This option was not implemented in LercDecode. It can be done after decoding (less efficient)
  2156. * removed computeUsedBitDepths.
  2157. *
  2158. *
  2159. * response changes compared to LERC1
  2160. * 1. encodedMaskData is not available
  2161. * 2. noDataValue is optional (returns only if user's noDataValue is with in the valid data type range)
  2162. * 3. maskData is always available
  2163. */
  2164. /*****************
  2165. * public properties
  2166. ******************/
  2167. //HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, not configurable
  2168. /*****************
  2169. * public methods
  2170. *****************/
  2171. /**
  2172. * Decode a LERC2 byte stream and return an object containing the pixel data and optional metadata.
  2173. *
  2174. * @param {ArrayBuffer} input The LERC input byte stream
  2175. * @param {object} [options] options Decoding options
  2176. * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid LERC file is expected at that position
  2177. * @param {boolean} [options.returnFileInfo] If true, the return value will have a fileInfo property that contains metadata obtained from the LERC headers and the decoding process
  2178. */
  2179. decode: function(/*byte array*/ input, /*object*/ options) {
  2180. //currently there's a bug in the sparse array, so please do not set to false
  2181. options = options || {};
  2182. var noDataValue = options.noDataValue;
  2183. //initialize
  2184. var i = 0, data = {};
  2185. data.ptr = options.inputOffset || 0;
  2186. data.pixels = {};
  2187. // File header
  2188. if (!Lerc2Helpers.readHeaderInfo(input, data)) {
  2189. return;
  2190. }
  2191. var headerInfo = data.headerInfo;
  2192. var fileVersion = headerInfo.fileVersion;
  2193. var OutPixelTypeArray = Lerc2Helpers.getDataTypeArray(headerInfo.imageType);
  2194. // Mask Header
  2195. Lerc2Helpers.readMask(input, data);
  2196. if (headerInfo.numValidPixel !== headerInfo.width * headerInfo.height && !data.pixels.resultMask) {
  2197. data.pixels.resultMask = options.maskData;
  2198. }
  2199. var numPixels = headerInfo.width * headerInfo.height;
  2200. data.pixels.resultPixels = new OutPixelTypeArray(numPixels * headerInfo.numDims);
  2201. data.counter = {
  2202. onesweep: 0,
  2203. uncompressed: 0,
  2204. lut: 0,
  2205. bitstuffer: 0,
  2206. constant: 0,
  2207. constantoffset: 0
  2208. };
  2209. if (headerInfo.numValidPixel !== 0) {
  2210. //not tested
  2211. if (headerInfo.zMax === headerInfo.zMin) //constant surface
  2212. {
  2213. Lerc2Helpers.constructConstantSurface(data);
  2214. }
  2215. else if (fileVersion >= 4 && Lerc2Helpers.checkMinMaxRanges(input, data)) {
  2216. Lerc2Helpers.constructConstantSurface(data);
  2217. }
  2218. else {
  2219. var view = new DataView(input, data.ptr, 2);
  2220. var bReadDataOneSweep = view.getUint8(0);
  2221. data.ptr++;
  2222. if (bReadDataOneSweep) {
  2223. //console.debug("OneSweep");
  2224. Lerc2Helpers.readDataOneSweep(input, data, OutPixelTypeArray);
  2225. }
  2226. else {
  2227. //lerc2.1: //bitstuffing + lut
  2228. //lerc2.2: //bitstuffing + lut + huffman
  2229. //lerc2.3: new bitstuffer
  2230. if (fileVersion > 1 && headerInfo.imageType <= 1 && Math.abs(headerInfo.maxZError - 0.5) < 0.00001) {
  2231. //this is 2.x plus 8 bit (unsigned and signed) data, possiblity of Huffman
  2232. var flagHuffman = view.getUint8(1);
  2233. data.ptr++;
  2234. data.encodeMode = flagHuffman;
  2235. if (flagHuffman > 2 || (fileVersion < 4 && flagHuffman > 1)) {
  2236. throw "Invalid Huffman flag " + flagHuffman;
  2237. }
  2238. if (flagHuffman) {//1 - delta Huffman, 2 - Huffman
  2239. //console.log("Huffman");
  2240. Lerc2Helpers.readHuffman(input, data, OutPixelTypeArray);
  2241. }
  2242. else {
  2243. //console.log("Tiles");
  2244. Lerc2Helpers.readTiles(input, data, OutPixelTypeArray);
  2245. }
  2246. }
  2247. else { //lerc2.x non-8 bit data
  2248. //console.log("Tiles");
  2249. Lerc2Helpers.readTiles(input, data, OutPixelTypeArray);
  2250. }
  2251. }
  2252. }
  2253. }
  2254. data.eofOffset = data.ptr;
  2255. var diff;
  2256. if (options.inputOffset) {
  2257. diff = data.headerInfo.blobSize + options.inputOffset - data.ptr;
  2258. if (Math.abs(diff) >= 1) {
  2259. //console.debug("incorrect eof: dataptr " + data.ptr + " offset " + options.inputOffset + " blobsize " + data.headerInfo.blobSize + " diff: " + diff);
  2260. data.eofOffset = options.inputOffset + data.headerInfo.blobSize;
  2261. }
  2262. }
  2263. else {
  2264. diff = data.headerInfo.blobSize - data.ptr;
  2265. if (Math.abs(diff) >= 1) {
  2266. //console.debug("incorrect first band eof: dataptr " + data.ptr + " blobsize " + data.headerInfo.blobSize + " diff: " + diff);
  2267. data.eofOffset = data.headerInfo.blobSize;
  2268. }
  2269. }
  2270. var result = {
  2271. width: headerInfo.width,
  2272. height: headerInfo.height,
  2273. pixelData: data.pixels.resultPixels,
  2274. minValue: headerInfo.zMin,
  2275. maxValue: headerInfo.zMax,
  2276. validPixelCount: headerInfo.numValidPixel,
  2277. dimCount: headerInfo.numDims,
  2278. dimStats: {
  2279. minValues: headerInfo.minValues,
  2280. maxValues: headerInfo.maxValues
  2281. },
  2282. maskData: data.pixels.resultMask
  2283. //noDataValue: noDataValue
  2284. };
  2285. //we should remove this if there's no existing client
  2286. //optional noDataValue processing, it's user's responsiblity
  2287. if (data.pixels.resultMask && Lerc2Helpers.isValidPixelValue(headerInfo.imageType, noDataValue)) {
  2288. var mask = data.pixels.resultMask;
  2289. for (i = 0; i < numPixels; i++) {
  2290. if (!mask[i]) {
  2291. result.pixelData[i] = noDataValue;
  2292. }
  2293. }
  2294. result.noDataValue = noDataValue;
  2295. }
  2296. data.noDataValue = noDataValue;
  2297. if (options.returnFileInfo) {
  2298. result.fileInfo = Lerc2Helpers.formatFileInfo(data);
  2299. }
  2300. return result;
  2301. },
  2302. getBandCount: function(/*byte array*/ input) {
  2303. var count = 0;
  2304. var i = 0;
  2305. var temp = {};
  2306. temp.ptr = 0;
  2307. temp.pixels = {};
  2308. while (i < input.byteLength - 58) {
  2309. Lerc2Helpers.readHeaderInfo(input, temp);
  2310. i += temp.headerInfo.blobSize;
  2311. count++;
  2312. temp.ptr = i;
  2313. }
  2314. return count;
  2315. }
  2316. };
  2317. return Lerc2Decode;
  2318. })();
  2319. var isPlatformLittleEndian = (function() {
  2320. var a = new ArrayBuffer(4);
  2321. var b = new Uint8Array(a);
  2322. var c = new Uint32Array(a);
  2323. c[0] = 1;
  2324. return b[0] === 1;
  2325. })();
  2326. var Lerc = {
  2327. /************wrapper**********************************************/
  2328. /**
  2329. * A wrapper for decoding both LERC1 and LERC2 byte streams capable of handling multiband pixel blocks for various pixel types.
  2330. *
  2331. * @alias module:Lerc
  2332. * @param {ArrayBuffer} input The LERC input byte stream
  2333. * @param {object} [options] The decoding options below are optional.
  2334. * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid Lerc file is expected at that position.
  2335. * @param {string} [options.pixelType] (LERC1 only) Default value is F32. Valid pixel types for input are U8/S8/S16/U16/S32/U32/F32.
  2336. * @param {number} [options.noDataValue] (LERC1 only). It is recommended to use the returned mask instead of setting this value.
  2337. * @returns {{width, height, pixels, pixelType, mask, statistics}}
  2338. * @property {number} width Width of decoded image.
  2339. * @property {number} height Height of decoded image.
  2340. * @property {array} pixels [band1, band2, …] Each band is a typed array of width*height.
  2341. * @property {string} pixelType The type of pixels represented in the output.
  2342. * @property {mask} mask Typed array with a size of width*height, or null if all pixels are valid.
  2343. * @property {array} statistics [statistics_band1, statistics_band2, …] Each element is a statistics object representing min and max values
  2344. **/
  2345. decode: function(encodedData, options) {
  2346. if (!isPlatformLittleEndian) {
  2347. throw "Big endian system is not supported.";
  2348. }
  2349. options = options || {};
  2350. var inputOffset = options.inputOffset || 0;
  2351. var fileIdView = new Uint8Array(encodedData, inputOffset, 10);
  2352. var fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  2353. var lerc, majorVersion;
  2354. if (fileIdentifierString.trim() === "CntZImage") {
  2355. lerc = LercDecode;
  2356. majorVersion = 1;
  2357. }
  2358. else if (fileIdentifierString.substring(0, 5) === "Lerc2") {
  2359. lerc = Lerc2Decode;
  2360. majorVersion = 2;
  2361. }
  2362. else {
  2363. throw "Unexpected file identifier string: " + fileIdentifierString;
  2364. }
  2365. var iPlane = 0, eof = encodedData.byteLength - 10, encodedMaskData, bandMasks = [], bandMask, maskData;
  2366. var decodedPixelBlock = {
  2367. width: 0,
  2368. height: 0,
  2369. pixels: [],
  2370. pixelType: options.pixelType,
  2371. mask: null,
  2372. statistics: []
  2373. };
  2374. while (inputOffset < eof) {
  2375. var result = lerc.decode(encodedData, {
  2376. inputOffset: inputOffset,//for both lerc1 and lerc2
  2377. encodedMaskData: encodedMaskData,//lerc1 only
  2378. maskData: maskData,//lerc2 only
  2379. returnMask: iPlane === 0 ? true : false,//lerc1 only
  2380. returnEncodedMask: iPlane === 0 ? true : false,//lerc1 only
  2381. returnFileInfo: true,//for both lerc1 and lerc2
  2382. pixelType: options.pixelType || null,//lerc1 only
  2383. noDataValue: options.noDataValue || null//lerc1 only
  2384. });
  2385. inputOffset = result.fileInfo.eofOffset;
  2386. if (iPlane === 0) {
  2387. encodedMaskData = result.encodedMaskData;//lerc1
  2388. maskData = result.maskData;//lerc2
  2389. decodedPixelBlock.width = result.width;
  2390. decodedPixelBlock.height = result.height;
  2391. decodedPixelBlock.dimCount = result.dimCount || 1;
  2392. //decodedPixelBlock.dimStats = decodedPixelBlock.dimStats;
  2393. decodedPixelBlock.pixelType = result.pixelType || result.fileInfo.pixelType;
  2394. decodedPixelBlock.mask = result.maskData;
  2395. }
  2396. if (majorVersion >1 && result.fileInfo.mask && result.fileInfo.mask.numBytes > 0) {
  2397. bandMasks.push(result.maskData);
  2398. }
  2399. iPlane++;
  2400. decodedPixelBlock.pixels.push(result.pixelData);
  2401. decodedPixelBlock.statistics.push({
  2402. minValue: result.minValue,
  2403. maxValue: result.maxValue,
  2404. noDataValue: result.noDataValue,
  2405. dimStats: result.dimStats
  2406. });
  2407. }
  2408. var i, j, numPixels;
  2409. if (majorVersion > 1 && bandMasks.length > 1) {
  2410. numPixels = decodedPixelBlock.width * decodedPixelBlock.height;
  2411. decodedPixelBlock.bandMasks = bandMasks;
  2412. maskData = new Uint8Array(numPixels);
  2413. maskData.set(bandMasks[0]);
  2414. for (i = 1; i < bandMasks.length; i++) {
  2415. bandMask = bandMasks[i];
  2416. for (j = 0; j < numPixels; j++) {
  2417. maskData[j] = maskData[j] & bandMask[j];
  2418. }
  2419. }
  2420. decodedPixelBlock.maskData = maskData;
  2421. }
  2422. return decodedPixelBlock;
  2423. }
  2424. };
  2425. tmp.Lerc = Lerc;
  2426. })();
  2427. var Lerc = tmp.Lerc;
  2428. function createVerticesFromHeightmap(parameters, transferableObjects) {
  2429. // LERC encoded buffers must be decoded, then we can process them like normal
  2430. if (parameters.encoding === HeightmapEncoding$1.LERC) {
  2431. var result;
  2432. try {
  2433. result = Lerc.decode(parameters.heightmap);
  2434. } catch (error) {
  2435. throw new RuntimeError.RuntimeError(error);
  2436. }
  2437. var lercStatistics = result.statistics[0];
  2438. if (lercStatistics.minValue === Number.MAX_VALUE) {
  2439. throw new RuntimeError.RuntimeError("Invalid tile data");
  2440. }
  2441. parameters.heightmap = result.pixels[0];
  2442. parameters.width = result.width;
  2443. parameters.height = result.height;
  2444. }
  2445. parameters.ellipsoid = Cartesian2.Ellipsoid.clone(parameters.ellipsoid);
  2446. parameters.rectangle = Cartesian2.Rectangle.clone(parameters.rectangle);
  2447. var statistics = HeightmapTessellator.computeVertices(parameters);
  2448. var vertices = statistics.vertices;
  2449. transferableObjects.push(vertices.buffer);
  2450. return {
  2451. vertices: vertices.buffer,
  2452. numberOfAttributes: statistics.encoding.getStride(),
  2453. minimumHeight: statistics.minimumHeight,
  2454. maximumHeight: statistics.maximumHeight,
  2455. gridWidth: parameters.width,
  2456. gridHeight: parameters.height,
  2457. boundingSphere3D: statistics.boundingSphere3D,
  2458. orientedBoundingBox: statistics.orientedBoundingBox,
  2459. occludeePointInScaledSpace: statistics.occludeePointInScaledSpace,
  2460. encoding: statistics.encoding,
  2461. westIndicesSouthToNorth: statistics.westIndicesSouthToNorth,
  2462. southIndicesEastToWest: statistics.southIndicesEastToWest,
  2463. eastIndicesNorthToSouth: statistics.eastIndicesNorthToSouth,
  2464. northIndicesWestToEast: statistics.northIndicesWestToEast,
  2465. };
  2466. }
  2467. var createVerticesFromHeightmap$1 = createTaskProcessorWorker(createVerticesFromHeightmap);
  2468. return createVerticesFromHeightmap$1;
  2469. });