PolygonPipeline-fd46002b.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /**
  2. * Cesium - https://github.com/CesiumGS/cesium
  3. *
  4. * Copyright 2011-2020 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/CesiumGS/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['exports', './when-8d13db60', './Check-70bec281', './Math-61ede240', './Cartographic-fe4be337', './Cartesian2-85064f09', './WebGLConstants-4c11ee5f', './ComponentDatatype-5862616f', './GeometryAttribute-ed9d707f', './PrimitiveType-97893bc7', './EllipsoidRhumbLine-f161e674', './earcut-2.2.1-b404d9e6'], function (exports, when, Check, _Math, Cartographic, Cartesian2, WebGLConstants, ComponentDatatype, GeometryAttribute, PrimitiveType, EllipsoidRhumbLine, earcut2_2_1) { 'use strict';
  24. /**
  25. * Winding order defines the order of vertices for a triangle to be considered front-facing.
  26. *
  27. * @exports WindingOrder
  28. */
  29. var WindingOrder = {
  30. /**
  31. * Vertices are in clockwise order.
  32. *
  33. * @type {Number}
  34. * @constant
  35. */
  36. CLOCKWISE : WebGLConstants.WebGLConstants.CW,
  37. /**
  38. * Vertices are in counter-clockwise order.
  39. *
  40. * @type {Number}
  41. * @constant
  42. */
  43. COUNTER_CLOCKWISE : WebGLConstants.WebGLConstants.CCW,
  44. /**
  45. * @private
  46. */
  47. validate : function(windingOrder) {
  48. return windingOrder === WindingOrder.CLOCKWISE ||
  49. windingOrder === WindingOrder.COUNTER_CLOCKWISE;
  50. }
  51. };
  52. var WindingOrder$1 = Object.freeze(WindingOrder);
  53. var scaleToGeodeticHeightN = new Cartographic.Cartesian3();
  54. var scaleToGeodeticHeightP = new Cartographic.Cartesian3();
  55. /**
  56. * @private
  57. */
  58. var PolygonPipeline = {};
  59. /**
  60. * @exception {DeveloperError} At least three positions are required.
  61. */
  62. PolygonPipeline.computeArea2D = function(positions) {
  63. //>>includeStart('debug', pragmas.debug);
  64. Check.Check.defined('positions', positions);
  65. Check.Check.typeOf.number.greaterThanOrEquals('positions.length', positions.length, 3);
  66. //>>includeEnd('debug');
  67. var length = positions.length;
  68. var area = 0.0;
  69. for ( var i0 = length - 1, i1 = 0; i1 < length; i0 = i1++) {
  70. var v0 = positions[i0];
  71. var v1 = positions[i1];
  72. area += (v0.x * v1.y) - (v1.x * v0.y);
  73. }
  74. return area * 0.5;
  75. };
  76. /**
  77. * @returns {WindingOrder} The winding order.
  78. *
  79. * @exception {DeveloperError} At least three positions are required.
  80. */
  81. PolygonPipeline.computeWindingOrder2D = function(positions) {
  82. var area = PolygonPipeline.computeArea2D(positions);
  83. return (area > 0.0) ? WindingOrder$1.COUNTER_CLOCKWISE : WindingOrder$1.CLOCKWISE;
  84. };
  85. /**
  86. * Triangulate a polygon.
  87. *
  88. * @param {Cartesian2[]} positions Cartesian2 array containing the vertices of the polygon
  89. * @param {Number[]} [holes] An array of the staring indices of the holes.
  90. * @returns {Number[]} Index array representing triangles that fill the polygon
  91. */
  92. PolygonPipeline.triangulate = function(positions, holes) {
  93. //>>includeStart('debug', pragmas.debug);
  94. Check.Check.defined('positions', positions);
  95. //>>includeEnd('debug');
  96. var flattenedPositions = Cartesian2.Cartesian2.packArray(positions);
  97. return earcut2_2_1.earcut(flattenedPositions, holes, 2);
  98. };
  99. var subdivisionV0Scratch = new Cartographic.Cartesian3();
  100. var subdivisionV1Scratch = new Cartographic.Cartesian3();
  101. var subdivisionV2Scratch = new Cartographic.Cartesian3();
  102. var subdivisionS0Scratch = new Cartographic.Cartesian3();
  103. var subdivisionS1Scratch = new Cartographic.Cartesian3();
  104. var subdivisionS2Scratch = new Cartographic.Cartesian3();
  105. var subdivisionMidScratch = new Cartographic.Cartesian3();
  106. /**
  107. * Subdivides positions and raises points to the surface of the ellipsoid.
  108. *
  109. * @param {Ellipsoid} ellipsoid The ellipsoid the polygon in on.
  110. * @param {Cartesian3[]} positions An array of {@link Cartesian3} positions of the polygon.
  111. * @param {Number[]} indices An array of indices that determines the triangles in the polygon.
  112. * @param {Number} [granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  113. *
  114. * @exception {DeveloperError} At least three indices are required.
  115. * @exception {DeveloperError} The number of indices must be divisable by three.
  116. * @exception {DeveloperError} Granularity must be greater than zero.
  117. */
  118. PolygonPipeline.computeSubdivision = function(ellipsoid, positions, indices, granularity, hasHeight) {
  119. hasHeight = when.defaultValue(hasHeight, false);
  120. granularity = when.defaultValue(granularity, _Math.CesiumMath.RADIANS_PER_DEGREE);
  121. //>>includeStart('debug', pragmas.debug);
  122. Check.Check.typeOf.object('ellipsoid', ellipsoid);
  123. Check.Check.defined('positions', positions);
  124. Check.Check.defined('indices', indices);
  125. Check.Check.typeOf.number.greaterThanOrEquals('indices.length', indices.length, 3);
  126. Check.Check.typeOf.number.equals('indices.length % 3', '0', indices.length % 3, 0);
  127. Check.Check.typeOf.number.greaterThan('granularity', granularity, 0.0);
  128. //>>includeEnd('debug');
  129. // triangles that need (or might need) to be subdivided.
  130. var triangles = indices.slice(0);
  131. // New positions due to edge splits are appended to the positions list.
  132. var i;
  133. var length = positions.length;
  134. var subdividedPositions = new Array(length * 3);
  135. var q = 0;
  136. for (i = 0; i < length; i++) {
  137. var item = positions[i];
  138. subdividedPositions[q++] = item.x;
  139. subdividedPositions[q++] = item.y;
  140. subdividedPositions[q++] = item.z;
  141. }
  142. var subdividedIndices = [];
  143. // Used to make sure shared edges are not split more than once.
  144. var edges = {};
  145. var radius = ellipsoid.maximumRadius;
  146. var minDistance = _Math.CesiumMath.chordLength(granularity, radius);
  147. var minDistanceSqrd = minDistance * minDistance;
  148. while (triangles.length > 0) {
  149. var i2 = triangles.pop();
  150. var i1 = triangles.pop();
  151. var i0 = triangles.pop();
  152. var v0 = Cartographic.Cartesian3.fromArray(subdividedPositions, i0 * 3, subdivisionV0Scratch);
  153. var v1 = Cartographic.Cartesian3.fromArray(subdividedPositions, i1 * 3, subdivisionV1Scratch);
  154. var v2 = Cartographic.Cartesian3.fromArray(subdividedPositions, i2 * 3, subdivisionV2Scratch);
  155. var s0 = hasHeight ? v0 : Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.normalize(v0, subdivisionS0Scratch), radius, subdivisionS0Scratch);
  156. var s1 = hasHeight ? v1 : Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.normalize(v1, subdivisionS1Scratch), radius, subdivisionS1Scratch);
  157. var s2 = hasHeight ? v2 : Cartographic.Cartesian3.multiplyByScalar(Cartographic.Cartesian3.normalize(v2, subdivisionS2Scratch), radius, subdivisionS2Scratch);
  158. var g0 = Cartographic.Cartesian3.magnitudeSquared(Cartographic.Cartesian3.subtract(s0, s1, subdivisionMidScratch));
  159. var g1 = Cartographic.Cartesian3.magnitudeSquared(Cartographic.Cartesian3.subtract(s1, s2, subdivisionMidScratch));
  160. var g2 = Cartographic.Cartesian3.magnitudeSquared(Cartographic.Cartesian3.subtract(s2, s0, subdivisionMidScratch));
  161. var max = Math.max(g0, g1, g2);
  162. var edge;
  163. var mid;
  164. // if the max length squared of a triangle edge is greater than the chord length of squared
  165. // of the granularity, subdivide the triangle
  166. if (max > minDistanceSqrd) {
  167. if (g0 === max) {
  168. edge = Math.min(i0, i1) + ' ' + Math.max(i0, i1);
  169. i = edges[edge];
  170. if (!when.defined(i)) {
  171. mid = Cartographic.Cartesian3.add(v0, v1, subdivisionMidScratch);
  172. Cartographic.Cartesian3.multiplyByScalar(mid, 0.5, mid);
  173. subdividedPositions.push(mid.x, mid.y, mid.z);
  174. i = subdividedPositions.length / 3 - 1;
  175. edges[edge] = i;
  176. }
  177. triangles.push(i0, i, i2);
  178. triangles.push(i, i1, i2);
  179. } else if (g1 === max) {
  180. edge = Math.min(i1, i2) + ' ' + Math.max(i1, i2);
  181. i = edges[edge];
  182. if (!when.defined(i)) {
  183. mid = Cartographic.Cartesian3.add(v1, v2, subdivisionMidScratch);
  184. Cartographic.Cartesian3.multiplyByScalar(mid, 0.5, mid);
  185. subdividedPositions.push(mid.x, mid.y, mid.z);
  186. i = subdividedPositions.length / 3 - 1;
  187. edges[edge] = i;
  188. }
  189. triangles.push(i1, i, i0);
  190. triangles.push(i, i2, i0);
  191. } else if (g2 === max) {
  192. edge = Math.min(i2, i0) + ' ' + Math.max(i2, i0);
  193. i = edges[edge];
  194. if (!when.defined(i)) {
  195. mid = Cartographic.Cartesian3.add(v2, v0, subdivisionMidScratch);
  196. Cartographic.Cartesian3.multiplyByScalar(mid, 0.5, mid);
  197. subdividedPositions.push(mid.x, mid.y, mid.z);
  198. i = subdividedPositions.length / 3 - 1;
  199. edges[edge] = i;
  200. }
  201. triangles.push(i2, i, i1);
  202. triangles.push(i, i0, i1);
  203. }
  204. } else {
  205. subdividedIndices.push(i0);
  206. subdividedIndices.push(i1);
  207. subdividedIndices.push(i2);
  208. }
  209. }
  210. return new GeometryAttribute.Geometry({
  211. attributes : {
  212. position : new GeometryAttribute.GeometryAttribute({
  213. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  214. componentsPerAttribute : 3,
  215. values : subdividedPositions
  216. })
  217. },
  218. indices : subdividedIndices,
  219. primitiveType : PrimitiveType.PrimitiveType.TRIANGLES
  220. });
  221. };
  222. var subdivisionC0Scratch = new Cartographic.Cartographic();
  223. var subdivisionC1Scratch = new Cartographic.Cartographic();
  224. var subdivisionC2Scratch = new Cartographic.Cartographic();
  225. var subdivisionCartographicScratch = new Cartographic.Cartographic();
  226. /**
  227. * Subdivides positions on rhumb lines and raises points to the surface of the ellipsoid.
  228. *
  229. * @param {Ellipsoid} ellipsoid The ellipsoid the polygon in on.
  230. * @param {Cartesian3[]} positions An array of {@link Cartesian3} positions of the polygon.
  231. * @param {Number[]} indices An array of indices that determines the triangles in the polygon.
  232. * @param {Number} [granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
  233. *
  234. * @exception {DeveloperError} At least three indices are required.
  235. * @exception {DeveloperError} The number of indices must be divisable by three.
  236. * @exception {DeveloperError} Granularity must be greater than zero.
  237. */
  238. PolygonPipeline.computeRhumbLineSubdivision = function(ellipsoid, positions, indices, granularity) {
  239. granularity = when.defaultValue(granularity, _Math.CesiumMath.RADIANS_PER_DEGREE);
  240. //>>includeStart('debug', pragmas.debug);
  241. Check.Check.typeOf.object('ellipsoid', ellipsoid);
  242. Check.Check.defined('positions', positions);
  243. Check.Check.defined('indices', indices);
  244. Check.Check.typeOf.number.greaterThanOrEquals('indices.length', indices.length, 3);
  245. Check.Check.typeOf.number.equals('indices.length % 3', '0', indices.length % 3, 0);
  246. Check.Check.typeOf.number.greaterThan('granularity', granularity, 0.0);
  247. //>>includeEnd('debug');
  248. // triangles that need (or might need) to be subdivided.
  249. var triangles = indices.slice(0);
  250. // New positions due to edge splits are appended to the positions list.
  251. var i;
  252. var length = positions.length;
  253. var subdividedPositions = new Array(length * 3);
  254. var q = 0;
  255. for (i = 0; i < length; i++) {
  256. var item = positions[i];
  257. subdividedPositions[q++] = item.x;
  258. subdividedPositions[q++] = item.y;
  259. subdividedPositions[q++] = item.z;
  260. }
  261. var subdividedIndices = [];
  262. // Used to make sure shared edges are not split more than once.
  263. var edges = {};
  264. var radius = ellipsoid.maximumRadius;
  265. var minDistance = _Math.CesiumMath.chordLength(granularity, radius);
  266. var rhumb0 = new EllipsoidRhumbLine.EllipsoidRhumbLine(undefined, undefined, ellipsoid);
  267. var rhumb1 = new EllipsoidRhumbLine.EllipsoidRhumbLine(undefined, undefined, ellipsoid);
  268. var rhumb2 = new EllipsoidRhumbLine.EllipsoidRhumbLine(undefined, undefined, ellipsoid);
  269. while (triangles.length > 0) {
  270. var i2 = triangles.pop();
  271. var i1 = triangles.pop();
  272. var i0 = triangles.pop();
  273. var v0 = Cartographic.Cartesian3.fromArray(subdividedPositions, i0 * 3, subdivisionV0Scratch);
  274. var v1 = Cartographic.Cartesian3.fromArray(subdividedPositions, i1 * 3, subdivisionV1Scratch);
  275. var v2 = Cartographic.Cartesian3.fromArray(subdividedPositions, i2 * 3, subdivisionV2Scratch);
  276. var c0 = ellipsoid.cartesianToCartographic(v0, subdivisionC0Scratch);
  277. var c1 = ellipsoid.cartesianToCartographic(v1, subdivisionC1Scratch);
  278. var c2 = ellipsoid.cartesianToCartographic(v2, subdivisionC2Scratch);
  279. rhumb0.setEndPoints(c0, c1);
  280. var g0 = rhumb0.surfaceDistance;
  281. rhumb1.setEndPoints(c1, c2);
  282. var g1 = rhumb1.surfaceDistance;
  283. rhumb2.setEndPoints(c2, c0);
  284. var g2 = rhumb2.surfaceDistance;
  285. var max = Math.max(g0, g1, g2);
  286. var edge;
  287. var mid;
  288. var midHeight;
  289. var midCartesian3;
  290. // if the max length squared of a triangle edge is greater than granularity, subdivide the triangle
  291. if (max > minDistance) {
  292. if (g0 === max) {
  293. edge = Math.min(i0, i1) + ' ' + Math.max(i0, i1);
  294. i = edges[edge];
  295. if (!when.defined(i)) {
  296. mid = rhumb0.interpolateUsingFraction(0.5, subdivisionCartographicScratch);
  297. midHeight = (c0.height + c1.height) * 0.5;
  298. midCartesian3 = Cartographic.Cartesian3.fromRadians(mid.longitude, mid.latitude, midHeight, ellipsoid, subdivisionMidScratch);
  299. subdividedPositions.push(midCartesian3.x, midCartesian3.y, midCartesian3.z);
  300. i = subdividedPositions.length / 3 - 1;
  301. edges[edge] = i;
  302. }
  303. triangles.push(i0, i, i2);
  304. triangles.push(i, i1, i2);
  305. } else if (g1 === max) {
  306. edge = Math.min(i1, i2) + ' ' + Math.max(i1, i2);
  307. i = edges[edge];
  308. if (!when.defined(i)) {
  309. mid = rhumb1.interpolateUsingFraction(0.5, subdivisionCartographicScratch);
  310. midHeight = (c1.height + c2.height) * 0.5;
  311. midCartesian3 = Cartographic.Cartesian3.fromRadians(mid.longitude, mid.latitude, midHeight, ellipsoid, subdivisionMidScratch);
  312. subdividedPositions.push(midCartesian3.x, midCartesian3.y, midCartesian3.z);
  313. i = subdividedPositions.length / 3 - 1;
  314. edges[edge] = i;
  315. }
  316. triangles.push(i1, i, i0);
  317. triangles.push(i, i2, i0);
  318. } else if (g2 === max) {
  319. edge = Math.min(i2, i0) + ' ' + Math.max(i2, i0);
  320. i = edges[edge];
  321. if (!when.defined(i)) {
  322. mid = rhumb2.interpolateUsingFraction(0.5, subdivisionCartographicScratch);
  323. midHeight = (c2.height + c0.height) * 0.5;
  324. midCartesian3 = Cartographic.Cartesian3.fromRadians(mid.longitude, mid.latitude, midHeight, ellipsoid, subdivisionMidScratch);
  325. subdividedPositions.push(midCartesian3.x, midCartesian3.y, midCartesian3.z);
  326. i = subdividedPositions.length / 3 - 1;
  327. edges[edge] = i;
  328. }
  329. triangles.push(i2, i, i1);
  330. triangles.push(i, i0, i1);
  331. }
  332. } else {
  333. subdividedIndices.push(i0);
  334. subdividedIndices.push(i1);
  335. subdividedIndices.push(i2);
  336. }
  337. }
  338. return new GeometryAttribute.Geometry({
  339. attributes : {
  340. position : new GeometryAttribute.GeometryAttribute({
  341. componentDatatype : ComponentDatatype.ComponentDatatype.DOUBLE,
  342. componentsPerAttribute : 3,
  343. values : subdividedPositions
  344. })
  345. },
  346. indices : subdividedIndices,
  347. primitiveType : PrimitiveType.PrimitiveType.TRIANGLES
  348. });
  349. };
  350. /**
  351. * Scales each position of a geometry's position attribute to a height, in place.
  352. *
  353. * @param {Number[]} positions The array of numbers representing the positions to be scaled
  354. * @param {Number} [height=0.0] The desired height to add to the positions
  355. * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid on which the positions lie.
  356. * @param {Boolean} [scaleToSurface=true] <code>true</code> if the positions need to be scaled to the surface before the height is added.
  357. * @returns {Number[]} The input array of positions, scaled to height
  358. */
  359. PolygonPipeline.scaleToGeodeticHeight = function(positions, height, ellipsoid, scaleToSurface) {
  360. ellipsoid = when.defaultValue(ellipsoid, Cartesian2.Ellipsoid.WGS84);
  361. var n = scaleToGeodeticHeightN;
  362. var p = scaleToGeodeticHeightP;
  363. height = when.defaultValue(height, 0.0);
  364. scaleToSurface = when.defaultValue(scaleToSurface, true);
  365. if (when.defined(positions)) {
  366. var length = positions.length;
  367. for ( var i = 0; i < length; i += 3) {
  368. Cartographic.Cartesian3.fromArray(positions, i, p);
  369. if (scaleToSurface) {
  370. p = ellipsoid.scaleToGeodeticSurface(p, p);
  371. }
  372. if (height !== 0) {
  373. n = ellipsoid.geodeticSurfaceNormal(p, n);
  374. Cartographic.Cartesian3.multiplyByScalar(n, height, n);
  375. Cartographic.Cartesian3.add(p, n, p);
  376. }
  377. positions[i] = p.x;
  378. positions[i + 1] = p.y;
  379. positions[i + 2] = p.z;
  380. }
  381. }
  382. return positions;
  383. };
  384. exports.PolygonPipeline = PolygonPipeline;
  385. exports.WindingOrder = WindingOrder$1;
  386. });