Explorar el Código

对接setPose getPose

bill hace 11 meses
padre
commit
35b50d8a32

+ 9 - 0
src/api/guide-path.ts

@@ -17,6 +17,7 @@ interface ServiceGuidePath {
   time: number
   sort: number
   speed: number
+  panoInfo?: string
   cover: string
 }
 
@@ -25,6 +26,12 @@ export interface GuidePath {
   guideId: Guide['id'],
   position: SceneLocalPos
   target: SceneLocalPos
+  panoInfo?: {
+    panoId: any,
+    modelId: string,
+    posInModel: SceneLocalPos,
+    rotInModel: SceneLocalPos
+  },
   time: number
   sort: number
   speed: number
@@ -39,10 +46,12 @@ const serviceToLocal = (servicePath: ServiceGuidePath): GuidePath => ({
   target: JSON.parse(servicePath.target),
   position: JSON.parse(servicePath.position),
   id: servicePath.guidePathId.toString(),
+  panoInfo: servicePath.panoInfo && JSON.parse(servicePath.panoInfo)
 })
 
 const localToService = (path: GuidePath): ServiceGuidePath => ({
   ...path,
+  panoInfo: path.panoInfo && JSON.stringify(path.panoInfo),
   guideId: Number(path.guideId),
   target: JSON.stringify(path.target),
   position: JSON.stringify(path.position),

+ 6 - 4
src/api/setting.ts

@@ -2,8 +2,6 @@ import { GET_SETTING, UPDATE_SETTING } from "./constant";
 import defaultCover from "@/assets/pic.jpg";
 import { params } from "@/env";
 import axios from "./instance";
-import { uploadFile } from "./sys";
-import { FuseModel } from "@/store";
 
 type ServeSetting = {
   settingsId?: string;
@@ -18,8 +16,12 @@ export type Setting = {
   pose?: {
     position: SceneLocalPos;
     target: SceneLocalPos;
-    mode?: "fuse" | "pano" | null;
-    model?: FuseModel | null;
+    panoInfo?: {
+      panoId: any,
+      modelId: string,
+      posInModel: SceneLocalPos,
+      rotInModel: SceneLocalPos
+    },
   };
   cover: string;
   back: string;

+ 1 - 19
src/sdk/association/fuseMode.ts

@@ -1,4 +1,4 @@
-import { sdk, SDK, SceneModel, ModelAttrRange } from "../sdk";
+import { SDK, SceneModel, ModelAttrRange } from "../sdk";
 import { toRaw, watch, reactive, ref } from "vue";
 import { custom, getResource } from "@/env";
 import {
@@ -144,24 +144,6 @@ const setModels = (sdk: SDK, models: FuseModels, oldModels: FuseModels) => {
   }
 };
 
-export const getSupperPanoModel = () => {
-  const supperModel = ref<FuseModel | null>(null);
-
-  sdk.sceneBus.on("cameraChange", () => {
-    const data = sdk.canTurnToPanoMode();
-    if (data?.model) {
-      for (const [f, s] of sceneModelMap.entries()) {
-        if (toRaw(data.model) === toRaw(s)) {
-          supperModel.value = f;
-          return;
-        }
-      }
-    }
-    supperModel.value = null;
-  });
-
-  return supperModel;
-};
 
 export const associationModels = (sdk: SDK) => {
   // watch(

+ 2 - 2
src/sdk/association/guide.ts

@@ -18,6 +18,7 @@ import {
 } from '@/store'
 
 import type { FuseModel, FuseModels, Guide } from '@/store'
+import { analysisPoseInfo } from '.'
 
 // -----------------导览关联--------------------
 
@@ -130,7 +131,7 @@ export const playSceneGuide = async (guide: Guide, changeIndexCallback?: (index:
   // pauseRecovery = await recovery(guide)
   isScenePlayIng.value = ScenePlayIngEnum.ing
 
-  const sceneGuide = sdk.enterSceneGuide(paths)
+  const sceneGuide = sdk.enterSceneGuide(paths.map(path => ({ ...path, ...analysisPoseInfo(path)})))
 
   changeIndexCallback && sceneGuide.bus.on('changePoint', changeIndexCallback)
 
@@ -169,7 +170,6 @@ export const playSceneGuide = async (guide: Guide, changeIndexCallback?: (index:
 }
 
 export const pauseSceneGuide = () => {
-  console.error('pause?')
   isScenePlayIng.value = ScenePlayIngEnum.stop
   pauseRecovery && pauseRecovery()
 }

+ 73 - 4
src/sdk/association/index.ts

@@ -1,11 +1,80 @@
-import { nextTick, watchEffect } from "vue"
-import { SDK } from "../sdk"
-import { associationModels } from "./fuseMode"
-import { fuseModelsLoaded, setting } from "@/store"
+import { nextTick, ref, toRaw, watchEffect } from "vue"
+import {Pose, SceneModel, sdk, SDK } from "../sdk"
+import { associationModels, sceneModelMap } from "./fuseMode"
+import { FuseModel, fuseModelsLoaded, GuidePath, setting } from "@/store"
 import { associationTaggings } from "./tagging"
 import { associationSetting } from "./setting"
 import { associationMessaures } from "./measure"
 
+
+export const getSupperPanoModel = () => {
+  const supperModel = ref<FuseModel | null>(null);
+
+  sdk.sceneBus.on("cameraChange", () => {
+    const data = sdk.canTurnToPanoMode();
+    if (data?.model) {
+      for (const [f, s] of sceneModelMap.entries()) {
+        if (toRaw(data.model) === toRaw(s)) {
+          supperModel.value = f;
+          return;
+        }
+      }
+    }
+    supperModel.value = null;
+  });
+
+  return supperModel;
+};
+
+export const analysisPose = (pose: Pose) => {
+  if ('model' in pose) {
+    let info: GuidePath['panoInfo'] | undefined = undefined
+    let fuseMode: FuseModel
+    for (const [k, v] of Array.from(sceneModelMap.entries())) {
+      if (toRaw(v) === toRaw(pose.model)) {
+        fuseMode = toRaw(k)
+      }
+    }
+    if (fuseMode!) {
+      info = {
+        panoId: pose.panoId,
+        modelId: fuseMode.id,
+        posInModel: pose.posInModel,
+        rotInModel: pose.rotInModel
+      }
+      return {
+        position: pose.position,
+        target: pose.target,
+        panoInfo: info
+      }
+    }
+  } 
+  return pose
+}
+
+export const analysisPoseInfo = (info: ReturnType<typeof analysisPose>) => {
+  let pose: Pose = { target: info.target, position: info.position }
+  if ('panoInfo' in info) {
+    let sceneModel: SceneModel
+    for (const [k, v] of Array.from(sceneModelMap.entries())) {
+      if (k.id === info.panoInfo.modelId) {
+        sceneModel = toRaw(v)
+      }
+    }
+    
+    if (sceneModel!) {
+      pose = {
+        ...pose,
+        model: sceneModel,
+        panoId: info.panoInfo.panoId,
+        posInModel: info.panoInfo.posInModel,
+        rotInModel: info.panoInfo.rotInModel,
+      }
+    }
+  }
+  return pose
+}
+
 export const setupAssociation = (mountEl: HTMLDivElement, sdk: SDK) => {
   associationModels(sdk)
 

+ 5 - 13
src/sdk/association/setting.ts

@@ -1,8 +1,7 @@
 import { setting } from "@/store";
 import { nextTick, watchEffect } from "vue";
 import { SDK } from "../sdk";
-import { getSceneModel, sceneModelMap } from "./fuseMode";
-import { custom } from '@/env'
+import { analysisPoseInfo } from ".";
 
 export const associationSetting = (sdk: SDK, mountEl: HTMLDivElement) => {
   watchEffect(() => {
@@ -11,17 +10,10 @@ export const associationSetting = (sdk: SDK, mountEl: HTMLDivElement) => {
 
   const stopWatchPose = watchEffect(() => {
     if (!setting.value?.pose) return;
-
-    setting.value && setting.value.pose && sdk.comeTo(setting.value.pose);
-
-    const modelId = setting.value.pose.model?.id
-    if (setting.value.pose.mode === "pano" && modelId) {
-      const fuseModel = Array.from(sceneModelMap.keys()).find(item => item.id === modelId)
-      const sceneModel = getSceneModel(fuseModel);
-      if (fuseModel && sceneModel && sceneModel.supportPano()) {
-        custom.showMode = 'pano'
-        custom.currentModel = fuseModel
-      }
+    if (sdk.setPose) {
+      sdk.setPose(analysisPoseInfo(setting.value.pose))
+    } else {
+      sdk.comeTo(setting.value.pose);
     }
     nextTick(() => stopWatchPose());
   });

+ 16 - 3
src/sdk/sdk.ts

@@ -74,8 +74,8 @@ export type AddModelProps = Pick<FuseModel, "url" | "id"> &
 
 export type SceneGuidePath = Pick<
   GuidePath,
-  "position" | "target" | "speed" | "time"
->;
+  "speed" | "time"
+> & Pose;
 export interface SceneGuide {
   bus: Emitter<{ changePoint: number; playComplete: void }>;
   play: () => void;
@@ -133,6 +133,18 @@ export type StartMeasure<T extends StoreMeasure["type"]> = Measure<T> & {
   }>;
 };
 
+export type Pose = {
+  position: SceneLocalPos; 
+  target: SceneLocalPos,
+} | {
+  panoId: any,
+  model: SceneModel,
+  posInModel: SceneLocalPos,
+  rotInModel: SceneLocalPos,
+  position: SceneLocalPos; 
+  target: SceneLocalPos,
+}
+
 export interface SDK {
   layout: HTMLDivElement;
   sceneBus: Emitter<{ cameraChange: SceneLocalPos }>;
@@ -165,7 +177,8 @@ export interface SDK {
     modelId?: FuseModel["id"]
   ) => ScreenPos | null;
   screenshot: (width: number, height: number) => Promise<string>;
-  getPose: () => { position: SceneLocalPos; target: SceneLocalPos };
+  getPose: () => Pose;
+  setPose: (pose: Pose &{dur?: number}) => void
   comeTo: (pos: CameraComeToProps) => void;
   enterSceneGuide: (data: SceneGuidePath[]) => SceneGuide;
 

+ 144 - 123
src/views/guide/edit-paths.vue

@@ -1,16 +1,16 @@
 <template>
   <div class="video">
     <div class="overflow">
-      <ui-icon 
-        ctrl 
-        :type="isScenePlayIng ? 'pause' : 'preview'" 
-        :disabled="!paths.length" 
+      <ui-icon
+        ctrl
+        :type="isScenePlayIng ? 'pause' : 'preview'"
+        :disabled="!paths.length"
         @click="play"
       />
-      <ui-button 
-        type="primary" 
-        @click="addPath" 
-        width="200px" 
+      <ui-button
+        type="primary"
+        @click="addPath"
+        width="200px"
         :class="{ disabled: isScenePlayIng }"
       >
         添加视角
@@ -19,11 +19,11 @@
     <div class="info" v-if="paths.length">
       <div class="meta">
         <div class="length">
-          <span>视频时长</span>{{paths.reduce((t, c) => t + c.time, 0).toFixed(1)}}s
+          <span>视频时长</span>{{ paths.reduce((t, c) => t + c.time, 0).toFixed(1) }}s
         </div>
-        <div 
-          class="fun-ctrl clear" 
-          @click="deleteAll" 
+        <div
+          class="fun-ctrl clear"
+          @click="deleteAll"
           :class="{ disabled: isScenePlayIng }"
         >
           <ui-icon type="del" />
@@ -33,48 +33,47 @@
 
       <div class="photo-list" ref="listVm">
         <template v-for="(path, i) in paths" :key="path.id">
-          <div 
-            class="photo" 
+          <div
+            class="photo"
             :class="{ active: current === path, disabled: isScenePlayIng }"
             @click="changeCurrent(path)"
           >
-            <ui-icon 
-              type="del" 
-              ctrl 
-              @click.stop="deletePath(path)" 
-              :class="{ disabled: isScenePlayIng }" 
+            <ui-icon
+              type="del"
+              ctrl
+              @click.stop="deletePath(path)"
+              :class="{ disabled: isScenePlayIng }"
             />
             <img :src="getResource(getFileUrl(path.cover))" />
           </div>
           <div class="set-phone-attr" v-if="i !== paths.length - 1">
-            <ui-input 
-              type="number" 
-              width="54px" 
+            <ui-input
+              type="number"
+              width="54px"
               height="26px"
-              :modelValue="path.speed" 
+              :modelValue="path.speed"
               @update:modelValue="(val: number) => updatePathInfo(i, { speed: val })"
-              :ctrl="false" 
-              :min="0.1" 
+              :ctrl="false"
+              :min="0.1"
               :max="10"
             >
               <template #icon><span>m/s</span></template>
             </ui-input>
-            <ui-input 
-              type="number" 
-              width="54px" 
-              height="26px" 
-              :modelValue="path.time" 
+            <ui-input
+              type="number"
+              width="54px"
+              height="26px"
+              :modelValue="path.time"
               @update:modelValue="(val: number) => updatePathInfo(i, { time: val })"
-              :ctrl="false" 
-              :min="0.1" 
-              :max="20" 
+              :ctrl="false"
+              :min="0.1"
+              :max="20"
               class="time"
             >
               <template #icon><span class="time">s</span></template>
             </ui-input>
           </div>
         </template>
-        
       </div>
     </div>
     <p class="un-video" v-else>暂无导览</p>
@@ -82,30 +81,47 @@
 </template>
 
 <script setup lang="ts">
-import { loadPack, togetherCallback, getFileUrl, asyncTimeout } from '@/utils'
-import { sdk, playSceneGuide, pauseSceneGuide, isScenePlayIng } from '@/sdk'
-import { createGuidePath, isTemploraryID, useAutoSetMode, guides, getGuidePaths, guidePaths } from '@/store'
-import { Dialog, Message } from 'bill/index'
-import { useViewStack } from '@/hook'
-import { nextTick, ref, toRaw, watchEffect } from 'vue'
-import { showRightPanoStack, showLeftCtrlPanoStack, showLeftPanoStack, showRightCtrlPanoStack, getResource } from '@/env'
+import { loadPack, togetherCallback, getFileUrl, asyncTimeout } from "@/utils";
+import {
+  sdk,
+  playSceneGuide,
+  pauseSceneGuide,
+  isScenePlayIng,
+  analysisPose,
+  analysisPoseInfo,
+} from "@/sdk";
+import {
+  createGuidePath,
+  isTemploraryID,
+  useAutoSetMode,
+  guides,
+  getGuidePaths,
+  guidePaths,
+} from "@/store";
+import { Dialog, Message } from "bill/index";
+import { useViewStack } from "@/hook";
+import { nextTick, ref, toRaw, watchEffect } from "vue";
+import {
+  showRightPanoStack,
+  showLeftCtrlPanoStack,
+  showLeftPanoStack,
+  showRightCtrlPanoStack,
+  getResource,
+} from "@/env";
 
-import type { Guide, GuidePaths, GuidePath } from '@/store'
-import type { CalcPathProps } from '@/sdk'
+import type { Guide, GuidePaths, GuidePath } from "@/store";
+import type { CalcPathProps } from "@/sdk";
 
-const props = defineProps< { data: Guide }>()
-const paths = ref<GuidePaths>(getGuidePaths(props.data))
-const current = ref<GuidePath>(paths.value[0])
+const props = defineProps<{ data: Guide }>();
+const paths = ref<GuidePaths>(getGuidePaths(props.data));
+const current = ref<GuidePath>(paths.value[0]);
 
 const updatePathInfo = (index: number, calcInfo: CalcPathProps[1]) => {
-  const info = sdk.calcPathInfo(
-    paths.value.slice(index, index + 2) as any,
-    calcInfo
-  )
-  Object.assign(paths.value[index], info)
-}
+  const info = sdk.calcPathInfo(paths.value.slice(index, index + 2) as any, calcInfo);
+  Object.assign(paths.value[index], info);
+};
 
-useViewStack(() => 
+useViewStack(() =>
   togetherCallback([
     showRightPanoStack.push(ref(false)),
     showLeftCtrlPanoStack.push(ref(false)),
@@ -114,97 +130,105 @@ useViewStack(() =>
   ])
 );
 
-useAutoSetMode(paths, {
-  save() {
-    if (!paths.value.length) {
-      Dialog.alert('无法保存空路径导览!')
-      throw '无法保存空路径导览!'
-    }
-    const oldPaths = getGuidePaths(props.data)
-    props.data.cover = paths.value[0].cover
-    guidePaths.value = guidePaths.value
-      .filter(path => !oldPaths.includes(path))
-      .concat(paths.value)
-    if (isTemploraryID(props.data.id)) {
-      console.error("现在才保存?")
-      guides.value.push(props.data)
-    }
+useAutoSetMode(
+  paths,
+  {
+    save() {
+      if (!paths.value.length) {
+        Dialog.alert("无法保存空路径导览!");
+        throw "无法保存空路径导览!";
+      }
+      const oldPaths = getGuidePaths(props.data);
+      props.data.cover = paths.value[0].cover;
+      guidePaths.value = guidePaths.value
+        .filter((path) => !oldPaths.includes(path))
+        .concat(paths.value);
+      if (isTemploraryID(props.data.id)) {
+        console.error("现在才保存?");
+        guides.value.push(props.data);
+      }
+    },
   },
-}, false)
+  false
+);
 
 const addPath = () => {
   loadPack(async () => {
-    const dataURL = await sdk.screenshot(260, 160)
-    const res = await fetch(dataURL)
-    const blob = await res.blob()
+    const dataURL = await sdk.screenshot(260, 160);
+    const res = await fetch(dataURL);
+    const blob = await res.blob();
 
-    const pose = sdk.getPose()
-    const index = paths.value.indexOf(current.value) + 1
-    const path: GuidePath = createGuidePath({ 
-      ...pose, 
+    const pose = sdk.getPose();
+    const index = paths.value.indexOf(current.value) + 1;
+    const path: GuidePath = createGuidePath({
+      ...analysisPose(pose),
       guideId: props.data.id,
-      cover: { url: dataURL, blob } 
-    })
-    paths.value.splice(index, 0, path)
-    current.value = path
+      cover: { url: dataURL, blob },
+    });
+    paths.value.splice(index, 0, path);
+    current.value = path;
     if (paths.value.length > 1) {
-      const index = paths.value.length - 2
-      updatePathInfo(index, { time: 3 })
+      const index = paths.value.length - 2;
+      updatePathInfo(index, { time: 3 });
     }
-  })
-}
+  });
+};
 
 const deletePath = async (path: GuidePath, fore: boolean = false) => {
-  if (fore || (await Dialog.confirm('确定要删除此画面吗?'))) {
-    const index = paths.value.indexOf(path)
+  if (fore || (await Dialog.confirm("确定要删除此画面吗?"))) {
+    const index = paths.value.indexOf(path);
     if (~index) {
-      paths.value.splice(index, 1)
+      paths.value.splice(index, 1);
     }
     if (path === current.value) {
-      current.value = paths.value[index + (index === 0 ? 0 : -1)]
+      current.value = paths.value[index + (index === 0 ? 0 : -1)];
     }
   }
-}
+};
 
 const deleteAll = async () => {
-  if (await Dialog.confirm('确定要清空画面吗?')) {
-    paths.value.length = 0
-    current.value = paths.value[0]
+  if (await Dialog.confirm("确定要清空画面吗?")) {
+    paths.value.length = 0;
+    current.value = paths.value[0];
   }
-}
+};
 
 const changeCurrent = (path: GuidePath) => {
-  sdk.comeTo({ dur: 300, ...path })
-  current.value = path
-}
+  if (sdk.setPose) {
+    sdk.setPose({ dur: 300, ...path, ...analysisPoseInfo(path) });
+  } else {
+    sdk.comeTo({ dur: 300, ...path });
+  }
+  current.value = path;
+};
 
 const play = async () => {
   if (isScenePlayIng.value) {
-    pauseSceneGuide()
+    pauseSceneGuide();
   } else {
-    changeCurrent(paths.value[0])
-    await asyncTimeout(400)
-    playSceneGuide(toRaw(paths.value), (index) => {
-      current.value = paths.value[index - 1]
-    })
+    changeCurrent(paths.value[0]);
+    await asyncTimeout(400);
+    playSceneGuide(toRaw(paths.value) as any, (index) => {
+      current.value = paths.value[index - 1];
+    });
   }
-}
+};
 
-const listVm = ref<HTMLDivElement>()
+const listVm = ref<HTMLDivElement>();
 watchEffect(async () => {
-  const index = paths.value.indexOf(current.value)
+  const index = paths.value.indexOf(current.value);
   if (~index && listVm.value) {
-    await nextTick()
-    const scrollWidth = listVm.value.scrollWidth / paths.value.length
-    const centerWidth = listVm.value.offsetWidth / 2
-    const offsetLeft = scrollWidth * index - centerWidth
+    await nextTick();
+    const scrollWidth = listVm.value.scrollWidth / paths.value.length;
+    const centerWidth = listVm.value.offsetWidth / 2;
+    const offsetLeft = scrollWidth * index - centerWidth;
 
     listVm.value.scroll({
       left: offsetLeft,
       top: 0,
-    })
+    });
   }
-})
+});
 </script>
 
 <style lang="scss" scoped>
@@ -229,11 +253,11 @@ watchEffect(async () => {
 
   .meta {
     font-size: 12px;
-    border-bottom: 1px solid rgba(255,255,255,.16);
+    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
     padding: 10px 20px;
     display: flex;
     justify-content: space-between;
-    
+
     .length span {
       margin-right: 10px;
     }
@@ -248,7 +272,6 @@ watchEffect(async () => {
     }
   }
 
-
   .photo-list {
     padding: 10px 20px 20px;
     overflow-x: auto;
@@ -264,8 +287,8 @@ watchEffect(async () => {
 
       &::before,
       &::after {
-        content: '';
-        color: rgba(255,255,255,.6);
+        content: "";
+        color: rgba(255, 255, 255, 0.6);
         position: absolute;
         top: 50%;
         transform: translateY(-50%);
@@ -284,12 +307,11 @@ watchEffect(async () => {
         border-left: 7px solid currentColor;
       }
     }
-    
+
     .photo {
       cursor: pointer;
       flex: none;
       position: relative;
-      
 
       &.active {
         outline: 2px solid var(--colors-primary-base);
@@ -302,8 +324,8 @@ watchEffect(async () => {
         width: 24px;
         font-size: 12px;
         height: 24px;
-        background-color: rgba(0,0,0,0.6);
-        color: rgba(255,255,255,.6);
+        background-color: rgba(0, 0, 0, 0.6);
+        color: rgba(255, 255, 255, 0.6);
         display: flex;
         align-items: center;
         justify-content: center;
@@ -311,7 +333,6 @@ watchEffect(async () => {
         border-radius: 50%;
       }
 
-
       img {
         width: 230px;
         height: 160px;
@@ -324,7 +345,7 @@ watchEffect(async () => {
   height: 100px;
   line-height: 100px;
   text-align: center;
-  color: rgba(255,255,255,0.6);
+  color: rgba(255, 255, 255, 0.6);
   font-size: 1.2em;
 }
 </style>
@@ -349,4 +370,4 @@ watchEffect(async () => {
     text-align: right;
   }
 }
-</style>
+</style>

+ 2 - 6
src/views/setting/index.vue

@@ -36,7 +36,7 @@ import { enterEdit, enterOld, setting, isEdit, updataSetting } from "@/store";
 import { ref, watchEffect } from "vue";
 import { togetherCallback, getFileUrl, loadPack } from "@/utils";
 import { showRightPanoStack, showRightCtrlPanoStack, custom } from "@/env";
-import { sdk, SettingResourceType } from "@/sdk";
+import { analysisPose, sdk, SettingResourceType } from "@/sdk";
 
 const backs = ref<{ label: string; type: string; image: string; value: string }[]>([]);
 watchEffect(async () => {
@@ -99,11 +99,7 @@ const enterSetPic = () => {
     setting.value = {
       ...setting.value!,
       cover: { url: dataURL, blob },
-      pose: {
-        ...sdk.getPose(),
-        mode: custom.showMode,
-        model: custom.currentModel,
-      },
+      pose: analysisPose(sdk.getPose()),
     };
     await updataSetting();
   });