一、初始化地图
<template>
<div class="cesium_map">
<div id="cesiumContainer"></div>
</div>
</template>
<script setup>
import { reactive, ref, onMounted } from "vue";
import { Cone } from "../../utils/Model";
// ---------------------------<<数据>>---------------------------
const me = reactive({
cone: null,
});
// ---------------------------<<函数>>---------------------------
// 初始化地图
const initMap = () => {
// 在线地图token
Cesium.Ion.defaultAccessToken = "map_token";
// 在线地图
let imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
url: "map_url",
});
window.viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false, // 右上角 搜索
homeButton: false, // 右上角 Home
sceneModePicker: false, // 右上角 2D/3D切换
baseLayerPicker: false, // 右上角 地形
navigationHelpButton: false, // 右上角 Help
animation: false, // 左下角 圆盘动画控件
timeline: false, // 时间轴
fullscreenButton: false, // 右下角 全屏控件
vrButton: false, // 如果设置为true,将创建VRButton小部件。
scene3DOnly: false, // 每个几何实例仅以3D渲染以节省GPU内存
infoBox: false, // 隐藏点击要素后的提示信息
imageryProvider: imageryProvider, // 地图地址
shouldAnimate: true,
});
viewer._cesiumWidget._creditContainer.style.display = "none";
viewer.scene.globe.enableLighting = false;
viewer.shadows = false;
viewer.scene.globe.enableLighting = false;
Cesium.Camera.DEFAULT_VIEW_FACTOR = 0.2; // 摄像机到地图的距离放大倍数
viewer.camera.flyHome(0);
// // 调整画面精细度
viewer.resolutionScale = 1; //默认值为1.0
viewer.scene.backgroundColor = Cesium.Color.TRANSPARENT;
viewer.scene.globe.baseColor = Cesium.Color.TRANSPARENT;
// //是否开启抗锯齿
viewer.scene.fxaa = false;
viewer.scene.postProcessStages.fxaa.enabled = false;
viewer.scene.globe.showGroundAtmosphere = true;
// 设置相机位置
viewer.scene.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
110.82474250408677,
22.095133670052277,
80000
),
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-90),
roll: 0.0,
},
});
//取消双击事件
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
};
// 初始化模型
const initModel = () => {
// 请查看 “步骤三” 使用示例
};
// 初始化模型类
const initModelClass = () => {
me.cone = new Cone(viewer, Cesium);
};
// ---------------------------<<执行>>---------------------------
// 挂载后生命周期
onMounted(() => {
initMap();
initModelClass();
initModel();
});
</script>
<style lang="less" scoped>
.cesium_map {
width: 100%;
height: 100%;
position: relative;
#cesiumContainer {
width: 100%;
height: 100%;
}
}
</style>
二、封装文件
export class Cone {
constructor(viewer, Cesium) {
this.viewer = viewer
this.Cesium = Cesium
}
add(option) {
let {
position,
config
} = option;
let {
id,
name,
color,
length,
releaseGeometry,
} = config
var result = this.calcBeamScaleMatrix4(position);
//绘制圆锥几何体
var cone = new this.Cesium.Primitive({
show: true,
releaseGeometryInstances: releaseGeometry, // 默认为true,自动清空geometryInstances配置
geometryInstances: new this.Cesium.GeometryInstance({
id,
name,
geometry: new this.Cesium.CylinderGeometry({
length,
topRadius: 0.0,
bottomRadius: result.bottomRadius,
}),
}),
modelMatrix: result.mm, //提供位置与姿态参数
appearance: new this.Cesium.EllipsoidSurfaceAppearance({
material: this.getRingM({ color }), // 交替
faceForward: true,
closed: true,
}),
});
this.viewer.scene.primitives.add(cone);
}
adjustAngle({ startAngle, endAngle }) {
if (endAngle < startAngle) {
if (endAngle > 180 && startAngle < 180) {
var Az = startAngle; //先大小-前后交换顺序
startAngle = endAngle;
endAngle = Az;
}
}
if (Math.abs(endAngle - startAngle) > 180) {
if (endAngle > 180) {
Az = startAngle;
startAngle = endAngle - 360;
endAngle = startAngle;
}
}
return {
startAngle,
endAngle,
};
}
calcBeamMatrix4({ lon, lat, alt, pitch, heading, length }) {
//北天东与cesium坐标系的差距
heading += 90;
pitch = 270 - pitch;
var center = this.Cesium.Cartesian3.fromDegrees(lon, lat, alt);
heading = this.Cesium.Math.toRadians(heading);
pitch = this.Cesium.Math.toRadians(pitch);
var deadingPitchRoll = new this.Cesium.HeadingPitchRoll(heading, pitch, 0);
var hprRotation = this.Cesium.Matrix3.fromHeadingPitchRoll(deadingPitchRoll);
var subtract = new this.Cesium.Cartesian3(0, 0, -length / 2);
var rotated = this.Cesium.Matrix3.multiplyByVector(
hprRotation,
subtract,
new this.Cesium.Cartesian3()
);
var hpr = this.Cesium.Matrix4.fromRotationTranslation(hprRotation, rotated);
var modelMatrix = this.Cesium.Transforms.eastNorthUpToFixedFrame(center);
this.Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix);
return modelMatrix;
}
calcBeamScaleMatrix4({
lon,
lat,
alt,
length,
startAz, //波束起始方位角
endAz, //波束终止方位角
startEl, //俯仰
endEl, //俯仰
}) {
//俯仰在正负180之间
if (startEl > 180) startEl -= 360;
if (startEl < -180) startEl += 360;
if (endEl > 180) endEl -= 360;
if (endEl < -180) endEl += 360;
var newParam = this.adjustAngle({
startAngle: startAz,
endAngle: endAz,
});
startAz = newParam.startAngle;
endAz = newParam.endAngle;
var newParam1 = this.adjustAngle({
startAngle: startEl,
endAngle: endEl,
});
startEl = newParam1.startAngle;
endEl = newParam1.endAngle;
var heading = (endAz + startAz) / 2; //圆锥的方位指向
var pitch = ((startEl + endEl) / 2) % 180; //圆锥的俯仰指向俯仰在-180到180之间
var angle0 = (endAz - startAz) / 2; //方位
var angle1 = (endEl - startEl) / 2; //俯仰
if (endAz < 0 && startAz < 0) {
//计算缩放比列,取最小角度和取绝对值
angle0 = Math.abs(((endAz % 360) - (startAz % 360)) / 2); //方位圆锥底面
angle1 = Math.abs(((endEl % 360) - (startEl % 360)) / 2); //俯仰圆锥底面
}
var angle = 0;
var scaleX = 1,
scaleY = 1;
if (angle0 < angle1) {
angle = angle1;
scaleX = angle0 / angle1; //计算x,y,z的缩放比例(以便形成椭圆面)
} else {
angle = angle0;
scaleY = angle1 / angle0; //计算x,y,z的缩放比例(以便形成椭圆面)
}
var bottomRadius = length * Math.tan(Cesium.Math.toRadians(angle)); //计算底边半径(以最小的方位或俯仰角为准)
var modelMatrix = this.calcBeamMatrix4({
lon,
lat,
alt,
heading,
pitch,
length,
});
var s = this.Cesium.Matrix3.fromScale(new Cesium.Cartesian3(scaleY, scaleX, 1.0));
var scaleMatrix = this.Cesium.Matrix4.fromRotationTranslation(s);
let mm = modelMatrix.clone();
this.Cesium.Matrix4.multiply(mm, scaleMatrix, mm);
return { mm, bottomRadius };
}
getRingM(params) {
var { color, thickness, repeat } = params || {};
var material = new this.Cesium.Material({
fabric: {
type: "VtxfShader",
uniforms: {
color: this.Cesium.Color.fromCssColorString(color || "rgba(255,0,0,0.3)"),
repeat: repeat || 40.0, //40.0,/重复次数
offset: 10, // 1.0,
thickness: thickness || 0.5, //环宽度比列(0, 1]
},
source: `
uniform vec4 color;
uniform float repeat;
uniform float offset;
uniform float thickness;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
float sp = 1.0/repeat;
vec2 st = materialInput.st;
float dis = distance(st, vec2(0.5));
float m = mod(dis + offset, sp);
float a = step(sp*(1.0-thickness), m);
material.diffuse = color.rgb;
material.alpha = a * color.a;
return material;
}
`,
},
// translucent: false,
});
return material;
}
}
三、使用示例
1、代码
const initModel = () => {
me.cone.add({
position: {
lon: 110.82474250408677, // 经度
lat: 22.095133670052277, // 纬度
alt: 0, // 高度
length: 8000, // 圆锥高度
startAz: 30, // 起始方位
endAz: 45, // 结束方位
startEl: 30, // 起始俯仰
endEl: 45, // 结束俯仰
},
config: {
id: "cone", // 圆锥id
name: "cone", // 圆锥name
color: "#00ff00", // 圆锥颜色
length: 8000, // 圆锥长度
releaseGeometry: false, // 是否自动清空geometryInstances配置,默认为true,
},
});
}
2、效果