Ver Fonte

提交优化点位,检测区域

wangming há 5 dias atrás
pai
commit
cec554598b

+ 4 - 1
src/pages/home/home.vue

@@ -219,7 +219,10 @@ export default {
                         "clientIDetail",
                         this.devDevice[0].clientId
                     );
-                    uni.setStorageSync("northAngle", item.northAngle);
+                    uni.setStorageSync(
+                        "northAngle",
+                        this.devDevice[0].northAngle
+                    );
                     uni.navigateTo({
                         url:
                             "/pagesA/deviceDetail/deviceDetail?devItem=" +

+ 26 - 10
src/pagesA/adDevice/adDevice.vue

@@ -95,13 +95,13 @@
                         <text>X轴范围(cm)</text>
                         <view class="inputBox">
                             <input
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="xxStart"
                                 placeholder="X开始"
                             /><text>—</text>
                             <input
                                 type="number"
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="xxEnd"
                                 placeholder="X结束"
                             />
@@ -111,13 +111,13 @@
                         <text>Y轴范围(cm)</text>
                         <view class="inputBox">
                             <input
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="yyStart"
                                 placeholder="Y开始"
                             /><text>—</text>
                             <input
                                 type="number"
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="yyEnd"
                                 placeholder="Y结束"
                             />
@@ -127,13 +127,13 @@
                         <text>Z轴范围(cm)</text>
                         <view class="inputBox">
                             <input
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="zzStart"
                                 placeholder="Z开始"
                             /><text>—</text>
                             <input
                                 type="number"
-                                style="width: 30%"
+                                style="width: 120rpx"
                                 v-model="zzEnd"
                                 placeholder="Z结束"
                             />
@@ -144,6 +144,7 @@
                         <view class="inputBox">
                             <input
                                 type="number"
+                                style="width: 120rpx"
                                 v-model="height"
                                 placeholder="请输入安装高度"
                             />
@@ -156,17 +157,26 @@
                                 @change="bindPickerChangeTwo"
                                 :value="northAngle"
                                 :range="angleArray"
-                                style="margin-left: auto"
+                                style="
+                                    margin-left: auto;
+                                    width: 100rpx;
+                                    text-align: right;
+                                "
                             >
                                 <view class="uni-input">{{
                                     angleArray[northAngleIndex]
                                 }}</view>
                             </picker>
-                            <!-- <image
+                            <image
                                 src="../../static/rightArrow.png"
                                 alt=""
                                 @click="showPicker"
-                            ></image> -->
+                                style="
+                                    width: 30rpx;
+                                    height: 30rpx;
+                                    margin-top: 8rpx;
+                                "
+                            ></image>
                         </view>
                     </view>
                     <!-- <view class="wifItem" style="margin-top: 30rpx">
@@ -477,6 +487,10 @@ export default {
                                 duration: 1500,
                             });
                             uni.setStorageSync("devId", res.data.data.devId);
+                            uni.setStorageSync(
+                                "northAngle",
+                                res.data.data.northAngle
+                            );
 
                             setTimeout(() => {
                                 uni.navigateBack({
@@ -580,6 +594,8 @@ export default {
             this.wifiName = devInfo.wifiName;
             this.wifiPassword = devInfo.wifiPassword;
             this.northAngle = devInfo.northAngle;
+            this.northAngleIndex = this.angleArray.indexOf(this.northAngle);
+
             if (this.northAngle == 0) {
                 this.northAngleIndex = 0;
             } else if (this.northAngle == 90) {
@@ -728,7 +744,7 @@ export default {
             }
             input {
                 margin-left: auto;
-                text-align: right;
+                text-align: center;
             }
 
             .refresh {

+ 93 - 128
src/pagesA/deviceDetail/deviceDetail.vue

@@ -7,14 +7,11 @@
         <view class="radar-box">
             <view
                 :style="{
-                    width: `${length}rpx`,
-                    height: `${width}rpx`,
+                    width: `${rotatedRect.width}rpx`,
+                    height: `${rotatedRect.height}rpx`,
                     position: 'absolute',
-                    top: '50%',
-                    left: '50%',
-                    transform: `translate(calc(-50% + ${
-                        xOffset / 2
-                    }rpx), calc(-50% + ${yOffset / 2}rpx))`,
+                    top: `${rotatedRect.top}rpx`,
+                    left: `${rotatedRect.left}rpx`,
                     border: `9rpx solid #333333`,
                 }"
                 class="tranStyle"
@@ -35,7 +32,7 @@
                             left: `${item.left}rpx`,
                             transform: `rotate(${item.rotate}deg)`,
                             'transform-origin': 'center center',
-                            zIndex: 4444,
+                            zIndex: 444,
                         }"
                     >
                         <image
@@ -320,6 +317,11 @@
 <script>
 import * as echarts from "../../uni_modules/lime-echart/static/echarts.min";
 import MqttService from "../../utils/globalMqtt.js";
+import {
+    convert_region_r2c,
+    rotateRect,
+    convert_furniture_r2c,
+} from "../../utils/changezb.js";
 
 export default {
     data() {
@@ -327,8 +329,6 @@ export default {
             clientId: "",
             width: 0, //检测区域宽度
             length: 0, //检测区域长度
-            xOffset: 0,
-            yOffset: 0,
             devInfo: "",
             actionName: "",
             startDate: "",
@@ -424,8 +424,10 @@ export default {
             setIntervalVal: null,
 
             // 重新计算雷达坐标位置
-            x_radar: 200,
-            y_radar: 200,
+            x_radar: 250,
+            y_radar: 250,
+            //检测区域计算
+            rotatedRect: {},
         };
     },
     computed: {},
@@ -449,8 +451,8 @@ export default {
                             this.devInfo.xxEnd - this.devInfo.xxStart
                         );
                         this.statusLight = this.devInfo.statusLight;
-                        this.calculate(this.width, this.length);
-                        this.calculateOffest();
+                        // this.calculate(this.width, this.length);
+                        this.calculateRegion();
                         // 设备分享权限判断
                         this.shareJudge =
                             this.devInfo.userId == uni.getStorageSync("userId")
@@ -467,14 +469,32 @@ export default {
                     devId: devId,
                 })
                 .then((res) => {
-                    if (res.data.data) {
-                        res.data.data.furnitures.forEach((item) => {
-                            item.left = this.x_radar + item.x;
-                            item.top = this.y_radar - item.y;
-                        });
+                    const pRadar = {
+                        x: this.x_radar,
+                        y: this.y_radar,
+                        angle: uni.getStorageSync("northAngle"),
+                        mountPlain: this.devInfo.mountPlain,
+                    };
 
+                    if (res.data.data) {
                         this.modules = res.data.data.furnitures;
                     }
+
+                    console.log(this.modules, 88888);
+                    this.modules.forEach((item) => {
+                        const rect = convert_furniture_r2c(item, pRadar);
+                        const rotatedRect = rotateRect(
+                            rect,
+                            pRadar,
+                            pRadar.angle
+                        );
+                        // console.log(rotatedRect, 999999);
+                        item.top = rotatedRect.top;
+                        item.left = rotatedRect.left;
+                        item.width = rotatedRect.width;
+                        item.height = rotatedRect.height;
+                    });
+                    console.log(this.modules, 99999);
                 });
         },
         // 处理设备状态灯
@@ -877,46 +897,21 @@ export default {
                     ...this.targetPoints,
                     ...newTargetPoints,
                 };
+                const northAngle = uni.getStorageSync("northAngle");
+                const radar = [this.x_radar, this.y_radar];
+                let points = [];
                 if (Array.isArray(this.targetPoints)) {
-                    this.targetPoints = this.targetPoints.filter(
-                        (item) => item !== null && item !== undefined
-                    );
+                    points = this.targetPoints;
+                } else if (
+                    this.targetPoints &&
+                    typeof this.targetPoints === "object"
+                ) {
+                    points = Object.values(this.targetPoints);
                 }
-                // console.log(
-                //     this.targetPoints,
-                //     this.devInfo,
-                //     "更新后的点位数据111"
-                // );
-                // this.targetPoints = this.targetPoints.map((point) => {
-                //     return this.rotatePoint(
-                //         point,
-                //         [this.x_radar, this.y_radar],
-                //         this.devInfo.northAngle
-                //     );
-                // });
-
-                // if (Array.isArray(this.targetPoints)) {
-                //     // 多个点
-                //     this.targetPoints = this.targetPoints.map((p) => {
-                //         return this.rotatePoint(
-                //             p,
-                //             [this.x_radar, this.y_radar],
-                //             uni.getStorageSync("northAngle")
-                //         );
-                //     });
-                // } else if (
-                //     this.targetPoints &&
-                //     typeof this.targetPoints === "object"
-                // ) {
-                //     // 单个点
-                //     this.targetPoints = this.rotatePoint(
-                //         this.targetPoints,
-                //         [this.x_radar, this.y_radar],
-                //         uni.getStorageSync("northAngle")
-                //     );
-                // }
-
-                // console.log(this.targetPoints, "更新后的点位数据333");
+                this.targetPoints = points.map((p) => {
+                    return this.rotatePoint(p, radar, northAngle);
+                });
+                console.log(this.targetPoints, "更新后的点位数据333");
             }
         },
         createNewTargetPoint(x, y, z, id) {
@@ -925,8 +920,8 @@ export default {
                 y,
                 z,
                 id,
-                displayX: this.x_radar + x,
-                displayY: this.y_radar - y,
+                displayX: x,
+                displayY: y,
                 lastX: x,
                 lastY: y,
             };
@@ -944,45 +939,25 @@ export default {
                     z,
                     lastX: x,
                     lastY: y,
-                    displayX: this.x_radar + x,
-                    displayY: this.y_radar - y,
+                    displayX: x,
+                    displayY: y,
                 };
             }
 
             return existingPoint;
         },
-
+        // 计算点位问题
         rotatePoint(point, radar, angle) {
-            console.log(point, radar, angle, "rotatePoint");
-            const [cx, cy] = radar;
-            const dx = point.displayX - cx;
-            const dy = point.displayY - cy;
-            let nx, ny;
-
-            switch (angle) {
-                case 0:
-                    nx = dx;
-                    ny = dy;
-                    break;
-                case 90:
-                    nx = dy;
-                    ny = -dx;
-                    break;
-                case 180:
-                    nx = -dx;
-                    ny = -dy;
-                    break;
-                case 270:
-                    nx = -dy;
-                    ny = dx;
-                    break;
-                default:
-                    throw new Error("angle must be 0, 90, 180, 270");
-            }
-
-            // ✅ 更新点坐标
-            point.displayX = cx + nx;
-            point.displayY = cy + ny;
+            const cx = this.x_radar;
+            const cy = this.y_radar;
+            const rad = (angle * Math.PI) / 180;
+            const cosA = Math.cos(rad);
+            const sinA = Math.sin(rad);
+            const xRot = point.x * cosA + point.y * sinA;
+            const yRot = -point.x * sinA + point.y * cosA;
+
+            point.displayX = cx + xRot;
+            point.displayY = cy - yRot;
             return point;
         },
 
@@ -996,38 +971,28 @@ export default {
             console.log(this.xOffset, this.yOffset, this.zoomTimes, "偏移量");
             this.lnbActionJudean = true;
         },
-        calculateOffest() {
-            let xxStart = "";
-            let xxEnd = "";
-            let yyStart = "";
-            let yyEnd = "";
-
-            if (this.devInfo.northAngle == 0) {
-                xxStart = this.devInfo.xxStart;
-                xxEnd = this.devInfo.xxEnd;
-                yyStart = this.devInfo.yyStart;
-                yyEnd = this.devInfo.yyEnd;
-            }
-            if (this.devInfo.northAngle == 90) {
-                xxStart = this.devInfo.xxStart;
-                xxEnd = this.devInfo.xxEnd;
-                yyStart = -this.devInfo.yyEnd;
-                yyEnd = -this.devInfo.yyStart;
-            }
-            if (this.devInfo.northAngle == 180) {
-                xxStart = -this.devInfo.xxEnd;
-                xxEnd = -this.devInfo.xxStart;
-                yyStart = -this.devInfo.yyEnd;
-                yyEnd = -this.devInfo.yyStart;
-            }
-            if (this.devInfo.northAngle == 270) {
-                xxStart = -this.devInfo.xxEnd;
-                xxEnd = -this.devInfo.xxStart;
-                yyStart = this.devInfo.yyStart;
-                yyEnd = this.devInfo.yyEnd;
-            }
-            this.xOffset = xxStart + xxEnd;
-            this.yOffset = -(yyStart + yyEnd);
+        calculateRegion() {
+            let x_cm_start = this.devInfo.xxStart;
+            let y_cm_start = this.devInfo.yyStart;
+            let x_cm_stop = this.devInfo.xxEnd;
+            let y_cm_stop = this.devInfo.yyEnd;
+
+            const trackingRegion = {
+                x_cm_start,
+                y_cm_start,
+                x_cm_stop,
+                y_cm_stop,
+            };
+
+            const pRadar = {
+                x: this.x_radar,
+                y: this.y_radar,
+                angle: uni.getStorageSync("northAngle"),
+                mountPlain: this.devInfo.mountPlain,
+            };
+            const rect = convert_region_r2c(trackingRegion, pRadar);
+            this.rotatedRect = rotateRect(rect, pRadar, pRadar.angle);
+            console.log(this.rotatedRect, "rotatedRect");
         },
 
         formatTime(time) {
@@ -1208,8 +1173,8 @@ export default {
         // display: flex;
         // align-items: center;
         // justify-content: center;
-        width: 400rpx;
-        height: 400rpx;
+        width: 500rpx;
+        height: 500rpx;
         background: #ffffff;
         border-radius: 37.5rpx;
         box-sizing: border-box;
@@ -1551,7 +1516,7 @@ export default {
         display: flex;
         justify-content: center;
         align-items: center;
-        z-index: 333;
+        z-index: 555;
 
         .modal-container {
             width: 80%;
@@ -1632,7 +1597,7 @@ export default {
             position: fixed;
             top: 10rpx;
             right: 10rpx;
-            z-index: 333;
+            z-index: 555;
         }
     }
 }

+ 5 - 1
src/pagesA/devices/devices.vue

@@ -233,7 +233,11 @@ export default {
     onHide() {
         this.showModle = false;
         if (this.unsubscribeFns) {
-            this.unsubscribeFns.forEach((fn) => fn && fn());
+            this.unsubscribeFns.forEach((fn) => {
+                if (fn) {
+                    fn(); // 执行一次取消订阅
+                }
+            });
             this.unsubscribeFns = [];
         }
     },

+ 126 - 61
src/pagesA/roomSetting/roomSetting.vue

@@ -4,14 +4,11 @@
             <view class="radar-box">
                 <view
                     :style="{
-                        width: `${length}rpx`,
-                        height: `${width}rpx`,
+                        width: `${rotatedRect.width}rpx`,
+                        height: `${rotatedRect.height}rpx`,
                         position: 'absolute',
-                        top: '50%',
-                        left: '50%',
-                        transform: `translate(calc(-50% + ${
-                            xOffset / 2
-                        }rpx), calc(-50% + ${yOffset / 2}rpx))`,
+                        top: `${rotatedRect.top}rpx`,
+                        left: `${rotatedRect.left}rpx`,
                         border: `9rpx solid #333333`,
                     }"
                     class="tranStyle"
@@ -254,6 +251,14 @@
 </template>
 <script>
 import MqttService from "../../utils/globalMqtt.js";
+import {
+    convert_region_r2c,
+    rotateRect,
+    convert_furniture_r2c,
+    convert_furniture_save,
+    rotateRectReverse,
+} from "../../utils/changezb.js";
+
 export default {
     name: "my",
     data() {
@@ -409,8 +414,9 @@ export default {
             clientId: null,
 
             // 重新计算雷达坐标位置
-            x_radar: 200,
-            y_radar: 200,
+            x_radar: 250,
+            y_radar: 250,
+            rotatedRect: {},
         };
     },
     computed: {},
@@ -470,8 +476,8 @@ export default {
                 type: featuriesType,
                 width: 0,
                 length: 0,
-                top: 200,
-                left: 200,
+                top: this.y_radar,
+                left: this.x_radar,
                 rotate: 0,
             };
             switch (featuriesType) {
@@ -643,21 +649,35 @@ export default {
         },
 
         saveRoom() {
-            console.log(this.modules, 9999);
-
-            if (this.modules.length > 0) {
-                this.modules.forEach((item) => {
-                    item.x = item.left - this.x_radar;
-                    item.y = this.y_radar - item.top;
-                });
-            }
+            console.log(this.modules, 88888);
 
+            const pRadar = {
+                x: this.x_radar,
+                y: this.y_radar,
+                angle: uni.getStorageSync("northAngle"),
+                mountPlain: "wall",
+            };
+            let copyModule = JSON.parse(JSON.stringify(this.modules));
+
+            copyModule.forEach((item) => {
+                const rect = convert_furniture_save(item, pRadar);
+                const rotatedRect = rotateRectReverse(
+                    rect,
+                    pRadar,
+                    pRadar.angle
+                );
+                console.log(rotatedRect, 999999);
+                item.x = rotatedRect.x;
+                item.y = rotatedRect.y;
+                item.width = rotatedRect.width;
+                item.length = rotatedRect.length;
+            });
             this.$http
                 .post(
                     "wap/room/saveRoom",
                     JSON.stringify({
                         devId: this.devId,
-                        furnitures: this.modules,
+                        furnitures: copyModule,
                     }),
                     {
                         header: {
@@ -704,7 +724,7 @@ export default {
                         this.length = Math.abs(
                             this.devInfo.xxEnd - this.devInfo.xxStart
                         );
-                        this.calculateOffest();
+                        this.calculateRegion();
                         this.statusLight = this.devInfo.statusLight;
                         this.xxStart = this.devInfo.xxStart;
                         this.xxEnd = this.devInfo.xxEnd;
@@ -721,40 +741,44 @@ export default {
                     console.log(err, 8888);
                 });
         },
+        // 计算检测区域问题
+        calculateRegion() {
+            let x_cm_start = this.devInfo.xxStart;
+            let y_cm_start = this.devInfo.yyStart;
+            let x_cm_stop = this.devInfo.xxEnd;
+            let y_cm_stop = this.devInfo.yyEnd;
+
+            const trackingRegion = {
+                x_cm_start,
+                y_cm_start,
+                x_cm_stop,
+                y_cm_stop,
+            };
 
-        calculateOffest() {
-            let xxStart = "";
-            let xxEnd = "";
-            let yyStart = "";
-            let yyEnd = "";
-            if (this.devInfo.northAngle == 0) {
-                xxStart = this.devInfo.xxStart;
-                xxEnd = this.devInfo.xxEnd;
-                yyStart = this.devInfo.yyStart;
-                yyEnd = this.devInfo.yyEnd;
-            }
-            if (this.devInfo.northAngle == 90) {
-                xxStart = this.devInfo.xxStart;
-                xxEnd = this.devInfo.xxEnd;
-                yyStart = -this.devInfo.yyEnd;
-                yyEnd = -this.devInfo.yyStart;
-            }
-            if (this.devInfo.northAngle == 180) {
-                xxStart = -this.devInfo.xxEnd;
-                xxEnd = -this.devInfo.xxStart;
-                yyStart = -this.devInfo.yyEnd;
-                yyEnd = -this.devInfo.yyStart;
-            }
-            if (this.devInfo.northAngle == 270) {
-                xxStart = -this.devInfo.xxEnd;
-                xxEnd = -this.devInfo.xxStart;
-                yyStart = this.devInfo.yyStart;
-                yyEnd = this.devInfo.yyEnd;
-            }
-            this.xOffset = xxStart + xxEnd;
-            this.yOffset = -(yyStart + yyEnd);
+            const pRadar = {
+                x: this.x_radar,
+                y: this.y_radar,
+                angle: uni.getStorageSync("northAngle"),
+                mountPlain: this.devInfo.mountPlain,
+            };
+            const rect = convert_region_r2c(trackingRegion, pRadar);
+            this.rotatedRect = rotateRect(rect, pRadar, pRadar.angle);
+            console.log(this.rotatedRect, "rotatedRect");
         },
         getRoomInfo(devId) {
+            // const trackingRegion = {
+            //     x_cm_start,
+            //     y_cm_start,
+            //     x_cm_stop,
+            //     y_cm_stop,
+            // };
+            const pRadar = {
+                x: this.x_radar,
+                y: this.y_radar,
+                angle: uni.getStorageSync("northAngle"),
+                mountPlain: "wall",
+            };
+
             this.$http
                 .get(`wap/room/readRoom`, {
                     devId: devId,
@@ -763,6 +787,23 @@ export default {
                     if (res.data.data) {
                         this.modules = res.data.data.furnitures;
                     }
+                    console.log(this.modules, 88888);
+                    this.modules.forEach((item) => {
+                        const rect = convert_furniture_r2c(item, pRadar);
+                        const rotatedRect = rotateRect(
+                            rect,
+                            pRadar,
+                            pRadar.angle
+                        );
+                        console.log(rotatedRect, 999999);
+                        item.top = rotatedRect.x;
+                        item.left = rotatedRect.y;
+                        item.x = rotatedRect.x;
+                        item.y = rotatedRect.y;
+                        item.width = rotatedRect.width;
+                        item.height = rotatedRect.height;
+                    });
+                    console.log(this.modules, 99999);
                 });
         },
 
@@ -839,21 +880,45 @@ export default {
                     ...newTargetPoints,
                 };
                 // console.log(this.targetPoints, "更新后的点位数据2222");
+                const northAngle = uni.getStorageSync("northAngle");
+                const radar = [this.x_radar, this.y_radar];
+                let points = [];
                 if (Array.isArray(this.targetPoints)) {
-                    this.targetPoints = this.targetPoints.filter(
-                        (item) => item !== null && item !== undefined
-                    );
+                    points = this.targetPoints;
+                } else if (
+                    this.targetPoints &&
+                    typeof this.targetPoints === "object"
+                ) {
+                    points = Object.values(this.targetPoints);
                 }
+                this.targetPoints = points.map((p) => {
+                    return this.rotatePoint(p, radar, northAngle);
+                });
+                // console.log(this.targetPoints, "更新后的点位数据333");
             }
         },
+
+        rotatePoint(point, radar, angle) {
+            const cx = this.x_radar;
+            const cy = this.y_radar;
+            const rad = (angle * Math.PI) / 180;
+            const cosA = Math.cos(rad);
+            const sinA = Math.sin(rad);
+            const xRot = point.x * cosA + point.y * sinA;
+            const yRot = -point.x * sinA + point.y * cosA;
+
+            point.displayX = cx + xRot;
+            point.displayY = cy - yRot;
+            return point;
+        },
         createNewTargetPoint(x, y, z, id) {
             return {
                 x,
                 y,
                 z,
                 id,
-                displayX: this.x_radar + x,
-                displayY: this.y_radar - y,
+                displayX: x,
+                displayY: y,
                 lastX: x,
                 lastY: y,
             };
@@ -871,8 +936,8 @@ export default {
                     z,
                     lastX: x,
                     lastY: y,
-                    displayX: this.x_radar + x,
-                    displayY: this.y_radar - y,
+                    displayX: x,
+                    displayY: y,
                 };
             }
 
@@ -1028,8 +1093,8 @@ export default {
         .radar-box {
             margin: 0 auto;
             position: relative;
-            width: 400rpx;
-            height: 400rpx;
+            width: 500rpx;
+            height: 500rpx;
             background: #ffffff;
             border-radius: 37.5rpx;
             box-sizing: border-box;

+ 281 - 0
src/utils/changezb.js

@@ -0,0 +1,281 @@
+// src/helpers/helper.js
+
+// ===============================
+// 坐标转换工具函数集 (coordConverter.js)
+// ===============================
+
+
+// ======== 坐标转换 ========
+/**
+ * 检测区域、子区域 矩形转换 雷达坐标系 --> 画布坐标系
+ * @param {Object} src_rect - 雷达坐标系矩形
+ * @param {Object} p_radar - 画布中雷达的位置
+ * @returns {Object} CSS 可用矩形
+ */
+export function convert_region_r2c(src_rect, p_radar) {
+    //   console.log('src_rect: ', src_rect)
+    const left = p_radar.x + src_rect.x_cm_start;
+    const top = p_radar.y - src_rect.y_cm_stop;
+    const width = src_rect.x_cm_stop - src_rect.x_cm_start;
+    const height = src_rect.y_cm_stop - src_rect.y_cm_start;
+
+    return { left, top, width, height };
+}
+
+/**
+ * 检测区域、子区域 矩形转换 画布坐标系 --> 雷达坐标系
+ * @param {Object} dst_rect - 画布矩形
+ * @param {Object} p_radar - 雷达在画布坐标系中的位置
+ * @returns {Object} 雷达坐标矩形
+ */
+export function convert_region_c2r(dst_rect, p_radar) {
+    const x_cm_start = dst_rect.left - p_radar.x;
+    const x_cm_stop = x_cm_start + dst_rect.width;
+    const y_cm_stop = p_radar.y - dst_rect.top;
+    const y_cm_start = y_cm_stop - dst_rect.height;
+
+    return {
+        x_cm_start,
+        x_cm_stop,
+        y_cm_start,
+        y_cm_stop
+    };
+}
+
+/**
+ * 家具 矩形转换 雷达坐标系 --> 画布坐标系
+ * @param {Object} furniture - 雷达坐标家具对象
+ * @param {Object} p_radar - 雷达在画布上的坐标
+ * @returns {Object} CSS 可用家具矩形
+ */
+export function convert_furniture_r2c(furniture, p_radar) {
+    const left = p_radar.x + furniture.x;
+    const top = p_radar.y - furniture.y;
+    const width = furniture.width;
+    const height = furniture.length;
+    //   console.log('convert_furniture_r2c', p_radar, furniture, {left, top, width, height})
+
+    return {
+        left,
+        top,
+        width,
+        height
+    };
+}
+
+/**
+ * 家具 矩形转换 画布坐标系 --> 雷达坐标系
+ * @param {Object} furniture_item - 画布矩形(CSS)
+ * @param {Object} p_radar - 雷达在画布上的坐标
+ * @returns {Object} 雷达坐标家具矩形
+ */
+export function convert_furniture_c2r(furniture_item, p_radar) {
+    const x = furniture_item.left - p_radar.x;
+    const y = p_radar.y - furniture_item.top;
+    const width = furniture_item.width;
+    const height = furniture_item.height;
+
+    return {
+        x,
+        y,
+        width,
+        height
+    };
+}
+
+
+/**
+ * 将雷达坐标系中的点转换到画布坐标系(旋转 + 平移)
+ * @param {{x: number, y: number}} src_point - 雷达坐标系中的点
+ * @param {{x: number, y: number}} pRadar - 雷达在画布坐标系中的坐标
+ * @param {number} angle - 雷达顺时针旋转角度(度)
+ * @returns {{x: number, y: number}} - 画布坐标系中的点
+ */
+export function convert_point_r2c(src_point, pRadar, angle) {
+    const rad = (angle * Math.PI) / 180; // 角度转弧度(顺时针为正)
+    const cosA = Math.cos(rad);
+    const sinA = Math.sin(rad);
+
+    // 顺时针旋转
+    const xRot = src_point.x * cosA + src_point.y * sinA;
+    const yRot = -src_point.x * sinA + src_point.y * cosA;
+
+    // 平移到画布坐标系
+    return {
+        x: pRadar.x + xRot,
+        y: pRadar.y - yRot,
+    };
+}
+
+
+
+
+// ======== 旋转 ========
+
+/**
+ * 顺时针旋转矩形(家具)
+ * @param {Object} src_rect - 输入矩形 { left, top, width, height }
+ * @param {Object} pRadar - 雷达中心坐标 { x, y }
+ * @param {number} angle - 顺时针旋转角度 0, 90, 180, 270
+ * @returns {Object} 旋转后的矩形 { left, top, width, height }
+ */
+export function rotateRect(src_rect, pRadar, angle) {
+    if (![0, 90, 180, 270].includes(angle)) angle = 0
+
+    const { left, top, width, height } = src_rect
+    const cx = left + width / 2
+    const cy = top + height / 2
+
+    let dx = cx - pRadar.x
+    let dy = cy - pRadar.y
+
+    let new_dx, new_dy
+
+    switch (angle) {
+        case 0:
+            new_dx = dx
+            new_dy = dy
+            break
+        case 90: // 顺时针 90°
+            new_dx = -dy
+            new_dy = dx
+            break
+        case 180:
+            new_dx = -dx
+            new_dy = -dy
+            break
+        case 270: // 顺时针 270° = 逆时针 90°
+            new_dx = dy
+            new_dy = -dx
+            break
+    }
+
+    const new_cx = pRadar.x + new_dx
+    const new_cy = pRadar.y + new_dy
+
+    // 对于 90/270 旋转,宽高交换
+    let new_width = width
+    let new_height = height
+    if (angle === 90 || angle === 270) {
+        new_width = height
+        new_height = width
+    }
+
+    return {
+        left: new_cx - new_width / 2,
+        top: new_cy - new_height / 2,
+        width: new_width,
+        height: new_height
+    }
+}
+
+
+
+/**
+ * 坐标系:x正轴朝右→, y正轴朝上↑
+ * 将 src_point 绕 point 旋转 angle 度
+ * @param {{x: number, y: number}} src_point - 原始点
+ * @param {{x: number, y: number}} point - 旋转中心点
+ * @param {number} angle - 旋转角度(度数)
+ * @returns {{x: number, y: number}} - 旋转后的点
+ */
+export function rotatePoint(src_point, point, angle) {
+    // console.log('rotatePoint 输入:', { src_point, point, angle });
+    const rad = (-angle * Math.PI) / 180; // 顺时针旋转
+    const cosA = Math.cos(rad);
+    const sinA = Math.sin(rad);
+
+    const x = src_point.x - point.x;
+    const y = src_point.y - point.y;
+
+    const xRot = x * cosA - y * sinA;
+    const yRot = x * sinA + y * cosA;
+
+    const result = {
+        x: parseFloat((xRot + point.x).toFixed(6)),
+        y: parseFloat((yRot + point.y).toFixed(6)),
+    };
+
+    // console.log('rotatePoint 返回:', result);
+    return result;
+}
+
+// 正向保存家具的方法
+
+// 从画布坐标系(c)转换为雷达坐标系(r)
+export function convert_furniture_save(furniture, p_radar) {
+    const x = furniture.left - p_radar.x;
+    const y = p_radar.y - furniture.top;
+    const width = furniture.width;
+    const length = furniture.length;
+
+    return {
+        x,
+        y,
+        width,
+        length
+    };
+}
+
+// 反向旋转:将画布坐标系的矩形,按指定角度反旋转回雷达坐标
+// 把画布坐标的家具位置旋转回雷达坐标系(用于保存)
+
+export function rotateRectReverse(src_rect, pRadar, angle) {
+    console.log('rotateRectReverse 输入:', { src_rect, pRadar, angle });
+    if (![0, 90, 180, 270].includes(angle)) angle = 0;
+
+    // ✅ 注意这里要用 length
+    let { x, y, width, length } = src_rect;
+
+    // 计算中心点
+    const cx = pRadar.x + x + width / 2;
+    const cy = pRadar.y - y - length / 2;
+
+    // 相对雷达点偏移
+    let dx = cx - pRadar.x;
+    let dy = cy - pRadar.y;
+    let new_dx, new_dy;
+
+    // 与 rotateRect 方向相反(逆旋转)
+    switch (angle) {
+        case 0:
+            new_dx = dx;
+            new_dy = dy;
+            break;
+        case 90: // 原来顺时针90°,现在逆时针90°
+            new_dx = dy;
+            new_dy = -dx;
+            break;
+        case 180:
+            new_dx = -dx;
+            new_dy = -dy;
+            break;
+        case 270: // 原来顺时针270°(=逆时针90°)
+            new_dx = -dy;
+            new_dy = dx;
+            break;
+    }
+
+    const new_cx = pRadar.x + new_dx;
+    const new_cy = pRadar.y + new_dy;
+
+    // 对于 90/270,宽高要交换回来
+    let new_width = width;
+    let new_length = length;
+    if (angle === 90 || angle === 270) {
+        new_width = length;
+        new_length = width;
+    }
+
+    // ⚠️ 注意:这里是雷达坐标系
+    const new_x = new_cx - pRadar.x;
+    const new_y = pRadar.y - new_cy;
+
+    return {
+        x: new_x,
+        y: new_y,
+        width: new_width,
+        length: new_length
+    };
+}
+

+ 0 - 56
src/utils/rotatePoint.js

@@ -1,56 +0,0 @@
-/**
- * point: [x, y]
- * radar: [radarX, radarY]  //雷达在画布的坐标 目前是200,200
- * angle: 0, 90, 180, 270 顺时针旋转角度
- * 返回旋转后的点 [x2, y2]
- */
-function rotatePoint(point, radar, angle) {
-    const [x, y] = point;
-    const [cx, cy] = radar;
-    const dx = x - cx;
-    const dy = y - cy;
-    let nx, ny;
-
-    switch (angle) {
-        case 0:
-            nx = dx;
-            ny = dy;
-            break;
-        case 90:
-            nx = dy;
-            ny = -dx;
-            break;
-        case 180:
-            nx = -dx;
-            ny = -dy;
-            break;
-        case 270:
-            nx = -dy;
-            ny = dx;
-            break;
-        default:
-            throw new Error("angle must be 0, 90, 180, 270");
-    }
-
-    return [cx + nx, cy + ny];
-}
-
-// ✅ 导出函数
-export default rotatePoint;
-
-
-
-
-// 测试
-// const point = [3, 2];
-// const radar = [2, 1];
-
-// [0, 90, 180, 270].forEach(angle => {
-//     const newPoint = rotatePoint(point, radar, angle);
-//     console.log(`angle=${angle}:`, newPoint);
-// });
-// 预期输出
-// angle=0: [3, 2]
-// angle=90: [2, 0]
-// angle=180: [1, 0]
-// angle=270: [2, 2]

+ 0 - 75
src/utils/rotateRect.js

@@ -1,75 +0,0 @@
-/**
- * rect: [left, top, w, h]
- * radar: [radarX, radarY]
- * angle: 0, 90, 180, 270
- * 返回旋转后的矩形 [left, top, w, h]
- */
-function rotateRect(rect, radar, angle) {
-    const [left, top, w, h] = rect;
-    const [cx, cy] = radar;
-
-    // 矩形四个角
-    const corners = [
-        [left, top],
-        [left + w, top],
-        [left + w, top + h],
-        [left, top + h]
-    ];
-
-    const newCorners = corners.map(([x, y]) => {
-        const dx = x - cx;
-        const dy = y - cy;
-        let nx, ny;
-        switch (angle) {
-            case 0:
-                nx = dx;
-                ny = dy;
-                break;
-            case 90:
-                nx = dy;
-                ny = -dx;
-                break;
-            case 180:
-                nx = -dx;
-                ny = -dy;
-                break;
-            case 270:
-                nx = -dy;
-                ny = dx;
-                break;
-            default:
-                throw new Error("angle must be 0, 90, 180, 270");
-        }
-        return [cx + nx, cy + ny];
-    });
-
-    const xs = newCorners.map(p => p[0]);
-    const ys = newCorners.map(p => p[1]);
-
-    const newLeft = Math.min(...xs);
-    const newTop = Math.min(...ys);
-    const newW = Math.max(...xs) - newLeft;
-    const newH = Math.max(...ys) - newTop;
-
-    return [newLeft, newTop, newW, newH];
-}
-
-// 测试
-const rect = [0, 0, 2, 1];
-const radar = [2, 1];
-
-[0, 90, 180, 270].forEach(angle => {
-    const newRect = rotateRect(rect, radar, angle);
-    console.log(`angle=${angle}:`, newRect);
-});
-
-// 预期输出
-// angle=0: [0, 0, 2, 1]
-// angle=90: [2, -1, 1, 2]
-// angle=180: [2, 1, 2, 1]
-// angle=270: [1, 1, 1, 2]
-
-
-
-
-