RectangleGeometry.js 51 KB

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