From 6e436ebfe5113b819ac734a26127e4ba8a578c76 Mon Sep 17 00:00:00 2001 From: suixy <2277317060@qq.com> Date: Sat, 11 Oct 2025 15:53:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/index.vue | 86 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/src/views/index.vue b/src/views/index.vue index b5ae752..96fbc94 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -835,6 +835,83 @@ function getXYDistanceFromMin(current, minPoint) { 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) @@ -855,12 +932,15 @@ const processData = (data) => { lat: data.Latitude, } // boxPos.value = location - let res = getLocalPosition_Point1AsCenter({ + const rectInfo = calcRectangleFromPoints(areaPoints.value); + const point = { lon: data.Longitude, lat: data.Latitude, rotate: data.HeadingAngle - }, areaPoints.value, areaData.value) - console.log(res) + }; + const local = getLocalPositionRelativeToP4(point, areaPoints.value, rectInfo); + + console.log(local) } };