Cesium基础知识二

标签: Cesium 分类: Gis 创建时间:2020-10-12 02:47:47 更新时间:2025-01-17 10:39:22

我写的每一篇文章,都不成体系,简直就是一个杂烩,什么都有,用到什么就写什么,用到什么就学什么,我也觉得这样不好,但是还是无法避免出现这样的情况,因为每天都会遇到新的问题,但是脑子又很难记住,于是只能先找一个地方记录下来。

1.设置初始视角和homeButton按钮的默认位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 创建相机初始位置和朝向
var initialPosition = new Cesium.Cartesian3.fromDegrees(120.35295,30.3362,100.0);
var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(7.1077496389876024807, -31.987223091598949054, 0.025883251314954971306);
var homeCameraView = {
destination : initialPosition,
orientation : {
heading : initialOrientation.heading,
pitch : initialOrientation.pitch,
roll : initialOrientation.roll
}
};
// 设置视图
viewer.scene.camera.setView(homeCameraView);
// 增加相机飞行动画参数
homeCameraView.duration = 2.0;
homeCameraView.maximumHeight = 2000;
homeCameraView.pitchAdjustHeight = 2000;
homeCameraView.endTransform = Cesium.Matrix4.IDENTITY;
// Override the default home button
viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) {
e.cancel = true;
viewer.scene.camera.flyTo(homeCameraView);
});

修改homebutton的点击事件,除了修改源码,还有别的方法吗?

参考文章:
1.Cesium设置位置和视角
2.Cesium如何改变HomeButton(首页)的默认位置? (这里通过聚焦点击事件,然后覆盖了homebutton的默认点击事件)
3.new Cesium.HomeButton(container, scene, duration)
4.Ceisum官方教程2 – 项目实例(workshop) (在这篇文章的最后,有对设置相机的位置以及修改homebutton按钮的说明,这篇文章其实也是一篇入门文章,里面东西还是挺多的。)

2.增加导航栏

要增加导航栏,也有几个插件可以使用。最后我使用的是cesium-navigation,官方仓库中没有提供viewerCesiumNavigationMixin.min.js,需要自己下载源码,然后使用node build.js进行编译生成viewerCesiumNavigationMixin.min.js文件,然后才能独立使用。

1
2
3
4
5
6
7
8
9
10
<script src="./Build/Cesium/viewerCesiumNavigationMixin.min.js"></script>
// cesium 初始化
var viewer = new Cesium.Map('cesiumContainer', {
shouldAnimate: true,
selectionIndicator:true,
infoBox:false,
homeButton:true,
});
// 罗盘
viewer.extend(Cesium.viewerCesiumNavigationMixin, {});

简单的一句话,最后的效果就会有一个漂亮的导航条。

还可以修改css样式

1
2
3
4
5
6
7
8
9
10
.compass{
position: absolute;
right: 10px;
top:50px;
}
.navigation-controls{
position: absolute;
right: 40px;
top:150px;
}
参考文章:
1.cesium-navigation-es6 (这是cesium-navigation-es6 1.1.6仓库,可以结合vue使用)
2.cesium-navigation (这是cesium-navigation的仓库,需要从这里下载源码然后执行cnpm install和node build.js命令编译生成viewerCesiumNavigationMixin.min.js文件)
3.Cesium导航指针放大缩小定位平移详解 (这里改了cesium-navigation-es6 1.1.6源码,介绍了如何使用cesium-navigation-es6 1.1.6)
4.cesium导航 (这里讲了如何使用cesium-navigation但是没有说这个min.js如何来的)
5.cesiumjs学习笔记之三——cesium-navigation插件 【转】

5.加载WFS服务

(1) 加载WFS服务,主要就是获取数据,然后使用GeoJsonDataSource进行渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var datasource=Cesium.GeoJsonDataSource.load(data);

// 修改样式
var entities = dataSource.entities.values;
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
entity.billboard = undefined;
entity.point = new Cesium.PointGraphics({
color: Cesium.Color.FORESTGREEN,
pixelSize: 10
});
}

// 添加如场景中
viewer.dataSources.add(datasource);

默认的样式就是一个蓝色的图钉

参考文章:
1.cesium加载WFS服务(GeoServer发布)
2.Cesium 查询加载 geoserver的wfs 数据 (这篇文章主要其实是写的如何获取geojson数据,而不是如今加载)
3.Cesium加载OGC服务 (这篇文章写的较为详细,包括修改默认的样式)
4.Cesium:获取某个entity的位置属性 Cartesian3 (获取entity的位置)

