|
|
|
|
@ -1,6 +1,5 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- <div class="app-container" :style="{ transform: `scale(${scaleRatio})`,transformOrigin: `left top` }">-->
|
|
|
|
|
<!-- <div :style="{ transform: `scale(${scaleRatio})`,transformOrigin: `left top` }">-->
|
|
|
|
|
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
<TOP/>
|
|
|
|
|
<LEFT/>
|
|
|
|
|
@ -32,14 +31,66 @@ import {
|
|
|
|
|
UpdateCData, DeleteCData
|
|
|
|
|
} from "@/api/api";
|
|
|
|
|
import {useRouter} from "vue-router";
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
import {ElMessage} from "element-plus";
|
|
|
|
|
|
|
|
|
|
const scaleRatio = ref(window.innerWidth / 1080)
|
|
|
|
|
const onSubmit = (e) => {
|
|
|
|
|
console.log(e)
|
|
|
|
|
}
|
|
|
|
|
const boxPos = ref({x: 100, y: 100, rotate: 0})
|
|
|
|
|
const rulerRef = ref()
|
|
|
|
|
|
|
|
|
|
const getSocket = () => {
|
|
|
|
|
|
|
|
|
|
// const socket = new WebSocket("ws://192.168.1.123:7789/ws");
|
|
|
|
|
const socket = new WebSocket("ws://192.168.1.123:7789/ws");
|
|
|
|
|
|
|
|
|
|
// 2. 连接成功时触发
|
|
|
|
|
socket.addEventListener("open", () => {
|
|
|
|
|
console.log("✅ WebSocket 连接成功");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 3. 接收消息
|
|
|
|
|
socket.addEventListener("message", (event) => {
|
|
|
|
|
processData(JSON.parse(event.data))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 4. 连接关闭时触发
|
|
|
|
|
socket.addEventListener("close", () => {
|
|
|
|
|
console.log("❌ WebSocket 已关闭");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 5. 出错时触发
|
|
|
|
|
socket.addEventListener("error", (error) => {
|
|
|
|
|
console.error("⚠️ WebSocket 出错:", error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const processData = (data) => {
|
|
|
|
|
if (data.FodName === '雷达信息') {
|
|
|
|
|
radarWorkState.value = data.radar_work_state
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === '图像数据') {
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === 'fod信息') {
|
|
|
|
|
setDot(data)
|
|
|
|
|
}
|
|
|
|
|
if (data.ty === 3) {
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === '车辆信息') {
|
|
|
|
|
currentPosition.value = {
|
|
|
|
|
lon: data.Longitude,
|
|
|
|
|
lat: data.Latitude,
|
|
|
|
|
}
|
|
|
|
|
const rectInfo = calcRectangleFromPoints(areaPoints.value);
|
|
|
|
|
const point = {
|
|
|
|
|
lon: data.Longitude,
|
|
|
|
|
lat: data.Latitude,
|
|
|
|
|
rotate: data.HeadingAngle
|
|
|
|
|
};
|
|
|
|
|
const local = getLocalPositionRelativeToP4(point, areaPoints.value, rectInfo);
|
|
|
|
|
|
|
|
|
|
boxPos.value = local
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const TOP = defineComponent({
|
|
|
|
|
name: 'TOP',
|
|
|
|
|
setup() {
|
|
|
|
|
@ -86,7 +137,6 @@ const LEFT = defineComponent({
|
|
|
|
|
<div class="left">
|
|
|
|
|
<Ruler
|
|
|
|
|
ref={rulerRef}
|
|
|
|
|
index={dotIndex.value}
|
|
|
|
|
width={areaData.value.width}
|
|
|
|
|
height={areaData.value.height}
|
|
|
|
|
boxPos={boxPos.value}
|
|
|
|
|
@ -163,7 +213,7 @@ const RIGHT = defineComponent({
|
|
|
|
|
关闭雷达
|
|
|
|
|
</ElButton>
|
|
|
|
|
<ElButton type="warning" onClick={RestartWorkBtn}>重启雷达</ElButton>
|
|
|
|
|
<ElButton type="info" onClick={ShutDownWorkBtn}>急停雷达</ElButton>
|
|
|
|
|
<ElButton type="info" onClick={ShutDownWorkBtn}>关闭雷达</ElButton>
|
|
|
|
|
</ElCard>
|
|
|
|
|
|
|
|
|
|
<ElCard shadow="always" style={{marginTop: "12px"}}>
|
|
|
|
|
@ -360,20 +410,20 @@ const RIGHT = defineComponent({
|
|
|
|
|
</ElCard>
|
|
|
|
|
|
|
|
|
|
<ElCard shadow="always" style={{marginTop: "12px"}}>
|
|
|
|
|
{areaPoints.value.map((i, k) => (
|
|
|
|
|
{regionLabeling.value.map((i, k) => (
|
|
|
|
|
<div style={{marginBottom: "12px"}} key={k}>
|
|
|
|
|
<ElInput disabled onUpdate:modelValue={val => (areaPoints.value[k].name = val)}
|
|
|
|
|
<ElInput disabled onUpdate:modelValue={val => (regionLabeling.value[k].name = val)}
|
|
|
|
|
modelValue={i.name}
|
|
|
|
|
placeholder="点位名称" style={{width: "100px"}}/>
|
|
|
|
|
<ElInput
|
|
|
|
|
modelValue={i.lon} placeholder="经度"
|
|
|
|
|
style={{width: "150px", marginLeft: "20px"}}
|
|
|
|
|
onUpdate:modelValue={val => (areaPoints.value[k].lon = val)}
|
|
|
|
|
onUpdate:modelValue={val => (regionLabeling.value[k].lon = val)}
|
|
|
|
|
/>
|
|
|
|
|
<ElInput
|
|
|
|
|
modelValue={i.lat} placeholder="纬度"
|
|
|
|
|
style={{width: "150px", marginLeft: "20px"}}
|
|
|
|
|
onUpdate:modelValue={val => (areaPoints.value[k].lat = val)}
|
|
|
|
|
onUpdate:modelValue={val => (regionLabeling.value[k].lat = val)}
|
|
|
|
|
/>
|
|
|
|
|
<ElButton type="primary" onClick={() => getPoint(k)}
|
|
|
|
|
style={{marginLeft: "20px"}}>获取</ElButton>
|
|
|
|
|
@ -385,7 +435,7 @@ const RIGHT = defineComponent({
|
|
|
|
|
|
|
|
|
|
<ElButton type="primary" onClick={() => {
|
|
|
|
|
InsertCListData([{
|
|
|
|
|
name: `点位${areaPoints.value.length + 1}`,
|
|
|
|
|
name: `点位${regionLabeling.value.length + 1}`,
|
|
|
|
|
lon: '1',
|
|
|
|
|
lat: '1',
|
|
|
|
|
fodAreaId: form6.value.region1,
|
|
|
|
|
@ -583,91 +633,30 @@ const RIGHT = defineComponent({
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const toAdmin = () => {
|
|
|
|
|
router.push('/serve')
|
|
|
|
|
// 默认方法
|
|
|
|
|
const onSubmit = (e) => {
|
|
|
|
|
console.log(e)
|
|
|
|
|
}
|
|
|
|
|
const areaType = ref(1)
|
|
|
|
|
// setTimeout(() => {
|
|
|
|
|
// setZoom({lon: 120.0005, lat: 30.005}, 2)
|
|
|
|
|
// }, 30000)
|
|
|
|
|
|
|
|
|
|
const socketData = [
|
|
|
|
|
{
|
|
|
|
|
"TimeQuality": 19124,
|
|
|
|
|
"GpsWeek": 2378,
|
|
|
|
|
"GpsSeconds": 443388.33,
|
|
|
|
|
"Latitude": 28.24388795549,
|
|
|
|
|
"Longitude": 113.00382002762,
|
|
|
|
|
"EllipsoidHeight": 14.6323,
|
|
|
|
|
"VelocityNorth": -0.1931,
|
|
|
|
|
"VelocityEast": 3.2447,
|
|
|
|
|
"ActualSpeed": 11.701587,
|
|
|
|
|
"RollAngle": 1.047412,
|
|
|
|
|
"HeadingAngle": 92.054855,
|
|
|
|
|
"IncludedAngle": 0.0,
|
|
|
|
|
"SolutionStatus": "",
|
|
|
|
|
"Fps": 3.485E-42,
|
|
|
|
|
"FpsNum": 0.0,
|
|
|
|
|
"MotorPitchAngle": 0.0,
|
|
|
|
|
"MotorAzimuthAngle": 0.0,
|
|
|
|
|
"ty": 3
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"radar_type": 0,
|
|
|
|
|
"radar_ver": "0.1.1",
|
|
|
|
|
"arm_ver": "0.0.0",
|
|
|
|
|
"al_ver": "0.0.0",
|
|
|
|
|
"pwc_ver": "0.0.0",
|
|
|
|
|
"cd_ver": "0.0.0",
|
|
|
|
|
"v1": 0,
|
|
|
|
|
"v2": 0,
|
|
|
|
|
"v3": 0,
|
|
|
|
|
"v4": 0,
|
|
|
|
|
"radar_total_vol": 23.5,
|
|
|
|
|
"radar_total_cur": 0.0,
|
|
|
|
|
"nx_vol": 0.0,
|
|
|
|
|
"nx_cur": 0.0,
|
|
|
|
|
"nx_temp": 25.0,
|
|
|
|
|
"arm_vol": 23.5,
|
|
|
|
|
"arm_cur": 0.0,
|
|
|
|
|
"arm_temp": 25.0,
|
|
|
|
|
"ant_vol": 23.5,
|
|
|
|
|
"ant_cur": 0.0,
|
|
|
|
|
"ant_temp": 0.0,
|
|
|
|
|
"at_work_area_status": 0,
|
|
|
|
|
"pwb_err_code": 0,
|
|
|
|
|
"pwa_err_code": 0,
|
|
|
|
|
"al_err_code": 0,
|
|
|
|
|
"arm_err_code": 0,
|
|
|
|
|
"radar_err_code": 0,
|
|
|
|
|
"radar_work_state": 0,
|
|
|
|
|
"ty": 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"Seq": 3.0,
|
|
|
|
|
"MD5": null,
|
|
|
|
|
"TimeStamp": 5.644776E+24,
|
|
|
|
|
"MissionID": 5.644776E+24,
|
|
|
|
|
"RngRes": 0.075,
|
|
|
|
|
"RngNum": 0.0,
|
|
|
|
|
"RngMin": 15.0,
|
|
|
|
|
"AziRes": 0.1,
|
|
|
|
|
"AziNum": 0.0,
|
|
|
|
|
"AziMin": 600.0,
|
|
|
|
|
"DataType": 2.8E-44,
|
|
|
|
|
"LonMin": 112.99582,
|
|
|
|
|
"LatMin": 28.242912,
|
|
|
|
|
"TarNum": 6E-45,
|
|
|
|
|
"ty": 4
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
let area = {
|
|
|
|
|
"LatMin": 0,
|
|
|
|
|
"LatMax": 0,
|
|
|
|
|
"LonMin": 0,
|
|
|
|
|
"LonMax": 0,
|
|
|
|
|
// 当前菜单id
|
|
|
|
|
const itemsId = ref(1)
|
|
|
|
|
// 菜单id跳转
|
|
|
|
|
const setItemsId = (e) => {
|
|
|
|
|
itemsId.value = e
|
|
|
|
|
}
|
|
|
|
|
// 雷达状态
|
|
|
|
|
const radarWorkState = ref(0)
|
|
|
|
|
// 车辆位置
|
|
|
|
|
const boxPos = ref({x: 100, y: 100, rotate: 0})
|
|
|
|
|
// 左侧区域宽高
|
|
|
|
|
const areaData = ref({
|
|
|
|
|
width: 500,
|
|
|
|
|
height: 1000,
|
|
|
|
|
angle: 0
|
|
|
|
|
})
|
|
|
|
|
// 缩放等级
|
|
|
|
|
const areaType = ref(1)
|
|
|
|
|
// 障碍物点位
|
|
|
|
|
const dots = ref([
|
|
|
|
|
// {
|
|
|
|
|
// x: 150,
|
|
|
|
|
@ -686,270 +675,18 @@ const dots = ref([
|
|
|
|
|
// y: 125
|
|
|
|
|
// }
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
const points = ref([
|
|
|
|
|
{
|
|
|
|
|
lon: 120.38532472236,
|
|
|
|
|
lat: 36.14505053622,
|
|
|
|
|
name: '点位1',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 120.38532472236,
|
|
|
|
|
lat: 36.15302618219,
|
|
|
|
|
name: '点位2',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 120.39109582218,
|
|
|
|
|
lat: 36.15302618219,
|
|
|
|
|
name: '点位3',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 120.39109582218,
|
|
|
|
|
lat: 36.14505053622,
|
|
|
|
|
name: '点位4',
|
|
|
|
|
},
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
const a = ref(window)
|
|
|
|
|
|
|
|
|
|
const list = ref([
|
|
|
|
|
{
|
|
|
|
|
value1: '点位1',
|
|
|
|
|
value2: '经纬度:(528,11)'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
value1: '点位1',
|
|
|
|
|
value2: '经纬度:(528,11)'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
value1: '点位1',
|
|
|
|
|
value2: '经纬度:(528,11)'
|
|
|
|
|
},
|
|
|
|
|
])
|
|
|
|
|
const rulerRef = ref()
|
|
|
|
|
const itemsId = ref(1)
|
|
|
|
|
const form1 = ref({})
|
|
|
|
|
const form2 = ref({})
|
|
|
|
|
const form3 = ref({})
|
|
|
|
|
const form4 = ref({})
|
|
|
|
|
const form5 = ref({})
|
|
|
|
|
const form6 = ref({})
|
|
|
|
|
const radarWorkState = ref(0)
|
|
|
|
|
// 当前的目标障碍物
|
|
|
|
|
const dotIndex = ref(-1)
|
|
|
|
|
const tableData1 = ref([])
|
|
|
|
|
const tableData2 = ref([
|
|
|
|
|
{
|
|
|
|
|
"id": 2,
|
|
|
|
|
"name": "测试",
|
|
|
|
|
"lon": 12.2299995,
|
|
|
|
|
"lat": 323.329987,
|
|
|
|
|
"deviation": 12,
|
|
|
|
|
"shielding": 20
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": 1,
|
|
|
|
|
"name": "测试",
|
|
|
|
|
"lon": 12.2299995,
|
|
|
|
|
"lat": 323.329987,
|
|
|
|
|
"deviation": 12,
|
|
|
|
|
"shielding": 20
|
|
|
|
|
}
|
|
|
|
|
])
|
|
|
|
|
const date1 = ref([])
|
|
|
|
|
const setItemsId = (e) => {
|
|
|
|
|
itemsId.value = e
|
|
|
|
|
// 跳转到管理界面
|
|
|
|
|
const toAdmin = () => {
|
|
|
|
|
router.push('/serve')
|
|
|
|
|
}
|
|
|
|
|
const locationData = ref({})
|
|
|
|
|
const currentPosition = ref({})
|
|
|
|
|
|
|
|
|
|
function calcRectangleFromPoints1(points) {
|
|
|
|
|
if (!points || points.length !== 4) throw new Error("必须传入四个点");
|
|
|
|
|
|
|
|
|
|
const R = 111320;
|
|
|
|
|
const lat0 = points.reduce((a, b) => a + b.lat, 0) / 4;
|
|
|
|
|
const cosLat = Math.cos((lat0 * Math.PI) / 180);
|
|
|
|
|
|
|
|
|
|
// 经纬度转平面坐标
|
|
|
|
|
const toXY = p => ({
|
|
|
|
|
name: p.name,
|
|
|
|
|
x: p.lon * R * cosLat,
|
|
|
|
|
y: p.lat * R
|
|
|
|
|
});
|
|
|
|
|
const [p1, p2, p3, p4] = points.map(toXY);
|
|
|
|
|
|
|
|
|
|
// 距离函数
|
|
|
|
|
const dist = (a, b) => Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
|
|
|
|
|
|
|
|
|
|
// 各边长度
|
|
|
|
|
const top = dist(p2, p3);
|
|
|
|
|
const bottom = dist(p1, p4);
|
|
|
|
|
const left = dist(p4, p3);
|
|
|
|
|
const right = dist(p1, p2);
|
|
|
|
|
|
|
|
|
|
// 判断梯形:上下边差异超过5%
|
|
|
|
|
const trapezoid = Math.abs(top - bottom) / Math.max(top, bottom) > 0.05;
|
|
|
|
|
|
|
|
|
|
let width, height;
|
|
|
|
|
|
|
|
|
|
if (trapezoid) {
|
|
|
|
|
// 使用平均宽高
|
|
|
|
|
width = (top + bottom) / 2;
|
|
|
|
|
height = (left + right) / 2;
|
|
|
|
|
} else {
|
|
|
|
|
width = bottom;
|
|
|
|
|
height = right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 计算旋转角度(p1→p2)
|
|
|
|
|
const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
width: Math.floor(width.toFixed(2)),
|
|
|
|
|
height: Math.floor(height.toFixed(2)),
|
|
|
|
|
angle: Math.floor(angle.toFixed(2))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getXYDistanceFromMin(current, minPoint) {
|
|
|
|
|
const R = 6371000; // 地球半径(米)
|
|
|
|
|
const toRad = deg => deg * Math.PI / 180;
|
|
|
|
|
|
|
|
|
|
// 计算两点之间某一维的距离
|
|
|
|
|
const haversineDistance = (lat1, lon1, lat2, lon2) => {
|
|
|
|
|
const dLat = toRad(lat2 - lat1);
|
|
|
|
|
const dLon = toRad(lon2 - lon1);
|
|
|
|
|
const a =
|
|
|
|
|
Math.sin(dLat / 2) ** 2 +
|
|
|
|
|
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
|
|
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
|
|
|
return R * c;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 横向距离(经度方向)
|
|
|
|
|
const xDistance = haversineDistance(minPoint.lat, minPoint.lon, minPoint.lat, current.lon);
|
|
|
|
|
// 纵向距离(纬度方向)
|
|
|
|
|
const yDistance = haversineDistance(minPoint.lat, minPoint.lon, current.lat, minPoint.lon);
|
|
|
|
|
|
|
|
|
|
return {xDistance, yDistance};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DEG_TO_RAD = Math.PI / 180;
|
|
|
|
|
|
|
|
|
|
function lonLatToXY(lon, lat, lat0) {
|
|
|
|
|
const R = 111320; // 每度约等于 111.32 km
|
|
|
|
|
const cosLat = Math.cos(lat0 * DEG_TO_RAD);
|
|
|
|
|
return {x: lon * R * cosLat, y: lat * R};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calcRectangleFromPoints(points) {
|
|
|
|
|
if (!points || points.length !== 4) throw new Error("必须传入4个点");
|
|
|
|
|
// 期望 points 中有 name = "点位1","点位2","点位3","点位4"
|
|
|
|
|
const p1raw = points.find(p => p.name === "点位1") || points[0];
|
|
|
|
|
const p2raw = points.find(p => p.name === "点位2") || points[1];
|
|
|
|
|
const p3raw = points.find(p => p.name === "点位3") || points[2];
|
|
|
|
|
const p4raw = points.find(p => p.name === "点位4") || points[3];
|
|
|
|
|
|
|
|
|
|
const lat0 = (points.reduce((s, p) => s + p.lat, 0) / points.length);
|
|
|
|
|
const p1 = lonLatToXY(p1raw.lon, p1raw.lat, lat0);
|
|
|
|
|
const p2 = lonLatToXY(p2raw.lon, p2raw.lat, lat0);
|
|
|
|
|
const p3 = lonLatToXY(p3raw.lon, p3raw.lat, lat0);
|
|
|
|
|
const p4 = lonLatToXY(p4raw.lon, p4raw.lat, lat0);
|
|
|
|
|
|
|
|
|
|
const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
|
|
|
|
|
|
|
|
const top = dist(p2, p3); // 上底 (2->3)
|
|
|
|
|
const bottom = dist(p4, p1); // 下底 (4->1)
|
|
|
|
|
const left = dist(p4, p3); // 左边 (4->3)
|
|
|
|
|
const right = dist(p1, p2); // 右边 (1->2)
|
|
|
|
|
|
|
|
|
|
// 宽高:检测梯形(上下底差异较大)时取平均
|
|
|
|
|
const trapezoid = Math.abs(top - bottom) / Math.max(top, bottom) > 0.05;
|
|
|
|
|
const width = trapezoid ? (top + bottom) / 2 : bottom; // 宽为底边方向的长度
|
|
|
|
|
const height = trapezoid ? (left + right) / 2 : right; // 高为竖直方向的长度
|
|
|
|
|
|
|
|
|
|
// **重要**:矩形角度取为 p4 -> p1(左下到右下)方向的角度
|
|
|
|
|
// atan2 返回的是相对于 +X 的角(弧度),逆时针为正
|
|
|
|
|
const bottomAngleRad = Math.atan2(p1.y - p4.y, p1.x - p4.x);
|
|
|
|
|
const angleDeg = bottomAngleRad * 180 / Math.PI; // 保留度为输出角度
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
width: Number(width.toFixed(2)),
|
|
|
|
|
height: Number(height.toFixed(2)),
|
|
|
|
|
angle: Number(angleDeg.toFixed(6)) // 度,可能是负值或 >180,视位置而定
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getLocalPositionRelativeToP4(point, rectPoints, rectInfo) {
|
|
|
|
|
// rectInfo.angle 必须是由上面的 calcRectangleFromPoints 得到(以 p4->p1 为角度)
|
|
|
|
|
if (!rectInfo || typeof rectInfo.angle !== 'number') {
|
|
|
|
|
throw new Error("rectInfo.angle 必须是由 calcRectangleFromPoints 得到的角度");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lat0 = rectPoints.reduce((a, b) => a + b.lat, 0) / rectPoints.length;
|
|
|
|
|
const p4raw = rectPoints.find(p => p.name === "点位4") || rectPoints[3];
|
|
|
|
|
|
|
|
|
|
const p4 = lonLatToXY(p4raw.lon, p4raw.lat, lat0);
|
|
|
|
|
const p = lonLatToXY(point.lon, point.lat, lat0);
|
|
|
|
|
|
|
|
|
|
// 平移到以 p4 为原点
|
|
|
|
|
const dx = p.x - p4.x;
|
|
|
|
|
const dy = p.y - p4.y;
|
|
|
|
|
|
|
|
|
|
// 把底边旋转到 X 轴:旋转角为 -angle(弧度)
|
|
|
|
|
const rad = -rectInfo.angle * DEG_TO_RAD;
|
|
|
|
|
const x_local = dx * Math.cos(rad) - dy * Math.sin(rad);
|
|
|
|
|
const y_local = dx * Math.sin(rad) + dy * Math.cos(rad);
|
|
|
|
|
|
|
|
|
|
// 点自身相对旋转角(相对于矩形底边方向)
|
|
|
|
|
const rotate_local = ((point.rotate ?? 0) + rectInfo.angle + 360) % 360;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
x: Number(x_local.toFixed(2)),
|
|
|
|
|
y: Number(y_local.toFixed(2)),
|
|
|
|
|
rotate: Number(rotate_local.toFixed(2))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const processData = (data) => {
|
|
|
|
|
// console.log('data',data.ty)
|
|
|
|
|
// console.log('FodName', data.FodName)
|
|
|
|
|
if (data.FodName === '雷达信息') {
|
|
|
|
|
// console.log('雷达信息', data.radar_work_state)
|
|
|
|
|
radarWorkState.value = data.radar_work_state
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === '图像数据') {
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === 'fod信息') {
|
|
|
|
|
console.log(data)
|
|
|
|
|
setDot(data)
|
|
|
|
|
}
|
|
|
|
|
if (data.ty === 3) {
|
|
|
|
|
}
|
|
|
|
|
if (data.FodName === '车辆信息') {
|
|
|
|
|
currentPosition.value = {
|
|
|
|
|
lon: data.Longitude,
|
|
|
|
|
lat: data.Latitude,
|
|
|
|
|
}
|
|
|
|
|
// boxPos.value = location
|
|
|
|
|
const rectInfo = calcRectangleFromPoints(areaPoints.value);
|
|
|
|
|
const point = {
|
|
|
|
|
lon: data.Longitude,
|
|
|
|
|
lat: data.Latitude,
|
|
|
|
|
rotate: data.HeadingAngle
|
|
|
|
|
};
|
|
|
|
|
const local = getLocalPositionRelativeToP4(point, areaPoints.value, rectInfo);
|
|
|
|
|
|
|
|
|
|
// console.log(local)
|
|
|
|
|
boxPos.value = local
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 检测&成像设置
|
|
|
|
|
const parasSignalproForm = ref({
|
|
|
|
|
imaging: {},
|
|
|
|
|
dectection: {}
|
|
|
|
|
})
|
|
|
|
|
// 路线设置
|
|
|
|
|
const parasPosForm = ref({
|
|
|
|
|
runwaynum: {
|
|
|
|
|
startpos_num: 1
|
|
|
|
|
@ -966,66 +703,7 @@ const parasPosForm = ref({
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
getTableData()
|
|
|
|
|
ad()
|
|
|
|
|
getOption()
|
|
|
|
|
getShildTableList()
|
|
|
|
|
points.value = localStorage.getItem('points') ? JSON.parse(localStorage.getItem('points')) : [
|
|
|
|
|
{
|
|
|
|
|
lon: 117.213524,
|
|
|
|
|
lat: 36.837967,
|
|
|
|
|
name: '点位1',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 117.213524,
|
|
|
|
|
lat: 36.847967,
|
|
|
|
|
name: '点位2',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 117.223524,
|
|
|
|
|
lat: 36.847967,
|
|
|
|
|
name: '点位3',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lon: 117.223524,
|
|
|
|
|
lat: 36.837967,
|
|
|
|
|
name: '点位4',
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
getArea1()
|
|
|
|
|
|
|
|
|
|
// setDot({
|
|
|
|
|
// "DarDatas": [{"Lon": 117.213524, "Lat": 36.837967}, {"Lon": 0.0, "Lat": 0.0}, {
|
|
|
|
|
// "Lon": 0.0,
|
|
|
|
|
// "Lat": 0.0
|
|
|
|
|
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.2134, "Lat": 36.837967}, {"Lon": 0.0, "Lat": 0.0}, {
|
|
|
|
|
// "Lon": 0.0,
|
|
|
|
|
// "Lat": 0.0
|
|
|
|
|
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.21341, "Lat": 36.837986}, {"Lon": 0.0, "Lat": 0.0}, {
|
|
|
|
|
// "Lon": 0.0,
|
|
|
|
|
// "Lat": 0.0
|
|
|
|
|
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.21337, "Lat": 36.838}, {"Lon": 0.0, "Lat": 0.0}],
|
|
|
|
|
// "Seq": 0,
|
|
|
|
|
// "MD5": "038fb0493c415f58c703ab205f9f2c94",
|
|
|
|
|
// "TimeStamp": 1757556826,
|
|
|
|
|
// "MissionID": 1757556826,
|
|
|
|
|
// "RngRes": 0.075,
|
|
|
|
|
// "RngNum": 0,
|
|
|
|
|
// "RngMin": 10.0,
|
|
|
|
|
// "AziRes": 0.1,
|
|
|
|
|
// "AziNum": 0,
|
|
|
|
|
// "AziMin": 0.03593219,
|
|
|
|
|
// "DataType": 20,
|
|
|
|
|
// "LonMin": 117.213844,
|
|
|
|
|
// "LatMin": 36.83799,
|
|
|
|
|
// "TarNum": 14,
|
|
|
|
|
// "ty": 0,
|
|
|
|
|
// "FodName": "fod信息"
|
|
|
|
|
// })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 获取配置文件
|
|
|
|
|
const getOption = () => {
|
|
|
|
|
getParasPos().then((e) => {
|
|
|
|
|
parasPosForm.value = {
|
|
|
|
|
@ -1040,16 +718,19 @@ const getOption = () => {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存成像&检测设置
|
|
|
|
|
const saveParasSignalproForm = () => {
|
|
|
|
|
setParasSignalpro(parasSignalproForm.value).then(e => {
|
|
|
|
|
console.log(e)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 保存路线设置
|
|
|
|
|
const saveParasPosForm = () => {
|
|
|
|
|
setParasPos(parasPosForm.value).then(e => {
|
|
|
|
|
console.log(e)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 更新路线数量
|
|
|
|
|
const updateRunwayNum = (e) => {
|
|
|
|
|
let arr = new Array(e).fill(0)
|
|
|
|
|
.map((item, index) => {
|
|
|
|
|
@ -1071,6 +752,25 @@ const updateRunwayNum = (e) => {
|
|
|
|
|
parasPosForm.value.runwayedges = JSON.parse(JSON.stringify(arr))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动雷达
|
|
|
|
|
const StartWorkBtn = () => {
|
|
|
|
|
StartWork()
|
|
|
|
|
rulerRef.value.setDot([], true)
|
|
|
|
|
tableData1.value = []
|
|
|
|
|
}
|
|
|
|
|
// 停止雷达
|
|
|
|
|
const StopWorkBtn = () => {
|
|
|
|
|
StopWork()
|
|
|
|
|
}
|
|
|
|
|
// 重启雷达
|
|
|
|
|
const RestartWorkBtn = () => {
|
|
|
|
|
RestartWork()
|
|
|
|
|
}
|
|
|
|
|
// 关闭雷达
|
|
|
|
|
const ShutDownWorkBtn = () => {
|
|
|
|
|
ShutDownWork()
|
|
|
|
|
}
|
|
|
|
|
// 设置障碍物-不处理
|
|
|
|
|
const addShildItem = () => {
|
|
|
|
|
addShildData({
|
|
|
|
|
name: 'string',
|
|
|
|
|
@ -1082,11 +782,13 @@ const addShildItem = () => {
|
|
|
|
|
getShildTableList()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 删除已处理的障碍物
|
|
|
|
|
const delShildItem = (e) => {
|
|
|
|
|
delShildData(e).then(e => {
|
|
|
|
|
getShildTableList()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 获取已处理的障碍物列表
|
|
|
|
|
const getShildTableList = () => {
|
|
|
|
|
getShildList({
|
|
|
|
|
pageIndex: 1,
|
|
|
|
|
@ -1098,79 +800,109 @@ const getShildTableList = () => {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ad = () => {
|
|
|
|
|
const form1 = ref({})
|
|
|
|
|
const form2 = ref({})
|
|
|
|
|
const form3 = ref({})
|
|
|
|
|
const form4 = ref({})
|
|
|
|
|
const form5 = ref({})
|
|
|
|
|
const form6 = ref({})
|
|
|
|
|
|
|
|
|
|
// 1. 创建 WebSocket 连接(ws:// 或 wss://)
|
|
|
|
|
// const socket = new WebSocket("ws://192.168.1.123:7789/ws");
|
|
|
|
|
const socket = new WebSocket("ws://192.168.1.123:7789/ws");
|
|
|
|
|
const tableData1 = ref([])
|
|
|
|
|
const tableData2 = ref([
|
|
|
|
|
{
|
|
|
|
|
"id": 2,
|
|
|
|
|
"name": "测试",
|
|
|
|
|
"lon": 12.2299995,
|
|
|
|
|
"lat": 323.329987,
|
|
|
|
|
"deviation": 12,
|
|
|
|
|
"shielding": 20
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": 1,
|
|
|
|
|
"name": "测试",
|
|
|
|
|
"lon": 12.2299995,
|
|
|
|
|
"lat": 323.329987,
|
|
|
|
|
"deviation": 12,
|
|
|
|
|
"shielding": 20
|
|
|
|
|
}
|
|
|
|
|
])
|
|
|
|
|
const date1 = ref([])
|
|
|
|
|
const currentPosition = ref({})
|
|
|
|
|
|
|
|
|
|
// 2. 连接成功时触发
|
|
|
|
|
socket.addEventListener("open", () => {
|
|
|
|
|
console.log("✅ WebSocket 连接成功");
|
|
|
|
|
});
|
|
|
|
|
const DEG_TO_RAD = Math.PI / 180;
|
|
|
|
|
|
|
|
|
|
// 3. 接收消息
|
|
|
|
|
socket.addEventListener("message", (event) => {
|
|
|
|
|
// console.log(JSON.parse(event.data))
|
|
|
|
|
processData(JSON.parse(event.data))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 4. 连接关闭时触发
|
|
|
|
|
socket.addEventListener("close", () => {
|
|
|
|
|
console.log("❌ WebSocket 已关闭");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 5. 出错时触发
|
|
|
|
|
socket.addEventListener("error", (error) => {
|
|
|
|
|
console.error("⚠️ WebSocket 出错:", error);
|
|
|
|
|
});
|
|
|
|
|
function lonLatToXY(lon, lat, lat0) {
|
|
|
|
|
const R = 111320; // 每度约等于 111.32 km
|
|
|
|
|
const cosLat = Math.cos(lat0 * DEG_TO_RAD);
|
|
|
|
|
return {x: lon * R * cosLat, y: lat * R};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const StartWorkBtn = () => {
|
|
|
|
|
StartWork()
|
|
|
|
|
rulerRef.value.setDot([], true)
|
|
|
|
|
tableData1.value = []
|
|
|
|
|
function calcRectangleFromPoints(points) {
|
|
|
|
|
if (!points || points.length !== 4) throw new Error("必须传入4个点");
|
|
|
|
|
const p1raw = points.find(p => p.name === "点位1") || points[0];
|
|
|
|
|
const p2raw = points.find(p => p.name === "点位2") || points[1];
|
|
|
|
|
const p3raw = points.find(p => p.name === "点位3") || points[2];
|
|
|
|
|
const p4raw = points.find(p => p.name === "点位4") || points[3];
|
|
|
|
|
|
|
|
|
|
const lat0 = (points.reduce((s, p) => s + p.lat, 0) / points.length);
|
|
|
|
|
const p1 = lonLatToXY(p1raw.lon, p1raw.lat, lat0);
|
|
|
|
|
const p2 = lonLatToXY(p2raw.lon, p2raw.lat, lat0);
|
|
|
|
|
const p3 = lonLatToXY(p3raw.lon, p3raw.lat, lat0);
|
|
|
|
|
const p4 = lonLatToXY(p4raw.lon, p4raw.lat, lat0);
|
|
|
|
|
|
|
|
|
|
const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
|
|
|
|
|
|
|
|
const top = dist(p2, p3);
|
|
|
|
|
const bottom = dist(p4, p1);
|
|
|
|
|
const left = dist(p4, p3);
|
|
|
|
|
const right = dist(p1, p2);
|
|
|
|
|
|
|
|
|
|
const trapezoid = Math.abs(top - bottom) / Math.max(top, bottom) > 0.05;
|
|
|
|
|
const width = trapezoid ? (top + bottom) / 2 : bottom;
|
|
|
|
|
const height = trapezoid ? (left + right) / 2 : right;
|
|
|
|
|
|
|
|
|
|
const bottomAngleRad = Math.atan2(p1.y - p4.y, p1.x - p4.x);
|
|
|
|
|
const angleDeg = bottomAngleRad * 180 / Math.PI;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
width: Number(width.toFixed(2)),
|
|
|
|
|
height: Number(height.toFixed(2)),
|
|
|
|
|
angle: Number(angleDeg.toFixed(6))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
const StopWorkBtn = () => {
|
|
|
|
|
StopWork()
|
|
|
|
|
}
|
|
|
|
|
const RestartWorkBtn = () => {
|
|
|
|
|
RestartWork()
|
|
|
|
|
}
|
|
|
|
|
const ShutDownWorkBtn = () => {
|
|
|
|
|
ShutDownWork()
|
|
|
|
|
|
|
|
|
|
function getLocalPositionRelativeToP4(point, rectPoints, rectInfo) {
|
|
|
|
|
if (!rectInfo || typeof rectInfo.angle !== 'number') {
|
|
|
|
|
throw new Error("rectInfo.angle 必须是由 calcRectangleFromPoints 得到的角度");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lat0 = rectPoints.reduce((a, b) => a + b.lat, 0) / rectPoints.length;
|
|
|
|
|
const p4raw = rectPoints.find(p => p.name === "点位4") || rectPoints[3];
|
|
|
|
|
|
|
|
|
|
const p4 = lonLatToXY(p4raw.lon, p4raw.lat, lat0);
|
|
|
|
|
const p = lonLatToXY(point.lon, point.lat, lat0);
|
|
|
|
|
|
|
|
|
|
const dx = p.x - p4.x;
|
|
|
|
|
const dy = p.y - p4.y;
|
|
|
|
|
|
|
|
|
|
const rad = -rectInfo.angle * DEG_TO_RAD;
|
|
|
|
|
const x_local = dx * Math.cos(rad) - dy * Math.sin(rad);
|
|
|
|
|
const y_local = dx * Math.sin(rad) + dy * Math.cos(rad);
|
|
|
|
|
|
|
|
|
|
const rotate_local = ((point.rotate ?? 0) + rectInfo.angle + 360) % 360;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
x: Number(x_local.toFixed(2)),
|
|
|
|
|
y: Number(y_local.toFixed(2)),
|
|
|
|
|
rotate: Number(rotate_local.toFixed(2))
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getPoint = (k) => {
|
|
|
|
|
areaPoints.value[k].lon = currentPosition.value.lon || 0
|
|
|
|
|
areaPoints.value[k].lat = currentPosition.value.lat || 0
|
|
|
|
|
}
|
|
|
|
|
const getArea1 = () => {
|
|
|
|
|
if (points.value.length < 4) return
|
|
|
|
|
let data = points.value
|
|
|
|
|
|
|
|
|
|
let latMin = data[0].lat;
|
|
|
|
|
let latMax = data[0].lat;
|
|
|
|
|
let lonMin = data[0].lon;
|
|
|
|
|
let lonMax = data[0].lon;
|
|
|
|
|
|
|
|
|
|
for (let i = 1; i < data.length; i++) {
|
|
|
|
|
const p = data[i];
|
|
|
|
|
if (p.lat < latMin) latMin = p.lat;
|
|
|
|
|
if (p.lat > latMax) latMax = p.lat;
|
|
|
|
|
if (p.lon < lonMin) lonMin = p.lon;
|
|
|
|
|
if (p.lon > lonMax) lonMax = p.lon;
|
|
|
|
|
}
|
|
|
|
|
// area = {
|
|
|
|
|
// LatMin: latMin,
|
|
|
|
|
// LatMax: latMax,
|
|
|
|
|
// LonMin: lonMin,
|
|
|
|
|
// LonMax: lonMax,
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
const savePoint = () => {
|
|
|
|
|
localStorage.setItem('points', JSON.stringify(points.value))
|
|
|
|
|
getArea1()
|
|
|
|
|
}
|
|
|
|
|
const setDot = (e) => {
|
|
|
|
|
let dots = e.DarDatas.map((v, k) => {
|
|
|
|
|
if (v.Lon == 0 && v.Lat == 0) return null
|
|
|
|
|
@ -1222,152 +954,49 @@ const select2Update = (val) => {
|
|
|
|
|
const select3Update = (val) => {
|
|
|
|
|
form6.value.region1 = val
|
|
|
|
|
}
|
|
|
|
|
const areaPoints = ref([])
|
|
|
|
|
|
|
|
|
|
// 区域标定页面获取区域信息
|
|
|
|
|
const getArea2 = () => {
|
|
|
|
|
GetAllCData({areaId: form6.value.region1}).then((res) => {
|
|
|
|
|
areaPoints.value = res.data
|
|
|
|
|
regionLabeling.value = res.data
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getBoundingBoxAndSize(pointsArr) {
|
|
|
|
|
if (!pointsArr || pointsArr.length === 0) {
|
|
|
|
|
throw new Error('pointsArr 不能为空');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let maxLon = Math.max(...pointsArr.map(p => p.lon));
|
|
|
|
|
let minLon = Math.min(...pointsArr.map(p => p.lon));
|
|
|
|
|
let maxLat = Math.max(...pointsArr.map(p => p.lat));
|
|
|
|
|
let minLat = Math.min(...pointsArr.map(p => p.lat));
|
|
|
|
|
|
|
|
|
|
const R = 6371000;
|
|
|
|
|
const toRad = deg => deg * Math.PI / 180;
|
|
|
|
|
|
|
|
|
|
// Haversine 距离计算
|
|
|
|
|
const haversineDistance = (lat1, lon1, lat2, lon2) => {
|
|
|
|
|
const dLat = toRad(lat2 - lat1);
|
|
|
|
|
const dLon = toRad(lon2 - lon1);
|
|
|
|
|
const a =
|
|
|
|
|
Math.sin(dLat / 2) ** 2 +
|
|
|
|
|
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
|
|
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
|
|
|
return R * c;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 宽度(东西方向)
|
|
|
|
|
const width = Math.round(haversineDistance(minLat, minLon, minLat, maxLon));
|
|
|
|
|
// 高度(南北方向)
|
|
|
|
|
const height = Math.round(haversineDistance(minLat, minLon, maxLat, minLon));
|
|
|
|
|
|
|
|
|
|
// 左下角参考点
|
|
|
|
|
const refPoint = {lon: maxLon, lat: minLat};
|
|
|
|
|
|
|
|
|
|
// 找出距离 refPoint 最近的点
|
|
|
|
|
let nearestPoint = null;
|
|
|
|
|
let nearestDistance = Infinity;
|
|
|
|
|
|
|
|
|
|
for (const p of pointsArr) {
|
|
|
|
|
const d = haversineDistance(refPoint.lat, refPoint.lon, p.lat, p.lon);
|
|
|
|
|
if (d < nearestDistance) {
|
|
|
|
|
nearestDistance = d;
|
|
|
|
|
nearestPoint = p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nearestPoint.name === '点位1') {
|
|
|
|
|
areaType.value = 1
|
|
|
|
|
}
|
|
|
|
|
if (nearestPoint.name === '点位2') {
|
|
|
|
|
areaType.value = 2
|
|
|
|
|
}
|
|
|
|
|
if (nearestPoint.name === '点位3') {
|
|
|
|
|
areaType.value = 3
|
|
|
|
|
}
|
|
|
|
|
if (nearestPoint.name === '点位4') {
|
|
|
|
|
areaType.value = 4
|
|
|
|
|
}
|
|
|
|
|
console.log(nearestPoint)
|
|
|
|
|
return {
|
|
|
|
|
width: (areaType.value === 1 || areaType.value === 3) ? width : height,
|
|
|
|
|
height: (areaType.value === 1 || areaType.value === 3) ? height : width,
|
|
|
|
|
minLat,
|
|
|
|
|
minLon,
|
|
|
|
|
maxLat,
|
|
|
|
|
maxLon,
|
|
|
|
|
nearestPoint, // 距离左下角最近的点
|
|
|
|
|
nearestDistance: Math.round(nearestDistance) // 方便调试用
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getLocalPosition_Point1AsCenter(point, rectPoints, rectInfo) {
|
|
|
|
|
const R = 111320;
|
|
|
|
|
const lat0 = rectPoints.reduce((a, b) => a + b.lat, 0) / rectPoints.length;
|
|
|
|
|
const cosLat = Math.cos((lat0 * Math.PI) / 180);
|
|
|
|
|
const toXY = p => ({
|
|
|
|
|
name: p.name,
|
|
|
|
|
x: p.lon * R * cosLat,
|
|
|
|
|
y: p.lat * R
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 转换所有点为平面坐标
|
|
|
|
|
const pts = rectPoints.map(toXY);
|
|
|
|
|
const p1 = pts.find(p => p.name === "点位1"); // 右下角 ✅ 旋转中心
|
|
|
|
|
const p4 = pts.find(p => p.name === "点位4"); // 左下角 ✅ 局部坐标系原点
|
|
|
|
|
const p = toXY(point);
|
|
|
|
|
const angle = Number(rectInfo.angle);
|
|
|
|
|
const rad = (-angle * Math.PI) / 180;
|
|
|
|
|
|
|
|
|
|
// 将矩形“扶正”:对所有点执行同样的逆旋转
|
|
|
|
|
const rotateToLocal = (x, y) => ({
|
|
|
|
|
x: (x - p1.x) * Math.cos(rad) - (y - p1.y) * Math.sin(rad),
|
|
|
|
|
y: (x - p1.x) * Math.sin(rad) + (y - p1.y) * Math.cos(rad)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 旋转后的坐标
|
|
|
|
|
const p_local = rotateToLocal(p.x, p.y);
|
|
|
|
|
const p4_local = rotateToLocal(p4.x, p4.y);
|
|
|
|
|
|
|
|
|
|
// 相对于左下角的坐标
|
|
|
|
|
const x_local = p_local.x - p4_local.x;
|
|
|
|
|
const y_local = p_local.y - p4_local.y;
|
|
|
|
|
|
|
|
|
|
// 相对旋转角
|
|
|
|
|
const rotate_local = ((point.rotate ?? 0) - angle + 360) % 360;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
x: x_local.toFixed(2),
|
|
|
|
|
y: y_local.toFixed(2),
|
|
|
|
|
rotate: rotate_local.toFixed(2)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const areaData = ref({
|
|
|
|
|
width: 500,
|
|
|
|
|
height: 1000,
|
|
|
|
|
angle: 0
|
|
|
|
|
})
|
|
|
|
|
// 区域标定信息
|
|
|
|
|
const regionLabeling = ref([])
|
|
|
|
|
// 区域点位信息
|
|
|
|
|
const areaPoints = ref([])
|
|
|
|
|
// 保存区域信息
|
|
|
|
|
const saveAreaPoint = () => {
|
|
|
|
|
let arr = []
|
|
|
|
|
areaPoints.value.forEach((v, k) => {
|
|
|
|
|
regionLabeling.value.forEach((v, k) => {
|
|
|
|
|
arr.push(UpdateCData(v))
|
|
|
|
|
})
|
|
|
|
|
Promise.all(arr).then(() => {
|
|
|
|
|
areaPoints.value = JSON.parse(JSON.stringify(regionLabeling.value))
|
|
|
|
|
ElMessage.success('保存成功')
|
|
|
|
|
let data = calcRectangleFromPoints(areaPoints.value)
|
|
|
|
|
console.log(data)
|
|
|
|
|
areaData.value = data
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
ElMessage.error(err)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 主界面获取区域信息
|
|
|
|
|
const getAreaData = () => {
|
|
|
|
|
|
|
|
|
|
GetAllCData({areaId: form1.value.region1}).then((res) => {
|
|
|
|
|
areaPoints.value = res.data
|
|
|
|
|
let data = calcRectangleFromPoints(res.data)
|
|
|
|
|
areaData.value = data
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
getTableData()
|
|
|
|
|
getSocket()
|
|
|
|
|
getOption()
|
|
|
|
|
getShildTableList()
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
<style>
|
|
|
|
|
.app-container {
|
|
|
|
|
|