最近一直在研究在3d地图上添加区域还有车辆路径路线,很是秃然啊!在不断的百度百度再百度,终于有了一套解决办法,先演示一下操作过程,
drawLine()方法
drawPlane()方法
下面就来堆代码吧。
一、viewer.scene.pickPosition与viewer.camera.pickEllipsoid的区别
前提是开启了地形检测viewer.scene.globe.depthTestAgainstTerrain = true;一般开启会占用一定内存,但是获取笛卡尔坐标更精确了,否则用viewer.camera.pickEllipsoid的话,可能画线的鼠标位置跟线的实际位置差距很大
二、获取鼠标点击位置的笛卡尔坐标
在画区域面积的时候坐标是必备的,通常获取坐标的方法有两中viewer.scene.pickPosition()与viewer.camera.pickEllipsoid(),这就不得不说说两者的区别了
开启了地形检测的话viewer.scene.pickPosition()获取坐标要比viewer.camera.pickEllipsoid()更精确,(viewer.scene.globe.depthTestAgainstTerrain = true),直接用viewer.camera.pickEllipsoid的话,可能画线的鼠标位置跟线的实际位置差距很大,这里推荐使用开启地形检测的pickPosition()方法
//首先建立ScreenSpaceEventHandler对象获取鼠标左击事件
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);
以上是获取鼠标左击的迪卡尔坐标并且转换成经纬度坐标
三、根据多点坐标画点或面
两点一线,三点/多点一面,要画线/面必须要2个或多个坐标才能绘画,光有一个坐标是不够的,所以我们要先命名一个变量let positions = [],来记录点击点的坐标,然后根据后面的转换变为画线和面积的坐标,同时需要命名一个变量来存储层次结构的对象 polygon = new Cesium.PolygonHierarchy(),还需要一个codeInfo来记录移动点的所有数据
1.下面就可以通过绑定鼠标事件来获取初始位置
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.绑定鼠标移动来获取移动位置
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.绑定鼠标右键来获取终点位置
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);
这样的话就获取了所有点坐标的信息,接下来就画线/面了。
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,
},
});
}
这样我们就可以根据我们的鼠标来绘制我们的线/面了
四、根据记录的点实现线/面的绘制
我们根据codeInfo记录的数据获取了线/面的点坐标数据,只需在绘制方法中为其添加坐标参数,即可实现线/面的绘制
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数据从this.infoDetail中获取
export class Draw {
constructor(viewer, config) {
/**cesium实例对象 */
this.viewer = viewer;
/**绘制要素的相关配置
* 默认配置
* {
borderColor: Cesium.Color.BLUE, 边框颜色
borderWidth: 2, 边框宽度
material: Cesium.Color.GREEN.withAlpha(0.5),填充材质
}
*/
this.config = config || {
borderColor: Cesium.Color.BLUE,
borderWidth: 2,
material: Cesium.Color.GREEN.withAlpha(0.5),
};
/**存贮绘制的数据 坐标 */
this.infoDetail = {
point: [],
line: [],
rectangle: [],
circle: [],
planeSelf: [],
};
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
}
/*******
* @param: id 必须是唯一的 name、position是三点的笛卡尔坐标[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;
/**实体的唯一标注 */
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: 绘制矩形区域
* @return {*}
* @author: xk
*/
drawRectangle() {
this.handler.destroy();
/**
* 矩形四点坐标
*/
let westSouthEastNorth = [];
/**实体的唯一标注 */
let id = null;
/**地图点击对象 */
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.handler.setInputAction((click) => {
/**点击位置笛卡尔坐标 */
let cartesian = this.viewer.scene.pickPosition(click.position);
/**笛卡尔转弧度坐标 */
let cartographic = Cesium.Cartographic.fromCartesian(cartesian, false);
/**点击位置经度 */
let lng1 = Cesium.Math.toDegrees(cartographic.longitude);
/**点击位置维度 */
let lat1 = Cesium.Math.toDegrees(cartographic.latitude);
/**边框坐标 */
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,
// 是否被提供的材质填充
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: 绘制圆形区域
* @return {*}
* @author: xk
*/
drawCircle() {
this.handler.destroy();
/**实体的唯一标注 */
let id = null;
/**圆半径 */
let radius = 0;
/**圆心 */
let lngLat = [];
/**鼠标事件 */
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: "区域一",
// 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: 自定义区域绘制
* @return {*}
* @author: xk
*/
drawPlane() {
this.handler.destroy();
/**实体的唯一标注 */
let id = new Date().getTime();
/**记录拐点坐标 */
let positions = [],
/**记录返回结果 */
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();
/**实体的唯一标注 */
let id = null;
/**记录拐点坐标 */
let positions = [],
/**记录返回结果 */
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":
/**删除某一条数据 */
newPoint = this.infoDetail.point.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.point = newPoint;
break;
case "line":
/**删除某一条数据 */
newPoint = this.infoDetail.line.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.line = newPoint;
break;
case "rectangle":
/**删除某一条数据 */
newPoint = this.infoDetail.rectangle.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.rectangle = newPoint;
break;
case "planeSelf":
/**删除某一条数据 */
newPoint = this.infoDetail.planeSelf.filter(
(item) => item.id != pick.id._id
);
this.infoDetail.planeSelf = newPoint;
break;
case "circle":
/**删除某一条数据 */
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: 返回绘制数据
*/
backInfoDetail() {
return this.infoDetail;
}
}
六、方法使用
//新建绘画对象
let draw = new Draw(viewer, {
borderColor: Cesium.Color.RED,
material: Cesium.Color.BLUE.withAlpha(0.3),
});
draw.drawPlane();
绘画完后f12打开控制台会有这样的数据打印
红框中就是我们需要提取的position数据,通过addPlane方法就可以实现重绘了
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);
教程到这里就结束了,喜欢的不要忘记关注点赞收藏哦
这里附上gitee仓库地址,可以直接拉取查看代码cesium-test: 用于cesium学习测试的仓库文章来源:https://www.toymoban.com/news/detail-674839.html
这是我的qq:1711503830有什么问题欢迎添加讨论。文章来源地址https://www.toymoban.com/news/detail-674839.html
到了这里,关于关于cesium根据地形画区域面积并覆盖在3d表面上的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!