CoplanarPolygonGeometry.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. import arrayRemoveDuplicates from "./arrayRemoveDuplicates.js";
  2. import BoundingRectangle from "./BoundingRectangle.js";
  3. import BoundingSphere from "./BoundingSphere.js";
  4. import Cartesian2 from "./Cartesian2.js";
  5. import Cartesian3 from "./Cartesian3.js";
  6. import Check from "./Check.js";
  7. import ComponentDatatype from "./ComponentDatatype.js";
  8. import CoplanarPolygonGeometryLibrary from "./CoplanarPolygonGeometryLibrary.js";
  9. import defaultValue from "./defaultValue.js";
  10. import defined from "./defined.js";
  11. import Ellipsoid from "./Ellipsoid.js";
  12. import Geometry from "./Geometry.js";
  13. import GeometryAttribute from "./GeometryAttribute.js";
  14. import GeometryAttributes from "./GeometryAttributes.js";
  15. import GeometryInstance from "./GeometryInstance.js";
  16. import GeometryPipeline from "./GeometryPipeline.js";
  17. import IndexDatatype from "./IndexDatatype.js";
  18. import CesiumMath from "./Math.js";
  19. import Matrix3 from "./Matrix3.js";
  20. import PolygonGeometryLibrary from "./PolygonGeometryLibrary.js";
  21. import PolygonPipeline from "./PolygonPipeline.js";
  22. import PrimitiveType from "./PrimitiveType.js";
  23. import Quaternion from "./Quaternion.js";
  24. import VertexFormat from "./VertexFormat.js";
  25. var scratchPosition = new Cartesian3();
  26. var scratchBR = new BoundingRectangle();
  27. var stScratch = new Cartesian2();
  28. var textureCoordinatesOrigin = new Cartesian2();
  29. var scratchNormal = new Cartesian3();
  30. var scratchTangent = new Cartesian3();
  31. var scratchBitangent = new Cartesian3();
  32. var centerScratch = new Cartesian3();
  33. var axis1Scratch = new Cartesian3();
  34. var axis2Scratch = new Cartesian3();
  35. var quaternionScratch = new Quaternion();
  36. var textureMatrixScratch = new Matrix3();
  37. var tangentRotationScratch = new Matrix3();
  38. var surfaceNormalScratch = new Cartesian3();
  39. function createGeometryFromPolygon(
  40. polygon,
  41. vertexFormat,
  42. boundingRectangle,
  43. stRotation,
  44. projectPointTo2D,
  45. normal,
  46. tangent,
  47. bitangent
  48. ) {
  49. var positions = polygon.positions;
  50. var indices = PolygonPipeline.triangulate(polygon.positions2D, polygon.holes);
  51. /* If polygon is completely unrenderable, just use the first three vertices */
  52. if (indices.length < 3) {
  53. indices = [0, 1, 2];
  54. }
  55. var newIndices = IndexDatatype.createTypedArray(
  56. positions.length,
  57. indices.length
  58. );
  59. newIndices.set(indices);
  60. var textureMatrix = textureMatrixScratch;
  61. if (stRotation !== 0.0) {
  62. var rotation = Quaternion.fromAxisAngle(
  63. normal,
  64. stRotation,
  65. quaternionScratch
  66. );
  67. textureMatrix = Matrix3.fromQuaternion(rotation, textureMatrix);
  68. if (vertexFormat.tangent || vertexFormat.bitangent) {
  69. rotation = Quaternion.fromAxisAngle(
  70. normal,
  71. -stRotation,
  72. quaternionScratch
  73. );
  74. var tangentRotation = Matrix3.fromQuaternion(
  75. rotation,
  76. tangentRotationScratch
  77. );
  78. tangent = Cartesian3.normalize(
  79. Matrix3.multiplyByVector(tangentRotation, tangent, tangent),
  80. tangent
  81. );
  82. if (vertexFormat.bitangent) {
  83. bitangent = Cartesian3.normalize(
  84. Cartesian3.cross(normal, tangent, bitangent),
  85. bitangent
  86. );
  87. }
  88. }
  89. } else {
  90. textureMatrix = Matrix3.clone(Matrix3.IDENTITY, textureMatrix);
  91. }
  92. var stOrigin = textureCoordinatesOrigin;
  93. if (vertexFormat.st) {
  94. stOrigin.x = boundingRectangle.x;
  95. stOrigin.y = boundingRectangle.y;
  96. }
  97. var length = positions.length;
  98. var size = length * 3;
  99. var flatPositions = new Float64Array(size);
  100. var normals = vertexFormat.normal ? new Float32Array(size) : undefined;
  101. var tangents = vertexFormat.tangent ? new Float32Array(size) : undefined;
  102. var bitangents = vertexFormat.bitangent ? new Float32Array(size) : undefined;
  103. var textureCoordinates = vertexFormat.st
  104. ? new Float32Array(length * 2)
  105. : undefined;
  106. var positionIndex = 0;
  107. var normalIndex = 0;
  108. var bitangentIndex = 0;
  109. var tangentIndex = 0;
  110. var stIndex = 0;
  111. for (var i = 0; i < length; i++) {
  112. var position = positions[i];
  113. flatPositions[positionIndex++] = position.x;
  114. flatPositions[positionIndex++] = position.y;
  115. flatPositions[positionIndex++] = position.z;
  116. if (vertexFormat.st) {
  117. var p = Matrix3.multiplyByVector(
  118. textureMatrix,
  119. position,
  120. scratchPosition
  121. );
  122. var st = projectPointTo2D(p, stScratch);
  123. Cartesian2.subtract(st, stOrigin, st);
  124. var stx = CesiumMath.clamp(st.x / boundingRectangle.width, 0, 1);
  125. var sty = CesiumMath.clamp(st.y / boundingRectangle.height, 0, 1);
  126. textureCoordinates[stIndex++] = stx;
  127. textureCoordinates[stIndex++] = sty;
  128. }
  129. if (vertexFormat.normal) {
  130. normals[normalIndex++] = normal.x;
  131. normals[normalIndex++] = normal.y;
  132. normals[normalIndex++] = normal.z;
  133. }
  134. if (vertexFormat.tangent) {
  135. tangents[tangentIndex++] = tangent.x;
  136. tangents[tangentIndex++] = tangent.y;
  137. tangents[tangentIndex++] = tangent.z;
  138. }
  139. if (vertexFormat.bitangent) {
  140. bitangents[bitangentIndex++] = bitangent.x;
  141. bitangents[bitangentIndex++] = bitangent.y;
  142. bitangents[bitangentIndex++] = bitangent.z;
  143. }
  144. }
  145. var attributes = new GeometryAttributes();
  146. if (vertexFormat.position) {
  147. attributes.position = new GeometryAttribute({
  148. componentDatatype: ComponentDatatype.DOUBLE,
  149. componentsPerAttribute: 3,
  150. values: flatPositions,
  151. });
  152. }
  153. if (vertexFormat.normal) {
  154. attributes.normal = new GeometryAttribute({
  155. componentDatatype: ComponentDatatype.FLOAT,
  156. componentsPerAttribute: 3,
  157. values: normals,
  158. });
  159. }
  160. if (vertexFormat.tangent) {
  161. attributes.tangent = new GeometryAttribute({
  162. componentDatatype: ComponentDatatype.FLOAT,
  163. componentsPerAttribute: 3,
  164. values: tangents,
  165. });
  166. }
  167. if (vertexFormat.bitangent) {
  168. attributes.bitangent = new GeometryAttribute({
  169. componentDatatype: ComponentDatatype.FLOAT,
  170. componentsPerAttribute: 3,
  171. values: bitangents,
  172. });
  173. }
  174. if (vertexFormat.st) {
  175. attributes.st = new GeometryAttribute({
  176. componentDatatype: ComponentDatatype.FLOAT,
  177. componentsPerAttribute: 2,
  178. values: textureCoordinates,
  179. });
  180. }
  181. return new Geometry({
  182. attributes: attributes,
  183. indices: newIndices,
  184. primitiveType: PrimitiveType.TRIANGLES,
  185. });
  186. }
  187. /**
  188. * A description of a polygon composed of arbitrary coplanar positions.
  189. *
  190. * @alias CoplanarPolygonGeometry
  191. * @constructor
  192. *
  193. * @param {Object} options Object with the following properties:
  194. * @param {PolygonHierarchy} options.polygonHierarchy A polygon hierarchy that can include holes.
  195. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  196. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  197. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  198. *
  199. * @example
  200. * var polygon = new Cesium.CoplanarPolygonGeometry({
  201. * positions : Cesium.Cartesian3.fromDegreesArrayHeights([
  202. * -90.0, 30.0, 0.0,
  203. * -90.0, 30.0, 1000.0,
  204. * -80.0, 30.0, 1000.0,
  205. * -80.0, 30.0, 0.0
  206. * ])
  207. * });
  208. * var geometry = Cesium.CoplanarPolygonGeometry.createGeometry(polygon);
  209. *
  210. * @see CoplanarPolygonGeometry.createGeometry
  211. */
  212. function CoplanarPolygonGeometry(options) {
  213. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  214. var polygonHierarchy = options.polygonHierarchy;
  215. //>>includeStart('debug', pragmas.debug);
  216. Check.defined("options.polygonHierarchy", polygonHierarchy);
  217. //>>includeEnd('debug');
  218. var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT);
  219. this._vertexFormat = VertexFormat.clone(vertexFormat);
  220. this._polygonHierarchy = polygonHierarchy;
  221. this._stRotation = defaultValue(options.stRotation, 0.0);
  222. this._ellipsoid = Ellipsoid.clone(
  223. defaultValue(options.ellipsoid, Ellipsoid.WGS84)
  224. );
  225. this._workerName = "createCoplanarPolygonGeometry";
  226. /**
  227. * The number of elements used to pack the object into an array.
  228. * @type {Number}
  229. */
  230. this.packedLength =
  231. PolygonGeometryLibrary.computeHierarchyPackedLength(polygonHierarchy) +
  232. VertexFormat.packedLength +
  233. Ellipsoid.packedLength +
  234. 2;
  235. }
  236. /**
  237. * A description of a coplanar polygon from an array of positions.
  238. *
  239. * @param {Object} options Object with the following properties:
  240. * @param {Cartesian3[]} options.positions An array of positions that defined the corner points of the polygon.
  241. * @param {VertexFormat} [options.vertexFormat=VertexFormat.DEFAULT] The vertex attributes to be computed.
  242. * @param {Number} [options.stRotation=0.0] The rotation of the texture coordinates, in radians. A positive rotation is counter-clockwise.
  243. * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
  244. * @returns {CoplanarPolygonGeometry}
  245. *
  246. * @example
  247. * // create a polygon from points
  248. * var polygon = Cesium.CoplanarPolygonGeometry.fromPositions({
  249. * positions : Cesium.Cartesian3.fromDegreesArray([
  250. * -72.0, 40.0,
  251. * -70.0, 35.0,
  252. * -75.0, 30.0,
  253. * -70.0, 30.0,
  254. * -68.0, 40.0
  255. * ])
  256. * });
  257. * var geometry = Cesium.PolygonGeometry.createGeometry(polygon);
  258. *
  259. * @see PolygonGeometry#createGeometry
  260. */
  261. CoplanarPolygonGeometry.fromPositions = function (options) {
  262. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  263. //>>includeStart('debug', pragmas.debug);
  264. Check.defined("options.positions", options.positions);
  265. //>>includeEnd('debug');
  266. var newOptions = {
  267. polygonHierarchy: {
  268. positions: options.positions,
  269. },
  270. vertexFormat: options.vertexFormat,
  271. stRotation: options.stRotation,
  272. ellipsoid: options.ellipsoid,
  273. };
  274. return new CoplanarPolygonGeometry(newOptions);
  275. };
  276. /**
  277. * Stores the provided instance into the provided array.
  278. *
  279. * @param {CoplanarPolygonGeometry} value The value to pack.
  280. * @param {Number[]} array The array to pack into.
  281. * @param {Number} [startingIndex=0] The index into the array at which to start packing the elements.
  282. *
  283. * @returns {Number[]} The array that was packed into
  284. */
  285. CoplanarPolygonGeometry.pack = function (value, array, startingIndex) {
  286. //>>includeStart('debug', pragmas.debug);
  287. Check.typeOf.object("value", value);
  288. Check.defined("array", array);
  289. //>>includeEnd('debug');
  290. startingIndex = defaultValue(startingIndex, 0);
  291. startingIndex = PolygonGeometryLibrary.packPolygonHierarchy(
  292. value._polygonHierarchy,
  293. array,
  294. startingIndex
  295. );
  296. Ellipsoid.pack(value._ellipsoid, array, startingIndex);
  297. startingIndex += Ellipsoid.packedLength;
  298. VertexFormat.pack(value._vertexFormat, array, startingIndex);
  299. startingIndex += VertexFormat.packedLength;
  300. array[startingIndex++] = value._stRotation;
  301. array[startingIndex] = value.packedLength;
  302. return array;
  303. };
  304. var scratchEllipsoid = Ellipsoid.clone(Ellipsoid.UNIT_SPHERE);
  305. var scratchVertexFormat = new VertexFormat();
  306. var scratchOptions = {
  307. polygonHierarchy: {},
  308. };
  309. /**
  310. * Retrieves an instance from a packed array.
  311. *
  312. * @param {Number[]} array The packed array.
  313. * @param {Number} [startingIndex=0] The starting index of the element to be unpacked.
  314. * @param {CoplanarPolygonGeometry} [result] The object into which to store the result.
  315. * @returns {CoplanarPolygonGeometry} The modified result parameter or a new CoplanarPolygonGeometry instance if one was not provided.
  316. */
  317. CoplanarPolygonGeometry.unpack = function (array, startingIndex, result) {
  318. //>>includeStart('debug', pragmas.debug);
  319. Check.defined("array", array);
  320. //>>includeEnd('debug');
  321. startingIndex = defaultValue(startingIndex, 0);
  322. var polygonHierarchy = PolygonGeometryLibrary.unpackPolygonHierarchy(
  323. array,
  324. startingIndex
  325. );
  326. startingIndex = polygonHierarchy.startingIndex;
  327. delete polygonHierarchy.startingIndex;
  328. var ellipsoid = Ellipsoid.unpack(array, startingIndex, scratchEllipsoid);
  329. startingIndex += Ellipsoid.packedLength;
  330. var vertexFormat = VertexFormat.unpack(
  331. array,
  332. startingIndex,
  333. scratchVertexFormat
  334. );
  335. startingIndex += VertexFormat.packedLength;
  336. var stRotation = array[startingIndex++];
  337. var packedLength = array[startingIndex];
  338. if (!defined(result)) {
  339. result = new CoplanarPolygonGeometry(scratchOptions);
  340. }
  341. result._polygonHierarchy = polygonHierarchy;
  342. result._ellipsoid = Ellipsoid.clone(ellipsoid, result._ellipsoid);
  343. result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat);
  344. result._stRotation = stRotation;
  345. result.packedLength = packedLength;
  346. return result;
  347. };
  348. /**
  349. * Computes the geometric representation of an arbitrary coplanar polygon, including its vertices, indices, and a bounding sphere.
  350. *
  351. * @param {CoplanarPolygonGeometry} polygonGeometry A description of the polygon.
  352. * @returns {Geometry|undefined} The computed vertices and indices.
  353. */
  354. CoplanarPolygonGeometry.createGeometry = function (polygonGeometry) {
  355. var vertexFormat = polygonGeometry._vertexFormat;
  356. var polygonHierarchy = polygonGeometry._polygonHierarchy;
  357. var stRotation = polygonGeometry._stRotation;
  358. var outerPositions = polygonHierarchy.positions;
  359. outerPositions = arrayRemoveDuplicates(
  360. outerPositions,
  361. Cartesian3.equalsEpsilon,
  362. true
  363. );
  364. if (outerPositions.length < 3) {
  365. return;
  366. }
  367. var normal = scratchNormal;
  368. var tangent = scratchTangent;
  369. var bitangent = scratchBitangent;
  370. var axis1 = axis1Scratch;
  371. var axis2 = axis2Scratch;
  372. var validGeometry = CoplanarPolygonGeometryLibrary.computeProjectTo2DArguments(
  373. outerPositions,
  374. centerScratch,
  375. axis1,
  376. axis2
  377. );
  378. if (!validGeometry) {
  379. return undefined;
  380. }
  381. normal = Cartesian3.cross(axis1, axis2, normal);
  382. normal = Cartesian3.normalize(normal, normal);
  383. if (
  384. !Cartesian3.equalsEpsilon(
  385. centerScratch,
  386. Cartesian3.ZERO,
  387. CesiumMath.EPSILON6
  388. )
  389. ) {
  390. var surfaceNormal = polygonGeometry._ellipsoid.geodeticSurfaceNormal(
  391. centerScratch,
  392. surfaceNormalScratch
  393. );
  394. if (Cartesian3.dot(normal, surfaceNormal) < 0) {
  395. normal = Cartesian3.negate(normal, normal);
  396. axis1 = Cartesian3.negate(axis1, axis1);
  397. }
  398. }
  399. var projectPoints = CoplanarPolygonGeometryLibrary.createProjectPointsTo2DFunction(
  400. centerScratch,
  401. axis1,
  402. axis2
  403. );
  404. var projectPoint = CoplanarPolygonGeometryLibrary.createProjectPointTo2DFunction(
  405. centerScratch,
  406. axis1,
  407. axis2
  408. );
  409. if (vertexFormat.tangent) {
  410. tangent = Cartesian3.clone(axis1, tangent);
  411. }
  412. if (vertexFormat.bitangent) {
  413. bitangent = Cartesian3.clone(axis2, bitangent);
  414. }
  415. var results = PolygonGeometryLibrary.polygonsFromHierarchy(
  416. polygonHierarchy,
  417. projectPoints,
  418. false
  419. );
  420. var hierarchy = results.hierarchy;
  421. var polygons = results.polygons;
  422. if (hierarchy.length === 0) {
  423. return;
  424. }
  425. outerPositions = hierarchy[0].outerRing;
  426. var boundingSphere = BoundingSphere.fromPoints(outerPositions);
  427. var boundingRectangle = PolygonGeometryLibrary.computeBoundingRectangle(
  428. normal,
  429. projectPoint,
  430. outerPositions,
  431. stRotation,
  432. scratchBR
  433. );
  434. var geometries = [];
  435. for (var i = 0; i < polygons.length; i++) {
  436. var geometryInstance = new GeometryInstance({
  437. geometry: createGeometryFromPolygon(
  438. polygons[i],
  439. vertexFormat,
  440. boundingRectangle,
  441. stRotation,
  442. projectPoint,
  443. normal,
  444. tangent,
  445. bitangent
  446. ),
  447. });
  448. geometries.push(geometryInstance);
  449. }
  450. var geometry = GeometryPipeline.combineInstances(geometries)[0];
  451. geometry.attributes.position.values = new Float64Array(
  452. geometry.attributes.position.values
  453. );
  454. geometry.indices = IndexDatatype.createTypedArray(
  455. geometry.attributes.position.values.length / 3,
  456. geometry.indices
  457. );
  458. var attributes = geometry.attributes;
  459. if (!vertexFormat.position) {
  460. delete attributes.position;
  461. }
  462. return new Geometry({
  463. attributes: attributes,
  464. indices: geometry.indices,
  465. primitiveType: geometry.primitiveType,
  466. boundingSphere: boundingSphere,
  467. });
  468. };
  469. export default CoplanarPolygonGeometry;