EllipseOutlineGeometry.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. import arrayFill from './arrayFill.js';
  2. import BoundingSphere from './BoundingSphere.js';
  3. import Cartesian3 from './Cartesian3.js';
  4. import ComponentDatatype from './ComponentDatatype.js';
  5. import defaultValue from './defaultValue.js';
  6. import defined from './defined.js';
  7. import DeveloperError from './DeveloperError.js';
  8. import EllipseGeometryLibrary from './EllipseGeometryLibrary.js';
  9. import Ellipsoid from './Ellipsoid.js';
  10. import Geometry from './Geometry.js';
  11. import GeometryAttribute from './GeometryAttribute.js';
  12. import GeometryAttributes from './GeometryAttributes.js';
  13. import GeometryOffsetAttribute from './GeometryOffsetAttribute.js';
  14. import IndexDatatype from './IndexDatatype.js';
  15. import CesiumMath from './Math.js';
  16. import PrimitiveType from './PrimitiveType.js';
  17. var scratchCartesian1 = new Cartesian3();
  18. var boundingSphereCenter = new Cartesian3();
  19. function computeEllipse(options) {
  20. var center = options.center;
  21. boundingSphereCenter = Cartesian3.multiplyByScalar(options.ellipsoid.geodeticSurfaceNormal(center, boundingSphereCenter), options.height, boundingSphereCenter);
  22. boundingSphereCenter = Cartesian3.add(center, boundingSphereCenter, boundingSphereCenter);
  23. var boundingSphere = new BoundingSphere(boundingSphereCenter, options.semiMajorAxis);
  24. var positions = EllipseGeometryLibrary.computeEllipsePositions(options, false, true).outerPositions;
  25. var attributes = new GeometryAttributes({
  26. position: new GeometryAttribute({
  27. componentDatatype : ComponentDatatype.DOUBLE,
  28. componentsPerAttribute : 3,
  29. values : EllipseGeometryLibrary.raisePositionsToHeight(positions, options, false)
  30. })
  31. });
  32. var length = positions.length / 3;
  33. var indices = IndexDatatype.createTypedArray(length, length * 2);
  34. var index = 0;
  35. for ( var i = 0; i < length; ++i) {
  36. indices[index++] = i;
  37. indices[index++] = (i + 1) % length;
  38. }
  39. return {
  40. boundingSphere : boundingSphere,
  41. attributes : attributes,
  42. indices : indices
  43. };
  44. }
  45. var topBoundingSphere = new BoundingSphere();
  46. var bottomBoundingSphere = new BoundingSphere();
  47. function computeExtrudedEllipse(options) {
  48. var center = options.center;
  49. var ellipsoid = options.ellipsoid;
  50. var semiMajorAxis = options.semiMajorAxis;
  51. var scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scratchCartesian1), options.height, scratchCartesian1);
  52. topBoundingSphere.center = Cartesian3.add(center, scaledNormal, topBoundingSphere.center);
  53. topBoundingSphere.radius = semiMajorAxis;
  54. scaledNormal = Cartesian3.multiplyByScalar(ellipsoid.geodeticSurfaceNormal(center, scaledNormal), options.extrudedHeight, scaledNormal);
  55. bottomBoundingSphere.center = Cartesian3.add(center, scaledNormal, bottomBoundingSphere.center);
  56. bottomBoundingSphere.radius = semiMajorAxis;
  57. var positions = EllipseGeometryLibrary.computeEllipsePositions(options, false, true).outerPositions;
  58. var attributes = new GeometryAttributes({
  59. position: new GeometryAttribute({
  60. componentDatatype : ComponentDatatype.DOUBLE,
  61. componentsPerAttribute : 3,
  62. values : EllipseGeometryLibrary.raisePositionsToHeight(positions, options, true)
  63. })
  64. });
  65. positions = attributes.position.values;
  66. var boundingSphere = BoundingSphere.union(topBoundingSphere, bottomBoundingSphere);
  67. var length = positions.length/3;
  68. if (defined(options.offsetAttribute)) {
  69. var applyOffset = new Uint8Array(length);
  70. if (options.offsetAttribute === GeometryOffsetAttribute.TOP) {
  71. applyOffset = arrayFill(applyOffset, 1, 0, length / 2);
  72. } else {
  73. var offsetValue = options.offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1;
  74. applyOffset = arrayFill(applyOffset, offsetValue);
  75. }
  76. attributes.applyOffset = new GeometryAttribute({
  77. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  78. componentsPerAttribute : 1,
  79. values: applyOffset
  80. });
  81. }
  82. var numberOfVerticalLines = defaultValue(options.numberOfVerticalLines, 16);
  83. numberOfVerticalLines = CesiumMath.clamp(numberOfVerticalLines, 0, length/2);
  84. var indices = IndexDatatype.createTypedArray(length, length * 2 + numberOfVerticalLines * 2);
  85. length /= 2;
  86. var index = 0;
  87. var i;
  88. for (i = 0; i < length; ++i) {
  89. indices[index++] = i;
  90. indices[index++] = (i + 1) % length;
  91. indices[index++] = i + length;
  92. indices[index++] = ((i + 1) % length) + length;
  93. }
  94. var numSide;
  95. if (numberOfVerticalLines > 0) {
  96. var numSideLines = Math.min(numberOfVerticalLines, length);
  97. numSide = Math.round(length / numSideLines);
  98. var maxI = Math.min(numSide * numberOfVerticalLines, length);
  99. for (i = 0; i < maxI; i += numSide) {
  100. indices[index++] = i;
  101. indices[index++] = i + length;
  102. }
  103. }
  104. return {
  105. boundingSphere : boundingSphere,
  106. attributes : attributes,
  107. indices : indices
  108. };
  109. }
  110. /**
  111. * A description of the outline of an ellipse on an ellipsoid.
  112. *
  113. * @alias EllipseOutlineGeometry
  114. * @constructor
  115. *
  116. * @param {Object} options Object with the following properties:
  117. * @param {Cartesian3} options.center The ellipse's center point in the fixed frame.
  118. * @param {Number} options.semiMajorAxis The length of the ellipse's semi-major axis in meters.
  119. * @param {Number} options.semiMinorAxis The length of the ellipse's semi-minor axis in meters.
  120. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid the ellipse will be on.
  121. * @param {Number} [options.height=0.0] The distance in meters between the ellipse and the ellipsoid surface.
  122. * @param {Number} [options.extrudedHeight] The distance in meters between the ellipse's extruded face and the ellipsoid surface.
  123. * @param {Number} [options.rotation=0.0] The angle from north (counter-clockwise) in radians.
  124. * @param {Number} [options.granularity=0.02] The angular distance between points on the ellipse in radians.
  125. * @param {Number} [options.numberOfVerticalLines=16] Number of lines to draw between the top and bottom surface of an extruded ellipse.
  126. *
  127. * @exception {DeveloperError} semiMajorAxis and semiMinorAxis must be greater than zero.
  128. * @exception {DeveloperError} semiMajorAxis must be greater than or equal to the semiMinorAxis.
  129. * @exception {DeveloperError} granularity must be greater than zero.
  130. *
  131. * @see EllipseOutlineGeometry.createGeometry
  132. *
  133. * @example
  134. * var ellipse = new Cesium.EllipseOutlineGeometry({
  135. * center : Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
  136. * semiMajorAxis : 500000.0,
  137. * semiMinorAxis : 300000.0,
  138. * rotation : Cesium.Math.toRadians(60.0)
  139. * });
  140. * var geometry = Cesium.EllipseOutlineGeometry.createGeometry(ellipse);
  141. */
  142. function EllipseOutlineGeometry(options) {
  143. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  144. var center = options.center;
  145. var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
  146. var semiMajorAxis = options.semiMajorAxis;
  147. var semiMinorAxis = options.semiMinorAxis;
  148. var granularity = defaultValue(options.granularity, CesiumMath.RADIANS_PER_DEGREE);
  149. //>>includeStart('debug', pragmas.debug);
  150. if (!defined(center)) {
  151. throw new DeveloperError('center is required.');
  152. }
  153. if (!defined(semiMajorAxis)) {
  154. throw new DeveloperError('semiMajorAxis is required.');
  155. }
  156. if (!defined(semiMinorAxis)) {
  157. throw new DeveloperError('semiMinorAxis is required.');
  158. }
  159. if (semiMajorAxis < semiMinorAxis) {
  160. throw new DeveloperError('semiMajorAxis must be greater than or equal to the semiMinorAxis.');
  161. }
  162. if (granularity <= 0.0) {
  163. throw new DeveloperError('granularity must be greater than zero.');
  164. }
  165. //>>includeEnd('debug');
  166. var height = defaultValue(options.height, 0.0);
  167. var extrudedHeight = defaultValue(options.extrudedHeight, height);
  168. this._center = Cartesian3.clone(center);
  169. this._semiMajorAxis = semiMajorAxis;
  170. this._semiMinorAxis = semiMinorAxis;
  171. this._ellipsoid = Ellipsoid.clone(ellipsoid);
  172. this._rotation = defaultValue(options.rotation, 0.0);
  173. this._height = Math.max(extrudedHeight, height);
  174. this._granularity = granularity;
  175. this._extrudedHeight = Math.min(extrudedHeight, height);
  176. this._numberOfVerticalLines = Math.max(defaultValue(options.numberOfVerticalLines, 16), 0);
  177. this._offsetAttribute = options.offsetAttribute;
  178. this._workerName = 'createEllipseOutlineGeometry';
  179. }
  180. /**
  181. * The number of elements used to pack the object into an array.
  182. * @type {Number}
  183. */
  184. EllipseOutlineGeometry.packedLength = Cartesian3.packedLength + Ellipsoid.packedLength + 8;
  185. /**
  186. * Stores the provided instance into the provided array.
  187. *
  188. * @param {EllipseOutlineGeometry} value The value to pack.
  189. * @param {Number[]} array The array to pack into.
  190. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  191. *
  192. * @returns {Number[]} The array that was packed into
  193. */
  194. EllipseOutlineGeometry.pack = function(value, array, startingIndex) {
  195. //>>includeStart('debug', pragmas.debug);
  196. if (!defined(value)) {
  197. throw new DeveloperError('value is required');
  198. }
  199. if (!defined(array)) {
  200. throw new DeveloperError('array is required');
  201. }
  202. //>>includeEnd('debug');
  203. startingIndex = defaultValue(startingIndex, 0);
  204. Cartesian3.pack(value._center, array, startingIndex);
  205. startingIndex += Cartesian3.packedLength;
  206. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  207. startingIndex += Ellipsoid.packedLength;
  208. array[startingIndex++] = value._semiMajorAxis;
  209. array[startingIndex++] = value._semiMinorAxis;
  210. array[startingIndex++] = value._rotation;
  211. array[startingIndex++] = value._height;
  212. array[startingIndex++] = value._granularity;
  213. array[startingIndex++] = value._extrudedHeight;
  214. array[startingIndex++] = value._numberOfVerticalLines;
  215. array[startingIndex] = defaultValue(value._offsetAttribute, -1);
  216. return array;
  217. };
  218. var scratchCenter = new Cartesian3();
  219. var scratchEllipsoid = new Ellipsoid();
  220. var scratchOptions = {
  221. center : scratchCenter,
  222. ellipsoid : scratchEllipsoid,
  223. semiMajorAxis : undefined,
  224. semiMinorAxis : undefined,
  225. rotation : undefined,
  226. height : undefined,
  227. granularity : undefined,
  228. extrudedHeight : undefined,
  229. numberOfVerticalLines : undefined,
  230. offsetAttribute: undefined
  231. };
  232. /**
  233. * Retrieves an instance from a packed array.
  234. *
  235. * @param {Number[]} array The packed array.
  236. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  237. * @param {EllipseOutlineGeometry} [result] The object into which to store the result.
  238. * @returns {EllipseOutlineGeometry} The modified result parameter or a new EllipseOutlineGeometry instance if one was not provided.
  239. */
  240. EllipseOutlineGeometry.unpack = function(array, startingIndex, result) {
  241. //>>includeStart('debug', pragmas.debug);
  242. if (!defined(array)) {
  243. throw new DeveloperError('array is required');
  244. }
  245. //>>includeEnd('debug');
  246. startingIndex = defaultValue(startingIndex, 0);
  247. var center = Cartesian3.unpack(array, startingIndex, scratchCenter);
  248. startingIndex += Cartesian3.packedLength;
  249. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  250. startingIndex += Ellipsoid.packedLength;
  251. var semiMajorAxis = array[startingIndex++];
  252. var semiMinorAxis = array[startingIndex++];
  253. var rotation = array[startingIndex++];
  254. var height = array[startingIndex++];
  255. var granularity = array[startingIndex++];
  256. var extrudedHeight = array[startingIndex++];
  257. var numberOfVerticalLines = array[startingIndex++];
  258. var offsetAttribute = array[startingIndex];
  259. if (!defined(result)) {
  260. scratchOptions.height = height;
  261. scratchOptions.extrudedHeight = extrudedHeight;
  262. scratchOptions.granularity = granularity;
  263. scratchOptions.rotation = rotation;
  264. scratchOptions.semiMajorAxis = semiMajorAxis;
  265. scratchOptions.semiMinorAxis = semiMinorAxis;
  266. scratchOptions.numberOfVerticalLines = numberOfVerticalLines;
  267. scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute;
  268. return new EllipseOutlineGeometry(scratchOptions);
  269. }
  270. result._center = Cartesian3.clone(center, result._center);
  271. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  272. result._semiMajorAxis = semiMajorAxis;
  273. result._semiMinorAxis = semiMinorAxis;
  274. result._rotation = rotation;
  275. result._height = height;
  276. result._granularity = granularity;
  277. result._extrudedHeight = extrudedHeight;
  278. result._numberOfVerticalLines = numberOfVerticalLines;
  279. result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute;
  280. return result;
  281. };
  282. /**
  283. * Computes the geometric representation of an outline of an ellipse on an ellipsoid, including its vertices, indices, and a bounding sphere.
  284. *
  285. * @param {EllipseOutlineGeometry} ellipseGeometry A description of the ellipse.
  286. * @returns {Geometry|undefined} The computed vertices and indices.
  287. */
  288. EllipseOutlineGeometry.createGeometry = function(ellipseGeometry) {
  289. if ((ellipseGeometry._semiMajorAxis <= 0.0) || (ellipseGeometry._semiMinorAxis <= 0.0)) {
  290. return;
  291. }
  292. var height = ellipseGeometry._height;
  293. var extrudedHeight = ellipseGeometry._extrudedHeight;
  294. var extrude = !CesiumMath.equalsEpsilon(height, extrudedHeight, 0, CesiumMath.EPSILON2);
  295. ellipseGeometry._center = ellipseGeometry._ellipsoid.scaleToGeodeticSurface(ellipseGeometry._center, ellipseGeometry._center);
  296. var options = {
  297. center : ellipseGeometry._center,
  298. semiMajorAxis : ellipseGeometry._semiMajorAxis,
  299. semiMinorAxis : ellipseGeometry._semiMinorAxis,
  300. ellipsoid : ellipseGeometry._ellipsoid,
  301. rotation : ellipseGeometry._rotation,
  302. height : height,
  303. granularity : ellipseGeometry._granularity,
  304. numberOfVerticalLines : ellipseGeometry._numberOfVerticalLines
  305. };
  306. var geometry;
  307. if (extrude) {
  308. options.extrudedHeight = extrudedHeight;
  309. options.offsetAttribute = ellipseGeometry._offsetAttribute;
  310. geometry = computeExtrudedEllipse(options);
  311. } else {
  312. geometry = computeEllipse(options);
  313. if (defined(ellipseGeometry._offsetAttribute)) {
  314. var length = geometry.attributes.position.values.length;
  315. var applyOffset = new Uint8Array(length / 3);
  316. var offsetValue = ellipseGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1;
  317. arrayFill(applyOffset, offsetValue);
  318. geometry.attributes.applyOffset = new GeometryAttribute({
  319. componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
  320. componentsPerAttribute : 1,
  321. values: applyOffset
  322. });
  323. }
  324. }
  325. return new Geometry({
  326. attributes : geometry.attributes,
  327. indices : geometry.indices,
  328. primitiveType : PrimitiveType.LINES,
  329. boundingSphere : geometry.boundingSphere,
  330. offsetAttribute : ellipseGeometry._offsetAttribute
  331. });
  332. };
  333. export default EllipseOutlineGeometry;