createRectangleGeometry.js 51 KB

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