TerrainExcavation.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. //地形开挖
  2. class TerrainExcavation {
  3. constructor(viewer) {
  4. if (!viewer) throw new Error("no viewer object!");
  5. this.viewer = viewer;
  6. }
  7. //计算并更新wellData
  8. prepareWell(activePoints) {
  9. let pointLength = activePoints.length;
  10. let heightDiff = this.excavateMinHeight - this.height;
  11. let no_height_top = [],
  12. bottom_pos = [],
  13. lerp_pos = [];
  14. for (let l = 0; l < pointLength; l++) {
  15. let u = l == pointLength - 1 ? 0 : l + 1;
  16. let point0 = [
  17. Cesium.Cartographic.fromCartesian(activePoints[l]).longitude,
  18. Cesium.Cartographic.fromCartesian(activePoints[l]).latitude,
  19. ];
  20. let point1 = [
  21. Cesium.Cartographic.fromCartesian(activePoints[u]).longitude,
  22. Cesium.Cartographic.fromCartesian(activePoints[u]).latitude,
  23. ];
  24. if (0 == l) {
  25. lerp_pos.push(new Cesium.Cartographic(point0[0], point0[1]));
  26. bottom_pos.push(
  27. Cesium.Cartesian3.fromRadians(point0[0], point0[1], heightDiff)
  28. );
  29. no_height_top.push(
  30. Cesium.Cartesian3.fromRadians(point0[0], point0[1], 0)
  31. );
  32. }
  33. for (let p = 1; p <= this.splitNum; p++) {
  34. let m = Cesium.Math.lerp(point0[0], point1[0], p / this.splitNum);
  35. let g = Cesium.Math.lerp(point0[1], point1[1], p / this.splitNum);
  36. (l == pointLength - 1 && p == this.splitNum) ||
  37. (lerp_pos.push(new Cesium.Cartographic(m, g)),
  38. bottom_pos.push(Cesium.Cartesian3.fromRadians(m, g, heightDiff)),
  39. no_height_top.push(Cesium.Cartesian3.fromRadians(m, g, 0)));
  40. }
  41. }
  42. this.wellData = {
  43. lerp_pos: lerp_pos,
  44. bottom_pos: bottom_pos,
  45. no_height_top: no_height_top,
  46. };
  47. }
  48. //开始创建底面和侧面
  49. createWell(wallData) {
  50. let $this = this;
  51. if (this.viewer.terrainProvider._layers) {
  52. this.createBottomSurface(wallData.bottom_pos);
  53. let positions = Cesium.sampleTerrainMostDetailed(
  54. this.viewer.terrainProvider,
  55. wallData.lerp_pos
  56. );
  57. positions.then(function(pos) {
  58. let positionList = [];
  59. for (let index = 0; index < pos.length; index++) {
  60. const element = pos[index];
  61. let curPos = Cesium.Cartesian3.fromRadians(
  62. element.longitude,
  63. element.latitude,
  64. element.height
  65. );
  66. positionList.push(curPos);
  67. }
  68. $this.createWellWall(wallData.bottom_pos, positionList);
  69. });
  70. // Cesium.when(positions, function(pos) {
  71. // let positionList = [];
  72. // for (let index = 0; index < pos.length; index++) {
  73. // const element = pos[index];
  74. // let curPos = Cesium.Cartesian3.fromRadians(
  75. // element.longitude,
  76. // element.latitude,
  77. // element.height
  78. // );
  79. // positionList.push(curPos);
  80. // }
  81. // $this.createWellWall(wallData.bottom_pos, positionList);
  82. // });
  83. } else {
  84. this.createBottomSurface(wallData.bottom_pos);
  85. this.createWellWall(wallData.bottom_pos, wallData.no_height_top);
  86. }
  87. }
  88. //坐标转换,转出经纬度格式
  89. ellipsoidToDegree(pos) {
  90. let cartesian3 = new Cesium.Cartesian3(pos.x, pos.y, pos.z);
  91. let cartographic =
  92. this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
  93. return {
  94. longitude: Cesium.Math.toDegrees(cartographic.longitude),
  95. latitude: Cesium.Math.toDegrees(cartographic.latitude),
  96. altitude: cartographic.height,
  97. };
  98. }
  99. //创建地形开挖的底面对象
  100. createBottomSurface(points) {
  101. if (points.length) {
  102. let minHeight = this.getMinHeight(points);
  103. let positions = [];
  104. for (let i = 0; i < points.length; i++) {
  105. let curPoint = this.ellipsoidToDegree(points[i]);
  106. positions.push(curPoint.longitude, curPoint.latitude, minHeight);
  107. }
  108. let polygon = new Cesium.PolygonGeometry({
  109. polygonHierarchy: new Cesium.PolygonHierarchy(
  110. Cesium.Cartesian3.fromDegreesArrayHeights(positions)
  111. ),
  112. perPositionHeight: true,
  113. });
  114. let material = new Cesium.Material({
  115. fabric: {
  116. type: "Image",
  117. uniforms: {
  118. image: this.bottomImg,
  119. },
  120. },
  121. });
  122. let appearance = new Cesium.MaterialAppearance({
  123. translucent: false,
  124. flat: true,
  125. material: material,
  126. });
  127. this.bottomSurface = new Cesium.Primitive({
  128. geometryInstances: new Cesium.GeometryInstance({
  129. geometry: Cesium.PolygonGeometry.createGeometry(polygon),
  130. }),
  131. appearance: appearance,
  132. asynchronous: false,
  133. });
  134. this.viewer.scene.primitives.add(this.bottomSurface);
  135. }
  136. }
  137. // 创建地形开挖的侧面墙对象
  138. createWellWall(bottomPos, positionList) {
  139. let minHeight = this.getMinHeight(bottomPos);
  140. let maxHeights = [],
  141. minHeights = [];
  142. for (let i = 0; i < positionList.length; i++) {
  143. maxHeights.push(this.ellipsoidToDegree(positionList[i]).altitude);
  144. minHeights.push(minHeight);
  145. }
  146. let wall = new Cesium.WallGeometry({
  147. positions: positionList,
  148. maximumHeights: maxHeights,
  149. minimumHeights: minHeights,
  150. });
  151. let geometry = Cesium.WallGeometry.createGeometry(wall);
  152. let material = new Cesium.Material({
  153. fabric: {
  154. type: "Image",
  155. uniforms: {
  156. image: this.wallImg,
  157. },
  158. },
  159. });
  160. let appearance = new Cesium.MaterialAppearance({
  161. translucent: false,
  162. flat: true,
  163. material: material,
  164. });
  165. this.wellWall = new Cesium.Primitive({
  166. geometryInstances: new Cesium.GeometryInstance({
  167. geometry: geometry,
  168. attributes: {
  169. color: Cesium.ColorGeometryInstanceAttribute.fromColor(
  170. Cesium.Color.GREY
  171. ),
  172. },
  173. id: "PitWall",
  174. }),
  175. appearance: appearance,
  176. asynchronous: false,
  177. });
  178. this.viewer.scene.primitives.add(this.wellWall);
  179. }
  180. //获取地形开挖最低点高程值
  181. getMinHeight(points) {
  182. let minHeight = 5000000;
  183. let minPoint = null;
  184. for (let i = 0; i < points.length; i++) {
  185. let height = points[i]["z"];
  186. if (height < minHeight) {
  187. minHeight = height;
  188. minPoint = this.ellipsoidToDegree(points[i]);
  189. }
  190. }
  191. return minPoint.altitude;
  192. }
  193. switchExcavate(show) {
  194. if (show) {
  195. this.viewer.scene.globe.material = null;
  196. this.wellWall.show = true;
  197. this.bottomSurface.show = true;
  198. } else {
  199. this.viewer.scene.globe.material = null;
  200. this.wellWall.show = false;
  201. this.bottomSurface.show = false;
  202. }
  203. }
  204. updateExcavateDepth(height) {
  205. this.viewer.scene.primitives.remove(this.bottomSurface);
  206. this.viewer.scene.primitives.remove(this.wellWall);
  207. console.log(this.wellData, this.excavateMinHeight);
  208. let lerp_pos = this.wellData.lerp_pos;
  209. let posList = [];
  210. for (let n = 0; n < lerp_pos.length; n++) {
  211. posList.push(
  212. Cesium.Cartesian3.fromRadians(
  213. lerp_pos[n].longitude,
  214. lerp_pos[n].latitude,
  215. this.excavateMinHeight - height
  216. )
  217. );
  218. }
  219. this.wellData.bottom_pos = posList;
  220. this.createWell(this.wellData);
  221. }
  222. }
  223. Object.defineProperties(TerrainExcavation.prototype, {
  224. show: {
  225. get: function() {
  226. return this._show;
  227. },
  228. set: function(e) {
  229. this._show = e;
  230. this.switchExcavate(e);
  231. },
  232. },
  233. height: {
  234. get: function() {
  235. return this._height;
  236. },
  237. set: function(e) {
  238. this._height = e;
  239. this.updateExcavateDepth(e);
  240. },
  241. },
  242. });
  243. /**
  244. * 通用对外公开函数
  245. */
  246. Object.assign(TerrainExcavation.prototype, /** @lends TerrainExcavation.prototype */ {
  247. /**
  248. * @param {Object} activePoints
  249. * @param {Object} options 具有以下属性:
  250. * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层
  251. * @param {String} options.url 服务地址
  252. * @param {Number} [options.maximumScreenSpaceError=16] 用于驱动细节细化级别的最大屏幕空间误差
  253. * @return {String} 服务Id
  254. */
  255. add(activePoints, options) {
  256. options = options || {};
  257. this._height = options.excavateDepth || 10;
  258. this.bottomImg = options.bottomImg || "jt3dSDK/imgs/polygon/ground.png";
  259. this.wallImg = options.wallImg || "jt3dSDK/imgs/polygon/ground.png";
  260. this.splitNum = Cesium.defaultValue(options.splitNum, 50);
  261. activePoints = activePoints.map(point => {
  262. return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
  263. });
  264. let viewer = this.viewer;
  265. this.clear();
  266. let clippingPlanesList = [];
  267. let car3Difference = Cesium.Cartesian3.subtract(
  268. activePoints[0],
  269. activePoints[1],
  270. new Cesium.Cartesian3()
  271. ); //计算两个笛卡尔函数的分量差异
  272. let boolDiff = car3Difference.x > 0;
  273. this.excavateMinHeight = 999999999;
  274. for (let index = 0; index < activePoints.length; ++index) {
  275. let s = (index + 1) % activePoints.length;
  276. let curMidPoint = Cesium.Cartesian3.midpoint(
  277. activePoints[index],
  278. activePoints[s],
  279. new Cesium.Cartesian3()
  280. );
  281. let cartographic = Cesium.Cartographic.fromCartesian(activePoints[index]);
  282. let curHeight =
  283. viewer.scene.globe.getHeight(cartographic) || cartographic.height;
  284. console.log(curHeight);
  285. if (curHeight < this.excavateMinHeight) {
  286. this.excavateMinHeight = curHeight;
  287. }
  288. let curMidPointNormal = Cesium.Cartesian3.normalize(
  289. curMidPoint,
  290. new Cesium.Cartesian3()
  291. );
  292. let curMidPointDifference = boolDiff ?
  293. Cesium.Cartesian3.subtract(
  294. activePoints[index],
  295. curMidPoint,
  296. new Cesium.Cartesian3()
  297. ) :
  298. Cesium.Cartesian3.subtract(
  299. activePoints[s],
  300. curMidPoint,
  301. new Cesium.Cartesian3()
  302. );
  303. curMidPointDifference = Cesium.Cartesian3.normalize(
  304. curMidPointDifference,
  305. curMidPointDifference
  306. );
  307. let curMidPointCross = Cesium.Cartesian3.cross(
  308. curMidPointDifference,
  309. curMidPointNormal,
  310. new Cesium.Cartesian3()
  311. );
  312. curMidPointCross = Cesium.Cartesian3.normalize(
  313. curMidPointCross,
  314. curMidPointCross
  315. );
  316. let plane = new Cesium.Plane(curMidPointCross, 0);
  317. let distance = Cesium.Plane.getPointDistance(plane, curMidPoint);
  318. clippingPlanesList.push(
  319. new Cesium.ClippingPlane(curMidPointCross, distance)
  320. );
  321. }
  322. this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
  323. planes: clippingPlanesList,
  324. edgeWidth: 1,
  325. edgeColor: Cesium.Color.WHITE,
  326. enabled: true,
  327. });
  328. this.prepareWell(activePoints);
  329. this.createWell(this.wellData);
  330. },
  331. /**
  332. * 清除开挖
  333. */
  334. clear() {
  335. if (this.viewer.scene.globe.clippingPlanes) {
  336. this.viewer.scene.globe.clippingPlanes.removeAll();
  337. this.viewer.scene.primitives.remove(this.bottomSurface);
  338. this.viewer.scene.primitives.remove(this.wellWall);
  339. this.viewer.scene.render();
  340. }
  341. }
  342. });
  343. export default TerrainExcavation;