Source: Core/EllipseGeometry.js

  1. /*global define*/
  2. define([
  3. './BoundingSphere',
  4. './Cartesian2',
  5. './Cartesian3',
  6. './Cartographic',
  7. './ComponentDatatype',
  8. './defaultValue',
  9. './defined',
  10. './defineProperties',
  11. './DeveloperError',
  12. './EllipseGeometryLibrary',
  13. './Ellipsoid',
  14. './GeographicProjection',
  15. './Geometry',
  16. './GeometryAttribute',
  17. './GeometryAttributes',
  18. './GeometryInstance',
  19. './GeometryPipeline',
  20. './IndexDatatype',
  21. './Math',
  22. './Matrix3',
  23. './Matrix4',
  24. './PrimitiveType',
  25. './Quaternion',
  26. './Rectangle',
  27. './Transforms',
  28. './VertexFormat'
  29. ], function(
  30. BoundingSphere,
  31. Cartesian2,
  32. Cartesian3,
  33. Cartographic,
  34. ComponentDatatype,
  35. defaultValue,
  36. defined,
  37. defineProperties,
  38. DeveloperError,
  39. EllipseGeometryLibrary,
  40. Ellipsoid,
  41. GeographicProjection,
  42. Geometry,
  43. GeometryAttribute,
  44. GeometryAttributes,
  45. GeometryInstance,
  46. GeometryPipeline,
  47. IndexDatatype,
  48. CesiumMath,
  49. Matrix3,
  50. Matrix4,
  51. PrimitiveType,
  52. Quaternion,
  53. Rectangle,
  54. Transforms,
  55. VertexFormat) {
  56. 'use strict';
  57. var scratchCartesian1 = new Cartesian3();
  58. var scratchCartesian2 = new Cartesian3();
  59. var scratchCartesian3 = new Cartesian3();
  60. var scratchCartesian4 = new Cartesian3();
  61. var texCoordScratch = new Cartesian2();
  62. var textureMatrixScratch = new Matrix3();
  63. var quaternionScratch = new Quaternion();
  64. var scratchNormal = new Cartesian3();
  65. var scratchTangent = new Cartesian3();
  66. var scratchBinormal = new Cartesian3();
  67. var scratchCartographic = new Cartographic();
  68. var projectedCenterScratch = new Cartesian3();
  69. var scratchMinTexCoord = new Cartesian2();
  70. var scratchMaxTexCoord = new Cartesian2();
  71. function computeTopBottomAttributes(positions, options, extrude) {
  72. var vertexFormat = options.vertexFormat;
  73. var center = options.center;
  74. var semiMajorAxis = options.semiMajorAxis;
  75. var semiMinorAxis = options.semiMinorAxis;
  76. var ellipsoid = options.ellipsoid;
  77. var stRotation = options.stRotation;
  78. var size = (extrude) ? positions.length / 3 * 2 : positions.length / 3;
  79. var textureCoordinates = (vertexFormat.st) ? new Float32Array(size * 2) : undefined;
  80. var normals = (vertexFormat.normal) ? new Float32Array(size * 3) : undefined;
  81. var tangents = (vertexFormat.tangent) ? new Float32Array(size * 3) : undefined;
  82. var binormals = (vertexFormat.binormal) ? new Float32Array(size * 3) : undefined;
  83. var textureCoordIndex = 0;
  84. // Raise positions to a height above the ellipsoid and compute the
  85. // texture coordinates, normals, tangents, and binormals.
  86. var normal = scratchNormal;
  87. var tangent = scratchTangent;
  88. var binormal = scratchBinormal;
  89. var projection = new GeographicProjection(ellipsoid);
  90. var projectedCenter = projection.project(ellipsoid.cartesianToCartographic(center, scratchCartographic), projectedCenterScratch);
  91. var geodeticNormal = ellipsoid.scaleToGeodeticSurface(center, scratchCartesian1);
  92. ellipsoid.geodeticSurfaceNormal(geodeticNormal, geodeticNormal);
  93. var rotation = Quaternion.fromAxisAngle(geodeticNormal, stRotation, quaternionScratch);
  94. var textureMatrix = Matrix3.fromQuaternion(rotation, textureMatrixScratch);
  95. var minTexCoord = Cartesian2.fromElements(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, scratchMinTexCoord);
  96. var maxTexCoord = Cartesian2.fromElements(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, scratchMaxTexCoord);
  97. var length = positions.length;
  98. var bottomOffset = (extrude) ? length : 0;
  99. var stOffset = bottomOffset / 3 * 2;
  100. for (var i = 0; i < length; i += 3) {
  101. var i1 = i + 1;
  102. var i2 = i + 2;
  103. var position = Cartesian3.fromArray(positions, i, scratchCartesian1);
  104. if (vertexFormat.st) {
  105. var rotatedPoint = Matrix3.multiplyByVector(textureMatrix, position, scratchCartesian2);
  106. var projectedPoint = projection.project(ellipsoid.cartesianToCartographic(rotatedPoint, scratchCartographic), scratchCartesian3);
  107. Cartesian3.subtract(projectedPoint, projectedCenter, projectedPoint);
  108. texCoordScratch.x = (projectedPoint.x + semiMajorAxis) / (2.0 * semiMajorAxis);
  109. texCoordScratch.y = (projectedPoint.y + semiMinorAxis) / (2.0 * semiMinorAxis);
  110. minTexCoord.x = Math.min(texCoordScratch.x, minTexCoord.x);
  111. minTexCoord.y = Math.min(texCoordScratch.y, minTexCoord.y);
  112. maxTexCoord.x = Math.max(texCoordScratch.x, maxTexCoord.x);
  113. maxTexCoord.y = Math.max(texCoordScratch.y, maxTexCoord.y);
  114. if (extrude) {
  115. textureCoordinates[textureCoordIndex + stOffset] = texCoordScratch.x;
  116. textureCoordinates[textureCoordIndex + 1 + stOffset] = texCoordScratch.y;
  117. }
  118. textureCoordinates[textureCoordIndex++] = texCoordScratch.x;
  119. textureCoordinates[textureCoordIndex++] = texCoordScratch.y;
  120. }
  121. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  122. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  123. if (vertexFormat.tangent || vertexFormat.binormal) {
  124. tangent = Cartesian3.normalize(Cartesian3.cross(Cartesian3.UNIT_Z, normal, tangent), tangent);
  125. Matrix3.multiplyByVector(textureMatrix, tangent, tangent);
  126. }
  127. if (vertexFormat.normal) {
  128. normals[i] = normal.x;
  129. normals[i1] = normal.y;
  130. normals[i2] = normal.z;
  131. if (extrude) {
  132. normals[i + bottomOffset] = -normal.x;
  133. normals[i1 + bottomOffset] = -normal.y;
  134. normals[i2 + bottomOffset] = -normal.z;
  135. }
  136. }
  137. if (vertexFormat.tangent) {
  138. tangents[i] = tangent.x;
  139. tangents[i1] = tangent.y;
  140. tangents[i2] = tangent.z;
  141. if (extrude) {
  142. tangents[i + bottomOffset] = -tangent.x;
  143. tangents[i1 + bottomOffset] = -tangent.y;
  144. tangents[i2 + bottomOffset] = -tangent.z;
  145. }
  146. }
  147. if (vertexFormat.binormal) {
  148. binormal = Cartesian3.normalize(Cartesian3.cross(normal, tangent, binormal), binormal);
  149. binormals[i] = binormal.x;
  150. binormals[i1] = binormal.y;
  151. binormals[i2] = binormal.z;
  152. if (extrude) {
  153. binormals[i + bottomOffset] = binormal.x;
  154. binormals[i1 + bottomOffset] = binormal.y;
  155. binormals[i2 + bottomOffset] = binormal.z;
  156. }
  157. }
  158. }
  159. }
  160. if (vertexFormat.st) {
  161. length = textureCoordinates.length;
  162. for (var k = 0; k < length; k += 2) {
  163. textureCoordinates[k] = (textureCoordinates[k] - minTexCoord.x) / (maxTexCoord.x - minTexCoord.x);
  164. textureCoordinates[k + 1] = (textureCoordinates[k + 1] - minTexCoord.y) / (maxTexCoord.y - minTexCoord.y);
  165. }
  166. }
  167. var attributes = new GeometryAttributes();
  168. if (vertexFormat.position) {
  169. var finalPositions = EllipseGeometryLibrary.raisePositionsToHeight(positions, options, extrude);
  170. attributes.position = new GeometryAttribute({
  171. componentDatatype : ComponentDatatype.DOUBLE,
  172. componentsPerAttribute : 3,
  173. values : finalPositions
  174. });
  175. }
  176. if (vertexFormat.st) {
  177. attributes.st = new GeometryAttribute({
  178. componentDatatype : ComponentDatatype.FLOAT,
  179. componentsPerAttribute : 2,
  180. values : textureCoordinates
  181. });
  182. }
  183. if (vertexFormat.normal) {
  184. attributes.normal = new GeometryAttribute({
  185. componentDatatype : ComponentDatatype.FLOAT,
  186. componentsPerAttribute : 3,
  187. values : normals
  188. });
  189. }
  190. if (vertexFormat.tangent) {
  191. attributes.tangent = new GeometryAttribute({
  192. componentDatatype : ComponentDatatype.FLOAT,
  193. componentsPerAttribute : 3,
  194. values : tangents
  195. });
  196. }
  197. if (vertexFormat.binormal) {
  198. attributes.binormal = new GeometryAttribute({
  199. componentDatatype : ComponentDatatype.FLOAT,
  200. componentsPerAttribute : 3,
  201. values : binormals
  202. });
  203. }
  204. return attributes;
  205. }
  206. function topIndices(numPts) {
  207. // numTriangles in half = 3 + 8 + 12 + ... = -1 + 4 + (4 + 4) + (4 + 4 + 4) + ... = -1 + 4 * (1 + 2 + 3 + ...)
  208. // = -1 + 4 * ((n * ( n + 1)) / 2)
  209. // total triangles = 2 * numTrangles in half
  210. // indices = total triangles * 3;
  211. // Substitute numPts for n above
  212. var indices = new Array(12 * (numPts * ( numPts + 1)) - 6);
  213. var indicesIndex = 0;
  214. var prevIndex;
  215. var numInterior;
  216. var positionIndex;
  217. var i;
  218. var j;
  219. // Indices triangles to the 'right' of the north vector
  220. prevIndex = 0;
  221. positionIndex = 1;
  222. for (i = 0; i < 3; i++) {
  223. indices[indicesIndex++] = positionIndex++;
  224. indices[indicesIndex++] = prevIndex;
  225. indices[indicesIndex++] = positionIndex;
  226. }
  227. for (i = 2; i < numPts + 1; ++i) {
  228. positionIndex = i * (i + 1) - 1;
  229. prevIndex = (i - 1) * i - 1;
  230. indices[indicesIndex++] = positionIndex++;
  231. indices[indicesIndex++] = prevIndex;
  232. indices[indicesIndex++] = positionIndex;
  233. numInterior = 2 * i;
  234. for (j = 0; j < numInterior - 1; ++j) {
  235. indices[indicesIndex++] = positionIndex;
  236. indices[indicesIndex++] = prevIndex++;
  237. indices[indicesIndex++] = prevIndex;
  238. indices[indicesIndex++] = positionIndex++;
  239. indices[indicesIndex++] = prevIndex;
  240. indices[indicesIndex++] = positionIndex;
  241. }
  242. indices[indicesIndex++] = positionIndex++;
  243. indices[indicesIndex++] = prevIndex;
  244. indices[indicesIndex++] = positionIndex;
  245. }
  246. // Indices for center column of triangles
  247. numInterior = numPts * 2;
  248. ++positionIndex;
  249. ++prevIndex;
  250. for (i = 0; i < numInterior - 1; ++i) {
  251. indices[indicesIndex++] = positionIndex;
  252. indices[indicesIndex++] = prevIndex++;
  253. indices[indicesIndex++] = prevIndex;
  254. indices[indicesIndex++] = positionIndex++;
  255. indices[indicesIndex++] = prevIndex;
  256. indices[indicesIndex++] = positionIndex;
  257. }
  258. indices[indicesIndex++] = positionIndex;
  259. indices[indicesIndex++] = prevIndex++;
  260. indices[indicesIndex++] = prevIndex;
  261. indices[indicesIndex++] = positionIndex++;
  262. indices[indicesIndex++] = prevIndex++;
  263. indices[indicesIndex++] = prevIndex;
  264. // Reverse the process creating indices to the 'left' of the north vector
  265. ++prevIndex;
  266. for (i = numPts - 1; i > 1; --i) {
  267. indices[indicesIndex++] = prevIndex++;
  268. indices[indicesIndex++] = prevIndex;
  269. indices[indicesIndex++] = positionIndex;
  270. numInterior = 2 * i;
  271. for (j = 0; j < numInterior - 1; ++j) {
  272. indices[indicesIndex++] = positionIndex;
  273. indices[indicesIndex++] = prevIndex++;
  274. indices[indicesIndex++] = prevIndex;
  275. indices[indicesIndex++] = positionIndex++;
  276. indices[indicesIndex++] = prevIndex;
  277. indices[indicesIndex++] = positionIndex;
  278. }
  279. indices[indicesIndex++] = prevIndex++;
  280. indices[indicesIndex++] = prevIndex++;
  281. indices[indicesIndex++] = positionIndex++;
  282. }
  283. for (i = 0; i < 3; i++) {
  284. indices[indicesIndex++] = prevIndex++;
  285. indices[indicesIndex++] = prevIndex;
  286. indices[indicesIndex++] = positionIndex;
  287. }
  288. return indices;
  289. }
  290. var boundingSphereCenter = new Cartesian3();
  291. function computeEllipse(options) {
  292. var center = options.center;
  293. boundingSphereCenter = Cartesian3.multiplyByScalar(options.ellipsoid.geodeticSurfaceNormal(center, boundingSphereCenter), options.height, boundingSphereCenter);
  294. boundingSphereCenter = Cartesian3.add(center, boundingSphereCenter, boundingSphereCenter);
  295. var boundingSphere = new BoundingSphere(boundingSphereCenter, options.semiMajorAxis);
  296. var cep = EllipseGeometryLibrary.computeEllipsePositions(options, true, false);
  297. var positions = cep.positions;
  298. var numPts = cep.numPts;
  299. var attributes = computeTopBottomAttributes(positions, options, false);
  300. var indices = topIndices(numPts);
  301. indices = IndexDatatype.createTypedArray(positions.length / 3, indices);
  302. return {
  303. boundingSphere : boundingSphere,
  304. attributes : attributes,
  305. indices : indices
  306. };
  307. }
  308. function computeWallAttributes(positions, options) {
  309. var vertexFormat = options.vertexFormat;
  310. var center = options.center;
  311. var semiMajorAxis = options.semiMajorAxis;
  312. var semiMinorAxis = options.semiMinorAxis;
  313. var ellipsoid = options.ellipsoid;
  314. var height = options.height;
  315. var extrudedHeight = options.extrudedHeight;
  316. var stRotation = options.stRotation;
  317. var size = positions.length / 3 * 2;
  318. var finalPositions = new Float64Array(size * 3);
  319. var textureCoordinates = (vertexFormat.st) ? new Float32Array(size * 2) : undefined;
  320. var normals = (vertexFormat.normal) ? new Float32Array(size * 3) : undefined;
  321. var tangents = (vertexFormat.tangent) ? new Float32Array(size * 3) : undefined;
  322. var binormals = (vertexFormat.binormal) ? new Float32Array(size * 3) : undefined;
  323. var textureCoordIndex = 0;
  324. // Raise positions to a height above the ellipsoid and compute the
  325. // texture coordinates, normals, tangents, and binormals.
  326. var normal = scratchNormal;
  327. var tangent = scratchTangent;
  328. var binormal = scratchBinormal;
  329. var projection = new GeographicProjection(ellipsoid);
  330. var projectedCenter = projection.project(ellipsoid.cartesianToCartographic(center, scratchCartographic), projectedCenterScratch);
  331. var geodeticNormal = ellipsoid.scaleToGeodeticSurface(center, scratchCartesian1);
  332. ellipsoid.geodeticSurfaceNormal(geodeticNormal, geodeticNormal);
  333. var rotation = Quaternion.fromAxisAngle(geodeticNormal, stRotation, quaternionScratch);
  334. var textureMatrix = Matrix3.fromQuaternion(rotation, textureMatrixScratch);
  335. var minTexCoord = Cartesian2.fromElements(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, scratchMinTexCoord);
  336. var maxTexCoord = Cartesian2.fromElements(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, scratchMaxTexCoord);
  337. var length = positions.length;
  338. var stOffset = length / 3 * 2;
  339. for (var i = 0; i < length; i += 3) {
  340. var i1 = i + 1;
  341. var i2 = i + 2;
  342. var position = Cartesian3.fromArray(positions, i, scratchCartesian1);
  343. var extrudedPosition;
  344. if (vertexFormat.st) {
  345. var rotatedPoint = Matrix3.multiplyByVector(textureMatrix, position, scratchCartesian2);
  346. var projectedPoint = projection.project(ellipsoid.cartesianToCartographic(rotatedPoint, scratchCartographic), scratchCartesian3);
  347. Cartesian3.subtract(projectedPoint, projectedCenter, projectedPoint);
  348. texCoordScratch.x = (projectedPoint.x + semiMajorAxis) / (2.0 * semiMajorAxis);
  349. texCoordScratch.y = (projectedPoint.y + semiMinorAxis) / (2.0 * semiMinorAxis);
  350. minTexCoord.x = Math.min(texCoordScratch.x, minTexCoord.x);
  351. minTexCoord.y = Math.min(texCoordScratch.y, minTexCoord.y);
  352. maxTexCoord.x = Math.max(texCoordScratch.x, maxTexCoord.x);
  353. maxTexCoord.y = Math.max(texCoordScratch.y, maxTexCoord.y);
  354. textureCoordinates[textureCoordIndex + stOffset] = texCoordScratch.x;
  355. textureCoordinates[textureCoordIndex + 1 + stOffset] = texCoordScratch.y;
  356. textureCoordinates[textureCoordIndex++] = texCoordScratch.x;
  357. textureCoordinates[textureCoordIndex++] = texCoordScratch.y;
  358. }
  359. position = ellipsoid.scaleToGeodeticSurface(position, position);
  360. extrudedPosition = Cartesian3.clone(position, scratchCartesian2);
  361. normal = ellipsoid.geodeticSurfaceNormal(position, normal);
  362. var scaledNormal = Cartesian3.multiplyByScalar(normal, height, scratchCartesian4);
  363. position = Cartesian3.add(position, scaledNormal, position);
  364. scaledNormal = Cartesian3.multiplyByScalar(normal, extrudedHeight, scaledNormal);
  365. extrudedPosition = Cartesian3.add(extrudedPosition, scaledNormal, extrudedPosition);
  366. if (vertexFormat.position) {
  367. finalPositions[i + length] = extrudedPosition.x;
  368. finalPositions[i1 + length] = extrudedPosition.y;
  369. finalPositions[i2 + length] = extrudedPosition.z;
  370. finalPositions[i] = position.x;
  371. finalPositions[i1] = position.y;
  372. finalPositions[i2] = position.z;
  373. }
  374. if (vertexFormat.normal || vertexFormat.tangent || vertexFormat.binormal) {
  375. binormal = Cartesian3.clone(normal, binormal);
  376. var next = Cartesian3.fromArray(positions, (i + 3) % length, scratchCartesian4);
  377. Cartesian3.subtract(next, position, next);
  378. var bottom = Cartesian3.subtract(extrudedPosition, position, scratchCartesian3);
  379. normal = Cartesian3.normalize(Cartesian3.cross(bottom, next, normal), normal);
  380. if (vertexFormat.normal) {
  381. normals[i] = normal.x;
  382. normals[i1] = normal.y;
  383. normals[i2] = normal.z;
  384. normals[i + length] = normal.x;
  385. normals[i1 + length] = normal.y;
  386. normals[i2 + length] = normal.z;
  387. }
  388. if (vertexFormat.tangent) {
  389. tangent = Cartesian3.normalize(Cartesian3.cross(binormal, normal, tangent), tangent);
  390. tangents[i] = tangent.x;
  391. tangents[i1] = tangent.y;
  392. tangents[i2] = tangent.z;
  393. tangents[i + length] = tangent.x;
  394. tangents[i + 1 + length] = tangent.y;
  395. tangents[i + 2 + length] = tangent.z;
  396. }
  397. if (vertexFormat.binormal) {
  398. binormals[i] = binormal.x;
  399. binormals[i1] = binormal.y;
  400. binormals[i2] = binormal.z;
  401. binormals[i + length] = binormal.x;
  402. binormals[i1 + length] = binormal.y;
  403. binormals[i2 + length] = binormal.z;
  404. }
  405. }
  406. }
  407. if (vertexFormat.st) {
  408. length = textureCoordinates.length;
  409. for (var k = 0; k < length; k += 2) {
  410. textureCoordinates[k] = (textureCoordinates[k] - minTexCoord.x) / (maxTexCoord.x - minTexCoord.x);
  411. textureCoordinates[k + 1] = (textureCoordinates[k + 1] - minTexCoord.y) / (maxTexCoord.y - minTexCoord.y);
  412. }
  413. }
  414. var attributes = new GeometryAttributes();
  415. if (vertexFormat.position) {
  416. attributes.position = new GeometryAttribute({
  417. componentDatatype : ComponentDatatype.DOUBLE,
  418. componentsPerAttribute : 3,
  419. values : finalPositions
  420. });
  421. }
  422. if (vertexFormat.st) {
  423. attributes.st = new GeometryAttribute({
  424. componentDatatype : ComponentDatatype.FLOAT,
  425. componentsPerAttribute : 2,
  426. values : textureCoordinates
  427. });
  428. }
  429. if (vertexFormat.normal) {
  430. attributes.normal = new GeometryAttribute({
  431. componentDatatype : ComponentDatatype.FLOAT,
  432. componentsPerAttribute : 3,
  433. values : normals
  434. });
  435. }
  436. if (vertexFormat.tangent) {
  437. attributes.tangent = new GeometryAttribute({
  438. componentDatatype : ComponentDatatype.FLOAT,
  439. componentsPerAttribute : 3,
  440. values : tangents
  441. });
  442. }
  443. if (vertexFormat.binormal) {
  444. attributes.binormal = new GeometryAttribute({
  445. componentDatatype : ComponentDatatype.FLOAT,
  446. componentsPerAttribute : 3,
  447. values : binormals
  448. });
  449. }
  450. return attributes;
  451. }
  452. function computeWallIndices(positions) {
  453. var length = positions.length / 3;
  454. var indices = IndexDatatype.createTypedArray(length, length * 6);
  455. var index = 0;
  456. for (var i = 0; i < length; i++) {
  457. var UL = i;
  458. var LL = i + length;
  459. var UR = (UL + 1) % length;
  460. var LR = UR + length;
  461. indices[index++] = UL;
  462. indices[index++] = LL;
  463. indices[index++] = UR;
  464. indices[index++] = UR;
  465. indices[index++] = LL;
  466. indices[index++] = LR;
  467. }
  468. return indices;
  469. }
  470. var topBoundingSphere = new BoundingSphere();
  471. var bottomBoundingSphere = new BoundingSphere();
  472. function computeExtrudedEllipse(options) {
  473. var center = options.center;
  474. var ellipsoid = options.ellipsoid;
  475. var semiMajorAxis = options.semiMajorAxis;
  476. var scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scratchCartesian1), options.height, scratchCartesian1);
  477. topBoundingSphere.center = Cartesian3.add(center, scaledNormal, topBoundingSphere.center);
  478. topBoundingSphere.radius = semiMajorAxis;
  479. scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scaledNormal), options.extrudedHeight, scaledNormal);
  480. bottomBoundingSphere.center = Cartesian3.add(center, scaledNormal, bottomBoundingSphere.center);
  481. bottomBoundingSphere.radius = semiMajorAxis;
  482. var cep = EllipseGeometryLibrary.computeEllipsePositions(options, true, true);
  483. var positions = cep.positions;
  484. var numPts = cep.numPts;
  485. var outerPositions = cep.outerPositions;
  486. var boundingSphere = BoundingSphere.union(topBoundingSphere, bottomBoundingSphere);
  487. var topBottomAttributes = computeTopBottomAttributes(positions, options, true);
  488. var indices = topIndices(numPts);
  489. var length = indices.length;
  490. indices.length = length * 2;
  491. var posLength = positions.length / 3;
  492. for (var i = 0; i < length; i += 3) {
  493. indices[i + length] = indices[i + 2] + posLength;
  494. indices[i + 1 + length] = indices[i + 1] + posLength;
  495. indices[i + 2 + length] = indices[i] + posLength;
  496. }
  497. var topBottomIndices = IndexDatatype.createTypedArray(posLength * 2 / 3, indices);
  498. var topBottomGeo = new Geometry({
  499. attributes : topBottomAttributes,
  500. indices : topBottomIndices,
  501. primitiveType : PrimitiveType.TRIANGLES
  502. });
  503. var wallAttributes = computeWallAttributes(outerPositions, options);
  504. indices = computeWallIndices(outerPositions);
  505. var wallIndices = IndexDatatype.createTypedArray(outerPositions.length * 2 / 3, indices);
  506. var wallGeo = new Geometry({
  507. attributes : wallAttributes,
  508. indices : wallIndices,
  509. primitiveType : PrimitiveType.TRIANGLES
  510. });
  511. var geo = GeometryPipeline.combineInstances([
  512. new GeometryInstance({
  513. geometry : topBottomGeo
  514. }),
  515. new GeometryInstance({
  516. geometry : wallGeo
  517. })
  518. ]);
  519. return {
  520. boundingSphere : boundingSphere,
  521. attributes : geo[0].attributes,
  522. indices : geo[0].indices
  523. };
  524. }
  525. var scratchEnuToFixedMatrix = new Matrix4();
  526. var scratchFixedToEnuMatrix = new Matrix4();
  527. var scratchRotationMatrix = new Matrix3();
  528. var scratchRectanglePoints = [new Cartesian3(), new Cartesian3(), new Cartesian3(), new Cartesian3()];
  529. var scratchCartographicPoints = [new Cartographic(), new Cartographic(), new Cartographic(), new Cartographic()];
  530. function computeRectangle(center, ellipsoid, semiMajorAxis, semiMinorAxis, rotation) {
  531. Transforms.eastNorthUpToFixedFrame(center, ellipsoid, scratchEnuToFixedMatrix);
  532. Matrix4.inverseTransformation(scratchEnuToFixedMatrix, scratchFixedToEnuMatrix);
  533. // Find the 4 extreme points of the ellipse in ENU
  534. for (var i = 0; i < 4; ++i) {
  535. Cartesian3.clone(Cartesian3.ZERO, scratchRectanglePoints[i]);
  536. }
  537. scratchRectanglePoints[0].x += semiMajorAxis;
  538. scratchRectanglePoints[1].x -= semiMajorAxis;
  539. scratchRectanglePoints[2].y += semiMinorAxis;
  540. scratchRectanglePoints[3].y -= semiMinorAxis;
  541. Matrix3.fromRotationZ(rotation, scratchRotationMatrix);
  542. for (i = 0; i < 4; ++i) {
  543. // Apply the rotation
  544. Matrix3.multiplyByVector(scratchRotationMatrix, scratchRectanglePoints[i], scratchRectanglePoints[i]);
  545. // Convert back to fixed and then to cartographic
  546. Matrix4.multiplyByPoint(scratchEnuToFixedMatrix, scratchRectanglePoints[i], scratchRectanglePoints[i]);
  547. ellipsoid.cartesianToCartographic(scratchRectanglePoints[i], scratchCartographicPoints[i]);
  548. }
  549. return Rectangle.fromCartographicArray(scratchCartographicPoints);
  550. }
  551. /**
  552. * A description of an ellipse on an ellipsoid. Ellipse geometry can be rendered with both {@link Primitive} and {@link GroundPrimitive}.
  553. *
  554. * @alias EllipseGeometry
  555. * @constructor
  556. *
  557. * @param {Object} options Object with the following properties:
  558. * @param {Cartesian3} options.center The ellipse's center point in the fixed frame.
  559. * @param {Number} options.semiMajorAxis The length of the ellipse's semi-major axis in meters.
  560. * @param {Number} options.semiMinorAxis The length of the ellipse's semi-minor axis in meters.
  561. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the ellipse will be on.
  562. * @param {Number} [options.height=0.0] The distance in meters between the ellipse and the ellipsoid surface.
  563. * @param {Number} [options.extrudedHeight] The distance in meters between the ellipse's extruded face and the ellipsoid surface.
  564. * @param {Number} [options.rotation=0.0] The angle of rotation counter-clockwise from north.
  565. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates counter-clockwise from north.
  566. * @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The angular distance between points on the ellipse in radians.
  567. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  568. *
  569. * @exception {DeveloperError} semiMajorAxis and semiMinorAxis must be greater than zero.
  570. * @exception {DeveloperError} semiMajorAxis must be greater than or equal to the semiMinorAxis.
  571. * @exception {DeveloperError} granularity must be greater than zero.
  572. *
  573. *
  574. * @example
  575. * // Create an ellipse.
  576. * var ellipse = new Cesium.EllipseGeometry({
  577. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  578. * semiMajorAxis : 500000.0,
  579. * semiMinorAxis : 300000.0,
  580. * rotation : Cesium.Math.toRadians(60.0)
  581. * });
  582. * var geometry = Cesium.EllipseGeometry.createGeometry(ellipse);
  583. *
  584. * @see EllipseGeometry.createGeometry
  585. */
  586. function EllipseGeometry(options) {
  587. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  588. var center = options.center;
  589. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  590. var semiMajorAxis = options.semiMajorAxis;
  591. var semiMinorAxis = options.semiMinorAxis;
  592. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  593. var height = defaultValue(options.height, 0.0);
  594. var extrudedHeight = options.extrudedHeight;
  595. var extrude = (defined(extrudedHeight) && Math.abs(height - extrudedHeight) > 1.0);
  596. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  597. //>>includeStart('debug', pragmas.debug);
  598. if (!defined(center)) {
  599. throw new DeveloperError('center is required.');
  600. }
  601. if (!defined(semiMajorAxis)) {
  602. throw new DeveloperError('semiMajorAxis is required.');
  603. }
  604. if (!defined(semiMinorAxis)) {
  605. throw new DeveloperError('semiMinorAxis is required.');
  606. }
  607. if (semiMajorAxis < semiMinorAxis) {
  608. throw new DeveloperError('semiMajorAxis must be greater than or equal to the semiMinorAxis.');
  609. }
  610. if (granularity <= 0.0) {
  611. throw new DeveloperError('granularity must be greater than zero.');
  612. }
  613. //>>includeEnd('debug');
  614. this._center = Cartesian3.clone(center);
  615. this._semiMajorAxis = semiMajorAxis;
  616. this._semiMinorAxis = semiMinorAxis;
  617. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  618. this._rotation = defaultValue(options.rotation, 0.0);
  619. this._stRotation = defaultValue(options.stRotation, 0.0);
  620. this._height = height;
  621. this._granularity = granularity;
  622. this._vertexFormat = VertexFormat.clone(vertexFormat);
  623. this._extrudedHeight = defaultValue(extrudedHeight, height);
  624. this._extrude = extrude;
  625. this._workerName = 'createEllipseGeometry';
  626. this._rectangle = computeRectangle(this._center, this._ellipsoid, semiMajorAxis, semiMinorAxis, this._rotation);
  627. }
  628. /**
  629. * The number of elements used to pack the object into an array.
  630. * @type {Number}
  631. */
  632. EllipseGeometry.packedLength = Cartesian3.packedLength + Ellipsoid.packedLength + VertexFormat.packedLength + Rectangle.packedLength + 8;
  633. /**
  634. * Stores the provided instance into the provided array.
  635. *
  636. * @param {EllipseGeometry} value The value to pack.
  637. * @param {Number[]} array The array to pack into.
  638. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  639. *
  640. * @returns {Number[]} The array that was packed into
  641. */
  642. EllipseGeometry.pack = function(value, array, startingIndex) {
  643. //>>includeStart('debug', pragmas.debug);
  644. if (!defined(value)) {
  645. throw new DeveloperError('value is required');
  646. }
  647. if (!defined(array)) {
  648. throw new DeveloperError('array is required');
  649. }
  650. //>>includeEnd('debug');
  651. startingIndex = defaultValue(startingIndex, 0);
  652. Cartesian3.pack(value._center, array, startingIndex);
  653. startingIndex += Cartesian3.packedLength;
  654. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  655. startingIndex += Ellipsoid.packedLength;
  656. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  657. startingIndex += VertexFormat.packedLength;
  658. Rectangle.pack(value._rectangle, array, startingIndex);
  659. startingIndex += Rectangle.packedLength;
  660. array[startingIndex++] = value._semiMajorAxis;
  661. array[startingIndex++] = value._semiMinorAxis;
  662. array[startingIndex++] = value._rotation;
  663. array[startingIndex++] = value._stRotation;
  664. array[startingIndex++] = value._height;
  665. array[startingIndex++] = value._granularity;
  666. array[startingIndex++] = value._extrudedHeight;
  667. array[startingIndex] = value._extrude ? 1.0 : 0.0;
  668. return array;
  669. };
  670. var scratchCenter = new Cartesian3();
  671. var scratchEllipsoid = new Ellipsoid();
  672. var scratchVertexFormat = new VertexFormat();
  673. var scratchRectangle = new Rectangle();
  674. var scratchOptions = {
  675. center : scratchCenter,
  676. ellipsoid : scratchEllipsoid,
  677. vertexFormat : scratchVertexFormat,
  678. semiMajorAxis : undefined,
  679. semiMinorAxis : undefined,
  680. rotation : undefined,
  681. stRotation : undefined,
  682. height : undefined,
  683. granularity : undefined,
  684. extrudedHeight : undefined
  685. };
  686. /**
  687. * Retrieves an instance from a packed array.
  688. *
  689. * @param {Number[]} array The packed array.
  690. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  691. * @param {EllipseGeometry} [result] The object into which to store the result.
  692. * @returns {EllipseGeometry} The modified result parameter or a new EllipseGeometry instance if one was not provided.
  693. */
  694. EllipseGeometry.unpack = function(array, startingIndex, result) {
  695. //>>includeStart('debug', pragmas.debug);
  696. if (!defined(array)) {
  697. throw new DeveloperError('array is required');
  698. }
  699. //>>includeEnd('debug');
  700. startingIndex = defaultValue(startingIndex, 0);
  701. var center = Cartesian3.unpack(array, startingIndex, scratchCenter);
  702. startingIndex += Cartesian3.packedLength;
  703. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  704. startingIndex += Ellipsoid.packedLength;
  705. var vertexFormat = VertexFormat.unpack(array, startingIndex, scratchVertexFormat);
  706. startingIndex += VertexFormat.packedLength;
  707. var rectangle = Rectangle.unpack(array, startingIndex, scratchRectangle);
  708. startingIndex += Rectangle.packedLength;
  709. var semiMajorAxis = array[startingIndex++];
  710. var semiMinorAxis = array[startingIndex++];
  711. var rotation = array[startingIndex++];
  712. var stRotation = array[startingIndex++];
  713. var height = array[startingIndex++];
  714. var granularity = array[startingIndex++];
  715. var extrudedHeight = array[startingIndex++];
  716. var extrude = array[startingIndex] === 1.0;
  717. if (!defined(result)) {
  718. scratchOptions.height = height;
  719. scratchOptions.extrudedHeight = extrudedHeight;
  720. scratchOptions.granularity = granularity;
  721. scratchOptions.stRotation = stRotation;
  722. scratchOptions.rotation = rotation;
  723. scratchOptions.semiMajorAxis = semiMajorAxis;
  724. scratchOptions.semiMinorAxis = semiMinorAxis;
  725. return new EllipseGeometry(scratchOptions);
  726. }
  727. result._center = Cartesian3.clone(center, result._center);
  728. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  729. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  730. result._semiMajorAxis = semiMajorAxis;
  731. result._semiMinorAxis = semiMinorAxis;
  732. result._rotation = rotation;
  733. result._stRotation = stRotation;
  734. result._height = height;
  735. result._granularity = granularity;
  736. result._extrudedHeight = extrudedHeight;
  737. result._extrude = extrude;
  738. result._rectangle = Rectangle.clone(rectangle);
  739. return result;
  740. };
  741. /**
  742. * Computes the geometric representation of a ellipse on an ellipsoid, including its vertices, indices, and a bounding sphere.
  743. *
  744. * @param {EllipseGeometry} ellipseGeometry A description of the ellipse.
  745. * @returns {Geometry|undefined} The computed vertices and indices.
  746. */
  747. EllipseGeometry.createGeometry = function(ellipseGeometry) {
  748. if ((ellipseGeometry._semiMajorAxis <= 0.0) || (ellipseGeometry._semiMinorAxis <= 0.0)) {
  749. return;
  750. }
  751. ellipseGeometry._center = ellipseGeometry._ellipsoid.scaleToGeodeticSurface(ellipseGeometry._center, ellipseGeometry._center);
  752. var options = {
  753. center : ellipseGeometry._center,
  754. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  755. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  756. ellipsoid : ellipseGeometry._ellipsoid,
  757. rotation : ellipseGeometry._rotation,
  758. height : ellipseGeometry._height,
  759. extrudedHeight : ellipseGeometry._extrudedHeight,
  760. granularity : ellipseGeometry._granularity,
  761. vertexFormat : ellipseGeometry._vertexFormat,
  762. stRotation : ellipseGeometry._stRotation
  763. };
  764. var geometry;
  765. if (ellipseGeometry._extrude) {
  766. options.extrudedHeight = Math.min(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  767. options.height = Math.max(ellipseGeometry._extrudedHeight, ellipseGeometry._height);
  768. geometry = computeExtrudedEllipse(options);
  769. } else {
  770. geometry = computeEllipse(options);
  771. }
  772. return new Geometry({
  773. attributes : geometry.attributes,
  774. indices : geometry.indices,
  775. primitiveType : PrimitiveType.TRIANGLES,
  776. boundingSphere : geometry.boundingSphere
  777. });
  778. };
  779. /**
  780. * @private
  781. */
  782. EllipseGeometry.createShadowVolume = function(ellipseGeometry, minHeightFunc, maxHeightFunc) {
  783. var granularity = ellipseGeometry._granularity;
  784. var ellipsoid = ellipseGeometry._ellipsoid;
  785. var minHeight = minHeightFunc(granularity, ellipsoid);
  786. var maxHeight = maxHeightFunc(granularity, ellipsoid);
  787. return new EllipseGeometry({
  788. center : ellipseGeometry._center,
  789. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  790. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  791. ellipsoid : ellipsoid,
  792. rotation : ellipseGeometry._rotation,
  793. stRotation : ellipseGeometry._stRotation,
  794. granularity : granularity,
  795. extrudedHeight : minHeight,
  796. height : maxHeight,
  797. vertexFormat : VertexFormat.POSITION_ONLY
  798. });
  799. };
  800. defineProperties(EllipseGeometry.prototype, {
  801. /**
  802. * @private
  803. */
  804. rectangle : {
  805. get : function() {
  806. return this._rectangle;
  807. }
  808. }
  809. });
  810. return EllipseGeometry;
  811. });