上一篇學習了實體的一些基礎知識,這一篇來學習鼠標繪制實體多邊形的實現
一、方法一:
1,結果顯示
貼地:
不貼地:
2,方法全部代碼:
主方法:
/*** 繪制多邊形* @param {Object} option* @param {Boolean} option.ground 是否貼地*/ DrawPolygon(option) {var allPoints=[]// 設置返回值return new Promise((resolve, reject) => {// 1. 獲取Cesium Viewerlet viewer = this.viewer;// 2. 創建一個用于存儲多邊形頂點的數組let polygonPoints = [];// 3. 創建一個用于顯示當前繪制中的多邊形的實體let drawingPolygon = viewer.entities.add({id: "drawingPolygon",name: "畫多邊形",polygon: {hierarchy: new Cesium.CallbackProperty(() => {return new Cesium.PolygonHierarchy(polygonPoints);}, false),material: Cesium.Color.BLUE.withAlpha(0.2),perPositionHeight: (option&&option.ground)||false // true:不貼地/false:貼地},});// 4. 創建一個用于顯示當前繪制中的線的實體let drawingLine = viewer.entities.add({id: "drawingLine",name: "畫線",polyline: {positions: new Cesium.CallbackProperty(() => {return polygonPoints;}, false),width: 3,material: Cesium.Color.GREEN}});// 5. 監聽鼠標點擊事件,將點擊的點添加到頂點數組中,并添加點實體let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);handler.setInputAction(event => {var cartesian = this.getCatesian3FromPX(event.position);if (cartesian) {// 將點坐標添加到數組中polygonPoints.push(cartesian.clone());// 在第一次點擊時,添加一個克隆的點到數組中,用于動態更新if (polygonPoints.length === 1) {polygonPoints.push(cartesian.clone());}// 添加點實體viewer.entities.add({position: cartesian,point: {color: Cesium.Color.RED,pixelSize: 10}});//將三維笛卡爾坐標系點轉為經緯度坐標點,并保存到點數組中let cartesian3 = cartesian.clone()// 使用Cesium.Cartographic.fromCartesian將Cartesian3對象轉換為Cartographic對象let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);allPoints.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), cartographic.height]);}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 6. 監聽鼠標移動事件,動態更新多邊形和線的形狀handler.setInputAction(event => {var cartesian = this.getCatesian3FromPX(event.endPosition);if (polygonPoints.length >= 2) {if (cartesian && cartesian.x) {polygonPoints.pop();polygonPoints.push(cartesian);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 7. 監聽鼠標右鍵點擊事件,結束繪制handler.setInputAction(() => {var cartesian=polygonPoints[polygonPoints.length-1]// 添加點實體viewer.entities.add({position: cartesian,point: {color: Cesium.Color.RED,pixelSize: 10}});polygonPoints.push(polygonPoints[0]);handler.destroy(); // 關閉鼠標事件監聽,結束繪制resolve(allPoints);}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);})},
調用進行位置拾取和轉換的方法(此處三個方法來自測量插件):
/*** 拾取位置點* @param {Object} px 屏幕坐標* @return {Object} Cartesian3 三維坐標*/getCatesian3FromPX: function(px) {if (this.viewer && px) {var picks = this.viewer.scene.drillPick(px);var cartesian = null;var isOn3dtiles = false,isOnTerrain = false;// drillPickfor (let i in picks) {let pick = picks[i];if ((pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||(pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||(pick && pick.primitive instanceof Cesium.Model)) {//模型上拾取isOn3dtiles = true;}// 3dtilsetif (isOn3dtiles) {this.viewer.scene.pick(px); // pickcartesian = this.viewer.scene.pickPosition(px);if (cartesian) {let cartographic = Cesium.Cartographic.fromCartesian(cartesian);if (cartographic.height < 0) cartographic.height = 0;let lon = Cesium.Math.toDegrees(cartographic.longitude),lat = Cesium.Math.toDegrees(cartographic.latitude),height = cartographic.height;cartesian = this.transformWGS84ToCartesian({lng: lon,lat: lat,alt: height});}}}// 地形let boolTerrain =this.viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;// Terrainif (!isOn3dtiles && !boolTerrain) {var ray = this.viewer.scene.camera.getPickRay(px);if (!ray) return null;cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);isOnTerrain = true;}// 地球if (!isOn3dtiles && !isOnTerrain && boolTerrain) {cartesian = this.viewer.scene.camera.pickEllipsoid(px,this.viewer.scene.globe.ellipsoid);}if (cartesian) {let position = this.transformCartesianToWGS84(cartesian);if (position.alt < 0) {cartesian = this.transformWGS84ToCartesian(position, 0.1);}return cartesian;}return false;}},/**** 坐標轉換 84轉笛卡爾* @param {Object} {lng,lat,alt} 地理坐標* @return {Object} Cartesian3 三維位置坐標*/transformWGS84ToCartesian: function(position, alt) {if (this.viewer) {return position? Cesium.Cartesian3.fromDegrees(position.lng || position.lon,position.lat,(position.alt = alt || position.alt),Cesium.Ellipsoid.WGS84): Cesium.Cartesian3.ZERO;}},/**** 坐標轉換 笛卡爾轉84* @param {Object} Cartesian3 三維位置坐標* @return {Object} {lng,lat,alt} 地理坐標*/transformCartesianToWGS84: function(cartesian) {if (this.viewer && cartesian) {var ellipsoid = Cesium.Ellipsoid.WGS84;var cartographic = ellipsoid.cartesianToCartographic(cartesian);return {lng: Cesium.Math.toDegrees(cartographic.longitude),lat: Cesium.Math.toDegrees(cartographic.latitude),alt: cartographic.height};}},
3,調用方法:
let option = {ground: true //true:不貼地/false:貼地 };
DrawPolygon(option).then(allPoints => {// 在這里,allPoints是結束繪制后的點坐標數組var resultPoints=allPoints})
4,DrawPolygon方法說明:
1,定義返回結果的方式:
var allPoints=[]
return new Promise((resolve, reject) => {
......
}
在這個方法開始時,定義了一個allPoints數組,用于存儲繪制的多邊形的所有頂點,并且返回一個Promise,允許在繪制結束后將這些點的坐標返回。
2,獲取Cesium Viewer:
let viewer = this.viewer;
獲取Cesium的Viewer實例
3,創建一個實體以顯示繪制中的多邊形:
let drawingPolygon = viewer.entities.add({ ... });
這段代碼通過Cesium的entities.add方法創建一個新的實體,并將它添加到地圖上。這個實體用于實時顯示用戶繪制的多邊形。
4,創建一個實體以顯示繪制中的線:
let drawingLine = viewer.entities.add({ ... });
創建一個實體來實時顯示用戶繪制的線。
5,設置鼠標點擊事件的監聽:
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(event => { ... }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
這段代碼創建一個新的ScreenSpaceEventHandler實例來監聽鼠標和觸摸事件。然后設置一個函數來監聽左鍵點擊事件。每當用戶點擊鼠標左鍵時,這個函數就會被調用,并將點擊的位置添加到polygonPoints數組(即多邊形的頂點)和allPoints數組。
需要說明的是這一段代碼:
//將三維笛卡爾坐標系點轉為經緯度坐標點,并保存到點數組中let cartesian3 = cartesian.clone()// 使用Cesium.Cartographic.fromCartesian將Cartesian3對象轉換為Cartographic對象let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);allPoints.push([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), cartographic.height]);
加上這一段只是因為,如果要對獲取的點數組進行進一步使用,我更習慣使用經緯度坐標
6,設置鼠標移動事件的監聽:
handler.setInputAction(event => { ... }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
當用戶移動鼠標時,這個函數會被調用。它用于實時更新正在繪制的多邊形和線的形狀。
7,設置鼠標雙擊事件的監聽:
handler.setInputAction(() => { ... }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
這個函數監聽鼠標左鍵雙擊事件。當用戶雙擊鼠標左鍵時,這個函數會被調用,表示用戶完成了多邊形的繪制。此時,它會添加最后一個點實體,關閉鼠標事件監聽,結束繪制,并通過resolve(allPoints)將繪制的點坐標返回。
8,總說明:
這個方法允許用戶通過點擊和移動鼠標在Cesium地圖上繪制一個多邊形。在用戶完成繪制(通過雙擊鼠標左鍵)后,這個方法通過Promise的resolve函數將繪制的點坐標數組allPoints返回,供其他部分的代碼使用。
(比如進行填挖方的計算,將上面的點數組傳到地形填挖方計算的方法,用來生成三角網)
5,getCatesian3FromPX方法說明:
該方法根據給定的屏幕坐標px,計算出對應的三維世界坐標。該三維世界坐標可以代表一個具體的點在地圖上的位置。
使用drillPick方法來獲取屏幕坐標點上所有的對象。如果該點上有一個或多個對象,方法會嘗試從3D模型上拾取坐標。
如果拾取不在3D模型上,并且地形存在,則從地形上拾取坐標。
如果既不在3D模型上也不在地形上,則從地球橢球體上拾取坐標。
最后返回這個點的三維世界坐標,或者在無法確定時返回false。
6,transformWGS84ToCartesian方法說明:
該方法根據給定的地理坐標(WGS84格式)計算出相應的三維世界坐標(笛卡爾坐標)。
使用Cesium的Cartesian3.fromDegrees方法從給定的經緯度和高度計算出三維坐標。
7,transformCartesianToWGS84方法說明:
該方法根據給定的三維世界坐標(笛卡爾坐標)計算出相應的地理坐標(WGS84格式)。
使用Cesium的Ellipsoid.WGS84和cartesianToCartographic方法將三維世界坐標轉換為地理坐標。
8,后續學習記錄文章說明:
將火星科技(Mars3D)的一些例子,自己用Cesium來實現