Commit 232cadf0 authored by xinzhedeai's avatar xinzhedeai

add:电子围栏 init test

parent 1561d94f
...@@ -101,19 +101,19 @@ export const constantRoutes = [ ...@@ -101,19 +101,19 @@ export const constantRoutes = [
} }
] ]
}, },
// { {
// path: '/dp', path: '/wl',
// component: Layout, component: Layout,
// redirect: 'noredirect', redirect: 'noredirect',
// children: [ children: [
// { {
// path: 'screen', path: 'screen',
// component: () => import('@/views/index-dp'), component: () => import('@/views/index-wl'),
// name: 'Screen', name: 'Screen',
// meta: { title: '首页-DP', icon: 'dashboard', affix: true } meta: { title: '首页-WL', icon: 'dashboard', affix: true }
// } }
// ] ]
// }, },
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,
......
<template>
<div class="app-container home">
<!-- Cesium地图容器 -->
<div id="cesiumContainer" class="cesium-container"></div>
<!-- 人员实时追踪控制面板 -->
<div class="tracking-panel">
<select v-model="selectedPerson" @change="onPersonSelect">
<option value="">选择人员</option>
<option
v-for="person in personnelList"
:key="person.perName"
:value="person.perName"
>
{{ person.perName }}
</option>
</select>
</div>
<!-- 电子围栏管理面板 -->
<div class="fence-panel">
<div class="panel-header">
<h3>电子围栏管理</h3>
<div class="fence-type-switch">
<label>
<input
type="radio"
v-model="currentFenceType"
value="person"
checked
/>
人员围栏
</label>
<label>
<input type="radio" v-model="currentFenceType" value="vehicle" />
车辆围栏
</label>
</div>
</div>
<div class="fence-controls">
<button @click="startCreatingFence" :disabled="isCreatingFence">
创建围栏
</button>
<button @click="editSelectedFence" :disabled="!selectedFence">
编辑围栏
</button>
<button @click="deleteSelectedFence" :disabled="!selectedFence">
删除围栏
</button>
<button @click="stopCreatingFence" :disabled="!isCreatingFence">
取消创建
</button>
</div>
<div class="fence-list">
<h4>围栏列表</h4>
<ul>
<li
v-for="fence in getCurrentFences"
:key="fence.id"
:class="{ active: selectedFence && selectedFence.id === fence.id }"
@click="selectFence(fence)"
>
{{ fence.name }}
</li>
</ul>
</div>
</div>
<!-- 告警信息面板 -->
<div class="alarm-panel" v-if="alarms.length > 0">
<h3>越界告警</h3>
<div class="alarm-list">
<div v-for="alarm in alarms" :key="alarm.id" class="alarm-item">
<span class="alarm-time">{{ alarm.time }}</span>
<span class="alarm-content">{{ alarm.content }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Index",
data() {
return {
// 版本号
version: "3.8.9",
// Cesium查看器实例
viewer: null,
tileset: null,
personnelList: [],
vehicleList: [], // 添加车辆列表
personModelInterval: null,
trackingInterval: null,
bgEntities: {}, // 所有的key都对应一个实体对象
// 轨迹追踪相关数据
selectedPerson: "", // 选中的人员
timePoints: [], // 时间点数组
currentTimeIndex: 0, // 当前时间索引
personTrajectories: {}, // 人员轨迹数据 { 人员名称: [{time, lng, lat, height}] }
trailEntities: {}, // 轨迹实体
isTracking: false, // 是否正在实时追踪
currentTimeDisplay: "", // 当前显示时间
// 添加轨迹相关配置
trajectoryConfig: {
pointCount: 5, // 每个人员的轨迹点数量
maxRange: 0.001, // 约100米范围(1度约等于111公里,0.001度约等于111米)
heightOffset: 50, // 轨迹点高度偏移
},
// 电子围栏相关数据
personFences: [], // 人员电子围栏
vehicleFences: [], // 车辆电子围栏
isCreatingFence: false, // 是否正在创建围栏
currentFencePoints: [], // 当前围栏的点
selectedFence: null, // 当前选中的围栏
currentFenceType: "person", // 当前围栏类型
drawingEntity: null, // 绘制中的实体
fenceEntities: {}, // 围栏实体映射
// 告警相关
alarms: [], // 告警列表
};
},
mounted() {
// 组件挂载后初始化地图
this.initCesium();
this.personCardList(() => {
console.log("人员数据", this.personnelList);
});
this.vehicleCardList(); // 初始化车辆数据
// 开始定时检查越界
this.startBoundaryCheckInterval();
},
beforeDestroy() {
// 组件销毁前清理地图资源
if (this.viewer) {
this.viewer.destroy();
this.viewer = null;
}
if (this.personModelInterval) {
clearInterval(this.personModelInterval);
}
if (this.trackingInterval) {
clearInterval(this.trackingInterval);
}
if (this.boundaryCheckInterval) {
clearInterval(this.boundaryCheckInterval);
}
},
computed: {
// 获取当前类型的围栏列表
getCurrentFences() {
return this.currentFenceType === "person"
? this.personFences
: this.vehicleFences;
},
},
methods: {
// 新增:清除实体
clearEntities() {
if (this.viewer && this.bgEntities) {
for (let key in this.bgEntities) {
this.viewer.entities.remove(this.bgEntities[key]);
delete this.bgEntities[key];
}
}
},
// 为人员设置轨迹数据
initPersonTrajectories() {
// 将笛卡尔坐标转换为经纬度坐标作为基准点
const cartographic = Cesium.Cartographic.fromCartesian({
x: -2686273.730145489,
y: 4293961.185794622,
z: 3863430.5618300107,
});
const baseLongitude = Cesium.Math.toDegrees(cartographic.longitude);
const baseLatitude = Cesium.Math.toDegrees(cartographic.latitude);
const baseHeight = cartographic.height + 1;
// 为每个人生成轨迹数据
this.personnelList.forEach((person) => {
const trajectories = [];
// 为每个人生成一个随机的起始位置,在基准点附近
const personBaseLng =
baseLongitude +
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 0.5;
const personBaseLat =
baseLatitude +
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 0.5;
// 生成轨迹点,形成一个合理的移动路径
for (let i = 0; i < this.trajectoryConfig.pointCount; i++) {
// 在人员基准位置附近生成轨迹点,确保在100米范围内
const lngOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange;
const latOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange;
trajectories.push({
time: new Date().getTime() + i * 60000, // 每分钟一个点
lng: personBaseLng + lngOffset,
lat: personBaseLat + latOffset,
height: baseHeight,
});
}
this.personTrajectories[person.perName] = trajectories;
});
},
// 格式化时间显示
formatTime(date = new Date()) {
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
},
// 人员选择变化处理
onPersonSelect() {
this.clearTrails();
if (this.selectedPerson) {
this.showFullPath();
}
},
// 显示完整轨迹
showFullPath() {
if (
!this.selectedPerson ||
!this.personTrajectories[this.selectedPerson]
) {
return;
}
this.clearTrails();
this.updateTrailDisplay();
},
// 更新轨迹显示
updateTrailDisplay() {
const trajectories = this.personTrajectories[this.selectedPerson];
if (!trajectories || trajectories.length < 2) return;
// 创建轨迹点数组
const positions = [];
trajectories.forEach((point) => {
positions.push(
Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.height)
);
});
// 创建轨迹线,使用更明显的样式
const trailEntity = this.viewer.entities.add({
polyline: {
positions: positions,
width: 4,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.6,
color: Cesium.Color.YELLOW,
}),
clampToGround: false,
// 确保轨迹线在倾斜摄影上显示
heightReference: Cesium.HeightReference.CLAMP_TO_3D_TILE,
},
});
this.trailEntities[this.selectedPerson] = trailEntity;
},
// 清除轨迹
clearTrails() {
for (let key in this.trailEntities) {
this.viewer.entities.remove(this.trailEntities[key]);
}
this.trailEntities = {};
},
// 设置人员列表
personCardList(fn) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian({
x: -2686273.730145489,
y: 4293961.185794622,
z: 3863430.5618300107,
});
const baseLongitude = Cesium.Math.toDegrees(cartographic.longitude);
const baseLatitude = Cesium.Math.toDegrees(cartographic.latitude);
const baseHeight = cartographic.height + 1;
console.log("人员经纬度基准点:", {
longitude: baseLongitude,
latitude: baseLatitude,
height: baseHeight,
});
// 清除现有的人员列表
this.personnelList = [];
// 生成10个不同的经纬度坐标,范围在100米内
for (let index = 0; index < 10; index++) {
// 生成随机偏移量,确保在100米范围内
const lngOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange;
const latOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange;
this.personnelList.push({
lng: baseLongitude + lngOffset,
lat: baseLatitude + latOffset,
height: baseHeight,
perName: "人员" + (index + 1),
status: "online",
avatar: "/static/images/avatars/zhangsan.png",
});
}
// 重新初始化轨迹数据
this.initPersonTrajectories();
fn && fn(this.personnelList);
},
// 设置车辆列表
vehicleCardList() {
const cartographic = Cesium.Cartographic.fromCartesian({
x: -2686273.730145489,
y: 4293961.185794622,
z: 3863430.5618300107,
});
const baseLongitude = Cesium.Math.toDegrees(cartographic.longitude);
const baseLatitude = Cesium.Math.toDegrees(cartographic.latitude);
const baseHeight = cartographic.height + 1;
this.vehicleList = [];
// 生成5个车辆
for (let index = 0; index < 5; index++) {
const lngOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 1.5; // 车辆活动范围更大
const latOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 1.5;
this.vehicleList.push({
lng: baseLongitude + lngOffset,
lat: baseLatitude + latOffset,
height: baseHeight,
vehicleName: "车辆" + (index + 1),
status: "online",
});
}
},
// 初始化车辆轨迹
initVehicleTrajectories() {
const cartographic = Cesium.Cartographic.fromCartesian({
x: -2686273.730145489,
y: 4293961.185794622,
z: 3863430.5618300107,
});
const baseLongitude = Cesium.Math.toDegrees(cartographic.longitude);
const baseLatitude = Cesium.Math.toDegrees(cartographic.latitude);
const baseHeight = cartographic.height + 1;
this.vehicleList.forEach((vehicle) => {
const trajectories = [];
const vehicleBaseLng =
baseLongitude +
(Math.random() - 0.5) * this.trajectoryConfig.maxRange;
const vehicleBaseLat =
baseLatitude + (Math.random() - 0.5) * this.trajectoryConfig.maxRange;
for (let i = 0; i < this.trajectoryConfig.pointCount; i++) {
const lngOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 1.5;
const latOffset =
(Math.random() - 0.5) * this.trajectoryConfig.maxRange * 1.5;
trajectories.push({
time: new Date().getTime() + i * 60000,
lng: vehicleBaseLng + lngOffset,
lat: vehicleBaseLat + latOffset,
height: baseHeight,
});
}
// 为车辆添加轨迹属性
vehicle.trajectories = trajectories;
});
},
/**
* 初始化Cesium地图
*/
async initCesium() {
Cesium.Ion.defaultAccessToken =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZDAxZGFhYy02MjJlLTRiNzktODNhZi00N2VjZGY0NTk4YmIiLCJpZCI6Mjc0NDAxLCJpYXQiOjE3NjMzNDYwNTR9.ZQW2DZ4KaMGbHuwrtIbyI6EdSSvgMJUHmmD74eZW7PQ";
try {
// 创建Cesium Viewer实例
this.viewer = new Cesium.Viewer("cesiumContainer", {
// 设置地图提供者,这里使用默认的Bing Maps
imageryProvider: new Cesium.BingMapsImageryProvider({
url: "https://dev.virtualearth.net",
key: "AgcbDCAOb9zMfquaT4Z-MdHfx--9wUNrLRiiS7rIElFx8f-4lLulxZ0QnhqX5Lm6",
mapStyle: Cesium.BingMapsStyle.AERIAL,
}),
// 配置是否显示各种控件
animation: false, // 动画控件
baseLayerPicker: true, // 底图选择器
fullscreenButton: false, // 全屏按钮
geocoder: false, // 地址搜索
homeButton: false, // 主页按钮
infoBox: false, // 信息框
sceneModePicker: false, // 场景模式选择器
selectionIndicator: false, // 选择指示器
timeline: false, // 时间线
navigationHelpButton: false, // 导航帮助按钮
navigationInstructionsInitiallyVisible: false,
// 设置初始视图位置
center: Cesium.Cartesian3.fromDegrees(104.06, 30.67, 10000000),
});
this.viewer.scene.camera.setView({
// 视角-环翠
duration: 1,
destination: {
x: -2739843.563038797,
y: 4357442.794747324,
z: 3880768.3292693933,
},
orientation: {
heading: 6.037000745578596,
pitch: -1.2499586064720978,
roll: 0.000005306352659495417,
},
});
// 隐藏Cesium logo
this.viewer._cesiumWidget._creditContainer.style.display = "none";
const VUE_APP_GIS =
"http://192.168.2.11:8080/Apps/assets/media/gaoquyingji";
try {
const tileset = await Cesium.Cesium3DTileset.fromUrl(
VUE_APP_GIS + "/tiles/01_guanwei/tileset.json"
);
this.viewer.scene.primitives.add(tileset);
console.log("倾斜摄影模型加载成功tileset", tileset);
if (tileset) {
this.tileset = tileset;
this.locateToTileset();
}
} catch (error) {
console.error(`加载倾斜摄影模型失败: ${error}`);
}
console.log("Cesium地图初始化成功");
} catch (error) {
console.error("Cesium地图初始化失败:", error);
}
},
/**
* 获取倾斜摄影模型的经纬度并将摄像机视角转向模型上方
*/
locateToTileset() {
if (!this.tileset || !this.viewer) {
console.error("模型或视图未准备就绪");
return;
}
try {
// 获取模型的边界球
const boundingSphere = this.tileset.boundingSphere;
if (!boundingSphere) {
console.error("无法获取模型边界");
return;
}
// 获取模型中心点的笛卡尔坐标
const center = boundingSphere.center;
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(center);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
console.log("倾斜摄影模型中心点经纬度:", {
longitude: longitude,
latitude: latitude,
height: height,
});
// 计算合适的观察距离 - 基于模型半径的倍数
const distance = boundingSphere.radius * 2.5; // 可以根据需要调整倍数
// 设置相机位置在模型上方
const cameraPosition = Cesium.Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
height + distance // 相机高度为模型最高点加上观察距离
);
// 计算相机看向模型中心的方向
const heading = Cesium.Math.toRadians(0); // 方向角
const pitch = Cesium.Math.toRadians(-90); // 俯仰角 - 负数表示向下看
const roll = Cesium.Math.toRadians(0); // 翻滚角
// 使用flyTo方法平滑过渡到目标位置
this.viewer.camera.flyTo({
destination: cameraPosition,
orientation: {
heading: heading,
pitch: pitch,
roll: roll,
},
duration: 2, // 过渡时间2秒
complete: () => {
console.log("相机已成功定位到模型上方");
// 初始化车辆轨迹
this.initVehicleTrajectories();
// 创建默认的电子围栏示例
this.createDefaultFences();
// 创建人员和车辆实体
this.createPersonEntities();
this.createVehicleEntities();
},
});
} catch (error) {
console.error("定位到模型上方失败:", error);
}
},
// 创建默认的电子围栏示例
createDefaultFences() {
const cartographic = Cesium.Cartographic.fromCartesian({
x: -2686273.730145489,
y: 4293961.185794622,
z: 3863430.5618300107,
});
const baseLongitude = Cesium.Math.toDegrees(cartographic.longitude);
const baseLatitude = Cesium.Math.toDegrees(cartographic.latitude);
// 创建一个人员电子围栏示例
const personFencePoints = [
{ lng: baseLongitude - 0.0002, lat: baseLatitude - 0.0002 },
{ lng: baseLongitude + 0.0002, lat: baseLatitude - 0.0002 },
{ lng: baseLongitude + 0.0002, lat: baseLatitude + 0.0002 },
{ lng: baseLongitude - 0.0002, lat: baseLatitude + 0.0002 },
];
this.personFences.push({
id: Date.now(),
name: "人员限制区域1",
points: personFencePoints,
type: "person",
color: Cesium.Color.RED.withAlpha(0.3),
borderColor: Cesium.Color.RED,
});
// 创建一个车辆电子围栏示例
const vehicleFencePoints = [
{ lng: baseLongitude - 0.0004, lat: baseLatitude - 0.0004 },
{ lng: baseLongitude + 0.0004, lat: baseLatitude - 0.0004 },
{ lng: baseLongitude + 0.0004, lat: baseLatitude + 0.0004 },
{ lng: baseLongitude - 0.0004, lat: baseLatitude + 0.0004 },
];
this.vehicleFences.push({
id: Date.now() + 1,
name: "车辆限制区域1",
points: vehicleFencePoints,
type: "vehicle",
color: Cesium.Color.BLUE.withAlpha(0.3),
borderColor: Cesium.Color.BLUE,
});
// 渲染所有围栏
this.renderAllFences();
},
// 开始创建电子围栏
startCreatingFence() {
this.isCreatingFence = true;
this.currentFencePoints = [];
if (this.drawingEntity) {
this.viewer.entities.remove(this.drawingEntity);
this.drawingEntity = null;
}
// 添加鼠标点击事件监听
this.viewer.screenSpaceEventHandler.setInputAction((click) => {
const ray = this.viewer.camera.getPickRay(click.position);
const intersection = this.viewer.scene.globe.pick(
ray,
this.viewer.scene
);
if (intersection) {
const cartographic = Cesium.Cartographic.fromCartesian(intersection);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
this.currentFencePoints.push({ lng: longitude, lat: latitude });
this.updateDrawingFence();
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 添加右键点击完成绘制
this.viewer.screenSpaceEventHandler.setInputAction((click) => {
if (this.currentFencePoints.length >= 3) {
this.completeCreatingFence();
} else {
alert("围栏至少需要3个点");
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
},
// 更新绘制中的围栏
updateDrawingFence() {
if (this.drawingEntity) {
this.viewer.entities.remove(this.drawingEntity);
}
if (this.currentFencePoints.length < 2) return;
const positions = this.currentFencePoints.map((point) =>
Cesium.Cartesian3.fromDegrees(point.lng, point.lat, 1)
);
// 闭合多边形
if (this.currentFencePoints.length > 2) {
positions.push(positions[0]);
}
this.drawingEntity = this.viewer.entities.add({
polyline: {
positions: positions,
width: 2,
material: Cesium.Color.YELLOW,
clampToGround: true,
},
});
},
// 完成创建电子围栏
completeCreatingFence() {
const fenceName = prompt("请输入围栏名称:", "新建围栏");
if (!fenceName) return;
const newFence = {
id: Date.now(),
name: fenceName,
points: [...this.currentFencePoints],
type: this.currentFenceType,
color:
this.currentFenceType === "person"
? Cesium.Color.RED.withAlpha(0.3)
: Cesium.Color.BLUE.withAlpha(0.3),
borderColor:
this.currentFenceType === "person"
? Cesium.Color.RED
: Cesium.Color.BLUE,
};
if (this.currentFenceType === "person") {
this.personFences.push(newFence);
} else {
this.vehicleFences.push(newFence);
}
this.renderFence(newFence);
this.stopCreatingFence();
},
// 停止创建电子围栏
stopCreatingFence() {
this.isCreatingFence = false;
// 移除临时绘制的围栏
if (this.drawingEntity) {
this.viewer.entities.remove(this.drawingEntity);
this.drawingEntity = null;
}
// 移除事件监听
this.viewer.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
this.viewer.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.RIGHT_CLICK
);
},
// 选择围栏
selectFence(fence) {
this.selectedFence = fence;
// 高亮显示选中的围栏
this.renderAllFences();
},
// 编辑选中的围栏
editSelectedFence() {
// 这里可以实现围栏编辑功能,简化版暂时只允许重命名
const newName = prompt("请输入新的围栏名称:", this.selectedFence.name);
if (newName) {
this.selectedFence.name = newName;
this.renderAllFences();
}
},
// 删除选中的围栏
deleteSelectedFence() {
if (confirm(`确定要删除围栏"${this.selectedFence.name}"吗?`)) {
// 移除围栏实体
if (this.fenceEntities[this.selectedFence.id]) {
this.viewer.entities.remove(
this.fenceEntities[this.selectedFence.id]
);
delete this.fenceEntities[this.selectedFence.id];
}
// 从数组中移除
if (this.selectedFence.type === "person") {
this.personFences = this.personFences.filter(
(f) => f.id !== this.selectedFence.id
);
} else {
this.vehicleFences = this.vehicleFences.filter(
(f) => f.id !== this.selectedFence.id
);
}
this.selectedFence = null;
}
},
// 渲染所有围栏
renderAllFences() {
// 清除所有围栏实体
for (let id in this.fenceEntities) {
this.viewer.entities.remove(this.fenceEntities[id]);
}
this.fenceEntities = {};
// 重新渲染所有围栏
[...this.personFences, ...this.vehicleFences].forEach((fence) => {
this.renderFence(fence);
});
},
// 渲染单个围栏
renderFence(fence) {
const positions = fence.points.map(
(point) => Cesium.Cartesian3.fromDegrees(point.lng, point.lat, 2) // 稍微抬高一点,避免被地形遮挡
);
// 选择边框颜色,如果是选中的围栏则使用高亮色
const borderColor =
this.selectedFence && this.selectedFence.id === fence.id
? Cesium.Color.YELLOW
: fence.borderColor;
// 创建多边形实体
const fenceEntity = this.viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions),
material: fence.color,
outline: true,
outlineWidth: 2,
outlineColor: borderColor,
heightReference: Cesium.HeightReference.CLAMP_TO_3D_TILE,
disableDepthTestDistance: Number.POSITIVE_INFINITY, // 确保始终显示在最前面
},
});
this.fenceEntities[fence.id] = fenceEntity;
},
// 创建人员实体
createPersonEntities() {
this.personnelList.forEach((person) => {
const position = Cesium.Cartesian3.fromDegrees(
person.lng,
person.lat,
person.height
);
const entity = this.viewer.entities.add({
position: position,
billboard: {
image: "/static/images/avatars/zhangsan.png",
scale: 0.5,
heightReference: Cesium.HeightReference.CLAMP_TO_3D_TILE,
},
label: {
text: person.perName,
font: "14px sans-serif",
backgroundColor: Cesium.Color.BLACK.withAlpha(0.7),
fillColor: Cesium.Color.WHITE,
padding: new Cesium.Cartesian2(5, 5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -10),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
});
this.bgEntities[person.perName] = entity;
});
},
// 创建车辆实体
createVehicleEntities() {
this.vehicleList.forEach((vehicle) => {
const position = Cesium.Cartesian3.fromDegrees(
vehicle.lng,
vehicle.lat,
vehicle.height
);
const entity = this.viewer.entities.add({
position: position,
billboard: {
// 使用默认图标,实际项目中可以替换为车辆图标
image: "/poi-marker-vehicle.png",
scale: 0.5,
heightReference: Cesium.HeightReference.CLAMP_TO_3D_TILE,
},
label: {
text: vehicle.vehicleName,
font: "14px sans-serif",
backgroundColor: Cesium.Color.BLACK.withAlpha(0.7),
fillColor: Cesium.Color.CYAN,
padding: new Cesium.Cartesian2(5, 5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -10),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
});
this.bgEntities[vehicle.vehicleName] = entity;
});
},
// 开始越界检查定时器
startBoundaryCheckInterval() {
this.boundaryCheckInterval = setInterval(() => {
this.checkBoundaryViolations();
}, 3000); // 每3秒检查一次
},
// 检查越界
checkBoundaryViolations() {
// 检查人员越界
this.personnelList.forEach((person) => {
this.personFences.forEach((fence) => {
if (this.isPointInPolygon(person, fence.points)) {
this.addAlarm(`人员${person.perName}进入限制区域:${fence.name}`);
}
});
});
// 检查车辆越界
this.vehicleList.forEach((vehicle) => {
this.vehicleFences.forEach((fence) => {
if (this.isPointInPolygon(vehicle, fence.points)) {
this.addAlarm(
`车辆${vehicle.vehicleName}进入限制区域:${fence.name}`
);
}
});
});
},
// 判断点是否在多边形内(射线法)
isPointInPolygon(point, polygonPoints) {
let inside = false;
for (
let i = 0, j = polygonPoints.length - 1;
i < polygonPoints.length;
j = i++
) {
const xi = polygonPoints[i].lng,
yi = polygonPoints[i].lat;
const xj = polygonPoints[j].lng,
yj = polygonPoints[j].lat;
const intersect =
yi > point.lat != yj > point.lat &&
point.lng < ((xj - xi) * (point.lat - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
},
// 添加告警
addAlarm(content) {
// 检查是否已存在相同的告警(避免重复)
const exists = this.alarms.some((alarm) => alarm.content === content);
if (exists) return;
const alarm = {
id: Date.now(),
content: content,
time: this.formatTime(),
};
this.alarms.unshift(alarm);
// 限制告警数量
if (this.alarms.length > 20) {
this.alarms.pop();
}
// 可以在这里添加告警声音或其他提示
},
},
};
</script>
<style scoped lang="scss">
.home {
width: 100%;
height: 100vh;
position: relative;
overflow: hidden;
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
}
}
// Cesium容器样式
.cesium-container {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
// 追踪控制面板样式
.tracking-panel {
position: absolute;
left: 50%;
top: 20px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
width: 150px;
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 15px;
color: white;
z-index: 100;
select {
padding: 5px 10px;
border-radius: 4px;
border: none;
background: #333;
color: white;
width: 100%;
}
}
// 电子围栏管理面板样式
.fence-panel {
position: absolute;
left: 20px;
top: 20px;
width: 250px;
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 15px;
color: white;
z-index: 100;
.panel-header {
margin-bottom: 15px;
h3 {
margin: 0 0 10px 0;
font-size: 18px;
text-align: center;
}
.fence-type-switch {
display: flex;
justify-content: space-around;
label {
cursor: pointer;
display: flex;
align-items: center;
input {
margin-right: 5px;
}
}
}
}
.fence-controls {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-bottom: 15px;
button {
flex: 1;
min-width: calc(50% - 5px);
padding: 8px 5px;
border: none;
border-radius: 4px;
background: #173349;
color: white;
cursor: pointer;
&:hover:not(:disabled) {
background: #1e4763;
}
&:disabled {
background: #555;
cursor: not-allowed;
}
}
}
.fence-list {
max-height: 200px;
overflow-y: auto;
h4 {
margin: 0 0 10px 0;
font-size: 14px;
}
ul {
list-style: none;
padding: 0;
margin: 0;
li {
padding: 8px;
margin-bottom: 5px;
background: #333;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
&:hover {
background: #444;
}
&.active {
background: #1e4763;
border: 1px solid #fff;
}
}
}
}
}
// 告警面板样式
.alarm-panel {
position: absolute;
right: 20px;
bottom: 20px;
width: 300px;
max-height: 400px;
background: rgba(0, 0, 0, 0.9);
border-radius: 8px;
padding: 15px;
color: white;
z-index: 100;
h3 {
margin: 0 0 15px 0;
font-size: 18px;
color: #ff4444;
text-align: center;
}
.alarm-list {
max-height: 320px;
overflow-y: auto;
}
.alarm-item {
padding: 10px;
margin-bottom: 10px;
background: rgba(255, 68, 68, 0.2);
border-left: 3px solid #ff4444;
border-radius: 4px;
.alarm-time {
display: block;
font-size: 12px;
color: #aaa;
margin-bottom: 5px;
}
.alarm-content {
font-size: 14px;
}
}
}
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment