最近一直在研究在3d地圖上添加區(qū)域還有車輛路徑路線,很是禿然?。≡诓粩嗟陌俣劝俣仍侔俣?,終于有了一套解決辦法,先演示一下操作過程,
drawLine()方法
?drawPlane()方法
下面就來堆代碼吧。
一、viewer.scene.pickPosition與viewer.camera.pickEllipsoid的區(qū)別
前提是開啟了地形檢測viewer.scene.globe.depthTestAgainstTerrain = true;一般開啟會占用一定內(nèi)存,但是獲取笛卡爾坐標(biāo)更精確了,否則用viewer.camera.pickEllipsoid的話,可能畫線的鼠標(biāo)位置跟線的實際位置差距很大
二、獲取鼠標(biāo)點擊位置的笛卡爾坐標(biāo)
在畫區(qū)域面積的時候坐標(biāo)是必備的,通常獲取坐標(biāo)的方法有兩中viewer.scene.pickPosition()與viewer.camera.pickEllipsoid(),這就不得不說說兩者的區(qū)別了
開啟了地形檢測的話viewer.scene.pickPosition()獲取坐標(biāo)要比viewer.camera.pickEllipsoid()更精確,(viewer.scene.globe.depthTestAgainstTerrain = true),直接用viewer.camera.pickEllipsoid的話,可能畫線的鼠標(biāo)位置跟線的實際位置差距很大,這里推薦使用開啟地形檢測的pickPosition()方法
//首先建立ScreenSpaceEventHandler對象獲取鼠標(biāo)左擊事件
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.position);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
以上是獲取鼠標(biāo)左擊的迪卡爾坐標(biāo)并且轉(zhuǎn)換成經(jīng)緯度坐標(biāo)
三、根據(jù)多點坐標(biāo)畫點或面
兩點一線,三點/多點一面,要畫線/面必須要2個或多個坐標(biāo)才能繪畫,光有一個坐標(biāo)是不夠的,所以我們要先命名一個變量let positions = [],來記錄點擊點的坐標(biāo),然后根據(jù)后面的轉(zhuǎn)換變?yōu)楫嬀€和面積的坐標(biāo),同時需要命名一個變量來存儲層次結(jié)構(gòu)的對象? polygon = new Cesium.PolygonHierarchy(),還需要一個codeInfo來記錄移動點的所有數(shù)據(jù)
1.下面就可以通過綁定鼠標(biāo)事件來獲取初始位置
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
// left
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.position);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
// console.log("><><><><><>", cartographic);
if (cartesian && cartesian.x) {
if (positions.length == 0) {
positions.push(cartesian.clone());
}
codeInfo.push([lng, lat, hei]);
positions.push(cartesian.clone());
polygon.positions.push(cartesian.clone());
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
2.綁定鼠標(biāo)移動來獲取移動位置
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.endPosition);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
if (positions.length >= 0) {
if (cartesian && cartesian.x) {
positions.pop();
positions.push(cartesian);
polygon.positions.pop();
polygon.positions.push(cartesian);
codeInfo.pop();
codeInfo.push([lng, lat, hei]);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
3.綁定鼠標(biāo)右鍵來獲取終點位置
this.handler.setInputAction(() => {
this.infoDetail.planeSelf.push({ id: id, positions: codeInfo, polygon });
console.log("planeSelf", this.infoDetail.planeSelf);
this.handler.destroy();
positions.push(positions[0]);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
這樣的話就獲取了所有點坐標(biāo)的信息,接下來就畫線/面了。
4.繪畫
我們通過添加實體的方法來繪制線/面
polyObj = this.viewer.entities.add({
id: id,
name: "planeSelf",
polyline: {
positions: new Cesium.CallbackProperty(function () {
return positions;
}, false),
width: this.config.borderWidth,
material: this.config.borderColor,
clampToGround: true,
},
polygon: {
hierarchy: new Cesium.CallbackProperty(function () {
return polygon;
}, false),
material: this.config.material,
clampToGround: true,
},
});
}
這樣我們就可以根據(jù)我們的鼠標(biāo)來繪制我們的線/面了
四、根據(jù)記錄的點實現(xiàn)線/面的繪制
我們根據(jù)codeInfo記錄的數(shù)據(jù)獲取了線/面的點坐標(biāo)數(shù)據(jù),只需在繪制方法中為其添加坐標(biāo)參數(shù),即可實現(xiàn)線/面的繪制
addLine(id, name, positions) {
this.viewer.entities.add({
name: name,
id: id,
polyline: {
positions: new Cesium.CallbackProperty(function () {
return positions;
}, false),
width: this.config.borderWidth,
material: this.config.borderColor,
clampToGround: true,
},
});
}
五、完整繪制線/面的類方法
import * as Cesium from "cesium";
// add...方法的position數(shù)據(jù)從this.infoDetail中獲取
export class Draw {
constructor(viewer, config) {
/**cesium實例對象 */
this.viewer = viewer;
/**繪制要素的相關(guān)配置
* 默認(rèn)配置
* {
borderColor: Cesium.Color.BLUE, 邊框顏色
borderWidth: 2, 邊框?qū)挾? material: Cesium.Color.GREEN.withAlpha(0.5),填充材質(zhì)
}
*/
this.config = config || {
borderColor: Cesium.Color.BLUE,
borderWidth: 2,
material: Cesium.Color.GREEN.withAlpha(0.5),
};
/**存貯繪制的數(shù)據(jù) 坐標(biāo) */
this.infoDetail = {
point: [],
line: [],
rectangle: [],
circle: [],
planeSelf: [],
};
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
}
/*******
* @param: id 必須是唯一的 name、position是三點的笛卡爾坐標(biāo)[lng,lat,hei]
* @function: function
* @return {*}
* @description: 繪制方法
*/
addPoint(id, name, position) {
this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(...position),
name: name,
id: id,
point: {
color: this.config.material,
pixelSize: 12,
outlineColor: this.config.borderColor,
outlineWidth: this.config.borderWidth,
},
});
}
/*******
* @param: id 必須是唯一的 name、positions
* @function: function
* @return {*}
* @description: 繪制方法
*/
addLine(id, name, positions) {
this.viewer.entities.add({
name: name,
id: id,
polyline: {
positions: new Cesium.CallbackProperty(function() {
return positions;
}, false),
width: this.config.borderWidth,
material: this.config.borderColor,
clampToGround: true,
},
});
}
/*******
* @param: id 必須是唯一的 name、positions
* @function: function
* @return {*}
* @description: 添加平面方法
*/
addPlane(id, name, positions) {
let polygon = new Cesium.PolygonHierarchy();
polygon.positions = positions;
this.viewer.entities.add({
id: id,
name: name,
polyline: {
positions: new Cesium.CallbackProperty(function() {
return positions;
}, false),
width: this.config.borderWidth,
material: this.config.borderColor,
clampToGround: true,
},
polygon: {
hierarchy: new Cesium.CallbackProperty(function() {
return polygon;
}, false),
material: this.config.material,
clampToGround: true,
},
});
}
drawPoint() {
this.handler.destroy();
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((click) => {
let position = this.getMovement(click).position;
/**實體的唯一標(biāo)注 */
let id = new Date().getTime();
this.addPoint(id, "point", position);
this.infoDetail.point.push({ id, position });
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.setInputAction((click) => {
this.handler.destroy();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/*******
* @function: function
* @description: 繪制矩形區(qū)域
* @return {*}
* @author: xk
*/
drawRectangle() {
this.handler.destroy();
/**
* 矩形四點坐標(biāo)
*/
let westSouthEastNorth = [];
/**實體的唯一標(biāo)注 */
let id = null;
/**地圖點擊對象 */
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((click) => {
/**點擊位置笛卡爾坐標(biāo) */
let cartesian = this.viewer.scene.pickPosition(click.position);
/**笛卡爾轉(zhuǎn)弧度坐標(biāo) */
let cartographic = Cesium.Cartographic.fromCartesian(cartesian, false);
/**點擊位置經(jīng)度 */
let lng1 = Cesium.Math.toDegrees(cartographic.longitude);
/**點擊位置維度 */
let lat1 = Cesium.Math.toDegrees(cartographic.latitude);
/**邊框坐標(biāo) */
westSouthEastNorth = [lng1, lat1];
id = new Date().getTime();
if (westSouthEastNorth) {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
/**面實例對象 */
let polygons = this.viewer.entities.add({
name: "rectangle",
id: id,
polygon: {
hierarchy: new Cesium.CallbackProperty(function() {
return {
positions: Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth),
};
}),
height: 0,
// 填充的顏色,withAlpha透明度
material: this.config.material,
// 是否被提供的材質(zhì)填充
fill: true,
// 是否顯示
show: true,
},
polyline: {
positions: new Cesium.CallbackProperty(function() {
return Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth);
}),
material: this.config.borderColor,
width: this.config.borderWidth,
zIndex: 1,
},
});
this.handler.setInputAction((move) => {
let cartesian = this.viewer.scene.pickPosition(move.endPosition);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
westSouthEastNorth = [
lng1,
lat1,
lng1,
lat,
lng,
lat,
lng,
lat1,
lng1,
lat1,
];
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.setInputAction(() => {
this.handler.destroy();
this.infoDetail.rectangle.push({ id: id, position: westSouthEastNorth });
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/*******
* @function: function
* @description: 繪制圓形區(qū)域
* @return {*}
* @author: xk
*/
drawCircle() {
this.handler.destroy();
/**實體的唯一標(biāo)注 */
let id = null;
/**圓半徑 */
let radius = 0;
/**圓心 */
let lngLat = [];
/**鼠標(biāo)事件 */
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((click) => {
id = new Date().getTime();
let cartesian = this.viewer.scene.pickPosition(click.position);
// console.log(">>>", click.position);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
// console.log(">>>>>>>>>", cartographic);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
lngLat = [lng, lat, hei];
let entity = this.viewer.entities.add({
position: new Cesium.CallbackProperty(function() {
return new Cesium.Cartesian3.fromDegrees(...lngLat);
}, false),
name: "circle",
id: id,
ellipse: {
height: hei / 57.3,
outline: true,
material: this.config.material,
outlineColor: this.config.borderColor,
outlineWidth: this.config.borderWidth,
},
// label: {
// text: "區(qū)域一",
// font: "18px sans-serif",
// fillColor: Cesium.Color.GOLD,
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// outlineWidth: 2,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// pixelOffset: new Cesium.Cartesian2(0, 0),
// // 對齊方式(水平和豎直)
// horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
// showBackground: true,
// backgroundColor: new Cesium.Color.fromBytes(0, 0, 0),
// show: true,
// },
});
entity.ellipse.semiMajorAxis = new Cesium.CallbackProperty(function() {
return radius;
}, false);
entity.ellipse.semiMinorAxis = new Cesium.CallbackProperty(function() {
return radius;
}, false);
if (lngLat) {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
this.handler.setInputAction((move) => {
let cartesian2 = this.viewer.scene.pickPosition(move.endPosition);
radius = Cesium.Cartesian3.distance(cartesian, cartesian2);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.setInputAction(() => {
this.infoDetail.circle.push({ id: id, center: lngLat, radius: radius });
this.handler.destroy();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/*******
* @function: function
* @description: 自定義區(qū)域繪制
* @return {*}
* @author: xk
*/
drawPlane() {
this.handler.destroy();
/**實體的唯一標(biāo)注 */
let id = new Date().getTime();
/**記錄拐點坐標(biāo) */
let positions = [],
/**記錄返回結(jié)果 */
codeInfo = [],
/**面的hierarchy屬性 */
polygon = new Cesium.PolygonHierarchy(),
/**面對象配置 */
polyObj = null;
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
// left
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.position);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
// console.log("><><><><><>", cartographic);
if (cartesian && cartesian.x) {
if (positions.length == 0) {
positions.push(cartesian.clone());
}
codeInfo.push([lng, lat, hei]);
positions.push(cartesian.clone());
polygon.positions.push(cartesian.clone());
if (!polyObj) {
polyObj = this.viewer.entities.add({
id: id,
name: "planeSelf",
polyline: {
positions: new Cesium.CallbackProperty(function() {
return positions;
}, false),
width: this.config.borderWidth,
material: this.config.borderColor,
clampToGround: true,
},
polygon: {
hierarchy: new Cesium.CallbackProperty(function() {
return polygon;
}, false),
material: this.config.material,
clampToGround: true,
},
});
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// mouse
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.endPosition);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let hei = Cesium.Math.toDegrees(cartographic.height);
if (positions.length >= 0) {
if (cartesian && cartesian.x) {
positions.pop();
positions.push(cartesian);
polygon.positions.pop();
polygon.positions.push(cartesian);
codeInfo.pop();
codeInfo.push([lng, lat, hei]);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// right
this.handler.setInputAction((movement) => {
this.infoDetail.planeSelf.push({ id: id, positions: codeInfo, polygon });
console.log("planeSelf", this.infoDetail.planeSelf);
this.handler.destroy();
positions.push(positions[0]);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/*******
* @function: function
* @return {*}
* @author: xk
* @description: 繪制線段
*/
drawLine() {
this.handler.destroy();
/**實體的唯一標(biāo)注 */
let id = null;
/**記錄拐點坐標(biāo) */
let positions = [],
/**記錄返回結(jié)果 */
codeInfo = [],
/**面的hierarchy屬性 */
polygon = new Cesium.PolygonHierarchy(),
/**面對象配置 */
polyObj = null;
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
// left
this.handler.setInputAction((movement) => {
id = new Date().getTime();
let cartesian = this.getMovement(movement).cartesian;
let position = this.getMovement(movement).position;
if (cartesian && cartesian.x) {
if (positions.length == 0) {
positions.push(cartesian.clone());
}
codeInfo.push(position);
positions.push(cartesian.clone());
polygon.positions.push(cartesian.clone());
if (!polyObj) {
polyObj = this.addLine(id, "line", positions);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// mouse
this.handler.setInputAction((movement) => {
let cartesian = this.viewer.scene.pickPosition(movement.endPosition);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
if (positions.length >= 0) {
if (cartesian && cartesian.x) {
positions.pop();
positions.push(cartesian);
codeInfo.pop();
codeInfo.push([lng, lat]);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// right
this.handler.setInputAction((movement) => {
this.infoDetail.line.push({ id, positions: codeInfo });
console.log("infoDetail", this.infoDetail.line);
this.handler.destroy();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/*******
* @function: function
* @description: 移除實體對象
* @return {*}
* @author: xk
*/
removeEntity() {
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((move) => {
/**實體對象信息 {id:entities,primitive:。。} */
let pick = this.viewer.scene.pick(move.endPosition);
if (pick && pick.id && pick.id.id) {
document.body.style.cursor = "pointer";
this.handler.setInputAction((click) => {
let newPoint;
switch (pick.id.name) {
case "point":
/**刪除某一條數(shù)據(jù) */
newPoint = this.infoDetail.point.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.point = newPoint;
break;
case "line":
/**刪除某一條數(shù)據(jù) */
newPoint = this.infoDetail.line.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.line = newPoint;
break;
case "rectangle":
/**刪除某一條數(shù)據(jù) */
newPoint = this.infoDetail.rectangle.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.rectangle = newPoint;
break;
case "planeSelf":
/**刪除某一條數(shù)據(jù) */
newPoint = this.infoDetail.planeSelf.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.planeSelf = newPoint;
break;
case "circle":
/**刪除某一條數(shù)據(jù) */
newPoint = this.infoDetail.circle.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.circle = newPoint;
break;
default:
break;
}
this.viewer.entities.remove(pick.id);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
} else {
document.body.style = "cursor: default;";
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
/*******
* @function: function
* @return {*}
* @author: xk
* @description: 返回繪制數(shù)據(jù)
*/
backInfoDetail() {
return this.infoDetail;
}
}
六、方法使用
//新建繪畫對象
let draw = new Draw(viewer, {
borderColor: Cesium.Color.RED,
material: Cesium.Color.BLUE.withAlpha(0.3),
});
draw.drawPlane();
繪畫完后f12打開控制臺會有這樣的數(shù)據(jù)打印
紅框中就是我們需要提取的position數(shù)據(jù),通過addPlane方法就可以實現(xiàn)重繪了
let polygon = [
[
{
x: 337391.70993699186,
y: -4745401.190202851,
z: 4234046.05863133,
},
{
x: 338566.5104026345,
y: -4745705.230711781,
z: 4233614.397144763,
},
{
x: 337520.9493625825,
y: -4746057.340173215,
z: 4233305.240160256,
},
{
x: 337387.1903192716,
y: -4745398.61765625,
z: 4234049.280300835,
},
],
];
draw.addPlane(123123, "planeSelf", polygon);
?教程到這里就結(jié)束了,喜歡的不要忘記關(guān)注點贊收藏哦
這里附上gitee倉庫地址,可以直接拉取查看代碼cesium-test: 用于cesium學(xué)習(xí)測試的倉庫文章來源:http://www.zghlxwxcb.cn/news/detail-674839.html
這是我的qq:1711503830有什么問題歡迎添加討論。文章來源地址http://www.zghlxwxcb.cn/news/detail-674839.html
到了這里,關(guān)于關(guān)于cesium根據(jù)地形畫區(qū)域面積并覆蓋在3d表面上的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!