一、根据点跟角度计算另一点坐标(三维球体)
export const getAnotherPoint = (lon: number, lat: number, angle: number, distance: number) => {
// WGS84坐标系
var a = 6378137; // 赤道半径
var b = 6356752.3142; // 短半径
var f = 1 / 298.257223563; // 扁率
var alpha1 = angle * (Math.PI / 180)
var sinAlpha1 = Math.sin(alpha1);
var cosAlpha1 = Math.cos(alpha1);
var tanU1 = (1 - f) * Math.tan(lat * (Math.PI / 180));
var cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
var sigma1 = Math.atan2(tanU1, cosAlpha1);
var sinAlpha = cosU1 * sinAlpha1;
var cosSqAlpha = 1 - sinAlpha * sinAlpha;
var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
var sigma = distance / (b * A), sigmaP = 2 * Math.PI;
let sinSigma = 0
let cosSigma = 0
let cos2SigmaM = 0
while (Math.abs(sigma - sigmaP) > 1e-12) {
cos2SigmaM = Math.cos(2 * sigma1 + sigma);
sinSigma = Math.sin(sigma);
cosSigma = Math.cos(sigma);
var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = distance / (b * A) + deltaSigma;
}
var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
var lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
var lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
var L = lambda - (1 - C) * f * sinAlpha *
(sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
return {
lon: Number(lon) + L * (180 / Math.PI), lat: lat2 * (180 / Math.PI) };
}
二、渐变材质
export const getMaterial = () => {
let appearance = new Cesium.MaterialAppearance({
vertexShaderSource: `
attribute vec3 position3DHigh;
attribute vec3 position3DLow;
attribute float batchId;
varying vec4 v_positionEC;
attribute vec4 color;
varying vec4 v_color;
void main(){
v_color = color;
vec4 p = czm_computePosition(); // 获取模型相对于视点位置
vec4 eyePosition = czm_modelViewRelativeToEye * p; // 由模型坐标 得到视点坐标
v_positionEC = czm_inverseModelView * eyePosition; // 视点在 模型坐标系中的位置
gl_Position = czm_modelViewProjectionRelativeToEye * p; // 视点坐标转为屏幕坐标
}`,
fragmentShaderSource: `
varying vec4 v_positionEC;
varying vec3 v_normalEC;
varying vec4 v_color;
void main() {
float l = sqrt(pow(v_positionEC.x,2.0) + pow(v_positionEC.y,2.0) + pow(v_positionEC.z,2.0)); // 距离模型坐标系原点的距离
float cy3 = fract((abs(l-27.0))/40.0);
// 修改渐变方向 float cy3 = 1- fract((abs(l-27.0))/40.0);
gl_FragColor = vec4(v_color.rgb,cy3);
}
`,
})
return appearance
}
三、根据两点坐标获取偏航角和俯仰角
function getHeadingPitch(fromPosition, toPosition) {
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
const resultHead = Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y))
const resultPitch = Cesium.Math.toDegrees(Math.asin(finalPosition.z))
return {
resultHead ,resultPitch };
}
四、添加实体
(一)点
//entities.add(entity)
viewer.entities.add({
// fromDegrees(经度,纬度,高度,椭球,结果)从以度为单位的经度和纬度值返回Cartesian3位置
position: Cesium.Cartesian3.fromDegrees(108, 34, 10),
point: {
// 点的大小(像素)
pixelSize: 5,
// 点位颜色,fromCssColorString 可以直接使用CSS颜色
color: Cesium.Color.fromCssColorString('#ee0000'),
// 边框颜色
outlineColor: Cesium.Color.fromCssColorString('#fff'),
// 边框宽度(像素)
outlineWidth: 2,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true
}
});
(二)线
viewer.entities.add({
polyline: {
// fromDegrees返回给定的经度和纬度值数组(以度为单位),该数组由Cartesian3位置组成。
// Cesium.Cartesian3.fromDegreesArray([经度1, 纬度1, 经度2, 纬度2,])
// Cesium.Cartesian3.fromDegreesArrayHeights([经度1, 纬度1, 高度1, 经度2, 纬度2, 高度2])
positions: Cesium.Cartesian3.fromDegreesArray([
120.9677706, 30.7985748,
110.20, 34.55
]),
// 宽度
width: 2,
// 线的颜色
material: Cesium.Color.WHITE,
// 线的顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
zIndex: 10,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true
}
});
(三)面
viewer.entities.add({
polygon: {
// 获取指定属性(positions,holes(图形内需要挖空的区域))
hierarchy: {
positions: Cesium.Cartesian3.fromDegreesArray([
120.9677706, 30.7985748,
110.20, 34.55,
120.20, 50.55
]),
holes: [{
positions: Cesium.Cartesian3.fromDegreesArray([
119, 32,
115, 34,
119, 40
])
}]
},
// 边框
outline: true,
// 边框颜色
outlineColor: Cesium.Color.WHITE,
// 边框尺寸
outlineWidth: 2,
// 填充的颜色,withAlpha透明度
material: Cesium.Color.GREEN.withAlpha(0.5),
// 是否被提供的材质填充
fill: true,
// 恒定高度
height: 5000,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1000, 10000000),
// 是否显示
show: true,
// 顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
zIndex: 10
}
});
(四)文字
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(120, 30, 5),
// 点
point: {
color: Cesium.Color.RED, // 点位颜色
pixelSize: 10 // 像素点大小
},
// 文字
label: {
// 文本。支持显式换行符“ \ n”
text: '测试名称',
// 字体样式,以CSS语法指定字体
font: '14pt Source Han Sans CN',
// 字体颜色
fillColor: Cesium.Color.BLACK,
// 背景颜色
backgroundColor: Cesium.Color.AQUA,
// 是否显示背景颜色
showBackground: true,
// 字体边框
outline: true,
// 字体边框颜色
outlineColor: Cesium.Color.WHITE,
// 字体边框尺寸
outlineWidth: 10,
// 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
scale: 1.0,
// 设置样式:FILL:填写标签的文本,但不要勾勒轮廓;OUTLINE:概述标签的文本,但不要填写;FILL_AND_OUTLINE:填写并概述标签文本。
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// 相对于坐标的水平位置
verticalOrigin: Cesium.VerticalOrigin.CENTER,
// 相对于坐标的水平位置
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
// 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
pixelOffset: new Cesium.Cartesian2(10, 0),
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true
}
});
(五)广告牌(图片)
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(110.20, 34.55, 2.61),
billboard: {
// 图像地址,URI或Canvas的属性
image: '/location.png',
// 设置颜色和透明度
color: Cesium.Color.WHITE.withAlpha(0.8),
// 高度(以像素为单位)
height: 50,
// 宽度(以像素为单位)
width: 50,
// 逆时针旋转
rotation: 20,
// 大小是否以米为单位
sizeInMeters: false,
// 相对于坐标的垂直位置
verticalOrigin: Cesium.VerticalOrigin.CENTER,
// 相对于坐标的水平位置
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
// 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
pixelOffset: new Cesium.Cartesian2(10, 0),
// 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
scale: 1.0,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true
}
});
(六)模型
viewer.entities.add({
// 设置方向
orientation: orientation,
position: Cesium.Cartesian3.fromDegrees(120, 30, 10000),
model: {
// 引入模型
uri: '/SampleData/models/CesiumAir/Cesium_Air.glb',
// 模型的近似最小像素大小,而不考虑缩放。这可以用来确保即使观看者缩小也可以看到模型。如果为0.0,则不强制使用最小大小
minimumPixelSize: 1280,
// 模型的颜色(与模型的渲染颜色混合的属性)
color: Cesium.Color.WHITE.withAlpha(1),
// 模型的最大比例大小
maximumScale: 20000,
// 设置模型轮廓(边框)颜色
silhouetteColor: Cesium.Color.BLACK,
// 设置模型轮廓(边框)大小
silhouetteSize: 2,
// 是否执行模型动画
runAnimations: true,
// 应用于图像的统一比例。比例大于会1.0放大标签,而比例小于会1.0缩小标签。
scale: 1.0,
// 显示在距相机的距离处的属性,多少区间内是可以显示的
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
// 是否显示
show: true
}
});
如出现地形遮挡问题,可关闭cesium深度检测:viewer.scene.globe.depthTestAgainstTerrain = false;
五、添加primitive
(一)点
const pointsDataSource = viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection())
// 创建点
for (const index in points) {
pointsDataSource.add({
pixelSize: 10,
color: Cesium.Color.fromCssColorString('#fff'),
position: Cesium.Cartesian3.fromDegrees(item[0], item[1], item[2]),
});
}
// 销毁点
pointsDataSource?.removeAll();
(二)线
const newArr1 = []; let newArr2 = [];
// eslint-disable-next-line array-callback-return
points.map((item) => {
newArr1.push(item[0]);
newArr1.push(item[1])