bill 1 year ago
parent
commit
19c8b6924f

+ 0 - 39
pnpm-lock.yaml

@@ -18,7 +18,6 @@ specifiers:
   typescript: ^5.2.2
   vite: ^5.2.0
   vue: ^3.4.21
-  vue-drag-verify2: ^1.2.0
   vue-router: ^4.3.0
   vue-tsc: ^2.0.6
   xlsx: ^0.18.5
@@ -35,7 +34,6 @@ dependencies:
   proj4: 2.11.0
   qrcode: 1.5.3
   vue: 3.4.21_typescript@5.4.3
-  vue-drag-verify2: 1.2.0
   vue-router: 4.3.0_vue@3.4.21
   xlsx: 0.18.5
 
@@ -526,16 +524,6 @@ packages:
       '@vue/compiler-core': 3.4.21
       '@vue/shared': 3.4.21
 
-  /@vue/compiler-sfc/2.7.16:
-    resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==}
-    dependencies:
-      '@babel/parser': 7.24.1
-      postcss: 8.4.38
-      source-map: 0.6.1
-    optionalDependencies:
-      prettier: 2.8.8
-    dev: false
-
   /@vue/compiler-sfc/3.4.21:
     resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
     dependencies:
@@ -1162,14 +1150,6 @@ packages:
       picocolors: 1.0.0
       source-map-js: 1.2.0
 
-  /prettier/2.8.8:
-    resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
-    engines: {node: '>=10.13.0'}
-    hasBin: true
-    requiresBuild: true
-    dev: false
-    optional: true
-
   /process-nextick-args/2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
     dev: false
@@ -1304,11 +1284,6 @@ packages:
     resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
     engines: {node: '>=0.10.0'}
 
-  /source-map/0.6.1:
-    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
-    engines: {node: '>=0.10.0'}
-    dev: false
-
   /ssf/0.11.2:
     resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
     engines: {node: '>=0.8'}
@@ -1413,12 +1388,6 @@ packages:
       vue: 3.4.21_typescript@5.4.3
     dev: false
 
-  /vue-drag-verify2/1.2.0:
-    resolution: {integrity: sha512-Ie6cxw2K1fpDZDYwFaSxfNhJ9NDKWJyXQppDCPakN/HK92DHukdIFfZqaCS9hTgtSF3ZCuaVYYZ8UOYQHiOS7Q==}
-    dependencies:
-      vue: 2.7.16
-    dev: false
-
   /vue-router/4.3.0_vue@3.4.21:
     resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
     peerDependencies:
@@ -1447,14 +1416,6 @@ packages:
       typescript: 5.4.3
     dev: true
 
-  /vue/2.7.16:
-    resolution: {integrity: sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==}
-    deprecated: Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.
-    dependencies:
-      '@vue/compiler-sfc': 2.7.16
-      csstype: 3.1.3
-    dev: false
-
   /vue/3.4.21_typescript@5.4.3:
     resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
     peerDependencies:

+ 80 - 0
src/helper/coord-transform.ts

@@ -0,0 +1,80 @@
+import proj4 from "proj4";
+
+// 屏幕点和真实点通用对象
+type Pos = [number, number, number];
+type Conversion = {
+  scale: number;
+  rotation: number;
+  translate: number[];
+  startAltitude: number[];
+  altitude: number;
+};
+
+// 获取角度
+const getAngle = (p1: Pos, p2: Pos) => Math.atan2(p2[0] - p1[0], p2[1] - p1[1]);
+// 获取长度
+const getLength = (p1: Pos, p2: Pos) =>
+  Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
+
+// 获取本地与魔卡托的映射关系
+const getConversion2D = ([p1, p2]: Pos[], [b1, b2]: Pos[]) => {
+  const rotation = getAngle(p1, p2) - getAngle(b1, b2);
+  const scale = getLength(b1, b2) / getLength(p1, p2);
+  const translate = [
+    b1[0] - scale * (p1[0] * Math.cos(rotation) - p1[1] * Math.sin(rotation)),
+    b1[1] - scale * (p1[0] * Math.sin(rotation) + p1[1] * Math.cos(rotation)),
+  ];
+  const altitude = (b2[2] - b1[2]) / (p2[2] - p1[2]);
+  const startAltitude = [p1[2], b1[2]];
+
+  return {
+    rotation,
+    scale,
+    translate,
+    startAltitude,
+    altitude,
+  };
+};
+
+const transform = (point: Pos, cover: Conversion): Pos => {
+  const ctrla = cover.scale * Math.cos(cover.rotation);
+  const ctrlb = cover.scale * Math.sin(cover.rotation);
+  return [
+    ctrla * point[0] - ctrlb * point[1] + cover.translate[0],
+    ctrlb * point[0] + ctrla * point[1] + cover.translate[1],
+    cover.altitude * (point[2] - cover.startAltitude[0]) +
+      cover.startAltitude[1],
+  ];
+};
+
+const wCoordType = "EPSG:4326";
+const tCoordType = "EPSG:3857";
+
+proj4.defs(wCoordType, "+proj=longlat +ellps=GRS80 +no_defs");
+proj4.defs(
+  tCoordType,
+  "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs"
+);
+
+// 传入本地坐标与控制点的关系
+export const conversionFactory = (locals: [Pos, Pos], gpss: [Pos, Pos]) => {
+  const maps = gpss.map((pos) => proj4(wCoordType, tCoordType, pos));
+  const coverLocalToWeb = getConversion2D(locals, maps);
+  const coverWebToLocal = getConversion2D(maps, locals);
+
+  return {
+    toLocal(pos: Pos): Pos {
+      const tPos = transform(
+        proj4(wCoordType, tCoordType, [...pos]),
+        coverWebToLocal
+      );
+      return tPos;
+    },
+    toWGS84(pos: Pos): Pos {
+      const tPos = transform(pos, coverLocalToWeb);
+      const wPos = proj4(tCoordType, wCoordType, [...tPos]);
+
+      return [wPos[0], wPos[1], tPos[2]];
+    },
+  };
+};