(2) 加载Geoserver发布的WFS服务,并进行颜色的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
getFactoryLayer().then(data=>{
// 判断是否数据正常
if(data&&data.status&&data.status==500){
return
}
let viewer=window.cesiumViewer;
// 加载模型
Cesium.GeoJsonDataSource.load(data).then(datasource=>{
let dataSource=viewer.dataSources;
dataSource.add(datasource);
var entities = datasource.entities.values;
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
let polygon=entity.polygon;
polygon.material=new Cesium.Color(0.12, 0.45, 0.77,0.7);
}

});
});

6.获取鼠标点击位置

1.获取鼠标点的对应椭球面位置:世界坐标(Cartesian3)。
2.获取加载地形后对应的经纬度和高程:地标坐标;
3.获取倾斜摄影或模型点击处的坐标:场景坐标;
4.获取点击处屏幕坐标 :屏幕坐标(鼠标点击位置距离canvas左上角的像素值);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 这种方式不准确,有偏移,scene.pickPosition只有在开启地形深度检测,且不使用默认地形时是准确的。
// const cartesian = viewer.scene.pickPosition(e.position)

// 返回Cartesian3射线的位置和方向。
const ray = viewer.camera.getPickRay(e.position)
// 查找射线与渲染的地球表面之间的交点。射线必须以世界坐标给出。
const cartesian = viewer.scene.globe.pick(ray, viewer.scene)
// 输出结果
if (Cesium.defined(cartesian)) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
const longitudeString = Cesium.Math.toDegrees(cartographic.longitude)
const latitudeString = Cesium.Math.toDegrees(cartographic.latitude)
const heightString = cartographic.height

console.log(longitudeString, latitudeString, heightString)
}
参考文章:
1.Cesium4种获取鼠标点击位置
2.cesium拾取屏幕上指定点的真实坐标
3.Cesium 拾取 API 完全总结 1.仅拾取椭球体表面坐标;2.拾取带地形高度的地表坐标;3.拾取三维物体的坐标;
4.Cesium的坐标拾取详解 Scene.prototype.pickPosition、Scene.prototype.pick 和 Globe.prototype.pickRay 的准确性受深度缓存影响,所以,在深度检测不开启时,拾取的坐标会不准确。

7.鼠标移动

基本思想:在左键按下的时候,记录鼠标开始位置,和 entity 位置,在鼠标移动的时候,用鼠标当前位置减去鼠标开始位置,得到一个坐标差值,然后将全部的 entity 坐标加上这一个坐标差,得到了最终的坐标位置。
问题:目前存在的问题就是,当鼠标移动距离过大的时候,这个差值计算就会出现偏差,变得越来越大了,导致 entity 虽然跟着鼠标移动,但是位置和鼠标没有相对位置不动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
let pick: any = null;
let leftDownFlag = false;

let startPosition; // 开始坐标
let topEntityPosition; // 顶部entity位置
let bottomEntityPosition; // 底部 entity 位置
let polylinePreviousCoordinates; // 线位置

