智慧水务管理系统 - 精河县供水工程综合管理平台

ClippingPolygon.js 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import Check from "../Core/Check.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartographic from "../Core/Cartographic.js";
  4. import defined from "../Core/defined.js";
  5. import Ellipsoid from "../Core/Ellipsoid.js";
  6. import CesiumMath from "../Core/Math.js";
  7. import PolygonGeometry from "../Core/PolygonGeometry.js";
  8. import Rectangle from "../Core/Rectangle.js";
  9. /**
  10. * A geodesic polygon to be used with {@link ClippingPlaneCollection} for selectively hiding regions in a model, a 3D tileset, or the globe.
  11. * @alias ClippingPolygon
  12. * @constructor
  13. *
  14. * @param {object} options Object with the following properties:
  15. * @param {Cartesian3[]} options.positions A list of three or more Cartesian coordinates defining the outer ring of the clipping polygon.
  16. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.default]
  17. *
  18. * @example
  19. * const positions = Cesium.Cartesian3.fromRadiansArray([
  20. * -1.3194369277314022,
  21. * 0.6988062530900625,
  22. * -1.31941,
  23. * 0.69879,
  24. * -1.3193955980204217,
  25. * 0.6988091578771254,
  26. * -1.3193931220959367,
  27. * 0.698743632490865,
  28. * -1.3194358224045408,
  29. * 0.6987471965556998,
  30. * ]);
  31. *
  32. * const polygon = new Cesium.ClippingPolygon({
  33. * positions: positions
  34. * });
  35. */
  36. function ClippingPolygon(options) {
  37. //>>includeStart('debug', pragmas.debug);
  38. Check.typeOf.object("options", options);
  39. Check.typeOf.object("options.positions", options.positions);
  40. Check.typeOf.number.greaterThanOrEquals(
  41. "options.positions.length",
  42. options.positions.length,
  43. 3,
  44. );
  45. //>>includeEnd('debug');
  46. this._ellipsoid = options.ellipsoid ?? Ellipsoid.default;
  47. this._positions = copyArrayCartesian3(options.positions);
  48. /**
  49. * A copy of the input positions.
  50. *
  51. * This is used to detect modifications of the positions in
  52. * <code>coputeRectangle</code>: The rectangle only has
  53. * to be re-computed when these positions have changed.
  54. *
  55. * @type {Cartesian3[]|undefined}
  56. * @private
  57. */
  58. this._cachedPositions = undefined;
  59. /**
  60. * A cached version of the rectangle that is computed in
  61. * <code>computeRectangle</code>.
  62. *
  63. * This is only re-computed when the positions have changed, as
  64. * determined by comparing the <code>_positions</code> to the
  65. * <code>_cachedPositions</code>
  66. *
  67. * @type {Rectangle|undefined}
  68. * @private
  69. */
  70. this._cachedRectangle = undefined;
  71. }
  72. /**
  73. * Returns a deep copy of the given array.
  74. *
  75. * If the input is undefined, then <code>undefined</code> is returned.
  76. *
  77. * Otherwise, the result will be a copy of the given array, where
  78. * each element is copied with <code>Cartesian3.clone</code>.
  79. *
  80. * @param {Cartesian3[]|undefined} input The input array
  81. * @returns {Cartesian3[]|undefined} The copy
  82. */
  83. function copyArrayCartesian3(input) {
  84. if (!defined(input)) {
  85. return undefined;
  86. }
  87. const n = input.length;
  88. const output = Array(n);
  89. for (let i = 0; i < n; i++) {
  90. output[i] = Cartesian3.clone(input[i]);
  91. }
  92. return output;
  93. }
  94. /**
  95. * Returns whether the given arrays are component-wise equal.
  96. *
  97. * When both arrays are undefined, then <code>true</code> is returned.
  98. * When only one array is defined, or they are both defined but have
  99. * different lengths, then <code>false</code> is returned.
  100. *
  101. * Otherwise, returns whether the corresponding elements of the arrays
  102. * are equal, as of <code>Cartesian3.equals</code>.
  103. *
  104. * @param {Cartesian3[]|undefined} a The first array
  105. * @param {Cartesian3[]|undefined} b The second array
  106. * @returns {boolean} Whether the arrays are equal
  107. */
  108. function equalsArrayCartesian3(a, b) {
  109. if (!defined(a) && !defined(b)) {
  110. return true;
  111. }
  112. if (defined(a) !== defined(b)) {
  113. return false;
  114. }
  115. if (a.length !== b.length) {
  116. return false;
  117. }
  118. const n = a.length;
  119. for (let i = 0; i < n; i++) {
  120. const ca = a[i];
  121. const cb = b[i];
  122. if (!Cartesian3.equals(ca, cb)) {
  123. return false;
  124. }
  125. }
  126. return true;
  127. }
  128. Object.defineProperties(ClippingPolygon.prototype, {
  129. /**
  130. * Returns the total number of positions in the polygon, include any holes.
  131. *
  132. * @memberof ClippingPolygon.prototype
  133. * @type {number}
  134. * @readonly
  135. */
  136. length: {
  137. get: function () {
  138. return this._positions.length;
  139. },
  140. },
  141. /**
  142. * Returns the outer ring of positions.
  143. *
  144. * @memberof ClippingPolygon.prototype
  145. * @type {Cartesian3[]}
  146. * @readonly
  147. */
  148. positions: {
  149. get: function () {
  150. return this._positions;
  151. },
  152. },
  153. /**
  154. * Returns the ellipsoid used to project the polygon onto surfaces when clipping.
  155. *
  156. * @memberof ClippingPolygon.prototype
  157. * @type {Ellipsoid}
  158. * @readonly
  159. */
  160. ellipsoid: {
  161. get: function () {
  162. return this._ellipsoid;
  163. },
  164. },
  165. });
  166. /**
  167. * Clones the ClippingPolygon without setting its ownership.
  168. * @param {ClippingPolygon} polygon The ClippingPolygon to be cloned
  169. * @param {ClippingPolygon} [result] The object on which to store the cloned parameters.
  170. * @returns {ClippingPolygon} a clone of the input ClippingPolygon
  171. */
  172. ClippingPolygon.clone = function (polygon, result) {
  173. //>>includeStart('debug', pragmas.debug);
  174. Check.typeOf.object("polygon", polygon);
  175. //>>includeEnd('debug');
  176. if (!defined(result)) {
  177. return new ClippingPolygon({
  178. positions: polygon.positions,
  179. ellipsoid: polygon.ellipsoid,
  180. });
  181. }
  182. result._ellipsoid = polygon.ellipsoid;
  183. result._positions.length = 0;
  184. result._positions.push(...polygon.positions);
  185. return result;
  186. };
  187. /**
  188. * Compares the provided ClippingPolygons and returns
  189. * <code>true</code> if they are equal, <code>false</code> otherwise.
  190. *
  191. * @param {ClippingPolygon} left The first polygon.
  192. * @param {ClippingPolygon} right The second polygon.
  193. * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  194. */
  195. ClippingPolygon.equals = function (left, right) {
  196. //>>includeStart('debug', pragmas.debug);
  197. Check.typeOf.object("left", left);
  198. Check.typeOf.object("right", right);
  199. //>>includeEnd('debug');
  200. return (
  201. left.ellipsoid.equals(right.ellipsoid) && left.positions === right.positions
  202. );
  203. };
  204. /**
  205. * Computes a cartographic rectangle which encloses the polygon defined by the list of positions, including cases over the international date line and the poles.
  206. *
  207. * @param {Rectangle} [result] An object in which to store the result.
  208. * @returns {Rectangle} The result rectangle
  209. */
  210. ClippingPolygon.prototype.computeRectangle = function (result) {
  211. if (equalsArrayCartesian3(this._positions, this._cachedPositions)) {
  212. return Rectangle.clone(this._cachedRectangle, result);
  213. }
  214. const rectangle = PolygonGeometry.computeRectangleFromPositions(
  215. this.positions,
  216. this.ellipsoid,
  217. undefined,
  218. result,
  219. );
  220. this._cachedPositions = copyArrayCartesian3(this._positions);
  221. this._cachedRectangle = Rectangle.clone(rectangle);
  222. return rectangle;
  223. };
  224. const scratchRectangle = new Rectangle();
  225. const spherePointScratch = new Cartesian3();
  226. /**
  227. * Computes a rectangle with the spherical extents that encloses the polygon defined by the list of positions, including cases over the international date line and the poles.
  228. *
  229. * @private
  230. *
  231. * @param {Rectangle} [result] An object in which to store the result.
  232. * @returns {Rectangle} The result rectangle with spherical extents.
  233. */
  234. ClippingPolygon.prototype.computeSphericalExtents = function (result) {
  235. if (!defined(result)) {
  236. result = new Rectangle();
  237. }
  238. const rectangle = this.computeRectangle(scratchRectangle);
  239. let spherePoint = Cartographic.toCartesian(
  240. Rectangle.southwest(rectangle),
  241. this.ellipsoid,
  242. spherePointScratch,
  243. );
  244. // Project into plane with vertical for latitude
  245. let magXY = Math.sqrt(
  246. spherePoint.x * spherePoint.x + spherePoint.y * spherePoint.y,
  247. );
  248. // Use fastApproximateAtan2 for alignment with shader
  249. let sphereLatitude = CesiumMath.fastApproximateAtan2(magXY, spherePoint.z);
  250. let sphereLongitude = CesiumMath.fastApproximateAtan2(
  251. spherePoint.x,
  252. spherePoint.y,
  253. );
  254. result.south = sphereLatitude;
  255. result.west = sphereLongitude;
  256. spherePoint = Cartographic.toCartesian(
  257. Rectangle.northeast(rectangle),
  258. this.ellipsoid,
  259. spherePointScratch,
  260. );
  261. // Project into plane with vertical for latitude
  262. magXY = Math.sqrt(
  263. spherePoint.x * spherePoint.x + spherePoint.y * spherePoint.y,
  264. );
  265. // Use fastApproximateAtan2 for alignment with shader
  266. sphereLatitude = CesiumMath.fastApproximateAtan2(magXY, spherePoint.z);
  267. sphereLongitude = CesiumMath.fastApproximateAtan2(
  268. spherePoint.x,
  269. spherePoint.y,
  270. );
  271. result.north = sphereLatitude;
  272. result.east = sphereLongitude;
  273. return result;
  274. };
  275. export default ClippingPolygon;