+ 28 - 1
src/request/type.ts

@@ -39,10 +39,36 @@ export type ScenePoint = {
   id: number;
   uuid: number;
   name: string;
-  pos: number[];
+  pos: [number, number, number] | [];
+  location: [number, number, number];
+  centerLocation: [number, number, number];
   sceneCode: string;
 };
 
+export type DefCtrlPoints = {
+  defaultGisP1: [number, number];
+  defaultGisP2: [number, number];
+  defaultLocation1: [number, number, number];
+  defaultLocation2: [number, number, number];
+  panoId1: string;
+  panoId2: string;
+};
+
+export type AutCtrlPoint = {
+  ageControlLocation1: [number, number, number];
+  ageControlLocation2: [number, number, number];
+  gps84ControlCoordinate1: [number, number, number];
+  gps84ControlCoordinate2: [number, number, number];
+  gpsControlCoordinate1: [number, number, number];
+  gpsControlCoordinate2: [number, number, number];
+  gpsRaw1: [string, string, string];
+  gpsRaw2: [string, string, string];
+  roamingPointId1: string;
+  roamingPointId2: string;
+  epsg: string;
+};
+export type CtrlPoints = DefCtrlPoints & AutCtrlPoint & { status: number };
+
 export type Scene = {
   id: number;
   sceneId: number;
@@ -52,6 +78,7 @@ export type Scene = {
   sceneName: string;
   title: string;
   cameraType: DeviceType;
+  controlPoint: CtrlPoints;
   scenePos: ScenePoint[];
   algorithmTime: string;
   endTime: string;

+ 41 - 9
src/store/scene.ts

@@ -4,6 +4,7 @@ import { Scene, ScenePoint } from "@/request/type";
 import { gHeaders } from "@/request/state";
 import { relics } from "./relics";
 import { DeviceType, DeviceType as SceneType } from "./device";
+import { conversionFactory } from "@/helper/coord-transform";
 
 export type { Scene, ScenePoint };
 
@@ -13,7 +14,6 @@ export const scenePoints = computed(() =>
     t.push(
       ...scene.scenePos.map((point) => ({
         ...point,
-
         cameraType: scene.cameraType,
       }))
     );
@@ -39,15 +39,47 @@ export const getPointPano = (point: ScenePoint, tile = false) => {
 };
 export const refreshScenes = async () => {
   const sscenes = await relicsScenesFetch(relicsId.value);
+  scenes.value = sscenes.map((scene) => {
+    const c = scene.controlPoint;
+    let conversion: ReturnType<typeof conversionFactory> | null;
+    c && (c.status = 0);
+    if (
+      c &&
+      c.ageControlLocation1 &&
+      c.ageControlLocation1.length &&
+      c.status !== 0
+    ) {
+      conversion = conversionFactory(
+        [c.ageControlLocation1, c.ageControlLocation2],
+        [c.gpsControlCoordinate1, c.gpsControlCoordinate2]
+      );
+    }
+
+    return {
+      ...scene,
+      scenePos: scene.scenePos.map((pos) => {
+        let coord =
+          scene.calcStatus !== SceneStatus.SUCCESS ? ([] as any) : pos.pos;
+        if (conversion && scene.calcStatus === SceneStatus.SUCCESS) {
+          // 算出当前中心点与地理注册中心点偏差值
+          const center =
+            pos.sceneCode === scene.sceneCode
+              ? [0, 0, 0]
+              : conversion.toLocal(pos.centerLocation);
 
-  scenes.value = sscenes.map((scene) => ({
-    ...scene,
-    scenePos: scene.scenePos.map((pos) => ({
-      ...pos,
-      pos:
-        scene.calcStatus === SceneStatus.SUCCESS ? pos.pos : (undefined as any),
-    })),
-  }));
+          coord = conversion.toWGS84([
+            pos.location[0] + center[0],
+            pos.location[1] + center[1],
+            pos.location[2],
+          ]);
+        }
+        return {
+          ...pos,
+          pos: coord,
+        };
+      }),
+    };
+  });
 };
 
 export const updateScenePointName = async (

+ 1 - 0
src/view/map/map-right.vue

@@ -20,6 +20,7 @@
         <el-tree
           style="max-width: 600px"
           :data="treeNode"
+          :props="{ disabled: 'disable' }"
           node-key="id"
           ref="treeRef"
           :show-checkbox="router.currentRoute.value.name === 'map'"

+ 6 - 3
src/view/map/map.vue

@@ -165,9 +165,12 @@ const flyScene = (scene: Scene) => {
   const totalPos = [0, 0];
   let numCalc = 0;
   for (let i = 0; i < scene.scenePos.length; i++) {
-    totalPos[0] += scene.scenePos[i].pos[0];
-    totalPos[1] += scene.scenePos[i].pos[1];
-    numCalc++;
+    const coord = scene.scenePos[i].pos as number[];
+    if (coord && coord.length > 0) {
+      totalPos[0] += coord[0];
+      totalPos[1] += coord[1];
+      numCalc++;
+    }
   }
 
   totalPos[0] /= numCalc;

+ 19 - 12
src/view/pano/pano.vue

@@ -14,7 +14,7 @@
         size="large"
         style="margin-right: 20px; width: 100px"
         @click="copyGis"
-        v-if="point?.pos"
+        v-if="point?.pos && point.pos.length"
       >
         复制经纬度
       </el-button>
@@ -45,14 +45,19 @@ import { router, setDocTitle } from "@/router";
 import { mergeFuns } from "@/util";
 import { computed, onMounted, onUnmounted, ref, watchEffect } from "vue";
 import { init } from "./env";
-import { updateScenePointName, getPointPano, ScenePoint } from "@/store/scene";
+import {
+  updateScenePointName,
+  getPointPano,
+  ScenePoint,
+  scenePoints,
+} from "@/store/scene";
 import { copyText, toDegrees } from "@/util";
 import { ElMessage } from "element-plus";
-import { relicsScenePosInfoFetch } from "@/request";
 import saveAs from "@/util/file-serve";
 import { DeviceType } from "@/store/device";
+import { initRelics } from "@/store/relics";
 
-type Params = { pid?: string } | null;
+type Params = { pid?: string; relicsId?: string } | null;
 const params = computed(() => router.currentRoute.value.params as Params);
 const panoDomRef = ref<HTMLCanvasElement>();
 const destroyFns: (() => void)[] = [];
@@ -60,15 +65,17 @@ const point = ref<ScenePoint>();
 watchEffect(() => {
   if (params.value?.pid) {
     const pid = Number(params.value!.pid);
-    relicsScenePosInfoFetch(pid)
-      .then((data) => {
-        if (!data) {
-          router.replace({ name: "relics" });
+    point.value = scenePoints.value.find((scene) => scene.id === pid);
+
+    if (!point.value) {
+      initRelics(Number(params.value.relicsId)).then(() => {
+        if (scenePoints.value[pid]) {
+          point.value = scenePoints.value[pid];
         } else {
-          point.value = data;
+          router.replace({ name: "relics" });
         }
-      })
-      .catch(() => router.replace({ name: "relics" }));
+      });
+    }
   }
 });
 
@@ -81,7 +88,7 @@ const update = ref(false);
 const loading = ref(false);
 
 const copyGis = async () => {
-  const pos = point.value!.pos;
+  const pos = point.value!.pos as number[];
   await copyText(
     `经度:${toDegrees(pos[0])}, 纬度: ${toDegrees(pos[1])}, 高程: ${pos[2]}`
   );

+ 2 - 3
src/view/scene.vue

@@ -49,14 +49,14 @@
                 style="width: 250px"
               />
             </el-form-item>
-            <el-form-item label="绑定账号:">
+            <!-- <el-form-item label="绑定账号:">
               <el-input
                 clearable
                 v-model="pageProps.userName"
                 style="width: 250px"
                 placeholder="请输入"
               />
-            </el-form-item>
+            </el-form-item> -->
             <el-form-item v-if="!simple">
               <el-button type="primary" @click="refresh">查询</el-button>
               <el-button type="primary" plain @click="pageProps = { ...initProps }">
@@ -110,7 +110,6 @@
           <TexToolTip :text="row.gpsInfo" />
         </el-table-column>
 
-        <!-- <el-table-column label="绑定账号" prop="userName"></el-table-column> -->
         <el-table-column label="状态" v-slot:default="{ row }">
           <TexToolTip :text="SceneStatusDesc[(row.calcStatus as SceneStatus)]" />
         </el-table-column>