const EventListener_MouseLeftDown = (hanlder: any) => {
hanlder.setInputAction((evt: any) => {
pick = this.viewer.scene.pick(evt.position);
// if (!pick) return;
if (!pick?.id?.properties?.id?._value) return;
console.log(pick, 'pick');
if (Cesium.defined(pick) && pick.id.id && this.waylineStore.selectedPoint == pick.id.properties.id._value) {
//记录按下去的坐标
const ray = this.viewer.camera.getPickRay(evt.position);
startPosition = this.viewer.scene.globe.pick(ray!, this.viewer.scene);
leftDownFlag = true;
this.viewer.scene.screenSpaceCameraController.enableRotate = false; //锁定相机
this.viewer.scene.screenSpaceCameraController.enableZoom = false; //锁定缩放

const positionIndex = pick.id.properties.id._value;
let position = this.wayPoint[positionIndex].topEntity.position;
const time = Cesium.JulianDate.now();
topEntityPosition = position.getValue(time);
position = this.wayPoint[positionIndex].bottomEntity.position;
bottomEntityPosition = position.getValue(time);
polylinePreviousCoordinates = this.wayPoint[positionIndex].lineEntity.polyline.positions.getValue();
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
};
const EventListener_MouseMove = (handler: any) => {
handler.setInputAction((e: any) => {
if (Cesium.defined(pick) && leftDownFlag) {
// 记录结束坐标
const ray = this.viewer.camera.getPickRay(e.endPosition);
const endPosition = this.viewer.scene.globe.pick(ray!, this.viewer.scene);
if (startPosition && endPosition) {
//计算每次的偏差
const changed_x = endPosition.x - startPosition.x;
const changed_y = endPosition.y - startPosition.y;
const changed_z = endPosition.z - startPosition.z;

topEntityPosition.x = topEntityPosition.x + changed_x;
topEntityPosition.y = topEntityPosition.y + changed_y;
topEntityPosition.z = topEntityPosition.z + changed_z;
bottomEntityPosition.x = bottomEntityPosition.x + changed_x;
bottomEntityPosition.y = bottomEntityPosition.y + changed_y;
bottomEntityPosition.z = bottomEntityPosition.z + changed_z;
const positionIndex = pick.id.properties.id._value;
if (!positionIndex) return;
this.wayPoint[positionIndex].topEntity.position = topEntityPosition;
this.wayPoint[positionIndex].bottomEntity.position = bottomEntityPosition;

const currentsPoint: any[] = [];
for (let i = 0; i < polylinePreviousCoordinates.length; i++) {
//与之前的算差 替换掉
polylinePreviousCoordinates[i].x = polylinePreviousCoordinates[i].x + changed_x;
polylinePreviousCoordinates[i].y = polylinePreviousCoordinates[i].y + changed_y;
polylinePreviousCoordinates[i].z = polylinePreviousCoordinates[i].z + changed_z;
currentsPoint.push(polylinePreviousCoordinates[i]);
}
this.wayPoint[positionIndex].lineEntity.polyline.positions = new Cesium.CallbackProperty(function () {
return currentsPoint;
}, false);

// 替换开始点
startPosition = endPosition;
}

}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
};
const EventListener_MouseLeftUp = (handler: any) => {
handler.setInputAction((evt: any) => {
if (leftDownFlag && pick) {
leftDownFlag = false;
this.viewer.scene.screenSpaceCameraController.enableRotate = true; //解锁相机
this.viewer.scene.screenSpaceCameraController.enableZoom = true; //允许缩放
}
}, Cesium.ScreenSpaceEventType.LEFT_UP);
};
const EventListener_MouseLeftClick = (handler: any) => {
handler.setInputAction((evt: any) => {
pick = this.viewer.scene.pick(evt.position);
// if (!pick) return;
if (!pick?.id?.properties?.id?._value) return;
const positionIndex = pick.id.properties.id._value;
this.waylineStore.selectedPoint = positionIndex;
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};
this.handlerDrag = new ScreenSpaceEventHandler(this.viewer.scene.canvas);
EventListener_MouseLeftDown(this.handlerDrag);
EventListener_MouseMove(this.handlerDrag);
EventListener_MouseLeftUp(this.handlerDrag);
EventListener_MouseLeftClick(this.handlerDrag);
参考文章:
【1】.Cesium实现Entity的拖拽功能 这里有多个图形的移动,就是计算差值,然后进行移动
【2】.Cesium 实现拖动点或模型 移动的是选中的模型,需要先点选一下模型,然后再鼠标拖动。如果你想要直接拖动,就需要你再修改一下代码了。
【3】.cesium基础 1.cesium中的几种坐标和相互转换。2.关于贴地;3.Cesium鼠标事件。4.Cesium 中的pick,scene中:pick、drillPick、pickPosition,pick与drillPick的区别:pick只可获取一个entity对象(如该位置存在多个entity,哪怕面点线不在同一高度,面entity 都可能会盖住点线entity),但drillPick可获取当前坐标下的多个对象。5.Cesium的坐标拾取。6.Cesium中的Entity。7.Cesium中Primitive。8.Transforms对象。9.Cesium的Property机制。10.cesium轨迹回放,按路径飞行。
【4】.Scene.globe.pick delivers undefined
【5】.Cesium获取鼠标点击位置(PickPosition)解决viewer.scene.pickPosition(e.position)不准的问题
【6】.屏幕坐标、固定坐标、惯性坐标转换 entity.position = new Cesium.ConstantPositionProperty(position, Cesium.ReferenceFrame.INERTIAL)
【7】.Cesium 拖拽3D模型 1、鼠标按下事件,如果有模型的话,可以给模型设置一个颜色,知道按下选中的是哪个模型。2、然后再监听鼠标拖拽事件,获取鼠标拖拽的位置,赋值给模型。3、鼠标抬起事件,结束鼠标移动事件,然后把颜色改回去。
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。