PolygonGeometry.js 44 KB

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