GeologyClipPlan.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /* 引入Cesium */
  2. // import * as Cesium from 'Cesium';
  3. /**
  4. * 剖切
  5. */
  6. class GeologyClipPlan {
  7. /**
  8. * 默认初始化
  9. * @param {Object} viewer 三维场景
  10. */
  11. constructor(viewer) {
  12. if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
  13. this._viewer = viewer;
  14. this._camera = this._viewer.camera;
  15. this._scene = this._viewer.scene;
  16. this.tileset = undefined;
  17. this.targetY = 0.0;
  18. this.planeEntities = [];
  19. this._mouseHandler();
  20. }
  21. /**
  22. * @ignore 忽略注释,注释不生成Doc
  23. */
  24. _mouseHandler() {
  25. let _self = this;
  26. let viewer = _self._viewer;
  27. let scene = _self._scene;
  28. let selectedPlane;
  29. let downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  30. // 监听鼠标按下时,选择平面并设置样式
  31. downHandler.setInputAction(function(movement) {
  32. let pickedObject = scene.pick(movement.position);
  33. if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && Cesium.defined(pickedObject.id.plane)) {
  34. // 获取选中平面对象
  35. selectedPlane = pickedObject.id.plane;
  36. // 选中时修改平面的材质透明度
  37. selectedPlane.material = Cesium.Color.RED.withAlpha(0.05);
  38. selectedPlane.outlineColor = Cesium.Color.RED;
  39. // 当鼠标选中平面后,禁止场景的拖拽
  40. scene.screenSpaceCameraController.enableInputs = false;
  41. }
  42. }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
  43. // 监听鼠标向上释放时,平面设置样式
  44. let upHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  45. upHandler.setInputAction(function() {
  46. if (Cesium.defined(selectedPlane)) {
  47. // 鼠标松开时复原平面的材质透明度
  48. selectedPlane.material = Cesium.Color.RED.withAlpha(0.1);
  49. selectedPlane.outlineColor = Cesium.Color.RED;
  50. selectedPlane = undefined;
  51. }
  52. // 当鼠标松开选中平面后,开启场景的拖拽
  53. scene.screenSpaceCameraController.enableInputs = true;
  54. }, Cesium.ScreenSpaceEventType.LEFT_UP);
  55. // 监听鼠标选中移动时,设置平面
  56. let moveHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  57. moveHandler.setInputAction(function(movement) {
  58. //当存在选中平面时执行
  59. if (Cesium.defined(selectedPlane)) {
  60. // 移动起点的高度减去移动终点的高度
  61. let deltaY = movement.startPosition.y - movement.endPosition.y;
  62. // 目标高度
  63. _self.targetY += deltaY;
  64. }
  65. }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  66. }
  67. /**
  68. * 修改平面的高度
  69. * @ignore 忽略注释,注释不生成Doc
  70. */
  71. _createPlaneUpdateFunction(plane) {
  72. let _self = this;
  73. return function() {
  74. plane.distance = _self.targetY;
  75. return plane;
  76. };
  77. }
  78. }
  79. /**
  80. * 通用对外公开函数
  81. */
  82. Object.assign(GeologyClipPlan.prototype, /** @lends GeologyClipPlan.prototype */ {
  83. /**
  84. * @param {Object} tileset
  85. * @param {Object} options
  86. */
  87. activate(tileset, options) {
  88. let _self = this;
  89. options = options || {};
  90. let viewer = _self._viewer;
  91. // 创建裁剪平面
  92. let distance = 100000; //从原点到平面的最短距离。距离的符号决定了原点在平面的哪一边。如果距离为正,原点在法线方向的半空间中;如果是负的,原点在与法线相对的半空间中;如果为零,平面穿过原点。
  93. // 定义一个ClippingPlaneCollection类,用来存储裁剪面
  94. let clippingPlanes = new Cesium.ClippingPlaneCollection({
  95. // modelMatrix: Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, -500, Math.abs(2))),
  96. // modelMatrix: Cesium.Matrix4.IDENTITY,
  97. //一组ClippingPlane对象,用于选择性地禁用每个平面外部的渲染。
  98. planes: [ // ClippingPlane对象数组集合
  99. // 裁剪面两个参数的:第一个为平面法向量,第二个为原点到平面的垂直距离
  100. new Cesium.ClippingPlane( // 裁切面
  101. //笛卡尔3:表示为三维空间的平面的法向量,x表示为该法向量在x轴上的分量,y表示为该法向量在y轴上的分量,z表示为该法向量在z轴上的分量
  102. new Cesium.Cartesian3(0.0, 0.0, -1.0), // 法线
  103. // new Cesium.Cartesian3(1, 0, 0),
  104. // new Cesium.Cartesian3(0.0, 1.0, 0),
  105. distance, //原点到平面的最短距离,设置0就好
  106. ),
  107. ],
  108. //应用于裁剪对象的边缘的高光的宽度(以像素为单位)
  109. edgeWidth: 1.0, //模型被裁切部分的截面线宽
  110. });
  111. _self.tileset = tileset;
  112. tileset.clippingPlanes = clippingPlanes; //切割面
  113. tileset.debugShowBoundingVolume = false; //打开包围卷
  114. // tileset.modelMatrix = Cesium.Matrix4.fromArray(
  115. // [0.9972458032561666, 0.04372029028528979, 0.05991113506964879, 0,
  116. // -0.03623787897545647, 0.9920229449104262, -0.12073646051879428, 0,
  117. // -0.06471185374661931, 0.11823287609043515, 0.9908750491338749, 0,
  118. // -663.0794944260269, 1211.490494620055, 2974.1003134818748, 1
  119. // ]);
  120. // 当模型准备好时执行
  121. return tileset.readyPromise
  122. .then(function() {
  123. let boundingSphere = tileset.boundingSphere; //外包球
  124. let radius = boundingSphere.radius; //外包球半径
  125. if (
  126. !Cesium.Matrix4.equals( // Cesium.Matrix4.equals(a,b)判断两个四维矩阵是否相等
  127. tileset.root.transform, // 整个根节点模型矩阵,该tileSet=>世界坐标系
  128. Cesium.Matrix4.IDENTITY // 单位矩阵,对角线值为1.0的4*4矩阵
  129. )
  130. ) {
  131. // The clipping plane is initially positioned at the tileset's root transform.
  132. // Apply an additional matrix to center the clipping plane on the bounding sphere center.
  133. // 获取模型的世界坐标(笛卡尔)
  134. // Cesium.Matrix4.getTranslation 通过仿射变换矩阵获取该tileSet的世界坐标
  135. const transformCenter = Cesium.Matrix4.getTranslation(
  136. tileset.root.transform,
  137. new Cesium.Cartesian3()
  138. );
  139. // 将笛卡尔坐标转换为WGS84经纬度坐标(模型的)
  140. const transformCartographic = Cesium.Cartographic.fromCartesian(
  141. transformCenter
  142. );
  143. // 将笛卡尔坐标转换为WGS84经纬度坐标(截面的)
  144. const boundingSphereCartographic = Cesium.Cartographic.fromCartesian(
  145. tileset.boundingSphere.center
  146. );
  147. const height = boundingSphereCartographic.height - transformCartographic.height;
  148. // 从一个Cartesian3对象生成Matrix4变换矩阵(裁切面的)
  149. clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, 0.0, height));
  150. }
  151. //中心点
  152. // let entity = viewer.entities.add({
  153. // position: Cartesian33,
  154. // point: {
  155. // pixelSize: 10,
  156. // color: new Cesium.Color.fromCssColorString("red"),
  157. // outlineColor: new Cesium.Color.fromCssColorString("blue"),
  158. // outlineWidth: 2,
  159. // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //指定高度相对于什么的属性。
  160. // disableDepthTestDistance: Number.POSITIVE_INFINITY, //指定距离相机的距离,在这个距离上禁用深度测试。
  161. // }
  162. // });
  163. // 定位到模型,并设置相机的俯仰角和距离
  164. viewer.zoomTo(
  165. tileset,
  166. new Cesium.HeadingPitchRange(0.5, -0.2, radius / 10)
  167. );
  168. // Cesium.Matrix4.multiplyByPoint(tileset.root.transform, boundingSphere.center, new Cesium.Cartesian3(0, 0, 0))
  169. // clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0.0, radius/10, 0));
  170. // const redPlane = viewer.entities.add({
  171. // name: "Red plane with black outline",
  172. // position:Cartesian33,
  173. // plane: {
  174. // plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Y, 0.0),
  175. // dimensions: new Cesium.Cartesian2(200.0, 200.0),
  176. // material: Cesium.Color.RED.withAlpha(0.5),
  177. // outline: true,
  178. // outlineColor: Cesium.Color.BLACK,
  179. // },
  180. // });
  181. // const outlineOnly = viewer.entities.add({
  182. // name: "Yellow plane outline",
  183. // position: Cartesian33,
  184. // plane: {
  185. // plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Z, 0.0),
  186. // dimensions: new Cesium.Cartesian2(200.0, 200.0),
  187. // fill: false,
  188. // outline: true,
  189. // outlineColor: Cesium.Color.YELLOW,
  190. // },
  191. // });
  192. let cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
  193. //将弧度转为度的十进制度表示
  194. let lng = Cesium.Math.toDegrees(cartographic.longitude);
  195. let lat = Cesium.Math.toDegrees(cartographic.latitude);
  196. let alt = cartographic.height; //模型高度
  197. var Cartesian33 = Cesium.Cartesian3.fromDegrees(lng, lat, 105)
  198. // 遍历添加裁切面模型
  199. for (let i = 0; i < clippingPlanes.length; ++i) {
  200. let plane = clippingPlanes.get(i);
  201. let planeEntity = viewer.entities.add({
  202. // 笛卡儿坐标系的原点位置为模型外接圆的圆心
  203. position: Cartesian33,
  204. plane: {
  205. // 范围
  206. dimensions: new Cesium.Cartesian2(
  207. radius / 10,
  208. radius / 20
  209. ),
  210. // dimensions: new Cesium.Cartesian2(
  211. // 200,
  212. // 200
  213. // ),
  214. //设置材质透明度
  215. material: Cesium.Color.RED.withAlpha(0.1),
  216. //使用回调函数,动态改变模型位置
  217. plane: new Cesium.CallbackProperty(
  218. _self._createPlaneUpdateFunction(plane),
  219. false
  220. ),
  221. // 轮廓
  222. outline: true,
  223. //轮廓颜色
  224. outlineColor: Cesium.Color.RED,
  225. },
  226. });
  227. _self.planeEntities.push(planeEntity);
  228. }
  229. return tileset;
  230. })
  231. },
  232. /**
  233. * 移除裁切面
  234. */
  235. toggleClipping() {
  236. let _self = this;
  237. // // if (_self.isShowTileSet) {
  238. // _self.tileset._clippingPlanes = null;
  239. // // _self.isShowTileSet = false;
  240. // // } else {
  241. // // _self.tileset._clippingPlanes = _self.clippingPlanes;
  242. // // _self.isShowTileSet = true;
  243. // // }
  244. for (let i = 0; i < _self.planeEntities.length; i++) {
  245. _self._viewer.entities.remove(_self.planeEntities[i]);
  246. }
  247. _self.planeEntities = [];
  248. _self.targetY = 0.0;
  249. let boundingSphere = _self.tileset.boundingSphere;
  250. _self._camera.viewBoundingSphere(boundingSphere, new Cesium.HeadingPitchRange(Cesium.Math.toRadians(120.0), Cesium.Math.toRadians(-10), boundingSphere.radius * 2.5))
  251. _self._camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
  252. },
  253. // Track and create the bindings for the view model
  254. reset() {
  255. // viewer.entities.removeAll();
  256. // viewer.scene.primitives.remove(tileset);
  257. this.planeEntities = [];
  258. this.targetY = 0.0;
  259. // tileset = undefined;
  260. }
  261. });
  262. export default GeologyClipPlan;