createRectangleOutlineGeometry.js 20 KB

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