createRectangleOutlineGeometry.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /**
  2. * Cesium - https://github.com/AnalyticalGraphicsInc/cesium
  3. *
  4. * Copyright 2011-2017 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/AnalyticalGraphicsInc/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['./when-8d13db60', './Check-70bec281', './Math-61ede240', './Cartographic-fe4be337', './Cartesian2-85064f09', './BoundingSphere-775c5788', './Cartesian4-5af5bb24', './RuntimeError-ba10bc3e', './WebGLConstants-4c11ee5f', './ComponentDatatype-5862616f', './GeometryAttribute-91704ebb', './PrimitiveType-97893bc7', './FeatureDetection-7bd32c34', './Transforms-b2e71640', './buildModuleUrl-14bfe498', './GeometryAttributes-aacecde6', './IndexDatatype-9435b55f', './GeometryOffsetAttribute-ca302482', './EllipsoidRhumbLine-f161e674', './earcut-2.2.1-b404d9e6', './PolygonPipeline-6a35d737', './RectangleGeometryLibrary-fc273e18'], function (when, Check, _Math, Cartographic, Cartesian2, BoundingSphere, Cartesian4, RuntimeError, WebGLConstants, ComponentDatatype, GeometryAttribute, PrimitiveType, FeatureDetection, Transforms, buildModuleUrl, GeometryAttributes, IndexDatatype, GeometryOffsetAttribute, EllipsoidRhumbLine, earcut2_2_1, PolygonPipeline, RectangleGeometryLibrary) { 'use strict';
  24. var bottomBoundingSphere = new BoundingSphere.BoundingSphere();
  25. var topBoundingSphere = new BoundingSphere.BoundingSphere();
  26. var positionScratch = new Cartographic.Cartesian3();
  27. var rectangleScratch = new Cartesian2.Rectangle();
  28. function constructRectangle(geometry, computedOptions) {
  29. var ellipsoid = geometry._ellipsoid;
  30. var height = computedOptions.height;
  31. var width = computedOptions.width;
  32. var northCap = computedOptions.northCap;
  33. var southCap = computedOptions.southCap;
  34. var rowHeight = height;
  35. var widthMultiplier = 2;
  36. var size = 0;
  37. var corners = 4;
  38. if (northCap) {
  39. widthMultiplier -= 1;
  40. rowHeight -= 1;
  41. size += 1;
  42. corners -= 2;
  43. }
  44. if (southCap) {
  45. widthMultiplier -= 1;
  46. rowHeight -= 1;
  47. size += 1;
  48. corners -= 2;
  49. }
  50. size += (widthMultiplier * width + 2 * rowHeight - corners);
  51. var positions = new Float64Array(size * 3);
  52. var posIndex = 0;
  53. var row = 0;
  54. var col;
  55. var position = positionScratch;
  56. if (northCap) {
  57. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(computedOptions, ellipsoid, false, row, 0, position);
  58. positions[posIndex++] = position.x;
  59. positions[posIndex++] = position.y;
  60. positions[posIndex++] = position.z;
  61. } else {
  62. for (col = 0; col < width; col++) {
  63. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(computedOptions, ellipsoid, false, row, col, position);
  64. positions[posIndex++] = position.x;
  65. positions[posIndex++] = position.y;
  66. positions[posIndex++] = position.z;
  67. }
  68. }
  69. col = width - 1;
  70. for (row = 1; row < height; row++) {
  71. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(computedOptions, ellipsoid, false, row, col, position);
  72. positions[posIndex++] = position.x;
  73. positions[posIndex++] = position.y;
  74. positions[posIndex++] = position.z;
  75. }
  76. row = height - 1;
  77. if (!southCap) { // if southCap is true, we dont need to add any more points because the south pole point was added by the iteration above
  78. for (col = width - 2; col >= 0; col--) {
  79. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(computedOptions, ellipsoid, false, row, col, position);
  80. positions[posIndex++] = position.x;
  81. positions[posIndex++] = position.y;
  82. positions[posIndex++] = position.z;
  83. }
  84. }
  85. col = 0;
  86. for (row = height - 2; row > 0; row--) {
  87. RectangleGeometryLibrary.RectangleGeometryLibrary.computePosition(computedOptions, ellipsoid, false, row, col, position);
  88. positions[posIndex++] = position.x;
  89. positions[posIndex++] = position.y;
  90. positions[posIndex++] = position.z;
  91. }
  92. var indicesSize = positions.length / 3 * 2;
  93. var indices = IndexDatatype.IndexDatatype.createTypedArray(positions.length / 3, indicesSize);
  94. var index = 0;
  95. for (var i = 0; i < (positions.length / 3) - 1; i++) {
  96. indices[index++] = i;
  97. indices[index++] = i + 1;
  98. }
  99. indices[index++] = (positions.length / 3) - 1;
  100. indices[index++] = 0;
  101. var geo = new GeometryAttribute.Geometry({
  102. attributes : new GeometryAttributes.GeometryAttributes(),
  103. primitiveType : PrimitiveType.PrimitiveType.LINES
  104. });
  105. geo.attributes.position = new GeometryAttribute.GeometryAttribute({
  106. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  107. componentsPerAttribute : 3,
  108. values : positions
  109. });
  110. geo.indices = indices;
  111. return geo;
  112. }
  113. function constructExtrudedRectangle(rectangleGeometry, computedOptions) {
  114. var surfaceHeight = rectangleGeometry._surfaceHeight;
  115. var extrudedHeight = rectangleGeometry._extrudedHeight;
  116. var ellipsoid = rectangleGeometry._ellipsoid;
  117. var minHeight = extrudedHeight;
  118. var maxHeight = surfaceHeight;
  119. var geo = constructRectangle(rectangleGeometry, computedOptions);
  120. var height = computedOptions.height;
  121. var width = computedOptions.width;
  122. var topPositions = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(geo.attributes.position.values, maxHeight, ellipsoid, false);
  123. var length = topPositions.length;
  124. var positions = new Float64Array(length * 2);
  125. positions.set(topPositions);
  126. var bottomPositions = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(geo.attributes.position.values, minHeight, ellipsoid);
  127. positions.set(bottomPositions, length);
  128. geo.attributes.position.values = positions;
  129. var northCap = computedOptions.northCap;
  130. var southCap = computedOptions.southCap;
  131. var corners = 4;
  132. if (northCap) {
  133. corners -= 1;
  134. }
  135. if (southCap) {
  136. corners -= 1;
  137. }
  138. var indicesSize = (positions.length / 3 + corners) * 2;
  139. var indices = IndexDatatype.IndexDatatype.createTypedArray(positions.length / 3, indicesSize);
  140. length = positions.length / 6;
  141. var index = 0;
  142. for (var i = 0; i < length - 1; i++) {
  143. indices[index++] = i;
  144. indices[index++] = i + 1;
  145. indices[index++] = i + length;
  146. indices[index++] = i + length + 1;
  147. }
  148. indices[index++] = length - 1;
  149. indices[index++] = 0;
  150. indices[index++] = length + length - 1;
  151. indices[index++] = length;
  152. indices[index++] = 0;
  153. indices[index++] = length;
  154. var bottomCorner;
  155. if (northCap) {
  156. bottomCorner = height - 1;
  157. } else {
  158. var topRightCorner = width - 1;
  159. indices[index++] = topRightCorner;
  160. indices[index++] = topRightCorner + length;
  161. bottomCorner = width + height - 2;
  162. }
  163. indices[index++] = bottomCorner;
  164. indices[index++] = bottomCorner + length;
  165. if (!southCap) {
  166. var bottomLeftCorner = width + bottomCorner - 1;
  167. indices[index++] = bottomLeftCorner;
  168. indices[index] = bottomLeftCorner + length;
  169. }
  170. geo.indices = indices;
  171. return geo;
  172. }
  173. /**
  174. * A description of the outline of a a cartographic rectangle on an ellipsoid centered at the origin.
  175. *
  176. * @alias RectangleOutlineGeometry
  177. * @constructor
  178. *
  179. * @param {Object} options Object with the following properties:
  180. * @param {Rectangle} options.rectangle A cartographic rectangle with north, south, east and west properties in radians.
  181. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the rectangle lies.
  182. * @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.
  183. * @param {Number} [options.height=0.0] The distance in meters between the rectangle and the ellipsoid surface.
  184. * @param {Number} [options.rotation=0.0] The rotation of the rectangle, in radians. A positive rotation is counter-clockwise.
  185. * @param {Number} [options.extrudedHeight] The distance in meters between the rectangle's extruded face and the ellipsoid surface.
  186. *
  187. * @exception {DeveloperError} <code>options.rectangle.north</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  188. * @exception {DeveloperError} <code>options.rectangle.south</code> must be in the interval [<code>-Pi/2</code>, <code>Pi/2</code>].
  189. * @exception {DeveloperError} <code>options.rectangle.east</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  190. * @exception {DeveloperError} <code>options.rectangle.west</code> must be in the interval [<code>-Pi</code>, <code>Pi</code>].
  191. * @exception {DeveloperError} <code>options.rectangle.north</code> must be greater than <code>rectangle.south</code>.
  192. *
  193. * @see RectangleOutlineGeometry#createGeometry
  194. *
  195. * @example
  196. * var rectangle = new Cesium.RectangleOutlineGeometry({
  197. * ellipsoid : Cesium.Ellipsoid.WGS84,
  198. * rectangle : Cesium.Rectangle.fromDegrees(-80.0, 39.0, -74.0, 42.0),
  199. * height : 10000.0
  200. * });
  201. * var geometry = Cesium.RectangleOutlineGeometry.createGeometry(rectangle);
  202. */
  203. function RectangleOutlineGeometry(options) {
  204. options = when.defaultValue(options, when.defaultValue.EMPTY_OBJECT);
  205. var rectangle = options.rectangle;
  206. var granularity = when.defaultValue(options.granularity, _Math.CesiumMath.RADIANS_PER_DEGREE);
  207. var ellipsoid = when.defaultValue(options.ellipsoid, Cartesian2.Ellipsoid.WGS84);
  208. var rotation = when.defaultValue(options.rotation, 0.0);
  209. //>>includeStart('debug', pragmas.debug);
  210. if (!when.defined(rectangle)) {
  211. throw new Check.DeveloperError('rectangle is required.');
  212. }
  213. Cartesian2.Rectangle.validate(rectangle);
  214. if (rectangle.north < rectangle.south) {
  215. throw new Check.DeveloperError('options.rectangle.north must be greater than options.rectangle.south');
  216. }
  217. //>>includeEnd('debug');
  218. var height = when.defaultValue(options.height, 0.0);
  219. var extrudedHeight = when.defaultValue(options.extrudedHeight, height);
  220. this._rectangle = Cartesian2.Rectangle.clone(rectangle);
  221. this._granularity = granularity;
  222. this._ellipsoid = ellipsoid;
  223. this._surfaceHeight = Math.max(height, extrudedHeight);
  224. this._rotation = rotation;
  225. this._extrudedHeight = Math.min(height, extrudedHeight);
  226. this._offsetAttribute = options.offsetAttribute;
  227. this._workerName = 'createRectangleOutlineGeometry';
  228. }
  229. /**
  230. * The number of elements used to pack the object into an array.
  231. * @type {Number}
  232. */
  233. RectangleOutlineGeometry.packedLength = Cartesian2.Rectangle.packedLength + Cartesian2.Ellipsoid.packedLength + 5;
  234. /**
  235. * Stores the provided instance into the provided array.
  236. *
  237. * @param {RectangleOutlineGeometry} value The value to pack.
  238. * @param {Number[]} array The array to pack into.
  239. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  240. *
  241. * @returns {Number[]} The array that was packed into
  242. */
  243. RectangleOutlineGeometry.pack = function(value, array, startingIndex) {
  244. //>>includeStart('debug', pragmas.debug);
  245. if (!when.defined(value)) {
  246. throw new Check.DeveloperError('value is required');
  247. }
  248. if (!when.defined(array)) {
  249. throw new Check.DeveloperError('array is required');
  250. }
  251. //>>includeEnd('debug');
  252. startingIndex = when.defaultValue(startingIndex, 0);
  253. Cartesian2.Rectangle.pack(value._rectangle, array, startingIndex);
  254. startingIndex += Cartesian2.Rectangle.packedLength;
  255. Cartesian2.Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  256. startingIndex += Cartesian2.Ellipsoid.packedLength;
  257. array[startingIndex++] = value._granularity;
  258. array[startingIndex++] = value._surfaceHeight;
  259. array[startingIndex++] = value._rotation;
  260. array[startingIndex++] = value._extrudedHeight;
  261. array[startingIndex] = when.defaultValue(value._offsetAttribute, -1);
  262. return array;
  263. };
  264. var scratchRectangle = new Cartesian2.Rectangle();
  265. var scratchEllipsoid = Cartesian2.Ellipsoid.clone(Cartesian2.Ellipsoid.UNIT_SPHERE);
  266. var scratchOptions = {
  267. rectangle : scratchRectangle,
  268. ellipsoid : scratchEllipsoid,
  269. granularity : undefined,
  270. height : undefined,
  271. rotation : undefined,
  272. extrudedHeight : undefined,
  273. offsetAttribute : undefined
  274. };
  275. /**
  276. * Retrieves an instance from a packed array.
  277. *
  278. * @param {Number[]} array The packed array.
  279. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  280. * @param {RectangleOutlineGeometry} [result] The object into which to store the result.
  281. * @returns {RectangleOutlineGeometry} The modified result parameter or a new Quaternion instance if one was not provided.
  282. */
  283. RectangleOutlineGeometry.unpack = function(array, startingIndex, result) {
  284. //>>includeStart('debug', pragmas.debug);
  285. if (!when.defined(array)) {
  286. throw new Check.DeveloperError('array is required');
  287. }
  288. //>>includeEnd('debug');
  289. startingIndex = when.defaultValue(startingIndex, 0);
  290. var rectangle = Cartesian2.Rectangle.unpack(array, startingIndex, scratchRectangle);
  291. startingIndex += Cartesian2.Rectangle.packedLength;
  292. var ellipsoid = Cartesian2.Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  293. startingIndex += Cartesian2.Ellipsoid.packedLength;
  294. var granularity = array[startingIndex++];
  295. var height = array[startingIndex++];
  296. var rotation = array[startingIndex++];
  297. var extrudedHeight = array[startingIndex++];
  298. var offsetAttribute = array[startingIndex];
  299. if (!when.defined(result)) {
  300. scratchOptions.granularity = granularity;
  301. scratchOptions.height = height;
  302. scratchOptions.rotation = rotation;
  303. scratchOptions.extrudedHeight = extrudedHeight;
  304. scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute;
  305. return new RectangleOutlineGeometry(scratchOptions);
  306. }
  307. result._rectangle = Cartesian2.Rectangle.clone(rectangle, result._rectangle);
  308. result._ellipsoid = Cartesian2.Ellipsoid.clone(ellipsoid, result._ellipsoid);
  309. result._surfaceHeight = height;
  310. result._rotation = rotation;
  311. result._extrudedHeight = extrudedHeight;
  312. result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute;
  313. return result;
  314. };
  315. var nwScratch = new Cartographic.Cartographic();
  316. /**
  317. * Computes the geometric representation of an outline of a rectangle, including its vertices, indices, and a bounding sphere.
  318. *
  319. * @param {RectangleOutlineGeometry} rectangleGeometry A description of the rectangle outline.
  320. * @returns {Geometry|undefined} The computed vertices and indices.
  321. *
  322. * @exception {DeveloperError} Rotated rectangle is invalid.
  323. */
  324. RectangleOutlineGeometry.createGeometry = function(rectangleGeometry) {
  325. var rectangle = rectangleGeometry._rectangle;
  326. var ellipsoid = rectangleGeometry._ellipsoid;
  327. var computedOptions = RectangleGeometryLibrary.RectangleGeometryLibrary.computeOptions(rectangle, rectangleGeometry._granularity, rectangleGeometry._rotation, 0, rectangleScratch, nwScratch);
  328. var geometry;
  329. var boundingSphere;
  330. if ((_Math.CesiumMath.equalsEpsilon(rectangle.north, rectangle.south, _Math.CesiumMath.EPSILON10) ||
  331. (_Math.CesiumMath.equalsEpsilon(rectangle.east, rectangle.west, _Math.CesiumMath.EPSILON10)))) {
  332. return undefined;
  333. }
  334. var surfaceHeight = rectangleGeometry._surfaceHeight;
  335. var extrudedHeight = rectangleGeometry._extrudedHeight;
  336. var extrude = !_Math.CesiumMath.equalsEpsilon(surfaceHeight, extrudedHeight, 0, _Math.CesiumMath.EPSILON2);
  337. var offsetValue;
  338. if (extrude) {
  339. geometry = constructExtrudedRectangle(rectangleGeometry, computedOptions);
  340. if (when.defined(rectangleGeometry._offsetAttribute)) {
  341. var size = geometry.attributes.position.values.length / 3;
  342. var offsetAttribute = new Uint8Array(size);
  343. if (rectangleGeometry._offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.TOP) {
  344. offsetAttribute = GeometryOffsetAttribute.arrayFill(offsetAttribute, 1, 0, size / 2);
  345. } else {
  346. offsetValue = rectangleGeometry._offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE ? 0 : 1;
  347. offsetAttribute = GeometryOffsetAttribute.arrayFill(offsetAttribute, offsetValue);
  348. }
  349. geometry.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  350. componentDatatype : ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  351. componentsPerAttribute : 1,
  352. values : offsetAttribute
  353. });
  354. }
  355. var topBS = BoundingSphere.BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight, topBoundingSphere);
  356. var bottomBS = BoundingSphere.BoundingSphere.fromRectangle3D(rectangle, ellipsoid, extrudedHeight, bottomBoundingSphere);
  357. boundingSphere = BoundingSphere.BoundingSphere.union(topBS, bottomBS);
  358. } else {
  359. geometry = constructRectangle(rectangleGeometry, computedOptions);
  360. geometry.attributes.position.values = PolygonPipeline.PolygonPipeline.scaleToGeodeticHeight(geometry.attributes.position.values, surfaceHeight, ellipsoid, false);
  361. if (when.defined(rectangleGeometry._offsetAttribute)) {
  362. var length = geometry.attributes.position.values.length;
  363. var applyOffset = new Uint8Array(length / 3);
  364. offsetValue = rectangleGeometry._offsetAttribute === GeometryOffsetAttribute.GeometryOffsetAttribute.NONE ? 0 : 1;
  365. GeometryOffsetAttribute.arrayFill(applyOffset, offsetValue);
  366. geometry.attributes.applyOffset = new GeometryAttribute.GeometryAttribute({
  367. componentDatatype : ComponentDatatype.ComponentDatatype.UNSIGNED_BYTE,
  368. componentsPerAttribute : 1,
  369. values : applyOffset
  370. });
  371. }
  372. boundingSphere = BoundingSphere.BoundingSphere.fromRectangle3D(rectangle, ellipsoid, surfaceHeight);
  373. }
  374. return new GeometryAttribute.Geometry({
  375. attributes : geometry.attributes,
  376. indices : geometry.indices,
  377. primitiveType : PrimitiveType.PrimitiveType.LINES,
  378. boundingSphere : boundingSphere,
  379. offsetAttribute : rectangleGeometry._offsetAttribute
  380. });
  381. };
  382. function createRectangleOutlineGeometry(rectangleGeometry, offset) {
  383. if (when.defined(offset)) {
  384. rectangleGeometry = RectangleOutlineGeometry.unpack(rectangleGeometry, offset);
  385. }
  386. rectangleGeometry._ellipsoid = Cartesian2.Ellipsoid.clone(rectangleGeometry._ellipsoid);
  387. rectangleGeometry._rectangle = Cartesian2.Rectangle.clone(rectangleGeometry._rectangle);
  388. return RectangleOutlineGeometry.createGeometry(rectangleGeometry);
  389. }
  390. return createRectangleOutlineGeometry;
  391. });