PolygonGeometry.js 47 KB

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