createPolygonGeometry.js 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445
  1. /**
  2. * @license
  3. * Cesium - https://github.com/CesiumGS/cesium
  4. * Version 1.97
  5. *
  6. * Copyright 2011-2022 Cesium Contributors
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. *
  20. * Columbus View (Pat. Pend.)
  21. *
  22. * Portions licensed separately.
  23. * See https://github.com/CesiumGS/cesium/blob/main/LICENSE.md for full licensing details.
  24. */
  25. define(['./defaultValue-a6eb9f34', './Matrix2-ab676047', './ArcType-b714639b', './BoundingRectangle-66558952', './Transforms-c78c4637', './RuntimeError-1088cc64', './ComponentDatatype-e06f4e16', './EllipsoidGeodesic-f7721517', './EllipsoidTangentPlane-6691e012', './GeometryAttribute-4f02e2ad', './GeometryInstance-6f541616', './GeometryOffsetAttribute-102da468', './GeometryPipeline-5a61c463', './IndexDatatype-c2232ebd', './PolygonGeometryLibrary-5dd88675', './PolygonPipeline-dd4a5392', './VertexFormat-65fd4be5', './_commonjsHelpers-89c9b271', './combine-7cf28d88', './WebGLConstants-d81b330d', './AxisAlignedBoundingBox-51d5a498', './IntersectionTests-f96cd46d', './Plane-c985a1d2', './AttributeCompression-8033f934', './EncodedCartesian3-7959a913', './arrayRemoveDuplicates-63722a6f', './EllipsoidRhumbLine-34574f75', './GeometryAttributes-aff51037'], (function (defaultValue, Matrix2, ArcType, BoundingRectangle, Transforms, RuntimeError, ComponentDatatype, EllipsoidGeodesic, EllipsoidTangentPlane, GeometryAttribute, GeometryInstance, GeometryOffsetAttribute, GeometryPipeline, IndexDatatype, PolygonGeometryLibrary, PolygonPipeline, VertexFormat, _commonjsHelpers, combine, WebGLConstants, AxisAlignedBoundingBox, IntersectionTests, Plane, AttributeCompression, EncodedCartesian3, arrayRemoveDuplicates, EllipsoidRhumbLine, GeometryAttributes) { 'use strict';
  26. const scratchCarto1 = new Matrix2.Cartographic();
  27. const scratchCarto2 = new Matrix2.Cartographic();
  28. function adjustPosHeightsForNormal(position, p1, p2, ellipsoid) {
  29. const carto1 = ellipsoid.cartesianToCartographic(position, scratchCarto1);
  30. const height = carto1.height;
  31. const p1Carto = ellipsoid.cartesianToCartographic(p1, scratchCarto2);
  32. p1Carto.height = height;
  33. ellipsoid.cartographicToCartesian(p1Carto, p1);
  34. const p2Carto = ellipsoid.cartesianToCartographic(p2, scratchCarto2);
  35. p2Carto.height = height - 100;
  36. ellipsoid.cartographicToCartesian(p2Carto, p2);
  37. }
  38. const scratchBoundingRectangle = new BoundingRectangle.BoundingRectangle();
  39. const scratchPosition = new Matrix2.Cartesian3();
  40. const scratchNormal = new Matrix2.Cartesian3();
  41. const scratchTangent = new Matrix2.Cartesian3();
  42. const scratchBitangent = new Matrix2.Cartesian3();
  43. const p1Scratch = new Matrix2.Cartesian3();
  44. const p2Scratch = new Matrix2.Cartesian3();
  45. let scratchPerPosNormal = new Matrix2.Cartesian3();
  46. let scratchPerPosTangent = new Matrix2.Cartesian3();
  47. let scratchPerPosBitangent = new Matrix2.Cartesian3();
  48. const appendTextureCoordinatesOrigin = new Matrix2.Cartesian2();
  49. const appendTextureCoordinatesCartesian2 = new Matrix2.Cartesian2();
  50. const appendTextureCoordinatesCartesian3 = new Matrix2.Cartesian3();
  51. const appendTextureCoordinatesQuaternion = new Transforms.Quaternion();
  52. const appendTextureCoordinatesMatrix3 = new Matrix2.Matrix3();
  53. const tangentMatrixScratch = new Matrix2.Matrix3();
  54. function computeAttributes(options) {
  55. const vertexFormat = options.vertexFormat;
  56. const geometry = options.geometry;
  57. const shadowVolume = options.shadowVolume;
  58. const flatPositions = geometry.attributes.position.values;
  59. const flatTexcoords = defaultValue.defined(geometry.attributes.st)
  60. ? geometry.attributes.st.values
  61. : undefined;
  62. let length = flatPositions.length;
  63. const wall = options.wall;
  64. const top = options.top || wall;
  65. const bottom = options.bottom || wall;
  66. if (
  67. vertexFormat.st ||
  68. vertexFormat.normal ||
  69. vertexFormat.tangent ||
  70. vertexFormat.bitangent ||
  71. shadowVolume
  72. ) {
  73. // PERFORMANCE_IDEA: Compute before subdivision, then just interpolate during subdivision.
  74. // PERFORMANCE_IDEA: Compute with createGeometryFromPositions() for fast path when there's no holes.
  75. const boundingRectangle = options.boundingRectangle;
  76. const tangentPlane = options.tangentPlane;
  77. const ellipsoid = options.ellipsoid;
  78. const stRotation = options.stRotation;
  79. const perPositionHeight = options.perPositionHeight;
  80. const origin = appendTextureCoordinatesOrigin;
  81. origin.x = boundingRectangle.x;
  82. origin.y = boundingRectangle.y;
  83. const textureCoordinates = vertexFormat.st
  84. ? new Float32Array(2 * (length / 3))
  85. : undefined;
  86. let normals;
  87. if (vertexFormat.normal) {
  88. if (perPositionHeight && top && !wall) {
  89. normals = geometry.attributes.normal.values;
  90. } else {
  91. normals = new Float32Array(length);
  92. }
  93. }
  94. const tangents = vertexFormat.tangent
  95. ? new Float32Array(length)
  96. : undefined;
  97. const bitangents = vertexFormat.bitangent
  98. ? new Float32Array(length)
  99. : undefined;
  100. const extrudeNormals = shadowVolume ? new Float32Array(length) : undefined;
  101. let textureCoordIndex = 0;
  102. let attrIndex = 0;
  103. let normal = scratchNormal;
  104. let tangent = scratchTangent;
  105. let bitangent = scratchBitangent;
  106. let recomputeNormal = true;
  107. let textureMatrix = appendTextureCoordinatesMatrix3;
  108. let tangentRotationMatrix = tangentMatrixScratch;
  109. if (stRotation !== 0.0) {
  110. let rotation = Transforms.Quaternion.fromAxisAngle(
  111. tangentPlane._plane.normal,
  112. stRotation,
  113. appendTextureCoordinatesQuaternion
  114. );
  115. textureMatrix = Matrix2.Matrix3.fromQuaternion(rotation, textureMatrix);
  116. rotation = Transforms.Quaternion.fromAxisAngle(
  117. tangentPlane._plane.normal,
  118. -stRotation,
  119. appendTextureCoordinatesQuaternion
  120. );
  121. tangentRotationMatrix = Matrix2.Matrix3.fromQuaternion(
  122. rotation,
  123. tangentRotationMatrix
  124. );
  125. } else {
  126. textureMatrix = Matrix2.Matrix3.clone(Matrix2.Matrix3.IDENTITY, textureMatrix);
  127. tangentRotationMatrix = Matrix2.Matrix3.clone(
  128. Matrix2.Matrix3.IDENTITY,
  129. tangentRotationMatrix
  130. );
  131. }
  132. let bottomOffset = 0;
  133. let bottomOffset2 = 0;
  134. if (top && bottom) {
  135. bottomOffset = length / 2;
  136. bottomOffset2 = length / 3;
  137. length /= 2;
  138. }
  139. for (let i = 0; i < length; i += 3) {
  140. const position = Matrix2.Cartesian3.fromArray(
  141. flatPositions,
  142. i,
  143. appendTextureCoordinatesCartesian3
  144. );
  145. if (vertexFormat.st) {
  146. if (!defaultValue.defined(flatTexcoords)) {
  147. let p = Matrix2.Matrix3.multiplyByVector(
  148. textureMatrix,
  149. position,
  150. scratchPosition
  151. );
  152. p = ellipsoid.scaleToGeodeticSurface(p, p);
  153. const st = tangentPlane.projectPointOntoPlane(
  154. p,
  155. appendTextureCoordinatesCartesian2
  156. );
  157. Matrix2.Cartesian2.subtract(st, origin, st);
  158. const stx = ComponentDatatype.CesiumMath.clamp(st.x / boundingRectangle.width, 0, 1);
  159. const sty = ComponentDatatype.CesiumMath.clamp(st.y / boundingRectangle.height, 0, 1);
  160. if (bottom) {
  161. textureCoordinates[textureCoordIndex + bottomOffset2] = stx;
  162. textureCoordinates[textureCoordIndex + 1 + bottomOffset2] = sty;
  163. }
  164. if (top) {
  165. textureCoordinates[textureCoordIndex] = stx;
  166. textureCoordinates[textureCoordIndex + 1] = sty;
  167. }
  168. textureCoordIndex += 2;
  169. }
  170. }
  171. if (
  172. vertexFormat.normal ||
  173. vertexFormat.tangent ||
  174. vertexFormat.bitangent ||
  175. shadowVolume
  176. ) {
  177. const attrIndex1 = attrIndex + 1;
  178. const attrIndex2 = attrIndex + 2;
  179. if (wall) {
  180. if (i + 3 < length) {
  181. const p1 = Matrix2.Cartesian3.fromArray(flatPositions, i + 3, p1Scratch);
  182. if (recomputeNormal) {
  183. const p2 = Matrix2.Cartesian3.fromArray(
  184. flatPositions,
  185. i + length,
  186. p2Scratch
  187. );
  188. if (perPositionHeight) {
  189. adjustPosHeightsForNormal(position, p1, p2, ellipsoid);
  190. }
  191. Matrix2.Cartesian3.subtract(p1, position, p1);
  192. Matrix2.Cartesian3.subtract(p2, position, p2);
  193. normal = Matrix2.Cartesian3.normalize(
  194. Matrix2.Cartesian3.cross(p2, p1, normal),
  195. normal
  196. );
  197. recomputeNormal = false;
  198. }
  199. if (Matrix2.Cartesian3.equalsEpsilon(p1, position, ComponentDatatype.CesiumMath.EPSILON10)) {
  200. // if we've reached a corner
  201. recomputeNormal = true;
  202. }
  203. }
  204. if (vertexFormat.tangent || vertexFormat.bitangent) {
  205. bitangent = ellipsoid.geodeticSurfaceNormal(position, bitangent);
  206. if (vertexFormat.tangent) {
  207. tangent = Matrix2.Cartesian3.normalize(
  208. Matrix2.Cartesian3.cross(bitangent, normal, tangent),
  209. tangent
  210. );
  211. }
  212. }
  213. } else {
  214. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  215. if (vertexFormat.tangent || vertexFormat.bitangent) {
  216. if (perPositionHeight) {
  217. scratchPerPosNormal = Matrix2.Cartesian3.fromArray(
  218. normals,
  219. attrIndex,
  220. scratchPerPosNormal
  221. );
  222. scratchPerPosTangent = Matrix2.Cartesian3.cross(
  223. Matrix2.Cartesian3.UNIT_Z,
  224. scratchPerPosNormal,
  225. scratchPerPosTangent
  226. );
  227. scratchPerPosTangent = Matrix2.Cartesian3.normalize(
  228. Matrix2.Matrix3.multiplyByVector(
  229. tangentRotationMatrix,
  230. scratchPerPosTangent,
  231. scratchPerPosTangent
  232. ),
  233. scratchPerPosTangent
  234. );
  235. if (vertexFormat.bitangent) {
  236. scratchPerPosBitangent = Matrix2.Cartesian3.normalize(
  237. Matrix2.Cartesian3.cross(
  238. scratchPerPosNormal,
  239. scratchPerPosTangent,
  240. scratchPerPosBitangent
  241. ),
  242. scratchPerPosBitangent
  243. );
  244. }
  245. }
  246. tangent = Matrix2.Cartesian3.cross(Matrix2.Cartesian3.UNIT_Z, normal, tangent);
  247. tangent = Matrix2.Cartesian3.normalize(
  248. Matrix2.Matrix3.multiplyByVector(tangentRotationMatrix, tangent, tangent),
  249. tangent
  250. );
  251. if (vertexFormat.bitangent) {
  252. bitangent = Matrix2.Cartesian3.normalize(
  253. Matrix2.Cartesian3.cross(normal, tangent, bitangent),
  254. bitangent
  255. );
  256. }
  257. }
  258. }
  259. if (vertexFormat.normal) {
  260. if (options.wall) {
  261. normals[attrIndex + bottomOffset] = normal.x;
  262. normals[attrIndex1 + bottomOffset] = normal.y;
  263. normals[attrIndex2 + bottomOffset] = normal.z;
  264. } else if (bottom) {
  265. normals[attrIndex + bottomOffset] = -normal.x;
  266. normals[attrIndex1 + bottomOffset] = -normal.y;
  267. normals[attrIndex2 + bottomOffset] = -normal.z;
  268. }
  269. if ((top && !perPositionHeight) || wall) {
  270. normals[attrIndex] = normal.x;
  271. normals[attrIndex1] = normal.y;
  272. normals[attrIndex2] = normal.z;
  273. }
  274. }
  275. if (shadowVolume) {
  276. if (wall) {
  277. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  278. }
  279. extrudeNormals[attrIndex + bottomOffset] = -normal.x;
  280. extrudeNormals[attrIndex1 + bottomOffset] = -normal.y;
  281. extrudeNormals[attrIndex2 + bottomOffset] = -normal.z;
  282. }
  283. if (vertexFormat.tangent) {
  284. if (options.wall) {
  285. tangents[attrIndex + bottomOffset] = tangent.x;
  286. tangents[attrIndex1 + bottomOffset] = tangent.y;
  287. tangents[attrIndex2 + bottomOffset] = tangent.z;
  288. } else if (bottom) {
  289. tangents[attrIndex + bottomOffset] = -tangent.x;
  290. tangents[attrIndex1 + bottomOffset] = -tangent.y;
  291. tangents[attrIndex2 + bottomOffset] = -tangent.z;
  292. }
  293. if (top) {
  294. if (perPositionHeight) {
  295. tangents[attrIndex] = scratchPerPosTangent.x;
  296. tangents[attrIndex1] = scratchPerPosTangent.y;
  297. tangents[attrIndex2] = scratchPerPosTangent.z;
  298. } else {
  299. tangents[attrIndex] = tangent.x;
  300. tangents[attrIndex1] = tangent.y;
  301. tangents[attrIndex2] = tangent.z;
  302. }
  303. }
  304. }
  305. if (vertexFormat.bitangent) {
  306. if (bottom) {
  307. bitangents[attrIndex + bottomOffset] = bitangent.x;
  308. bitangents[attrIndex1 + bottomOffset] = bitangent.y;
  309. bitangents[attrIndex2 + bottomOffset] = bitangent.z;
  310. }
  311. if (top) {
  312. if (perPositionHeight) {
  313. bitangents[attrIndex] = scratchPerPosBitangent.x;
  314. bitangents[attrIndex1] = scratchPerPosBitangent.y;
  315. bitangents[attrIndex2] = scratchPerPosBitangent.z;
  316. } else {
  317. bitangents[attrIndex] = bitangent.x;
  318. bitangents[attrIndex1] = bitangent.y;
  319. bitangents[attrIndex2] = bitangent.z;
  320. }
  321. }
  322. }
  323. attrIndex += 3;
  324. }
  325. }
  326. if (vertexFormat.st && !defaultValue.defined(flatTexcoords)) {
  327. geometry.attributes.st = new GeometryAttribute.GeometryAttribute({
  328. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  329. componentsPerAttribute: 2,
  330. values: textureCoordinates,
  331. });
  332. }
  333. if (vertexFormat.normal) {
  334. geometry.attributes.normal = new GeometryAttribute.GeometryAttribute({
  335. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  336. componentsPerAttribute: 3,
  337. values: normals,
  338. });
  339. }
  340. if (vertexFormat.tangent) {
  341. geometry.attributes.tangent = new GeometryAttribute.GeometryAttribute({
  342. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  343. componentsPerAttribute: 3,
  344. values: tangents,
  345. });
  346. }
  347. if (vertexFormat.bitangent) {
  348. geometry.attributes.bitangent = new GeometryAttribute.GeometryAttribute({
  349. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  350. componentsPerAttribute: 3,
  351. values: bitangents,
  352. });
  353. }
  354. if (shadowVolume) {
  355. geometry.attributes.extrudeDirection = new GeometryAttribute.GeometryAttribute({
  356. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  357. componentsPerAttribute: 3,
  358. values: extrudeNormals,
  359. });
  360. }
  361. }
  362. if (options.extrude && defaultValue.defined(options.offsetAttribute)) {
  363. const size = flatPositions.length / 3;
  364. let offsetAttribute = new Uint8Array(size);
  365. if (options.offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.TOP) {
  366. if ((top && bottom) || wall) {
  367. offsetAttribute = offsetAttribute.fill(1, 0, size / 2);
  368. } else if (top) {
  369. offsetAttribute = offsetAttribute.fill(1);
  370. }
  371. } else {
  372. const offsetValue =
  373. options.offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE ? 0 : 1;
  374. offsetAttribute = offsetAttribute.fill(offsetValue);
  375. }
  376. geometry.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  377. componentDatatype: ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  378. componentsPerAttribute: 1,
  379. values: offsetAttribute,
  380. });
  381. }
  382. return geometry;
  383. }
  384. const startCartographicScratch = new Matrix2.Cartographic();
  385. const endCartographicScratch = new Matrix2.Cartographic();
  386. const idlCross = {
  387. westOverIDL: 0.0,
  388. eastOverIDL: 0.0,
  389. };
  390. let ellipsoidGeodesic = new EllipsoidGeodesic.EllipsoidGeodesic();
  391. function computeRectangle(positions, ellipsoid, arcType, granularity, result) {
  392. result = defaultValue.defaultValue(result, new Matrix2.Rectangle());
  393. if (!defaultValue.defined(positions) || positions.length < 3) {
  394. result.west = 0.0;
  395. result.north = 0.0;
  396. result.south = 0.0;
  397. result.east = 0.0;
  398. return result;
  399. }
  400. if (arcType === ArcType.ArcType.RHUMB) {
  401. return Matrix2.Rectangle.fromCartesianArray(positions, ellipsoid, result);
  402. }
  403. if (!ellipsoidGeodesic.ellipsoid.equals(ellipsoid)) {
  404. ellipsoidGeodesic = new EllipsoidGeodesic.EllipsoidGeodesic(undefined, undefined, ellipsoid);
  405. }
  406. result.west = Number.POSITIVE_INFINITY;
  407. result.east = Number.NEGATIVE_INFINITY;
  408. result.south = Number.POSITIVE_INFINITY;
  409. result.north = Number.NEGATIVE_INFINITY;
  410. idlCross.westOverIDL = Number.POSITIVE_INFINITY;
  411. idlCross.eastOverIDL = Number.NEGATIVE_INFINITY;
  412. const inverseChordLength =
  413. 1.0 / ComponentDatatype.CesiumMath.chordLength(granularity, ellipsoid.maximumRadius);
  414. const positionsLength = positions.length;
  415. let endCartographic = ellipsoid.cartesianToCartographic(
  416. positions[0],
  417. endCartographicScratch
  418. );
  419. let startCartographic = startCartographicScratch;
  420. let swap;
  421. for (let i = 1; i < positionsLength; i++) {
  422. swap = startCartographic;
  423. startCartographic = endCartographic;
  424. endCartographic = ellipsoid.cartesianToCartographic(positions[i], swap);
  425. ellipsoidGeodesic.setEndPoints(startCartographic, endCartographic);
  426. interpolateAndGrowRectangle(
  427. ellipsoidGeodesic,
  428. inverseChordLength,
  429. result,
  430. idlCross
  431. );
  432. }
  433. swap = startCartographic;
  434. startCartographic = endCartographic;
  435. endCartographic = ellipsoid.cartesianToCartographic(positions[0], swap);
  436. ellipsoidGeodesic.setEndPoints(startCartographic, endCartographic);
  437. interpolateAndGrowRectangle(
  438. ellipsoidGeodesic,
  439. inverseChordLength,
  440. result,
  441. idlCross
  442. );
  443. if (result.east - result.west > idlCross.eastOverIDL - idlCross.westOverIDL) {
  444. result.west = idlCross.westOverIDL;
  445. result.east = idlCross.eastOverIDL;
  446. if (result.east > ComponentDatatype.CesiumMath.PI) {
  447. result.east = result.east - ComponentDatatype.CesiumMath.TWO_PI;
  448. }
  449. if (result.west > ComponentDatatype.CesiumMath.PI) {
  450. result.west = result.west - ComponentDatatype.CesiumMath.TWO_PI;
  451. }
  452. }
  453. return result;
  454. }
  455. const interpolatedCartographicScratch = new Matrix2.Cartographic();
  456. function interpolateAndGrowRectangle(
  457. ellipsoidGeodesic,
  458. inverseChordLength,
  459. result,
  460. idlCross
  461. ) {
  462. const segmentLength = ellipsoidGeodesic.surfaceDistance;
  463. const numPoints = Math.ceil(segmentLength * inverseChordLength);
  464. const subsegmentDistance =
  465. numPoints > 0 ? segmentLength / (numPoints - 1) : Number.POSITIVE_INFINITY;
  466. let interpolationDistance = 0.0;
  467. for (let i = 0; i < numPoints; i++) {
  468. const interpolatedCartographic = ellipsoidGeodesic.interpolateUsingSurfaceDistance(
  469. interpolationDistance,
  470. interpolatedCartographicScratch
  471. );
  472. interpolationDistance += subsegmentDistance;
  473. const longitude = interpolatedCartographic.longitude;
  474. const latitude = interpolatedCartographic.latitude;
  475. result.west = Math.min(result.west, longitude);
  476. result.east = Math.max(result.east, longitude);
  477. result.south = Math.min(result.south, latitude);
  478. result.north = Math.max(result.north, latitude);
  479. const lonAdjusted =
  480. longitude >= 0 ? longitude : longitude + ComponentDatatype.CesiumMath.TWO_PI;
  481. idlCross.westOverIDL = Math.min(idlCross.westOverIDL, lonAdjusted);
  482. idlCross.eastOverIDL = Math.max(idlCross.eastOverIDL, lonAdjusted);
  483. }
  484. }
  485. const createGeometryFromPositionsExtrudedPositions = [];
  486. function createGeometryFromPositionsExtruded(
  487. ellipsoid,
  488. polygon,
  489. textureCoordinates,
  490. granularity,
  491. hierarchy,
  492. perPositionHeight,
  493. closeTop,
  494. closeBottom,
  495. vertexFormat,
  496. arcType
  497. ) {
  498. const geos = {
  499. walls: [],
  500. };
  501. let i;
  502. if (closeTop || closeBottom) {
  503. const topGeo = PolygonGeometryLibrary.PolygonGeometryLibrary.createGeometryFromPositions(
  504. ellipsoid,
  505. polygon,
  506. textureCoordinates,
  507. granularity,
  508. perPositionHeight,
  509. vertexFormat,
  510. arcType
  511. );
  512. const edgePoints = topGeo.attributes.position.values;
  513. const indices = topGeo.indices;
  514. let numPositions;
  515. let newIndices;
  516. if (closeTop && closeBottom) {
  517. const topBottomPositions = edgePoints.concat(edgePoints);
  518. numPositions = topBottomPositions.length / 3;
  519. newIndices = IndexDatatype.IndexDatatype.createTypedArray(
  520. numPositions,
  521. indices.length * 2
  522. );
  523. newIndices.set(indices);
  524. const ilength = indices.length;
  525. const length = numPositions / 2;
  526. for (i = 0; i < ilength; i += 3) {
  527. const i0 = newIndices[i] + length;
  528. const i1 = newIndices[i + 1] + length;
  529. const i2 = newIndices[i + 2] + length;
  530. newIndices[i + ilength] = i2;
  531. newIndices[i + 1 + ilength] = i1;
  532. newIndices[i + 2 + ilength] = i0;
  533. }
  534. topGeo.attributes.position.values = topBottomPositions;
  535. if (perPositionHeight && vertexFormat.normal) {
  536. const normals = topGeo.attributes.normal.values;
  537. topGeo.attributes.normal.values = new Float32Array(
  538. topBottomPositions.length
  539. );
  540. topGeo.attributes.normal.values.set(normals);
  541. }
  542. if (vertexFormat.st && defaultValue.defined(textureCoordinates)) {
  543. const texcoords = topGeo.attributes.st.values;
  544. topGeo.attributes.st.values = new Float32Array(numPositions * 2);
  545. topGeo.attributes.st.values = texcoords.concat(texcoords);
  546. }
  547. topGeo.indices = newIndices;
  548. } else if (closeBottom) {
  549. numPositions = edgePoints.length / 3;
  550. newIndices = IndexDatatype.IndexDatatype.createTypedArray(numPositions, indices.length);
  551. for (i = 0; i < indices.length; i += 3) {
  552. newIndices[i] = indices[i + 2];
  553. newIndices[i + 1] = indices[i + 1];
  554. newIndices[i + 2] = indices[i];
  555. }
  556. topGeo.indices = newIndices;
  557. }
  558. geos.topAndBottom = new GeometryInstance.GeometryInstance({
  559. geometry: topGeo,
  560. });
  561. }
  562. let outerRing = hierarchy.outerRing;
  563. let tangentPlane = EllipsoidTangentPlane.EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid);
  564. let positions2D = tangentPlane.projectPointsOntoPlane(
  565. outerRing,
  566. createGeometryFromPositionsExtrudedPositions
  567. );
  568. let windingOrder = PolygonPipeline.PolygonPipeline.computeWindingOrder2D(positions2D);
  569. if (windingOrder === PolygonPipeline.WindingOrder.CLOCKWISE) {
  570. outerRing = outerRing.slice().reverse();
  571. }
  572. let wallGeo = PolygonGeometryLibrary.PolygonGeometryLibrary.computeWallGeometry(
  573. outerRing,
  574. textureCoordinates,
  575. ellipsoid,
  576. granularity,
  577. perPositionHeight,
  578. arcType
  579. );
  580. geos.walls.push(
  581. new GeometryInstance.GeometryInstance({
  582. geometry: wallGeo,
  583. })
  584. );
  585. const holes = hierarchy.holes;
  586. for (i = 0; i < holes.length; i++) {
  587. let hole = holes[i];
  588. tangentPlane = EllipsoidTangentPlane.EllipsoidTangentPlane.fromPoints(hole, ellipsoid);
  589. positions2D = tangentPlane.projectPointsOntoPlane(
  590. hole,
  591. createGeometryFromPositionsExtrudedPositions
  592. );
  593. windingOrder = PolygonPipeline.PolygonPipeline.computeWindingOrder2D(positions2D);
  594. if (windingOrder === PolygonPipeline.WindingOrder.COUNTER_CLOCKWISE) {
  595. hole = hole.slice().reverse();
  596. }
  597. wallGeo = PolygonGeometryLibrary.PolygonGeometryLibrary.computeWallGeometry(
  598. hole,
  599. textureCoordinates,
  600. ellipsoid,
  601. granularity,
  602. perPositionHeight,
  603. arcType
  604. );
  605. geos.walls.push(
  606. new GeometryInstance.GeometryInstance({
  607. geometry: wallGeo,
  608. })
  609. );
  610. }
  611. return geos;
  612. }
  613. /**
  614. * A description of a polygon on the ellipsoid. The polygon is defined by a polygon hierarchy. Polygon geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  615. *
  616. * @alias PolygonGeometry
  617. * @constructor
  618. *
  619. * @param {Object} options Object with the following properties:
  620. * @param {PolygonHierarchy} options.polygonHierarchy A polygon hierarchy that can include holes.
  621. * @param {Number} [options.height=0.0] The distance in meters between the polygon and the ellipsoid surface.
  622. * @param {Number} [options.extrudedHeight] The distance in meters between the polygon's extruded face and the ellipsoid surface.
  623. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  624. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  625. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  626. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  627. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  628. * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open.
  629. * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open.
  630. * @param {ArcType} [options.arcType=ArcType.GEODESIC] The type of line the polygon edges must follow. Valid options are {@link ArcType.GEODESIC} and {@link ArcType.RHUMB}.
  631. * @param {PolygonHierarchy} [options.textureCoordinates] Texture coordinates as a {@link PolygonHierarchy} of {@link Cartesian2} points. Has no effect for ground primitives.
  632. *
  633. * @see PolygonGeometry#createGeometry
  634. * @see PolygonGeometry#fromPositions
  635. *
  636. * @demo {@link https://sandcastle.cesium.com/index.html?src=Polygon.html|Cesium Sandcastle Polygon Demo}
  637. *
  638. * @example
  639. * // 1. create a polygon from points
  640. * const polygon = new Cesium.PolygonGeometry({
  641. * polygonHierarchy : new Cesium.PolygonHierarchy(
  642. * Cesium.Cartesian3.fromDegreesArray([
  643. * -72.0, 40.0,
  644. * -70.0, 35.0,
  645. * -75.0, 30.0,
  646. * -70.0, 30.0,
  647. * -68.0, 40.0
  648. * ])
  649. * )
  650. * });
  651. * const geometry = Cesium.PolygonGeometry.createGeometry(polygon);
  652. *
  653. * // 2. create a nested polygon with holes
  654. * const polygonWithHole = new Cesium.PolygonGeometry({
  655. * polygonHierarchy : new Cesium.PolygonHierarchy(
  656. * Cesium.Cartesian3.fromDegreesArray([
  657. * -109.0, 30.0,
  658. * -95.0, 30.0,
  659. * -95.0, 40.0,
  660. * -109.0, 40.0
  661. * ]),
  662. * [new Cesium.PolygonHierarchy(
  663. * Cesium.Cartesian3.fromDegreesArray([
  664. * -107.0, 31.0,
  665. * -107.0, 39.0,
  666. * -97.0, 39.0,
  667. * -97.0, 31.0
  668. * ]),
  669. * [new Cesium.PolygonHierarchy(
  670. * Cesium.Cartesian3.fromDegreesArray([
  671. * -105.0, 33.0,
  672. * -99.0, 33.0,
  673. * -99.0, 37.0,
  674. * -105.0, 37.0
  675. * ]),
  676. * [new Cesium.PolygonHierarchy(
  677. * Cesium.Cartesian3.fromDegreesArray([
  678. * -103.0, 34.0,
  679. * -101.0, 34.0,
  680. * -101.0, 36.0,
  681. * -103.0, 36.0
  682. * ])
  683. * )]
  684. * )]
  685. * )]
  686. * )
  687. * });
  688. * const geometry = Cesium.PolygonGeometry.createGeometry(polygonWithHole);
  689. *
  690. * // 3. create extruded polygon
  691. * const extrudedPolygon = new Cesium.PolygonGeometry({
  692. * polygonHierarchy : new Cesium.PolygonHierarchy(
  693. * Cesium.Cartesian3.fromDegreesArray([
  694. * -72.0, 40.0,
  695. * -70.0, 35.0,
  696. * -75.0, 30.0,
  697. * -70.0, 30.0,
  698. * -68.0, 40.0
  699. * ])
  700. * ),
  701. * extrudedHeight: 300000
  702. * });
  703. * const geometry = Cesium.PolygonGeometry.createGeometry(extrudedPolygon);
  704. */
  705. function PolygonGeometry(options) {
  706. //>>includeStart('debug', pragmas.debug);
  707. RuntimeError.Check.typeOf.object("options", options);
  708. RuntimeError.Check.typeOf.object("options.polygonHierarchy", options.polygonHierarchy);
  709. if (
  710. defaultValue.defined(options.perPositionHeight) &&
  711. options.perPositionHeight &&
  712. defaultValue.defined(options.height)
  713. ) {
  714. throw new RuntimeError.DeveloperError(
  715. "Cannot use both options.perPositionHeight and options.height"
  716. );
  717. }
  718. if (
  719. defaultValue.defined(options.arcType) &&
  720. options.arcType !== ArcType.ArcType.GEODESIC &&
  721. options.arcType !== ArcType.ArcType.RHUMB
  722. ) {
  723. throw new RuntimeError.DeveloperError(
  724. "Invalid arcType. Valid options are ArcType.GEODESIC and ArcType.RHUMB."
  725. );
  726. }
  727. //>>includeEnd('debug');
  728. const polygonHierarchy = options.polygonHierarchy;
  729. const vertexFormat = defaultValue.defaultValue(options.vertexFormat, VertexFormat.VertexFormat.DEFAULT);
  730. const ellipsoid = defaultValue.defaultValue(options.ellipsoid, Matrix2.Ellipsoid.WGS84);
  731. const granularity = defaultValue.defaultValue(
  732. options.granularity,
  733. ComponentDatatype.CesiumMath.RADIANS_PER_DEGREE
  734. );
  735. const stRotation = defaultValue.defaultValue(options.stRotation, 0.0);
  736. const textureCoordinates = options.textureCoordinates;
  737. const perPositionHeight = defaultValue.defaultValue(options.perPositionHeight, false);
  738. const perPositionHeightExtrude =
  739. perPositionHeight && defaultValue.defined(options.extrudedHeight);
  740. let height = defaultValue.defaultValue(options.height, 0.0);
  741. let extrudedHeight = defaultValue.defaultValue(options.extrudedHeight, height);
  742. if (!perPositionHeightExtrude) {
  743. const h = Math.max(height, extrudedHeight);
  744. extrudedHeight = Math.min(height, extrudedHeight);
  745. height = h;
  746. }
  747. this._vertexFormat = VertexFormat.VertexFormat.clone(vertexFormat);
  748. this._ellipsoid = Matrix2.Ellipsoid.clone(ellipsoid);
  749. this._granularity = granularity;
  750. this._stRotation = stRotation;
  751. this._height = height;
  752. this._extrudedHeight = extrudedHeight;
  753. this._closeTop = defaultValue.defaultValue(options.closeTop, true);
  754. this._closeBottom = defaultValue.defaultValue(options.closeBottom, true);
  755. this._polygonHierarchy = polygonHierarchy;
  756. this._perPositionHeight = perPositionHeight;
  757. this._perPositionHeightExtrude = perPositionHeightExtrude;
  758. this._shadowVolume = defaultValue.defaultValue(options.shadowVolume, false);
  759. this._workerName = "createPolygonGeometry";
  760. this._offsetAttribute = options.offsetAttribute;
  761. this._arcType = defaultValue.defaultValue(options.arcType, ArcType.ArcType.GEODESIC);
  762. this._rectangle = undefined;
  763. this._textureCoordinateRotationPoints = undefined;
  764. this._textureCoordinates = textureCoordinates;
  765. /**
  766. * The number of elements used to pack the object into an array.
  767. * @type {Number}
  768. */
  769. this.packedLength =
  770. PolygonGeometryLibrary.PolygonGeometryLibrary.computeHierarchyPackedLength(
  771. polygonHierarchy,
  772. Matrix2.Cartesian3
  773. ) +
  774. Matrix2.Ellipsoid.packedLength +
  775. VertexFormat.VertexFormat.packedLength +
  776. (textureCoordinates
  777. ? PolygonGeometryLibrary.PolygonGeometryLibrary.computeHierarchyPackedLength(
  778. textureCoordinates,
  779. Matrix2.Cartesian2
  780. )
  781. : 1) +
  782. 12;
  783. }
  784. /**
  785. * A description of a polygon from an array of positions. Polygon geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  786. *
  787. * @param {Object} options Object with the following properties:
  788. * @param {Cartesian3[]} options.positions An array of positions that defined the corner points of the polygon.
  789. * @param {Number} [options.height=0.0] The height of the polygon.
  790. * @param {Number} [options.extrudedHeight] The height of the polygon extrusion.
  791. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  792. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  793. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  794. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  795. * @param {Boolean} [options.perPositionHeight=false] Use the height of options.positions for each position instead of using options.height to determine the height.
  796. * @param {Boolean} [options.closeTop=true] When false, leaves off the top of an extruded polygon open.
  797. * @param {Boolean} [options.closeBottom=true] When false, leaves off the bottom of an extruded polygon open.
  798. * @param {ArcType} [options.arcType=ArcType.GEODESIC] The type of line the polygon edges must follow. Valid options are {@link ArcType.GEODESIC} and {@link ArcType.RHUMB}.
  799. * @param {PolygonHierarchy} [options.textureCoordinates] Texture coordinates as a {@link PolygonHierarchy} of {@link Cartesian2} points. Has no effect for ground primitives.
  800. * @returns {PolygonGeometry}
  801. *
  802. * @example
  803. * // create a polygon from points
  804. * const polygon = Cesium.PolygonGeometry.fromPositions({
  805. * positions : Cesium.Cartesian3.fromDegreesArray([
  806. * -72.0, 40.0,
  807. * -70.0, 35.0,
  808. * -75.0, 30.0,
  809. * -70.0, 30.0,
  810. * -68.0, 40.0
  811. * ])
  812. * });
  813. * const geometry = Cesium.PolygonGeometry.createGeometry(polygon);
  814. *
  815. * @see PolygonGeometry#createGeometry
  816. */
  817. PolygonGeometry.fromPositions = function (options) {
  818. options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);
  819. //>>includeStart('debug', pragmas.debug);
  820. RuntimeError.Check.defined("options.positions", options.positions);
  821. //>>includeEnd('debug');
  822. const newOptions = {
  823. polygonHierarchy: {
  824. positions: options.positions,
  825. },
  826. height: options.height,
  827. extrudedHeight: options.extrudedHeight,
  828. vertexFormat: options.vertexFormat,
  829. stRotation: options.stRotation,
  830. ellipsoid: options.ellipsoid,
  831. granularity: options.granularity,
  832. perPositionHeight: options.perPositionHeight,
  833. closeTop: options.closeTop,
  834. closeBottom: options.closeBottom,
  835. offsetAttribute: options.offsetAttribute,
  836. arcType: options.arcType,
  837. textureCoordinates: options.textureCoordinates,
  838. };
  839. return new PolygonGeometry(newOptions);
  840. };
  841. /**
  842. * Stores the provided instance into the provided array.
  843. *
  844. * @param {PolygonGeometry} value The value to pack.
  845. * @param {Number[]} array The array to pack into.
  846. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  847. *
  848. * @returns {Number[]} The array that was packed into
  849. */
  850. PolygonGeometry.pack = function (value, array, startingIndex) {
  851. //>>includeStart('debug', pragmas.debug);
  852. RuntimeError.Check.typeOf.object("value", value);
  853. RuntimeError.Check.defined("array", array);
  854. //>>includeEnd('debug');
  855. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  856. startingIndex = PolygonGeometryLibrary.PolygonGeometryLibrary.packPolygonHierarchy(
  857. value._polygonHierarchy,
  858. array,
  859. startingIndex,
  860. Matrix2.Cartesian3
  861. );
  862. Matrix2.Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  863. startingIndex += Matrix2.Ellipsoid.packedLength;
  864. VertexFormat.VertexFormat.pack(value._vertexFormat, array, startingIndex);
  865. startingIndex += VertexFormat.VertexFormat.packedLength;
  866. array[startingIndex++] = value._height;
  867. array[startingIndex++] = value._extrudedHeight;
  868. array[startingIndex++] = value._granularity;
  869. array[startingIndex++] = value._stRotation;
  870. array[startingIndex++] = value._perPositionHeightExtrude ? 1.0 : 0.0;
  871. array[startingIndex++] = value._perPositionHeight ? 1.0 : 0.0;
  872. array[startingIndex++] = value._closeTop ? 1.0 : 0.0;
  873. array[startingIndex++] = value._closeBottom ? 1.0 : 0.0;
  874. array[startingIndex++] = value._shadowVolume ? 1.0 : 0.0;
  875. array[startingIndex++] = defaultValue.defaultValue(value._offsetAttribute, -1);
  876. array[startingIndex++] = value._arcType;
  877. if (defaultValue.defined(value._textureCoordinates)) {
  878. startingIndex = PolygonGeometryLibrary.PolygonGeometryLibrary.packPolygonHierarchy(
  879. value._textureCoordinates,
  880. array,
  881. startingIndex,
  882. Matrix2.Cartesian2
  883. );
  884. } else {
  885. array[startingIndex++] = -1.0;
  886. }
  887. array[startingIndex++] = value.packedLength;
  888. return array;
  889. };
  890. const scratchEllipsoid = Matrix2.Ellipsoid.clone(Matrix2.Ellipsoid.UNIT_SPHERE);
  891. const scratchVertexFormat = new VertexFormat.VertexFormat();
  892. //Only used to avoid inability to default construct.
  893. const dummyOptions = {
  894. polygonHierarchy: {},
  895. };
  896. /**
  897. * Retrieves an instance from a packed array.
  898. *
  899. * @param {Number[]} array The packed array.
  900. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  901. * @param {PolygonGeometry} [result] The object into which to store the result.
  902. */
  903. PolygonGeometry.unpack = function (array, startingIndex, result) {
  904. //>>includeStart('debug', pragmas.debug);
  905. RuntimeError.Check.defined("array", array);
  906. //>>includeEnd('debug');
  907. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  908. const polygonHierarchy = PolygonGeometryLibrary.PolygonGeometryLibrary.unpackPolygonHierarchy(
  909. array,
  910. startingIndex,
  911. Matrix2.Cartesian3
  912. );
  913. startingIndex = polygonHierarchy.startingIndex;
  914. delete polygonHierarchy.startingIndex;
  915. const ellipsoid = Matrix2.Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  916. startingIndex += Matrix2.Ellipsoid.packedLength;
  917. const vertexFormat = VertexFormat.VertexFormat.unpack(
  918. array,
  919. startingIndex,
  920. scratchVertexFormat
  921. );
  922. startingIndex += VertexFormat.VertexFormat.packedLength;
  923. const height = array[startingIndex++];
  924. const extrudedHeight = array[startingIndex++];
  925. const granularity = array[startingIndex++];
  926. const stRotation = array[startingIndex++];
  927. const perPositionHeightExtrude = array[startingIndex++] === 1.0;
  928. const perPositionHeight = array[startingIndex++] === 1.0;
  929. const closeTop = array[startingIndex++] === 1.0;
  930. const closeBottom = array[startingIndex++] === 1.0;
  931. const shadowVolume = array[startingIndex++] === 1.0;
  932. const offsetAttribute = array[startingIndex++];
  933. const arcType = array[startingIndex++];
  934. const textureCoordinates =
  935. array[startingIndex] === -1.0
  936. ? undefined
  937. : PolygonGeometryLibrary.PolygonGeometryLibrary.unpackPolygonHierarchy(
  938. array,
  939. startingIndex,
  940. Matrix2.Cartesian2
  941. );
  942. if (defaultValue.defined(textureCoordinates)) {
  943. startingIndex = textureCoordinates.startingIndex;
  944. delete textureCoordinates.startingIndex;
  945. } else {
  946. startingIndex++;
  947. }
  948. const packedLength = array[startingIndex++];
  949. if (!defaultValue.defined(result)) {
  950. result = new PolygonGeometry(dummyOptions);
  951. }
  952. result._polygonHierarchy = polygonHierarchy;
  953. result._ellipsoid = Matrix2.Ellipsoid.clone(ellipsoid, result._ellipsoid);
  954. result._vertexFormat = VertexFormat.VertexFormat.clone(vertexFormat, result._vertexFormat);
  955. result._height = height;
  956. result._extrudedHeight = extrudedHeight;
  957. result._granularity = granularity;
  958. result._stRotation = stRotation;
  959. result._perPositionHeightExtrude = perPositionHeightExtrude;
  960. result._perPositionHeight = perPositionHeight;
  961. result._closeTop = closeTop;
  962. result._closeBottom = closeBottom;
  963. result._shadowVolume = shadowVolume;
  964. result._offsetAttribute =
  965. offsetAttribute === -1 ? undefined : offsetAttribute;
  966. result._arcType = arcType;
  967. result._textureCoordinates = textureCoordinates;
  968. result.packedLength = packedLength;
  969. return result;
  970. };
  971. /**
  972. * Returns the bounding rectangle given the provided options
  973. *
  974. * @param {Object} options Object with the following properties:
  975. * @param {PolygonHierarchy} options.polygonHierarchy A polygon hierarchy that can include holes.
  976. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions sampled.
  977. * @param {ArcType} [options.arcType=ArcType.GEODESIC] The type of line the polygon edges must follow. Valid options are {@link ArcType.GEODESIC} and {@link ArcType.RHUMB}.
  978. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  979. * @param {Rectangle} [result] An object in which to store the result.
  980. *
  981. * @returns {Rectangle} The result rectangle
  982. */
  983. PolygonGeometry.computeRectangle = function (options, result) {
  984. //>>includeStart('debug', pragmas.debug);
  985. RuntimeError.Check.typeOf.object("options", options);
  986. RuntimeError.Check.typeOf.object("options.polygonHierarchy", options.polygonHierarchy);
  987. //>>includeEnd('debug');
  988. const granularity = defaultValue.defaultValue(
  989. options.granularity,
  990. ComponentDatatype.CesiumMath.RADIANS_PER_DEGREE
  991. );
  992. const arcType = defaultValue.defaultValue(options.arcType, ArcType.ArcType.GEODESIC);
  993. //>>includeStart('debug', pragmas.debug);
  994. if (arcType !== ArcType.ArcType.GEODESIC && arcType !== ArcType.ArcType.RHUMB) {
  995. throw new RuntimeError.DeveloperError(
  996. "Invalid arcType. Valid options are ArcType.GEODESIC and ArcType.RHUMB."
  997. );
  998. }
  999. //>>includeEnd('debug');
  1000. const polygonHierarchy = options.polygonHierarchy;
  1001. const ellipsoid = defaultValue.defaultValue(options.ellipsoid, Matrix2.Ellipsoid.WGS84);
  1002. return computeRectangle(
  1003. polygonHierarchy.positions,
  1004. ellipsoid,
  1005. arcType,
  1006. granularity,
  1007. result
  1008. );
  1009. };
  1010. /**
  1011. * Computes the geometric representation of a polygon, including its vertices, indices, and a bounding sphere.
  1012. *
  1013. * @param {PolygonGeometry} polygonGeometry A description of the polygon.
  1014. * @returns {Geometry|undefined} The computed vertices and indices.
  1015. */
  1016. PolygonGeometry.createGeometry = function (polygonGeometry) {
  1017. const vertexFormat = polygonGeometry._vertexFormat;
  1018. const ellipsoid = polygonGeometry._ellipsoid;
  1019. const granularity = polygonGeometry._granularity;
  1020. const stRotation = polygonGeometry._stRotation;
  1021. const polygonHierarchy = polygonGeometry._polygonHierarchy;
  1022. const perPositionHeight = polygonGeometry._perPositionHeight;
  1023. const closeTop = polygonGeometry._closeTop;
  1024. const closeBottom = polygonGeometry._closeBottom;
  1025. const arcType = polygonGeometry._arcType;
  1026. const textureCoordinates = polygonGeometry._textureCoordinates;
  1027. const hasTextureCoordinates = defaultValue.defined(textureCoordinates);
  1028. let outerPositions = polygonHierarchy.positions;
  1029. if (outerPositions.length < 3) {
  1030. return;
  1031. }
  1032. const tangentPlane = EllipsoidTangentPlane.EllipsoidTangentPlane.fromPoints(
  1033. outerPositions,
  1034. ellipsoid
  1035. );
  1036. const results = PolygonGeometryLibrary.PolygonGeometryLibrary.polygonsFromHierarchy(
  1037. polygonHierarchy,
  1038. hasTextureCoordinates,
  1039. tangentPlane.projectPointsOntoPlane.bind(tangentPlane),
  1040. !perPositionHeight,
  1041. ellipsoid
  1042. );
  1043. const hierarchy = results.hierarchy;
  1044. const polygons = results.polygons;
  1045. const dummyFunction = function (identity) {
  1046. return identity;
  1047. };
  1048. const textureCoordinatePolygons = hasTextureCoordinates
  1049. ? PolygonGeometryLibrary.PolygonGeometryLibrary.polygonsFromHierarchy(
  1050. textureCoordinates,
  1051. true,
  1052. dummyFunction,
  1053. false
  1054. ).polygons
  1055. : undefined;
  1056. if (hierarchy.length === 0) {
  1057. return;
  1058. }
  1059. outerPositions = hierarchy[0].outerRing;
  1060. const boundingRectangle = PolygonGeometryLibrary.PolygonGeometryLibrary.computeBoundingRectangle(
  1061. tangentPlane.plane.normal,
  1062. tangentPlane.projectPointOntoPlane.bind(tangentPlane),
  1063. outerPositions,
  1064. stRotation,
  1065. scratchBoundingRectangle
  1066. );
  1067. const geometries = [];
  1068. const height = polygonGeometry._height;
  1069. const extrudedHeight = polygonGeometry._extrudedHeight;
  1070. const extrude =
  1071. polygonGeometry._perPositionHeightExtrude ||
  1072. !ComponentDatatype.CesiumMath.equalsEpsilon(height, extrudedHeight, 0, ComponentDatatype.CesiumMath.EPSILON2);
  1073. const options = {
  1074. perPositionHeight: perPositionHeight,
  1075. vertexFormat: vertexFormat,
  1076. geometry: undefined,
  1077. tangentPlane: tangentPlane,
  1078. boundingRectangle: boundingRectangle,
  1079. ellipsoid: ellipsoid,
  1080. stRotation: stRotation,
  1081. textureCoordinates: undefined,
  1082. bottom: false,
  1083. top: true,
  1084. wall: false,
  1085. extrude: false,
  1086. arcType: arcType,
  1087. };
  1088. let i;
  1089. if (extrude) {
  1090. options.extrude = true;
  1091. options.top = closeTop;
  1092. options.bottom = closeBottom;
  1093. options.shadowVolume = polygonGeometry._shadowVolume;
  1094. options.offsetAttribute = polygonGeometry._offsetAttribute;
  1095. for (i = 0; i < polygons.length; i++) {
  1096. const splitGeometry = createGeometryFromPositionsExtruded(
  1097. ellipsoid,
  1098. polygons[i],
  1099. hasTextureCoordinates ? textureCoordinatePolygons[i] : undefined,
  1100. granularity,
  1101. hierarchy[i],
  1102. perPositionHeight,
  1103. closeTop,
  1104. closeBottom,
  1105. vertexFormat,
  1106. arcType
  1107. );
  1108. let topAndBottom;
  1109. if (closeTop && closeBottom) {
  1110. topAndBottom = splitGeometry.topAndBottom;
  1111. options.geometry = PolygonGeometryLibrary.PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(
  1112. topAndBottom.geometry,
  1113. height,
  1114. extrudedHeight,
  1115. ellipsoid,
  1116. perPositionHeight
  1117. );
  1118. } else if (closeTop) {
  1119. topAndBottom = splitGeometry.topAndBottom;
  1120. topAndBottom.geometry.attributes.position.values = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  1121. topAndBottom.geometry.attributes.position.values,
  1122. height,
  1123. ellipsoid,
  1124. !perPositionHeight
  1125. );
  1126. options.geometry = topAndBottom.geometry;
  1127. } else if (closeBottom) {
  1128. topAndBottom = splitGeometry.topAndBottom;
  1129. topAndBottom.geometry.attributes.position.values = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  1130. topAndBottom.geometry.attributes.position.values,
  1131. extrudedHeight,
  1132. ellipsoid,
  1133. true
  1134. );
  1135. options.geometry = topAndBottom.geometry;
  1136. }
  1137. if (closeTop || closeBottom) {
  1138. options.wall = false;
  1139. topAndBottom.geometry = computeAttributes(options);
  1140. geometries.push(topAndBottom);
  1141. }
  1142. const walls = splitGeometry.walls;
  1143. options.wall = true;
  1144. for (let k = 0; k < walls.length; k++) {
  1145. const wall = walls[k];
  1146. options.geometry = PolygonGeometryLibrary.PolygonGeometryLibrary.scaleToGeodeticHeightExtruded(
  1147. wall.geometry,
  1148. height,
  1149. extrudedHeight,
  1150. ellipsoid,
  1151. perPositionHeight
  1152. );
  1153. wall.geometry = computeAttributes(options);
  1154. geometries.push(wall);
  1155. }
  1156. }
  1157. } else {
  1158. for (i = 0; i < polygons.length; i++) {
  1159. const geometryInstance = new GeometryInstance.GeometryInstance({
  1160. geometry: PolygonGeometryLibrary.PolygonGeometryLibrary.createGeometryFromPositions(
  1161. ellipsoid,
  1162. polygons[i],
  1163. hasTextureCoordinates ? textureCoordinatePolygons[i] : undefined,
  1164. granularity,
  1165. perPositionHeight,
  1166. vertexFormat,
  1167. arcType
  1168. ),
  1169. });
  1170. geometryInstance.geometry.attributes.position.values = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  1171. geometryInstance.geometry.attributes.position.values,
  1172. height,
  1173. ellipsoid,
  1174. !perPositionHeight
  1175. );
  1176. options.geometry = geometryInstance.geometry;
  1177. geometryInstance.geometry = computeAttributes(options);
  1178. if (defaultValue.defined(polygonGeometry._offsetAttribute)) {
  1179. const length =
  1180. geometryInstance.geometry.attributes.position.values.length;
  1181. const offsetValue =
  1182. polygonGeometry._offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE
  1183. ? 0
  1184. : 1;
  1185. const applyOffset = new Uint8Array(length / 3).fill(offsetValue);
  1186. geometryInstance.geometry.attributes.applyOffset = new GeometryAttribute.GeometryAttribute(
  1187. {
  1188. componentDatatype: ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  1189. componentsPerAttribute: 1,
  1190. values: applyOffset,
  1191. }
  1192. );
  1193. }
  1194. geometries.push(geometryInstance);
  1195. }
  1196. }
  1197. const geometry = GeometryPipeline.GeometryPipeline.combineInstances(geometries)[0];
  1198. geometry.attributes.position.values = new Float64Array(
  1199. geometry.attributes.position.values
  1200. );
  1201. geometry.indices = IndexDatatype.IndexDatatype.createTypedArray(
  1202. geometry.attributes.position.values.length / 3,
  1203. geometry.indices
  1204. );
  1205. const attributes = geometry.attributes;
  1206. const boundingSphere = Transforms.BoundingSphere.fromVertices(
  1207. attributes.position.values
  1208. );
  1209. if (!vertexFormat.position) {
  1210. delete attributes.position;
  1211. }
  1212. return new GeometryAttribute.Geometry({
  1213. attributes: attributes,
  1214. indices: geometry.indices,
  1215. primitiveType: geometry.primitiveType,
  1216. boundingSphere: boundingSphere,
  1217. offsetAttribute: polygonGeometry._offsetAttribute,
  1218. });
  1219. };
  1220. /**
  1221. * @private
  1222. */
  1223. PolygonGeometry.createShadowVolume = function (
  1224. polygonGeometry,
  1225. minHeightFunc,
  1226. maxHeightFunc
  1227. ) {
  1228. const granularity = polygonGeometry._granularity;
  1229. const ellipsoid = polygonGeometry._ellipsoid;
  1230. const minHeight = minHeightFunc(granularity, ellipsoid);
  1231. const maxHeight = maxHeightFunc(granularity, ellipsoid);
  1232. return new PolygonGeometry({
  1233. polygonHierarchy: polygonGeometry._polygonHierarchy,
  1234. ellipsoid: ellipsoid,
  1235. stRotation: polygonGeometry._stRotation,
  1236. granularity: granularity,
  1237. perPositionHeight: false,
  1238. extrudedHeight: minHeight,
  1239. height: maxHeight,
  1240. vertexFormat: VertexFormat.VertexFormat.POSITION_ONLY,
  1241. shadowVolume: true,
  1242. arcType: polygonGeometry._arcType,
  1243. });
  1244. };
  1245. function textureCoordinateRotationPoints(polygonGeometry) {
  1246. const stRotation = -polygonGeometry._stRotation;
  1247. if (stRotation === 0.0) {
  1248. return [0, 0, 0, 1, 1, 0];
  1249. }
  1250. const ellipsoid = polygonGeometry._ellipsoid;
  1251. const positions = polygonGeometry._polygonHierarchy.positions;
  1252. const boundingRectangle = polygonGeometry.rectangle;
  1253. return GeometryAttribute.Geometry._textureCoordinateRotationPoints(
  1254. positions,
  1255. stRotation,
  1256. ellipsoid,
  1257. boundingRectangle
  1258. );
  1259. }
  1260. Object.defineProperties(PolygonGeometry.prototype, {
  1261. /**
  1262. * @private
  1263. */
  1264. rectangle: {
  1265. get: function () {
  1266. if (!defaultValue.defined(this._rectangle)) {
  1267. const positions = this._polygonHierarchy.positions;
  1268. this._rectangle = computeRectangle(
  1269. positions,
  1270. this._ellipsoid,
  1271. this._arcType,
  1272. this._granularity
  1273. );
  1274. }
  1275. return this._rectangle;
  1276. },
  1277. },
  1278. /**
  1279. * For remapping texture coordinates when rendering PolygonGeometries as GroundPrimitives.
  1280. * @private
  1281. */
  1282. textureCoordinateRotationPoints: {
  1283. get: function () {
  1284. if (!defaultValue.defined(this._textureCoordinateRotationPoints)) {
  1285. this._textureCoordinateRotationPoints = textureCoordinateRotationPoints(
  1286. this
  1287. );
  1288. }
  1289. return this._textureCoordinateRotationPoints;
  1290. },
  1291. },
  1292. });
  1293. function createPolygonGeometry(polygonGeometry, offset) {
  1294. if (defaultValue.defined(offset)) {
  1295. polygonGeometry = PolygonGeometry.unpack(polygonGeometry, offset);
  1296. }
  1297. polygonGeometry._ellipsoid = Matrix2.Ellipsoid.clone(polygonGeometry._ellipsoid);
  1298. return PolygonGeometry.createGeometry(polygonGeometry);
  1299. }
  1300. return createPolygonGeometry;
  1301. }));