createRectangleGeometry.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  1. /**
  2. * @license
  3. * Cesium - https://github.com/CesiumGS/cesium
  4. * Version 1.97
  5. *
  6. * Copyright 2011-2022 Cesium Contributors
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. *
  20. * Columbus View (Pat. Pend.)
  21. *
  22. * Portions licensed separately.
  23. * See https://github.com/CesiumGS/cesium/blob/main/LICENSE.md for full licensing details.
  24. */
  25. define(['./defaultValue-a6eb9f34', './Matrix2-ab676047', './Transforms-c78c4637', './RuntimeError-1088cc64', './ComponentDatatype-e06f4e16', './GeometryAttribute-4f02e2ad', './GeometryAttributes-aff51037', './GeometryInstance-6f541616', './GeometryOffsetAttribute-102da468', './GeometryPipeline-5a61c463', './IndexDatatype-c2232ebd', './PolygonPipeline-dd4a5392', './RectangleGeometryLibrary-ef977e90', './VertexFormat-65fd4be5', './_commonjsHelpers-89c9b271', './combine-7cf28d88', './WebGLConstants-d81b330d', './AttributeCompression-8033f934', './EncodedCartesian3-7959a913', './IntersectionTests-f96cd46d', './Plane-c985a1d2', './EllipsoidRhumbLine-34574f75'], (function (defaultValue, Matrix2, Transforms, RuntimeError, ComponentDatatype, GeometryAttribute, GeometryAttributes, GeometryInstance, GeometryOffsetAttribute, GeometryPipeline, IndexDatatype, PolygonPipeline, RectangleGeometryLibrary, VertexFormat, _commonjsHelpers, combine, WebGLConstants, AttributeCompression, EncodedCartesian3, IntersectionTests, Plane, EllipsoidRhumbLine) { 'use strict';
  26. const positionScratch = new Matrix2.Cartesian3();
  27. const normalScratch = new Matrix2.Cartesian3();
  28. const tangentScratch = new Matrix2.Cartesian3();
  29. const bitangentScratch = new Matrix2.Cartesian3();
  30. const rectangleScratch = new Matrix2.Rectangle();
  31. const stScratch = new Matrix2.Cartesian2();
  32. const bottomBoundingSphere = new Transforms.BoundingSphere();
  33. const topBoundingSphere = new Transforms.BoundingSphere();
  34. function createAttributes(vertexFormat, attributes) {
  35. const geo = new GeometryAttribute.Geometry({
  36. attributes: new GeometryAttributes.GeometryAttributes(),
  37. primitiveType: GeometryAttribute.PrimitiveType.TRIANGLES,
  38. });
  39. geo.attributes.position = new GeometryAttribute.GeometryAttribute({
  40. componentDatatype: ComponentDatatype.ComponentDatatype.DOUBLE,
  41. componentsPerAttribute: 3,
  42. values: attributes.positions,
  43. });
  44. if (vertexFormat.normal) {
  45. geo.attributes.normal = new GeometryAttribute.GeometryAttribute({
  46. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  47. componentsPerAttribute: 3,
  48. values: attributes.normals,
  49. });
  50. }
  51. if (vertexFormat.tangent) {
  52. geo.attributes.tangent = new GeometryAttribute.GeometryAttribute({
  53. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  54. componentsPerAttribute: 3,
  55. values: attributes.tangents,
  56. });
  57. }
  58. if (vertexFormat.bitangent) {
  59. geo.attributes.bitangent = new GeometryAttribute.GeometryAttribute({
  60. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  61. componentsPerAttribute: 3,
  62. values: attributes.bitangents,
  63. });
  64. }
  65. return geo;
  66. }
  67. function calculateAttributes(
  68. positions,
  69. vertexFormat,
  70. ellipsoid,
  71. tangentRotationMatrix
  72. ) {
  73. const length = positions.length;
  74. const normals = vertexFormat.normal ? new Float32Array(length) : undefined;
  75. const tangents = vertexFormat.tangent ? new Float32Array(length) : undefined;
  76. const bitangents = vertexFormat.bitangent
  77. ? new Float32Array(length)
  78. : undefined;
  79. let attrIndex = 0;
  80. const bitangent = bitangentScratch;
  81. const tangent = tangentScratch;
  82. let normal = normalScratch;
  83. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) {
  84. for (let i = 0; i < length; i += 3) {
  85. const p = Matrix2.Cartesian3.fromArray(positions, i, positionScratch);
  86. const attrIndex1 = attrIndex + 1;
  87. const attrIndex2 = attrIndex + 2;
  88. normal = ellipsoid.geodeticSurfaceNormal(p, normal);
  89. if (vertexFormat.tangent || vertexFormat.bitangent) {
  90. Matrix2.Cartesian3.cross(Matrix2.Cartesian3.UNIT_Z, normal, tangent);
  91. Matrix2.Matrix3.multiplyByVector(tangentRotationMatrix, tangent, tangent);
  92. Matrix2.Cartesian3.normalize(tangent, tangent);
  93. if (vertexFormat.bitangent) {
  94. Matrix2.Cartesian3.normalize(
  95. Matrix2.Cartesian3.cross(normal, tangent, bitangent),
  96. bitangent
  97. );
  98. }
  99. }
  100. if (vertexFormat.normal) {
  101. normals[attrIndex] = normal.x;
  102. normals[attrIndex1] = normal.y;
  103. normals[attrIndex2] = normal.z;
  104. }
  105. if (vertexFormat.tangent) {
  106. tangents[attrIndex] = tangent.x;
  107. tangents[attrIndex1] = tangent.y;
  108. tangents[attrIndex2] = tangent.z;
  109. }
  110. if (vertexFormat.bitangent) {
  111. bitangents[attrIndex] = bitangent.x;
  112. bitangents[attrIndex1] = bitangent.y;
  113. bitangents[attrIndex2] = bitangent.z;
  114. }
  115. attrIndex += 3;
  116. }
  117. }
  118. return createAttributes(vertexFormat, {
  119. positions: positions,
  120. normals: normals,
  121. tangents: tangents,
  122. bitangents: bitangents,
  123. });
  124. }
  125. const v1Scratch = new Matrix2.Cartesian3();
  126. const v2Scratch = new Matrix2.Cartesian3();
  127. function calculateAttributesWall(positions, vertexFormat, ellipsoid) {
  128. const length = positions.length;
  129. const normals = vertexFormat.normal ? new Float32Array(length) : undefined;
  130. const tangents = vertexFormat.tangent ? new Float32Array(length) : undefined;
  131. const bitangents = vertexFormat.bitangent
  132. ? new Float32Array(length)
  133. : undefined;
  134. let normalIndex = 0;
  135. let tangentIndex = 0;
  136. let bitangentIndex = 0;
  137. let recomputeNormal = true;
  138. let bitangent = bitangentScratch;
  139. let tangent = tangentScratch;
  140. let normal = normalScratch;
  141. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent) {
  142. for (let i = 0; i < length; i += 6) {
  143. const p = Matrix2.Cartesian3.fromArray(positions, i, positionScratch);
  144. const p1 = Matrix2.Cartesian3.fromArray(positions, (i + 6) % length, v1Scratch);
  145. if (recomputeNormal) {
  146. const p2 = Matrix2.Cartesian3.fromArray(positions, (i + 3) % length, v2Scratch);
  147. Matrix2.Cartesian3.subtract(p1, p, p1);
  148. Matrix2.Cartesian3.subtract(p2, p, p2);
  149. normal = Matrix2.Cartesian3.normalize(Matrix2.Cartesian3.cross(p2, p1, normal), normal);
  150. recomputeNormal = false;
  151. }
  152. if (Matrix2.Cartesian3.equalsEpsilon(p1, p, ComponentDatatype.CesiumMath.EPSILON10)) {
  153. // if we've reached a corner
  154. recomputeNormal = true;
  155. }
  156. if (vertexFormat.tangent || vertexFormat.bitangent) {
  157. bitangent = ellipsoid.geodeticSurfaceNormal(p, bitangent);
  158. if (vertexFormat.tangent) {
  159. tangent = Matrix2.Cartesian3.normalize(
  160. Matrix2.Cartesian3.cross(bitangent, normal, tangent),
  161. tangent
  162. );
  163. }
  164. }
  165. if (vertexFormat.normal) {
  166. normals[normalIndex++] = normal.x;
  167. normals[normalIndex++] = normal.y;
  168. normals[normalIndex++] = normal.z;
  169. normals[normalIndex++] = normal.x;
  170. normals[normalIndex++] = normal.y;
  171. normals[normalIndex++] = normal.z;
  172. }
  173. if (vertexFormat.tangent) {
  174. tangents[tangentIndex++] = tangent.x;
  175. tangents[tangentIndex++] = tangent.y;
  176. tangents[tangentIndex++] = tangent.z;
  177. tangents[tangentIndex++] = tangent.x;
  178. tangents[tangentIndex++] = tangent.y;
  179. tangents[tangentIndex++] = tangent.z;
  180. }
  181. if (vertexFormat.bitangent) {
  182. bitangents[bitangentIndex++] = bitangent.x;
  183. bitangents[bitangentIndex++] = bitangent.y;
  184. bitangents[bitangentIndex++] = bitangent.z;
  185. bitangents[bitangentIndex++] = bitangent.x;
  186. bitangents[bitangentIndex++] = bitangent.y;
  187. bitangents[bitangentIndex++] = bitangent.z;
  188. }
  189. }
  190. }
  191. return createAttributes(vertexFormat, {
  192. positions: positions,
  193. normals: normals,
  194. tangents: tangents,
  195. bitangents: bitangents,
  196. });
  197. }
  198. function constructRectangle(rectangleGeometry, computedOptions) {
  199. const vertexFormat = rectangleGeometry._vertexFormat;
  200. const ellipsoid = rectangleGeometry._ellipsoid;
  201. const height = computedOptions.height;
  202. const width = computedOptions.width;
  203. const northCap = computedOptions.northCap;
  204. const southCap = computedOptions.southCap;
  205. let rowStart = 0;
  206. let rowEnd = height;
  207. let rowHeight = height;
  208. let size = 0;
  209. if (northCap) {
  210. rowStart = 1;
  211. rowHeight -= 1;
  212. size += 1;
  213. }
  214. if (southCap) {
  215. rowEnd -= 1;
  216. rowHeight -= 1;
  217. size += 1;
  218. }
  219. size += width * rowHeight;
  220. const positions = vertexFormat.position
  221. ? new Float64Array(size * 3)
  222. : undefined;
  223. const textureCoordinates = vertexFormat.st
  224. ? new Float32Array(size * 2)
  225. : undefined;
  226. let posIndex = 0;
  227. let stIndex = 0;
  228. const position = positionScratch;
  229. const st = stScratch;
  230. let minX = Number.MAX_VALUE;
  231. let minY = Number.MAX_VALUE;
  232. let maxX = -Number.MAX_VALUE;
  233. let maxY = -Number.MAX_VALUE;
  234. for (let row = rowStart; row < rowEnd; ++row) {
  235. for (let col = 0; col < width; ++col) {
  236. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  237. computedOptions,
  238. ellipsoid,
  239. vertexFormat.st,
  240. row,
  241. col,
  242. position,
  243. st
  244. );
  245. positions[posIndex++] = position.x;
  246. positions[posIndex++] = position.y;
  247. positions[posIndex++] = position.z;
  248. if (vertexFormat.st) {
  249. textureCoordinates[stIndex++] = st.x;
  250. textureCoordinates[stIndex++] = st.y;
  251. minX = Math.min(minX, st.x);
  252. minY = Math.min(minY, st.y);
  253. maxX = Math.max(maxX, st.x);
  254. maxY = Math.max(maxY, st.y);
  255. }
  256. }
  257. }
  258. if (northCap) {
  259. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  260. computedOptions,
  261. ellipsoid,
  262. vertexFormat.st,
  263. 0,
  264. 0,
  265. position,
  266. st
  267. );
  268. positions[posIndex++] = position.x;
  269. positions[posIndex++] = position.y;
  270. positions[posIndex++] = position.z;
  271. if (vertexFormat.st) {
  272. textureCoordinates[stIndex++] = st.x;
  273. textureCoordinates[stIndex++] = st.y;
  274. minX = st.x;
  275. minY = st.y;
  276. maxX = st.x;
  277. maxY = st.y;
  278. }
  279. }
  280. if (southCap) {
  281. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  282. computedOptions,
  283. ellipsoid,
  284. vertexFormat.st,
  285. height - 1,
  286. 0,
  287. position,
  288. st
  289. );
  290. positions[posIndex++] = position.x;
  291. positions[posIndex++] = position.y;
  292. positions[posIndex] = position.z;
  293. if (vertexFormat.st) {
  294. textureCoordinates[stIndex++] = st.x;
  295. textureCoordinates[stIndex] = st.y;
  296. minX = Math.min(minX, st.x);
  297. minY = Math.min(minY, st.y);
  298. maxX = Math.max(maxX, st.x);
  299. maxY = Math.max(maxY, st.y);
  300. }
  301. }
  302. if (
  303. vertexFormat.st &&
  304. (minX < 0.0 || minY < 0.0 || maxX > 1.0 || maxY > 1.0)
  305. ) {
  306. for (let k = 0; k < textureCoordinates.length; k += 2) {
  307. textureCoordinates[k] = (textureCoordinates[k] - minX) / (maxX - minX);
  308. textureCoordinates[k + 1] =
  309. (textureCoordinates[k + 1] - minY) / (maxY - minY);
  310. }
  311. }
  312. const geo = calculateAttributes(
  313. positions,
  314. vertexFormat,
  315. ellipsoid,
  316. computedOptions.tangentRotationMatrix
  317. );
  318. let indicesSize = 6 * (width - 1) * (rowHeight - 1);
  319. if (northCap) {
  320. indicesSize += 3 * (width - 1);
  321. }
  322. if (southCap) {
  323. indicesSize += 3 * (width - 1);
  324. }
  325. const indices = IndexDatatype.IndexDatatype.createTypedArray(size, indicesSize);
  326. let index = 0;
  327. let indicesIndex = 0;
  328. let i;
  329. for (i = 0; i < rowHeight - 1; ++i) {
  330. for (let j = 0; j < width - 1; ++j) {
  331. const upperLeft = index;
  332. const lowerLeft = upperLeft + width;
  333. const lowerRight = lowerLeft + 1;
  334. const upperRight = upperLeft + 1;
  335. indices[indicesIndex++] = upperLeft;
  336. indices[indicesIndex++] = lowerLeft;
  337. indices[indicesIndex++] = upperRight;
  338. indices[indicesIndex++] = upperRight;
  339. indices[indicesIndex++] = lowerLeft;
  340. indices[indicesIndex++] = lowerRight;
  341. ++index;
  342. }
  343. ++index;
  344. }
  345. if (northCap || southCap) {
  346. let northIndex = size - 1;
  347. const southIndex = size - 1;
  348. if (northCap && southCap) {
  349. northIndex = size - 2;
  350. }
  351. let p1;
  352. let p2;
  353. index = 0;
  354. if (northCap) {
  355. for (i = 0; i < width - 1; i++) {
  356. p1 = index;
  357. p2 = p1 + 1;
  358. indices[indicesIndex++] = northIndex;
  359. indices[indicesIndex++] = p1;
  360. indices[indicesIndex++] = p2;
  361. ++index;
  362. }
  363. }
  364. if (southCap) {
  365. index = (rowHeight - 1) * width;
  366. for (i = 0; i < width - 1; i++) {
  367. p1 = index;
  368. p2 = p1 + 1;
  369. indices[indicesIndex++] = p1;
  370. indices[indicesIndex++] = southIndex;
  371. indices[indicesIndex++] = p2;
  372. ++index;
  373. }
  374. }
  375. }
  376. geo.indices = indices;
  377. if (vertexFormat.st) {
  378. geo.attributes.st = new GeometryAttribute.GeometryAttribute({
  379. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  380. componentsPerAttribute: 2,
  381. values: textureCoordinates,
  382. });
  383. }
  384. return geo;
  385. }
  386. function addWallPositions(
  387. wallPositions,
  388. posIndex,
  389. i,
  390. topPositions,
  391. bottomPositions
  392. ) {
  393. wallPositions[posIndex++] = topPositions[i];
  394. wallPositions[posIndex++] = topPositions[i + 1];
  395. wallPositions[posIndex++] = topPositions[i + 2];
  396. wallPositions[posIndex++] = bottomPositions[i];
  397. wallPositions[posIndex++] = bottomPositions[i + 1];
  398. wallPositions[posIndex] = bottomPositions[i + 2];
  399. return wallPositions;
  400. }
  401. function addWallTextureCoordinates(wallTextures, stIndex, i, st) {
  402. wallTextures[stIndex++] = st[i];
  403. wallTextures[stIndex++] = st[i + 1];
  404. wallTextures[stIndex++] = st[i];
  405. wallTextures[stIndex] = st[i + 1];
  406. return wallTextures;
  407. }
  408. const scratchVertexFormat = new VertexFormat.VertexFormat();
  409. function constructExtrudedRectangle(rectangleGeometry, computedOptions) {
  410. const shadowVolume = rectangleGeometry._shadowVolume;
  411. const offsetAttributeValue = rectangleGeometry._offsetAttribute;
  412. const vertexFormat = rectangleGeometry._vertexFormat;
  413. const minHeight = rectangleGeometry._extrudedHeight;
  414. const maxHeight = rectangleGeometry._surfaceHeight;
  415. const ellipsoid = rectangleGeometry._ellipsoid;
  416. const height = computedOptions.height;
  417. const width = computedOptions.width;
  418. let i;
  419. if (shadowVolume) {
  420. const newVertexFormat = VertexFormat.VertexFormat.clone(
  421. vertexFormat,
  422. scratchVertexFormat
  423. );
  424. newVertexFormat.normal = true;
  425. rectangleGeometry._vertexFormat = newVertexFormat;
  426. }
  427. const topBottomGeo = constructRectangle(rectangleGeometry, computedOptions);
  428. if (shadowVolume) {
  429. rectangleGeometry._vertexFormat = vertexFormat;
  430. }
  431. let topPositions = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  432. topBottomGeo.attributes.position.values,
  433. maxHeight,
  434. ellipsoid,
  435. false
  436. );
  437. topPositions = new Float64Array(topPositions);
  438. let length = topPositions.length;
  439. const newLength = length * 2;
  440. const positions = new Float64Array(newLength);
  441. positions.set(topPositions);
  442. const bottomPositions = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  443. topBottomGeo.attributes.position.values,
  444. minHeight,
  445. ellipsoid
  446. );
  447. positions.set(bottomPositions, length);
  448. topBottomGeo.attributes.position.values = positions;
  449. const normals = vertexFormat.normal ? new Float32Array(newLength) : undefined;
  450. const tangents = vertexFormat.tangent
  451. ? new Float32Array(newLength)
  452. : undefined;
  453. const bitangents = vertexFormat.bitangent
  454. ? new Float32Array(newLength)
  455. : undefined;
  456. const textures = vertexFormat.st
  457. ? new Float32Array((newLength / 3) * 2)
  458. : undefined;
  459. let topSt;
  460. let topNormals;
  461. if (vertexFormat.normal) {
  462. topNormals = topBottomGeo.attributes.normal.values;
  463. normals.set(topNormals);
  464. for (i = 0; i < length; i++) {
  465. topNormals[i] = -topNormals[i];
  466. }
  467. normals.set(topNormals, length);
  468. topBottomGeo.attributes.normal.values = normals;
  469. }
  470. if (shadowVolume) {
  471. topNormals = topBottomGeo.attributes.normal.values;
  472. if (!vertexFormat.normal) {
  473. topBottomGeo.attributes.normal = undefined;
  474. }
  475. const extrudeNormals = new Float32Array(newLength);
  476. for (i = 0; i < length; i++) {
  477. topNormals[i] = -topNormals[i];
  478. }
  479. extrudeNormals.set(topNormals, length); //only get normals for bottom layer that's going to be pushed down
  480. topBottomGeo.attributes.extrudeDirection = new GeometryAttribute.GeometryAttribute({
  481. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  482. componentsPerAttribute: 3,
  483. values: extrudeNormals,
  484. });
  485. }
  486. let offsetValue;
  487. const hasOffsets = defaultValue.defined(offsetAttributeValue);
  488. if (hasOffsets) {
  489. const size = (length / 3) * 2;
  490. let offsetAttribute = new Uint8Array(size);
  491. if (offsetAttributeValue === GeometryOffsetAttribute.GeometryOffsetAttribute.TOP) {
  492. offsetAttribute = offsetAttribute.fill(1, 0, size / 2);
  493. } else {
  494. offsetValue =
  495. offsetAttributeValue === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE ? 0 : 1;
  496. offsetAttribute = offsetAttribute.fill(offsetValue);
  497. }
  498. topBottomGeo.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  499. componentDatatype: ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  500. componentsPerAttribute: 1,
  501. values: offsetAttribute,
  502. });
  503. }
  504. if (vertexFormat.tangent) {
  505. const topTangents = topBottomGeo.attributes.tangent.values;
  506. tangents.set(topTangents);
  507. for (i = 0; i < length; i++) {
  508. topTangents[i] = -topTangents[i];
  509. }
  510. tangents.set(topTangents, length);
  511. topBottomGeo.attributes.tangent.values = tangents;
  512. }
  513. if (vertexFormat.bitangent) {
  514. const topBitangents = topBottomGeo.attributes.bitangent.values;
  515. bitangents.set(topBitangents);
  516. bitangents.set(topBitangents, length);
  517. topBottomGeo.attributes.bitangent.values = bitangents;
  518. }
  519. if (vertexFormat.st) {
  520. topSt = topBottomGeo.attributes.st.values;
  521. textures.set(topSt);
  522. textures.set(topSt, (length / 3) * 2);
  523. topBottomGeo.attributes.st.values = textures;
  524. }
  525. const indices = topBottomGeo.indices;
  526. const indicesLength = indices.length;
  527. const posLength = length / 3;
  528. const newIndices = IndexDatatype.IndexDatatype.createTypedArray(
  529. newLength / 3,
  530. indicesLength * 2
  531. );
  532. newIndices.set(indices);
  533. for (i = 0; i < indicesLength; i += 3) {
  534. newIndices[i + indicesLength] = indices[i + 2] + posLength;
  535. newIndices[i + 1 + indicesLength] = indices[i + 1] + posLength;
  536. newIndices[i + 2 + indicesLength] = indices[i] + posLength;
  537. }
  538. topBottomGeo.indices = newIndices;
  539. const northCap = computedOptions.northCap;
  540. const southCap = computedOptions.southCap;
  541. let rowHeight = height;
  542. let widthMultiplier = 2;
  543. let perimeterPositions = 0;
  544. let corners = 4;
  545. let dupliateCorners = 4;
  546. if (northCap) {
  547. widthMultiplier -= 1;
  548. rowHeight -= 1;
  549. perimeterPositions += 1;
  550. corners -= 2;
  551. dupliateCorners -= 1;
  552. }
  553. if (southCap) {
  554. widthMultiplier -= 1;
  555. rowHeight -= 1;
  556. perimeterPositions += 1;
  557. corners -= 2;
  558. dupliateCorners -= 1;
  559. }
  560. perimeterPositions += widthMultiplier * width + 2 * rowHeight - corners;
  561. const wallCount = (perimeterPositions + dupliateCorners) * 2;
  562. let wallPositions = new Float64Array(wallCount * 3);
  563. const wallExtrudeNormals = shadowVolume
  564. ? new Float32Array(wallCount * 3)
  565. : undefined;
  566. let wallOffsetAttribute = hasOffsets ? new Uint8Array(wallCount) : undefined;
  567. let wallTextures = vertexFormat.st
  568. ? new Float32Array(wallCount * 2)
  569. : undefined;
  570. const computeTopOffsets =
  571. offsetAttributeValue === GeometryOffsetAttribute.GeometryOffsetAttribute.TOP;
  572. if (hasOffsets && !computeTopOffsets) {
  573. offsetValue = offsetAttributeValue === GeometryOffsetAttribute.GeometryOffsetAttribute.ALL ? 1 : 0;
  574. wallOffsetAttribute = wallOffsetAttribute.fill(offsetValue);
  575. }
  576. let posIndex = 0;
  577. let stIndex = 0;
  578. let extrudeNormalIndex = 0;
  579. let wallOffsetIndex = 0;
  580. const area = width * rowHeight;
  581. let threeI;
  582. for (i = 0; i < area; i += width) {
  583. threeI = i * 3;
  584. wallPositions = addWallPositions(
  585. wallPositions,
  586. posIndex,
  587. threeI,
  588. topPositions,
  589. bottomPositions
  590. );
  591. posIndex += 6;
  592. if (vertexFormat.st) {
  593. wallTextures = addWallTextureCoordinates(
  594. wallTextures,
  595. stIndex,
  596. i * 2,
  597. topSt
  598. );
  599. stIndex += 4;
  600. }
  601. if (shadowVolume) {
  602. extrudeNormalIndex += 3;
  603. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  604. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  605. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  606. }
  607. if (computeTopOffsets) {
  608. wallOffsetAttribute[wallOffsetIndex++] = 1;
  609. wallOffsetIndex += 1;
  610. }
  611. }
  612. if (!southCap) {
  613. for (i = area - width; i < area; i++) {
  614. threeI = i * 3;
  615. wallPositions = addWallPositions(
  616. wallPositions,
  617. posIndex,
  618. threeI,
  619. topPositions,
  620. bottomPositions
  621. );
  622. posIndex += 6;
  623. if (vertexFormat.st) {
  624. wallTextures = addWallTextureCoordinates(
  625. wallTextures,
  626. stIndex,
  627. i * 2,
  628. topSt
  629. );
  630. stIndex += 4;
  631. }
  632. if (shadowVolume) {
  633. extrudeNormalIndex += 3;
  634. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  635. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  636. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  637. }
  638. if (computeTopOffsets) {
  639. wallOffsetAttribute[wallOffsetIndex++] = 1;
  640. wallOffsetIndex += 1;
  641. }
  642. }
  643. } else {
  644. const southIndex = northCap ? area + 1 : area;
  645. threeI = southIndex * 3;
  646. for (i = 0; i < 2; i++) {
  647. // duplicate corner points
  648. wallPositions = addWallPositions(
  649. wallPositions,
  650. posIndex,
  651. threeI,
  652. topPositions,
  653. bottomPositions
  654. );
  655. posIndex += 6;
  656. if (vertexFormat.st) {
  657. wallTextures = addWallTextureCoordinates(
  658. wallTextures,
  659. stIndex,
  660. southIndex * 2,
  661. topSt
  662. );
  663. stIndex += 4;
  664. }
  665. if (shadowVolume) {
  666. extrudeNormalIndex += 3;
  667. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  668. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  669. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  670. }
  671. if (computeTopOffsets) {
  672. wallOffsetAttribute[wallOffsetIndex++] = 1;
  673. wallOffsetIndex += 1;
  674. }
  675. }
  676. }
  677. for (i = area - 1; i > 0; i -= width) {
  678. threeI = i * 3;
  679. wallPositions = addWallPositions(
  680. wallPositions,
  681. posIndex,
  682. threeI,
  683. topPositions,
  684. bottomPositions
  685. );
  686. posIndex += 6;
  687. if (vertexFormat.st) {
  688. wallTextures = addWallTextureCoordinates(
  689. wallTextures,
  690. stIndex,
  691. i * 2,
  692. topSt
  693. );
  694. stIndex += 4;
  695. }
  696. if (shadowVolume) {
  697. extrudeNormalIndex += 3;
  698. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  699. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  700. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  701. }
  702. if (computeTopOffsets) {
  703. wallOffsetAttribute[wallOffsetIndex++] = 1;
  704. wallOffsetIndex += 1;
  705. }
  706. }
  707. if (!northCap) {
  708. for (i = width - 1; i >= 0; i--) {
  709. threeI = i * 3;
  710. wallPositions = addWallPositions(
  711. wallPositions,
  712. posIndex,
  713. threeI,
  714. topPositions,
  715. bottomPositions
  716. );
  717. posIndex += 6;
  718. if (vertexFormat.st) {
  719. wallTextures = addWallTextureCoordinates(
  720. wallTextures,
  721. stIndex,
  722. i * 2,
  723. topSt
  724. );
  725. stIndex += 4;
  726. }
  727. if (shadowVolume) {
  728. extrudeNormalIndex += 3;
  729. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  730. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  731. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  732. }
  733. if (computeTopOffsets) {
  734. wallOffsetAttribute[wallOffsetIndex++] = 1;
  735. wallOffsetIndex += 1;
  736. }
  737. }
  738. } else {
  739. const northIndex = area;
  740. threeI = northIndex * 3;
  741. for (i = 0; i < 2; i++) {
  742. // duplicate corner points
  743. wallPositions = addWallPositions(
  744. wallPositions,
  745. posIndex,
  746. threeI,
  747. topPositions,
  748. bottomPositions
  749. );
  750. posIndex += 6;
  751. if (vertexFormat.st) {
  752. wallTextures = addWallTextureCoordinates(
  753. wallTextures,
  754. stIndex,
  755. northIndex * 2,
  756. topSt
  757. );
  758. stIndex += 4;
  759. }
  760. if (shadowVolume) {
  761. extrudeNormalIndex += 3;
  762. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI];
  763. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 1];
  764. wallExtrudeNormals[extrudeNormalIndex++] = topNormals[threeI + 2];
  765. }
  766. if (computeTopOffsets) {
  767. wallOffsetAttribute[wallOffsetIndex++] = 1;
  768. wallOffsetIndex += 1;
  769. }
  770. }
  771. }
  772. let geo = calculateAttributesWall(wallPositions, vertexFormat, ellipsoid);
  773. if (vertexFormat.st) {
  774. geo.attributes.st = new GeometryAttribute.GeometryAttribute({
  775. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  776. componentsPerAttribute: 2,
  777. values: wallTextures,
  778. });
  779. }
  780. if (shadowVolume) {
  781. geo.attributes.extrudeDirection = new GeometryAttribute.GeometryAttribute({
  782. componentDatatype: ComponentDatatype.ComponentDatatype.FLOAT,
  783. componentsPerAttribute: 3,
  784. values: wallExtrudeNormals,
  785. });
  786. }
  787. if (hasOffsets) {
  788. geo.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  789. componentDatatype: ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  790. componentsPerAttribute: 1,
  791. values: wallOffsetAttribute,
  792. });
  793. }
  794. const wallIndices = IndexDatatype.IndexDatatype.createTypedArray(
  795. wallCount,
  796. perimeterPositions * 6
  797. );
  798. let upperLeft;
  799. let lowerLeft;
  800. let lowerRight;
  801. let upperRight;
  802. length = wallPositions.length / 3;
  803. let index = 0;
  804. for (i = 0; i < length - 1; i += 2) {
  805. upperLeft = i;
  806. upperRight = (upperLeft + 2) % length;
  807. const p1 = Matrix2.Cartesian3.fromArray(wallPositions, upperLeft * 3, v1Scratch);
  808. const p2 = Matrix2.Cartesian3.fromArray(wallPositions, upperRight * 3, v2Scratch);
  809. if (Matrix2.Cartesian3.equalsEpsilon(p1, p2, ComponentDatatype.CesiumMath.EPSILON10)) {
  810. continue;
  811. }
  812. lowerLeft = (upperLeft + 1) % length;
  813. lowerRight = (lowerLeft + 2) % length;
  814. wallIndices[index++] = upperLeft;
  815. wallIndices[index++] = lowerLeft;
  816. wallIndices[index++] = upperRight;
  817. wallIndices[index++] = upperRight;
  818. wallIndices[index++] = lowerLeft;
  819. wallIndices[index++] = lowerRight;
  820. }
  821. geo.indices = wallIndices;
  822. geo = GeometryPipeline.GeometryPipeline.combineInstances([
  823. new GeometryInstance.GeometryInstance({
  824. geometry: topBottomGeo,
  825. }),
  826. new GeometryInstance.GeometryInstance({
  827. geometry: geo,
  828. }),
  829. ]);
  830. return geo[0];
  831. }
  832. const scratchRectanglePoints = [
  833. new Matrix2.Cartesian3(),
  834. new Matrix2.Cartesian3(),
  835. new Matrix2.Cartesian3(),
  836. new Matrix2.Cartesian3(),
  837. ];
  838. const nwScratch = new Matrix2.Cartographic();
  839. const stNwScratch = new Matrix2.Cartographic();
  840. function computeRectangle(rectangle, granularity, rotation, ellipsoid, result) {
  841. if (rotation === 0.0) {
  842. return Matrix2.Rectangle.clone(rectangle, result);
  843. }
  844. const computedOptions = RectangleGeometryLibrary.RectangleGeometryLibrary.computeOptions(
  845. rectangle,
  846. granularity,
  847. rotation,
  848. 0,
  849. rectangleScratch,
  850. nwScratch
  851. );
  852. const height = computedOptions.height;
  853. const width = computedOptions.width;
  854. const positions = scratchRectanglePoints;
  855. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  856. computedOptions,
  857. ellipsoid,
  858. false,
  859. 0,
  860. 0,
  861. positions[0]
  862. );
  863. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  864. computedOptions,
  865. ellipsoid,
  866. false,
  867. 0,
  868. width - 1,
  869. positions[1]
  870. );
  871. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  872. computedOptions,
  873. ellipsoid,
  874. false,
  875. height - 1,
  876. 0,
  877. positions[2]
  878. );
  879. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(
  880. computedOptions,
  881. ellipsoid,
  882. false,
  883. height - 1,
  884. width - 1,
  885. positions[3]
  886. );
  887. return Matrix2.Rectangle.fromCartesianArray(positions, ellipsoid, result);
  888. }
  889. /**
  890. * A description of a cartographic rectangle on an ellipsoid centered at the origin. Rectangle geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  891. *
  892. * @alias RectangleGeometry
  893. * @constructor
  894. *
  895. * @param {Object} options Object with the following properties:
  896. * @param {Rectangle} options.rectangle A cartographic rectangle with north, south, east and west properties in radians.
  897. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  898. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle lies.
  899. * @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.
  900. * @param {Number} [options.height=0.0] The distance in meters between the rectangle and the ellipsoid surface.
  901. * @param {Number} [options.rotation=0.0] The rotation of the rectangle, in radians. A positive rotation is counter-clockwise.
  902. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  903. * @param {Number} [options.extrudedHeight] The distance in meters between the rectangle's extruded face and the ellipsoid surface.
  904. *
  905. * @exception {DeveloperError} <code>options.rectangle.north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  906. * @exception {DeveloperError} <code>options.rectangle.south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  907. * @exception {DeveloperError} <code>options.rectangle.east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  908. * @exception {DeveloperError} <code>options.rectangle.west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  909. * @exception {DeveloperError} <code>options.rectangle.north</code> must be greater than <code>options.rectangle.south</code>.
  910. *
  911. * @see RectangleGeometry#createGeometry
  912. *
  913. * @demo {@link https://sandcastle.cesium.com/index.html?src=Rectangle.html|Cesium Sandcastle Rectangle Demo}
  914. *
  915. * @example
  916. * // 1. create a rectangle
  917. * const rectangle = new Cesium.RectangleGeometry({
  918. * ellipsoid : Cesium.Ellipsoid.WGS84,
  919. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  920. * height : 10000.0
  921. * });
  922. * const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
  923. *
  924. * // 2. create an extruded rectangle without a top
  925. * const rectangle = new Cesium.RectangleGeometry({
  926. * ellipsoid : Cesium.Ellipsoid.WGS84,
  927. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  928. * height : 10000.0,
  929. * extrudedHeight: 300000
  930. * });
  931. * const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
  932. */
  933. function RectangleGeometry(options) {
  934. options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);
  935. const rectangle = options.rectangle;
  936. //>>includeStart('debug', pragmas.debug);
  937. RuntimeError.Check.typeOf.object("rectangle", rectangle);
  938. Matrix2.Rectangle.validate(rectangle);
  939. if (rectangle.north < rectangle.south) {
  940. throw new RuntimeError.DeveloperError(
  941. "options.rectangle.north must be greater than or equal to options.rectangle.south"
  942. );
  943. }
  944. //>>includeEnd('debug');
  945. const height = defaultValue.defaultValue(options.height, 0.0);
  946. const extrudedHeight = defaultValue.defaultValue(options.extrudedHeight, height);
  947. this._rectangle = Matrix2.Rectangle.clone(rectangle);
  948. this._granularity = defaultValue.defaultValue(
  949. options.granularity,
  950. ComponentDatatype.CesiumMath.RADIANS_PER_DEGREE
  951. );
  952. this._ellipsoid = Matrix2.Ellipsoid.clone(
  953. defaultValue.defaultValue(options.ellipsoid, Matrix2.Ellipsoid.WGS84)
  954. );
  955. this._surfaceHeight = Math.max(height, extrudedHeight);
  956. this._rotation = defaultValue.defaultValue(options.rotation, 0.0);
  957. this._stRotation = defaultValue.defaultValue(options.stRotation, 0.0);
  958. this._vertexFormat = VertexFormat.VertexFormat.clone(
  959. defaultValue.defaultValue(options.vertexFormat, VertexFormat.VertexFormat.DEFAULT)
  960. );
  961. this._extrudedHeight = Math.min(height, extrudedHeight);
  962. this._shadowVolume = defaultValue.defaultValue(options.shadowVolume, false);
  963. this._workerName = "createRectangleGeometry";
  964. this._offsetAttribute = options.offsetAttribute;
  965. this._rotatedRectangle = undefined;
  966. this._textureCoordinateRotationPoints = undefined;
  967. }
  968. /**
  969. * The number of elements used to pack the object into an array.
  970. * @type {Number}
  971. */
  972. RectangleGeometry.packedLength =
  973. Matrix2.Rectangle.packedLength +
  974. Matrix2.Ellipsoid.packedLength +
  975. VertexFormat.VertexFormat.packedLength +
  976. 7;
  977. /**
  978. * Stores the provided instance into the provided array.
  979. *
  980. * @param {RectangleGeometry} value The value to pack.
  981. * @param {Number[]} array The array to pack into.
  982. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  983. *
  984. * @returns {Number[]} The array that was packed into
  985. */
  986. RectangleGeometry.pack = function (value, array, startingIndex) {
  987. //>>includeStart('debug', pragmas.debug);
  988. RuntimeError.Check.typeOf.object("value", value);
  989. RuntimeError.Check.defined("array", array);
  990. //>>includeEnd('debug');
  991. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  992. Matrix2.Rectangle.pack(value._rectangle, array, startingIndex);
  993. startingIndex += Matrix2.Rectangle.packedLength;
  994. Matrix2.Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  995. startingIndex += Matrix2.Ellipsoid.packedLength;
  996. VertexFormat.VertexFormat.pack(value._vertexFormat, array, startingIndex);
  997. startingIndex += VertexFormat.VertexFormat.packedLength;
  998. array[startingIndex++] = value._granularity;
  999. array[startingIndex++] = value._surfaceHeight;
  1000. array[startingIndex++] = value._rotation;
  1001. array[startingIndex++] = value._stRotation;
  1002. array[startingIndex++] = value._extrudedHeight;
  1003. array[startingIndex++] = value._shadowVolume ? 1.0 : 0.0;
  1004. array[startingIndex] = defaultValue.defaultValue(value._offsetAttribute, -1);
  1005. return array;
  1006. };
  1007. const scratchRectangle = new Matrix2.Rectangle();
  1008. const scratchEllipsoid = Matrix2.Ellipsoid.clone(Matrix2.Ellipsoid.UNIT_SPHERE);
  1009. const scratchOptions = {
  1010. rectangle: scratchRectangle,
  1011. ellipsoid: scratchEllipsoid,
  1012. vertexFormat: scratchVertexFormat,
  1013. granularity: undefined,
  1014. height: undefined,
  1015. rotation: undefined,
  1016. stRotation: undefined,
  1017. extrudedHeight: undefined,
  1018. shadowVolume: undefined,
  1019. offsetAttribute: undefined,
  1020. };
  1021. /**
  1022. * Retrieves an instance from a packed array.
  1023. *
  1024. * @param {Number[]} array The packed array.
  1025. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  1026. * @param {RectangleGeometry} [result] The object into which to store the result.
  1027. * @returns {RectangleGeometry} The modified result parameter or a new RectangleGeometry instance if one was not provided.
  1028. */
  1029. RectangleGeometry.unpack = function (array, startingIndex, result) {
  1030. //>>includeStart('debug', pragmas.debug);
  1031. RuntimeError.Check.defined("array", array);
  1032. //>>includeEnd('debug');
  1033. startingIndex = defaultValue.defaultValue(startingIndex, 0);
  1034. const rectangle = Matrix2.Rectangle.unpack(array, startingIndex, scratchRectangle);
  1035. startingIndex += Matrix2.Rectangle.packedLength;
  1036. const ellipsoid = Matrix2.Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  1037. startingIndex += Matrix2.Ellipsoid.packedLength;
  1038. const vertexFormat = VertexFormat.VertexFormat.unpack(
  1039. array,
  1040. startingIndex,
  1041. scratchVertexFormat
  1042. );
  1043. startingIndex += VertexFormat.VertexFormat.packedLength;
  1044. const granularity = array[startingIndex++];
  1045. const surfaceHeight = array[startingIndex++];
  1046. const rotation = array[startingIndex++];
  1047. const stRotation = array[startingIndex++];
  1048. const extrudedHeight = array[startingIndex++];
  1049. const shadowVolume = array[startingIndex++] === 1.0;
  1050. const offsetAttribute = array[startingIndex];
  1051. if (!defaultValue.defined(result)) {
  1052. scratchOptions.granularity = granularity;
  1053. scratchOptions.height = surfaceHeight;
  1054. scratchOptions.rotation = rotation;
  1055. scratchOptions.stRotation = stRotation;
  1056. scratchOptions.extrudedHeight = extrudedHeight;
  1057. scratchOptions.shadowVolume = shadowVolume;
  1058. scratchOptions.offsetAttribute =
  1059. offsetAttribute === -1 ? undefined : offsetAttribute;
  1060. return new RectangleGeometry(scratchOptions);
  1061. }
  1062. result._rectangle = Matrix2.Rectangle.clone(rectangle, result._rectangle);
  1063. result._ellipsoid = Matrix2.Ellipsoid.clone(ellipsoid, result._ellipsoid);
  1064. result._vertexFormat = VertexFormat.VertexFormat.clone(vertexFormat, result._vertexFormat);
  1065. result._granularity = granularity;
  1066. result._surfaceHeight = surfaceHeight;
  1067. result._rotation = rotation;
  1068. result._stRotation = stRotation;
  1069. result._extrudedHeight = extrudedHeight;
  1070. result._shadowVolume = shadowVolume;
  1071. result._offsetAttribute =
  1072. offsetAttribute === -1 ? undefined : offsetAttribute;
  1073. return result;
  1074. };
  1075. /**
  1076. * Computes the bounding rectangle based on the provided options
  1077. *
  1078. * @param {Object} options Object with the following properties:
  1079. * @param {Rectangle} options.rectangle A cartographic rectangle with north, south, east and west properties in radians.
  1080. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle lies.
  1081. * @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.
  1082. * @param {Number} [options.rotation=0.0] The rotation of the rectangle, in radians. A positive rotation is counter-clockwise.
  1083. * @param {Rectangle} [result] An object in which to store the result.
  1084. *
  1085. * @returns {Rectangle} The result rectangle
  1086. */
  1087. RectangleGeometry.computeRectangle = function (options, result) {
  1088. options = defaultValue.defaultValue(options, defaultValue.defaultValue.EMPTY_OBJECT);
  1089. const rectangle = options.rectangle;
  1090. //>>includeStart('debug', pragmas.debug);
  1091. RuntimeError.Check.typeOf.object("rectangle", rectangle);
  1092. Matrix2.Rectangle.validate(rectangle);
  1093. if (rectangle.north < rectangle.south) {
  1094. throw new RuntimeError.DeveloperError(
  1095. "options.rectangle.north must be greater than or equal to options.rectangle.south"
  1096. );
  1097. }
  1098. //>>includeEnd('debug');
  1099. const granularity = defaultValue.defaultValue(
  1100. options.granularity,
  1101. ComponentDatatype.CesiumMath.RADIANS_PER_DEGREE
  1102. );
  1103. const ellipsoid = defaultValue.defaultValue(options.ellipsoid, Matrix2.Ellipsoid.WGS84);
  1104. const rotation = defaultValue.defaultValue(options.rotation, 0.0);
  1105. return computeRectangle(rectangle, granularity, rotation, ellipsoid, result);
  1106. };
  1107. const tangentRotationMatrixScratch = new Matrix2.Matrix3();
  1108. const quaternionScratch = new Transforms.Quaternion();
  1109. const centerScratch = new Matrix2.Cartographic();
  1110. /**
  1111. * Computes the geometric representation of a rectangle, including its vertices, indices, and a bounding sphere.
  1112. *
  1113. * @param {RectangleGeometry} rectangleGeometry A description of the rectangle.
  1114. * @returns {Geometry|undefined} The computed vertices and indices.
  1115. *
  1116. * @exception {DeveloperError} Rotated rectangle is invalid.
  1117. */
  1118. RectangleGeometry.createGeometry = function (rectangleGeometry) {
  1119. if (
  1120. ComponentDatatype.CesiumMath.equalsEpsilon(
  1121. rectangleGeometry._rectangle.north,
  1122. rectangleGeometry._rectangle.south,
  1123. ComponentDatatype.CesiumMath.EPSILON10
  1124. ) ||
  1125. ComponentDatatype.CesiumMath.equalsEpsilon(
  1126. rectangleGeometry._rectangle.east,
  1127. rectangleGeometry._rectangle.west,
  1128. ComponentDatatype.CesiumMath.EPSILON10
  1129. )
  1130. ) {
  1131. return undefined;
  1132. }
  1133. let rectangle = rectangleGeometry._rectangle;
  1134. const ellipsoid = rectangleGeometry._ellipsoid;
  1135. const rotation = rectangleGeometry._rotation;
  1136. const stRotation = rectangleGeometry._stRotation;
  1137. const vertexFormat = rectangleGeometry._vertexFormat;
  1138. const computedOptions = RectangleGeometryLibrary.RectangleGeometryLibrary.computeOptions(
  1139. rectangle,
  1140. rectangleGeometry._granularity,
  1141. rotation,
  1142. stRotation,
  1143. rectangleScratch,
  1144. nwScratch,
  1145. stNwScratch
  1146. );
  1147. const tangentRotationMatrix = tangentRotationMatrixScratch;
  1148. if (stRotation !== 0 || rotation !== 0) {
  1149. const center = Matrix2.Rectangle.center(rectangle, centerScratch);
  1150. const axis = ellipsoid.geodeticSurfaceNormalCartographic(center, v1Scratch);
  1151. Transforms.Quaternion.fromAxisAngle(axis, -stRotation, quaternionScratch);
  1152. Matrix2.Matrix3.fromQuaternion(quaternionScratch, tangentRotationMatrix);
  1153. } else {
  1154. Matrix2.Matrix3.clone(Matrix2.Matrix3.IDENTITY, tangentRotationMatrix);
  1155. }
  1156. const surfaceHeight = rectangleGeometry._surfaceHeight;
  1157. const extrudedHeight = rectangleGeometry._extrudedHeight;
  1158. const extrude = !ComponentDatatype.CesiumMath.equalsEpsilon(
  1159. surfaceHeight,
  1160. extrudedHeight,
  1161. 0,
  1162. ComponentDatatype.CesiumMath.EPSILON2
  1163. );
  1164. computedOptions.lonScalar = 1.0 / rectangleGeometry._rectangle.width;
  1165. computedOptions.latScalar = 1.0 / rectangleGeometry._rectangle.height;
  1166. computedOptions.tangentRotationMatrix = tangentRotationMatrix;
  1167. let geometry;
  1168. let boundingSphere;
  1169. rectangle = rectangleGeometry._rectangle;
  1170. if (extrude) {
  1171. geometry = constructExtrudedRectangle(rectangleGeometry, computedOptions);
  1172. const topBS = Transforms.BoundingSphere.fromRectangle3D(
  1173. rectangle,
  1174. ellipsoid,
  1175. surfaceHeight,
  1176. topBoundingSphere
  1177. );
  1178. const bottomBS = Transforms.BoundingSphere.fromRectangle3D(
  1179. rectangle,
  1180. ellipsoid,
  1181. extrudedHeight,
  1182. bottomBoundingSphere
  1183. );
  1184. boundingSphere = Transforms.BoundingSphere.union(topBS, bottomBS);
  1185. } else {
  1186. geometry = constructRectangle(rectangleGeometry, computedOptions);
  1187. geometry.attributes.position.values = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(
  1188. geometry.attributes.position.values,
  1189. surfaceHeight,
  1190. ellipsoid,
  1191. false
  1192. );
  1193. if (defaultValue.defined(rectangleGeometry._offsetAttribute)) {
  1194. const length = geometry.attributes.position.values.length;
  1195. const offsetValue =
  1196. rectangleGeometry._offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE
  1197. ? 0
  1198. : 1;
  1199. const applyOffset = new Uint8Array(length / 3).fill(offsetValue);
  1200. geometry.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  1201. componentDatatype: ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  1202. componentsPerAttribute: 1,
  1203. values: applyOffset,
  1204. });
  1205. }
  1206. boundingSphere = Transforms.BoundingSphere.fromRectangle3D(
  1207. rectangle,
  1208. ellipsoid,
  1209. surfaceHeight
  1210. );
  1211. }
  1212. if (!vertexFormat.position) {
  1213. delete geometry.attributes.position;
  1214. }
  1215. return new GeometryAttribute.Geometry({
  1216. attributes: geometry.attributes,
  1217. indices: geometry.indices,
  1218. primitiveType: geometry.primitiveType,
  1219. boundingSphere: boundingSphere,
  1220. offsetAttribute: rectangleGeometry._offsetAttribute,
  1221. });
  1222. };
  1223. /**
  1224. * @private
  1225. */
  1226. RectangleGeometry.createShadowVolume = function (
  1227. rectangleGeometry,
  1228. minHeightFunc,
  1229. maxHeightFunc
  1230. ) {
  1231. const granularity = rectangleGeometry._granularity;
  1232. const ellipsoid = rectangleGeometry._ellipsoid;
  1233. const minHeight = minHeightFunc(granularity, ellipsoid);
  1234. const maxHeight = maxHeightFunc(granularity, ellipsoid);
  1235. return new RectangleGeometry({
  1236. rectangle: rectangleGeometry._rectangle,
  1237. rotation: rectangleGeometry._rotation,
  1238. ellipsoid: ellipsoid,
  1239. stRotation: rectangleGeometry._stRotation,
  1240. granularity: granularity,
  1241. extrudedHeight: maxHeight,
  1242. height: minHeight,
  1243. vertexFormat: VertexFormat.VertexFormat.POSITION_ONLY,
  1244. shadowVolume: true,
  1245. });
  1246. };
  1247. const unrotatedTextureRectangleScratch = new Matrix2.Rectangle();
  1248. const points2DScratch = [new Matrix2.Cartesian2(), new Matrix2.Cartesian2(), new Matrix2.Cartesian2()];
  1249. const rotation2DScratch = new Matrix2.Matrix2();
  1250. const rectangleCenterScratch = new Matrix2.Cartographic();
  1251. function textureCoordinateRotationPoints(rectangleGeometry) {
  1252. if (rectangleGeometry._stRotation === 0.0) {
  1253. return [0, 0, 0, 1, 1, 0];
  1254. }
  1255. const rectangle = Matrix2.Rectangle.clone(
  1256. rectangleGeometry._rectangle,
  1257. unrotatedTextureRectangleScratch
  1258. );
  1259. const granularity = rectangleGeometry._granularity;
  1260. const ellipsoid = rectangleGeometry._ellipsoid;
  1261. // Rotate to align the texture coordinates with ENU
  1262. const rotation = rectangleGeometry._rotation - rectangleGeometry._stRotation;
  1263. const unrotatedTextureRectangle = computeRectangle(
  1264. rectangle,
  1265. granularity,
  1266. rotation,
  1267. ellipsoid,
  1268. unrotatedTextureRectangleScratch
  1269. );
  1270. // Assume a computed "east-north" texture coordinate system based on spherical or planar tricks, bounded by `boundingRectangle`.
  1271. // The "desired" texture coordinate system forms an oriented rectangle (un-oriented computed) around the geometry that completely and tightly bounds it.
  1272. // We want to map from the "east-north" texture coordinate system into the "desired" system using a pair of lines (analagous planes in 2D)
  1273. // Compute 3 corners of the "desired" texture coordinate system in "east-north" texture space by the following in cartographic space:
  1274. // - rotate 3 of the corners in unrotatedTextureRectangle by stRotation around the center of the bounding rectangle
  1275. // - apply the "east-north" system's normalization formula to the rotated cartographics, even though this is likely to produce values outside [0-1].
  1276. // This gives us a set of points in the "east-north" texture coordinate system that can be used to map "east-north" texture coordinates to "desired."
  1277. const points2D = points2DScratch;
  1278. points2D[0].x = unrotatedTextureRectangle.west;
  1279. points2D[0].y = unrotatedTextureRectangle.south;
  1280. points2D[1].x = unrotatedTextureRectangle.west;
  1281. points2D[1].y = unrotatedTextureRectangle.north;
  1282. points2D[2].x = unrotatedTextureRectangle.east;
  1283. points2D[2].y = unrotatedTextureRectangle.south;
  1284. const boundingRectangle = rectangleGeometry.rectangle;
  1285. const toDesiredInComputed = Matrix2.Matrix2.fromRotation(
  1286. rectangleGeometry._stRotation,
  1287. rotation2DScratch
  1288. );
  1289. const boundingRectangleCenter = Matrix2.Rectangle.center(
  1290. boundingRectangle,
  1291. rectangleCenterScratch
  1292. );
  1293. for (let i = 0; i < 3; ++i) {
  1294. const point2D = points2D[i];
  1295. point2D.x -= boundingRectangleCenter.longitude;
  1296. point2D.y -= boundingRectangleCenter.latitude;
  1297. Matrix2.Matrix2.multiplyByVector(toDesiredInComputed, point2D, point2D);
  1298. point2D.x += boundingRectangleCenter.longitude;
  1299. point2D.y += boundingRectangleCenter.latitude;
  1300. // Convert point into east-north texture coordinate space
  1301. point2D.x = (point2D.x - boundingRectangle.west) / boundingRectangle.width;
  1302. point2D.y =
  1303. (point2D.y - boundingRectangle.south) / boundingRectangle.height;
  1304. }
  1305. const minXYCorner = points2D[0];
  1306. const maxYCorner = points2D[1];
  1307. const maxXCorner = points2D[2];
  1308. const result = new Array(6);
  1309. Matrix2.Cartesian2.pack(minXYCorner, result);
  1310. Matrix2.Cartesian2.pack(maxYCorner, result, 2);
  1311. Matrix2.Cartesian2.pack(maxXCorner, result, 4);
  1312. return result;
  1313. }
  1314. Object.defineProperties(RectangleGeometry.prototype, {
  1315. /**
  1316. * @private
  1317. */
  1318. rectangle: {
  1319. get: function () {
  1320. if (!defaultValue.defined(this._rotatedRectangle)) {
  1321. this._rotatedRectangle = computeRectangle(
  1322. this._rectangle,
  1323. this._granularity,
  1324. this._rotation,
  1325. this._ellipsoid
  1326. );
  1327. }
  1328. return this._rotatedRectangle;
  1329. },
  1330. },
  1331. /**
  1332. * For remapping texture coordinates when rendering RectangleGeometries as GroundPrimitives.
  1333. * This version permits skew in textures by computing offsets directly in cartographic space and
  1334. * more accurately approximates rendering RectangleGeometries with height as standard Primitives.
  1335. * @see Geometry#_textureCoordinateRotationPoints
  1336. * @private
  1337. */
  1338. textureCoordinateRotationPoints: {
  1339. get: function () {
  1340. if (!defaultValue.defined(this._textureCoordinateRotationPoints)) {
  1341. this._textureCoordinateRotationPoints = textureCoordinateRotationPoints(
  1342. this
  1343. );
  1344. }
  1345. return this._textureCoordinateRotationPoints;
  1346. },
  1347. },
  1348. });
  1349. function createRectangleGeometry(rectangleGeometry, offset) {
  1350. if (defaultValue.defined(offset)) {
  1351. rectangleGeometry = RectangleGeometry.unpack(rectangleGeometry, offset);
  1352. }
  1353. rectangleGeometry._ellipsoid = Matrix2.Ellipsoid.clone(rectangleGeometry._ellipsoid);
  1354. rectangleGeometry._rectangle = Matrix2.Rectangle.clone(rectangleGeometry._rectangle);
  1355. return RectangleGeometry.createGeometry(rectangleGeometry);
  1356. }
  1357. return createRectangleGeometry;
  1358. }));