Browse Source

fix: Merge branch 'master' of http://192.168.0.115:3000/bill/kankan-mix

# Conflicts:
#	public/test-case/model-list.json
#	src/sdk/cover/index.js
xzw 1 year ago
parent
commit
c2b7a3d4ed

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["Vue.volar"]
+}

File diff suppressed because it is too large
+ 143 - 75
public/lib/potree/potree.js


File diff suppressed because it is too large
+ 1 - 1
public/lib/potree/potree.js.map


+ 54 - 41
src/env/index.ts

@@ -1,24 +1,30 @@
-import { stackFactory, flatStacksValue, strToParams } from '@/utils'
-import { reactive, ref } from 'vue'
+import { stackFactory, flatStacksValue, strToParams } from "@/utils";
+import { reactive, ref } from "vue";
 
-import type { FuseModel, TaggingPosition, View } from '@/store'
+import type { FuseModel, TaggingPosition, View } from "@/store";
 
-export const viewModeStack = stackFactory(ref<'full' | 'auto'>('auto'))
-export const showToolbarStack = stackFactory(ref<boolean>(false))
-export const showHeadBarStack = stackFactory(ref<boolean>(true))
-export const showRightPanoStack = stackFactory(ref<boolean>(true))
-export const showLeftPanoStack = stackFactory(ref<boolean>(false))
-export const showLeftCtrlPanoStack = stackFactory(ref<boolean>(true))
-export const showRightCtrlPanoStack = stackFactory(ref<boolean>(true))
-export const showBottomBarStack = stackFactory(ref<boolean>(false), true)
-export const bottomBarHeightStack = stackFactory(ref<string>('60px'))
-export const showTaggingsStack = stackFactory(ref<boolean>(true))
-export const showMeasuresStack = stackFactory(ref<boolean>(true))
-export const currentModelStack = stackFactory(ref<FuseModel | null>(null))
-export const showModelsMapStack = stackFactory(ref<WeakMap<FuseModel, boolean>>(new WeakMap()), true)
-export const modelsChangeStoreStack = stackFactory(ref<boolean>(false))
-export const showTaggingPositionsStack = stackFactory(ref<WeakSet<TaggingPosition>>(new WeakSet()))
-export const currentViewStack = stackFactory(ref<View>())
+export const viewModeStack = stackFactory(ref<"full" | "auto">("auto"));
+export const showToolbarStack = stackFactory(ref<boolean>(false));
+export const showHeadBarStack = stackFactory(ref<boolean>(true));
+export const showRightPanoStack = stackFactory(ref<boolean>(true));
+export const showLeftPanoStack = stackFactory(ref<boolean>(false));
+export const showLeftCtrlPanoStack = stackFactory(ref<boolean>(true));
+export const showRightCtrlPanoStack = stackFactory(ref<boolean>(true));
+export const showBottomBarStack = stackFactory(ref<boolean>(false), true);
+export const bottomBarHeightStack = stackFactory(ref<string>("60px"));
+export const showTaggingsStack = stackFactory(ref<boolean>(true));
+export const showMeasuresStack = stackFactory(ref<boolean>(true));
+export const currentModelStack = stackFactory(ref<FuseModel | null>(null));
+export const showModelsMapStack = stackFactory(
+  ref<WeakMap<FuseModel, boolean>>(new WeakMap()),
+  true
+);
+export const modelsChangeStoreStack = stackFactory(ref<boolean>(false));
+export const showTaggingPositionsStack = stackFactory(
+  ref<WeakSet<TaggingPosition>>(new WeakSet())
+);
+export const currentViewStack = stackFactory(ref<View>());
+export const showModeStack = stackFactory(ref<"pano" | "fuse">("fuse"));
 
 export const custom = flatStacksValue({
   viewMode: viewModeStack,
@@ -36,30 +42,37 @@ export const custom = flatStacksValue({
   showBottomBar: showBottomBarStack,
   bottomBarHeight: bottomBarHeightStack,
   showHeadBar: showHeadBarStack,
-  currentView: currentViewStack
-})
+  currentView: currentViewStack,
+  showMode: showModeStack,
+});
 
+export const params = reactive(
+  strToParams(location.search)
+) as unknown as Params;
+params.caseId = Number(params.caseId);
+params.share = Boolean(Number(params.share));
+params.single = Boolean(Number(params.single));
 
-export const params = reactive(strToParams(location.search)) as unknown as Params
-params.caseId = Number(params.caseId)
-params.share = Boolean(Number(params.share))
-params.single = Boolean(Number(params.single))
-
-export type Params = { 
-  caseId: number,
-  baseURL?: string,
-  modelId?: string,
-  m?: string
-  share?: boolean,
-  single?: boolean
-  token?: string
-}
-
-export const baseURL = params.baseURL ? params.baseURL : '/'
-export const appBackRoot =  'https://www.4dkankan.com/'
+export type Params = {
+  caseId: number;
+  baseURL?: string;
+  modelId?: string;
+  m?: string;
+  share?: boolean;
+  single?: boolean;
+  token?: string;
+};
 
+export const baseURL = params.baseURL ? params.baseURL : "/";
+export const appBackRoot = "https://www.4dkankan.com/";
 
 export const getResource = (uri: string) => {
-  if (~uri.indexOf('base64') || ~uri.indexOf('bolb') || ~uri.indexOf('//') || uri.startsWith('/')) return uri
-  return `${baseURL}/${uri}`
-}
+  if (
+    ~uri.indexOf("base64") ||
+    ~uri.indexOf("bolb") ||
+    ~uri.indexOf("//") ||
+    uri.startsWith("/")
+  )
+    return uri;
+  return `${baseURL}/${uri}`;
+};

+ 41 - 39
src/layout/model-list/index.vue

@@ -1,67 +1,69 @@
 <template>
-  <List :title="title" rawKey="id" :data="modelList" :showContent="showContent">
+  <List :title="title" rawKey="id" :data="modelList" :showContent="showContent" id="model-list">
     <template #action>
       <slot name="action" />
     </template>
     <template #atom="{ item }">
-      <ModelSign
-        :canChange="canChange"
-        :model="item.raw" 
-        @delete="modelDelete(item.raw)" 
-        @click="modelChangeSelect(item.raw)"
-      />
+      <ModelSign :canChange="canChange" :model="item.raw" @delete="modelDelete(item.raw)"
+        @click="modelChangeSelect(item.raw)" />
     </template>
   </List>
 </template>
 
 <script lang="ts" setup>
-import { computed, watchEffect } from 'vue'
-import { custom } from '@/env'
-import { getSceneModel } from '@/sdk'
-import List from '@/components/list/index.vue'
-import ModelSign from './sign.vue'
-import { fuseModels, getFuseModelShowVariable } from '@/store'
+import { computed, watchEffect } from "vue";
+import { custom } from "@/env";
+import { getSceneModel } from "@/sdk";
+import List from "@/components/list/index.vue";
+import ModelSign from "./sign.vue";
+import { fuseModels, getFuseModelShowVariable } from "@/store";
 
-import type { FuseModel } from '@/store'
-import { currentModel, fuseModel } from '@/model'
+import type { FuseModel } from "@/store";
+import { currentModel, fuseModel } from "@/model";
 
-export type ModelListProps = { 
-  title?: string, 
-  canChange?: boolean,
-  showContent?: boolean
-}
-withDefaults(
-  defineProps<ModelListProps>(),
-  { title: '数据列表', change: false, showContent: true }
-)
+export type ModelListProps = {
+  title?: string;
+  canChange?: boolean;
+  showContent?: boolean;
+};
+withDefaults(defineProps<ModelListProps>(), {
+  title: "数据列表",
+  change: false,
+  showContent: true,
+});
 defineEmits<{
-  (e: 'deleteModel', model: FuseModel): void,
-  (e: 'clickModel', model: FuseModel): void
-}>()
+  (e: "deleteModel", model: FuseModel): void;
+  (e: "clickModel", model: FuseModel): void;
+}>();
 
-const modelList = computed(() => 
-  fuseModels.value.map(model => ({
+const modelList = computed(() =>
+  fuseModels.value.map((model) => ({
     raw: model,
-    select: custom.currentModel === model && currentModel.value === fuseModel
+    select: custom.currentModel === model && currentModel.value === fuseModel,
   }))
-)
+);
 
 const modelChangeSelect = (model: FuseModel) => {
   if (getFuseModelShowVariable(model).value) {
-    custom.currentModel = custom.currentModel !== model ? model : null
+
+    custom.currentModel = custom.currentModel !== model ? model : null;
   }
-}
+};
 
 watchEffect(() => {
   if (custom.currentModel && !getFuseModelShowVariable(custom.currentModel).value) {
-    custom.currentModel = null
+    custom.currentModel = null;
   }
-})
+});
 
 const modelDelete = (model: FuseModel) => {
-  const index = fuseModels.value.indexOf(model)
+  const index = fuseModels.value.indexOf(model);
   if (~index) {
-    fuseModels.value.splice(index, 1)
+    fuseModels.value.splice(index, 1);
   }
-}
-</script>
+};
+
+watchEffect(() => {
+  console.log(custom.currentModel?.raw);
+});
+</script>

+ 63 - 28
src/layout/model-list/sign.vue

@@ -1,53 +1,88 @@
 <template>
-  <div @click="!model.error && $emit('click')" class="sign-layout">
+  <div
+    @click="!model.error && !(custom.showMode === 'pano' && active) && $emit('click')"
+    class="sign-layout"
+    :class="{ disabled: custom.showMode === 'pano' && !supperPano }"
+  >
     <div class="model-header">
       <p>{{ model.title }}</p>
       <div class="model-action">
-        <ui-input 
-          type="checkbox" 
-          v-model="show" 
-          @click.stop 
-          :class="{disabled: model.error}"
+        <ui-input
+          type="checkbox"
+          v-model="show"
+          @click.stop
+          :class="{
+            disabled: model.error || custom.showMode === 'pano',
+          }"
         />
-        <ui-icon 
-          v-if="custom.modelsChangeStore" 
-          type="del" 
-          ctrl 
-          @click="$emit('delete')" 
+        <ui-icon
+          v-if="custom.modelsChangeStore"
+          type="del"
+          ctrl
+          @click="$emit('delete')"
         />
       </div>
     </div>
-    <div class="model-desc"  v-if="active">
+    <div class="model-desc" v-if="active">
       <p><span>数据来源:</span>{{ SceneTypeDesc[model.type] }}</p>
       <p v-if="model.type !== SceneType.SWSS"><span>数据大小:</span>{{ model.size }}</p>
       <p><span>拍摄时间:</span>{{ model.time }}</p>
     </div>
   </div>
+
+  <Teleport to="#left-pano" v-if="active && supperPano">
+    <div class="mode-tab strengthen">
+      <div
+        class="mode-icon-layout"
+        @click="custom.showMode = 'fuse'"
+        :class="{ active: custom.showMode === 'fuse' }"
+      >
+        <ui-icon type="joint" class="icon" />
+      </div>
+      <div
+        class="mode-icon-layout"
+        @click="custom.showMode = 'pano'"
+        :class="{ active: custom.showMode === 'pano' }"
+      >
+        <ui-icon type="pin" class="icon" />
+      </div>
+    </div>
+  </Teleport>
 </template>
 
 <script lang="ts" setup>
-import { getFuseModelShowVariable, SceneTypeDesc, SceneType } from '@/store'
-import { custom } from '@/env'
+import { getFuseModelShowVariable, SceneTypeDesc, SceneType } from "@/store";
+import { custom, showModeStack } from "@/env";
+import { getSceneModel } from "@/sdk";
+
+import type { FuseModel } from "@/store";
+import { computed } from "vue";
+import { currentModel, fuseModel } from "@/model";
 
-import type { FuseModel } from '@/store'
-import { computed } from 'vue';
-import { currentModel, fuseModel } from '@/model';
+type ModelProps = { model: FuseModel; canChange?: boolean };
+const props = defineProps<ModelProps>();
 
-type ModelProps = { model: FuseModel, canChange?: boolean }
-const props = defineProps<ModelProps>()
-const active = computed(() => 
-  custom.currentModel === props.model && currentModel.value === fuseModel
-)
+const active = computed(
+  () => custom.currentModel === props.model && currentModel.value === fuseModel
+);
+const supperPano = computed(() => {
+  console.log(props.model.title, getSceneModel(props.model)?.supportPano());
+  return getSceneModel(props.model)?.supportPano();
+});
 
 type ModelEmits = {
-  (e: 'changeSelect', selected: boolean): void
-  (e: 'delete'): void
-  (e: 'click'): void
-}
+  (e: "changeSelect", selected: boolean): void;
+  (e: "delete"): void;
+  (e: "click"): void;
+};
 defineEmits<ModelEmits>();
 
-const show = getFuseModelShowVariable(props.model)
+const show = getFuseModelShowVariable(props.model);
 
+const switchMode = () => {
+  console.log("click");
+  custom.showMode = "pano";
+};
 </script>
 
-<style lang="scss" scoped src="./style.scss"></style>
+<style lang="scss" scoped src="./style.scss"></style>

+ 49 - 15
src/layout/model-list/style.scss

@@ -1,35 +1,69 @@
 .model-header {
-  display: flex;
+  display        : flex;
   justify-content: space-between;
-  align-items: center;
-  margin-bottom: 10px;
-  
+  align-items    : center;
+  margin-bottom  : 10px;
+
   p {
-    font-size: 14px;
-    color: #fff;
-    height: 1.5em;
-    overflow: hidden;
+    font-size    : 14px;
+    color        : #fff;
+    height       : 1.5em;
+    overflow     : hidden;
     text-overflow: ellipsis;
-    white-space: nowrap;
+    white-space  : nowrap;
   }
 }
 
 .model-desc {
-  color: rgba(255,255,255,0.6);
+  color      : rgba(255, 255, 255, 0.6);
   line-height: 18px;
-  font-size: 12px;
+  font-size  : 12px;
 }
 
 .model-action {
-  display: flex;
+  display    : flex;
   align-items: center;
-  flex: none;
-  > * {
+  flex       : none;
+
+  >* {
     margin-left: 20px;
   }
 }
 
 .sign-layout {
-  margin: -20px 0;
+  margin : -20px 0;
   padding: 20px 0;
 }
+
+
+.mode-tab {
+  position        : absolute;
+  z-index         : 2;
+  background-color: var(--editor-menu-back);
+  transition      : all .3s ease;
+  display         : flex;
+  align-items     : center;
+  justify-content : space-evenly;
+  height          : 34px;
+  border-radius   : 17px;
+  margin-left     : 10px;
+  bottom          : calc(10px + var(--editor-menu-bottom));
+  left            : calc(var(--left-pano-left) + var(--left-pano-width));
+  padding         : 0 5px;
+
+  .mode-icon-layout {
+    padding: 0 8px;
+
+    &.active .icon {
+      color: var(--color-main-normal);
+    }
+  }
+
+  .icon {
+    font-size : 18px;
+    cursor    : pointer;
+    transition: color .3s ease;
+
+  }
+
+}

+ 44 - 42
src/layout/scene-list/index.vue

@@ -4,28 +4,26 @@
       <slot name="action" />
     </template>
     <template #atom="{ item }">
-      <div v-if="item.raw === fuseModel" 
-        @click="updateCurrent(item.raw)"
-      >
+      <div v-if="item.raw === fuseModel" @click="updateCurrent(item.raw)">
         <ModelList
           class="scene-model-list"
-          :class="{active: current === fuseModel}"
+          :class="{ active: current === fuseModel }"
           :title="getModelTypeDesc(fuseModel as any)"
           :show-content="showModelList"
         >
-          <template #action>
+          <!-- <template #action>
             <ui-icon 
               :type="`pull-${showModelList ? 'up' : 'down'}`" 
               @click="showModelList = !showModelList"
               ctrl 
             />
-          </template>
+          </template> -->
         </ModelList>
       </div>
-      <div 
-        class="scene" 
-        :class="{disabled: item.raw.status !== SceneStatus.SUCCESS}" 
-        @click="updateCurrent(item.raw)" 
+      <div
+        class="scene"
+        :class="{ disabled: item.raw.status !== SceneStatus.SUCCESS }"
+        @click="updateCurrent(item.raw)"
         v-else
       >
         <p>{{ item.raw.name }}</p>
@@ -35,56 +33,59 @@
   </List>
 
   <Teleport to="#layout-app">
-    <div>
-      123
-    </div>
+    <div>123</div>
   </Teleport>
 </template>
 
 <script lang="ts" setup>
-import { computed, nextTick, ref, watch } from 'vue'
-import { scenes, SceneType, SceneTypeDesc, fuseModels, SceneStatus } from '@/store'
-import List from '@/components/list/index.vue'
-import ModelList from '../model-list/index.vue'
-import { fuseModel, getModelTypeDesc } from '@/model'
+import { computed, nextTick, ref, watch } from "vue";
+import { scenes, SceneType, SceneTypeDesc, fuseModels, SceneStatus } from "@/store";
+import List from "@/components/list/index.vue";
+import ModelList from "../model-list/index.vue";
+import { fuseModel, getModelTypeDesc } from "@/model";
 
-import type { ModelType, FuseModelType } from '@/model'
-import type { Scene } from '@/store'
+import type { ModelType, FuseModelType } from "@/model";
+import type { Scene } from "@/store";
 
-const emit = defineEmits<{ (e: 'update:current', data: ModelType): void }>()
-const props = defineProps<{ current: ModelType }>()
-const showModelList = ref(true)
+const emit = defineEmits<{ (e: "update:current", data: ModelType): void }>();
+const props = defineProps<{ current: ModelType }>();
+const showModelList = ref(true);
 
 const list = computed(() => {
-  const sceneList = scenes.value.map(scene => ({
+  const sceneList = scenes.value.map((scene) => ({
     raw: scene,
-    select: props.current !== fuseModel 
-      && (props.current.num === scene.num )
-      && props.current.type === scene.type
-  }))
+    select:
+      props.current !== fuseModel &&
+      props.current.num === scene.num &&
+      props.current.type === scene.type,
+  }));
   if (fuseModels.value.length) {
     // return [{ raw: fuseModel }, ...sceneList]
-    return [{ raw: fuseModel }]
+    return [{ raw: fuseModel }];
   } else {
-    return sceneList
+    return sceneList;
   }
-})
+});
 
 const updateCurrent = (scene: FuseModelType | Scene) => {
-  console.log(scene)
+  console.log(scene);
   if (scene === fuseModel) {
-    emit('update:current', scene)
+    emit("update:current", scene);
   } else {
-    emit('update:current', { type: scene.type, num: scene.num })
+    emit("update:current", { type: scene.type, num: scene.num });
   }
-}
+};
 
-const stopWatch = watch(list, () => {
-  if (!list.value.some(model => model.raw === fuseModel) && list.value.length) {
-    updateCurrent(list.value[0].raw as any)
-    nextTick(() => stopWatch())
-  }
-}, { immediate: true })
+const stopWatch = watch(
+  list,
+  () => {
+    if (!list.value.some((model) => model.raw === fuseModel) && list.value.length) {
+      updateCurrent(list.value[0].raw as any);
+      nextTick(() => stopWatch());
+    }
+  },
+  { immediate: true }
+);
 </script>
 
 <style lang="scss">
@@ -110,10 +111,11 @@ const stopWatch = watch(list, () => {
 
   .header {
     padding: 30px 20px 20px;
+
     h3 {
       font-size: 20px;
       font-weight: bold;
-      color: #FFFFFF;
+      color: #ffffff;
     }
   }
 

+ 41 - 35
src/layout/show/index.vue

@@ -1,10 +1,13 @@
 <template>
   <template v-if="loaded">
-    <div :class="{ hideLeft: !custom.showLeftPano }" :style="hasSingle ? {'--left-pano-left': '0px'} : ''">
-      <SlideMenu 
+    <div
+      :class="{ hideLeft: !custom.showLeftPano }"
+      :style="hasSingle ? { '--left-pano-left': '0px' } : ''"
+    >
+      <SlideMenu
         v-if="!hasSingle"
-        :activeName="(router.currentRoute.value.name as RoutesName)" 
-        @change-item="item => router.push({ name: item.name })"
+        :activeName="(router.currentRoute.value.name as RoutesName)"
+        @change-item="(item) => router.push({ name: item.name })"
       />
 
       <router-view v-slot="{ Component }">
@@ -12,23 +15,23 @@
           <component :is="Component" />
         </keep-alive>
       </router-view>
-
     </div>
   </template>
 </template>
 
 <script lang="ts" setup>
-import { custom, params } from '@/env'
-import { computed, nextTick, ref, watch, watchEffect } from 'vue'
-import { router, RoutesName } from '@/router'
-import { loadModel, fuseModel } from '@/model'
-import SlideMenu from './slide-menu.vue'
-import { 
-  initialFloders, 
-  initialFloderTypes, 
-  initialFuseModels, 
-  initialRecords, 
-  initialScenes, 
+import { custom, params } from "@/env";
+import { computed, nextTick, ref, watch, watchEffect } from "vue";
+import { router, RoutesName } from "@/router";
+import { loadModel, fuseModel } from "@/model";
+import SlideMenu from "./slide-menu.vue";
+import { sdk } from "@/sdk";
+import {
+  initialFloders,
+  initialFloderTypes,
+  initialFuseModels,
+  initialRecords,
+  initialScenes,
   initialViews,
   defTitle,
   initialTaggingStyles,
@@ -37,12 +40,12 @@ import {
   initialGuides,
   scenes,
   fuseModels,
-  appEl
-} from '@/store'
+  appEl,
+} from "@/store";
 
-const hasSingle = new URLSearchParams(location.search).has("single")
+const hasSingle = new URLSearchParams(location.search).has("single");
 
-const loaded = ref(false)
+const loaded = ref(false);
 const initialSys = async () => {
   await Promise.all([
     initialFuseModels(),
@@ -53,23 +56,24 @@ const initialSys = async () => {
     initialFloderTypes(),
     initialTaggingStyles(),
     initialTaggings(),
-    initialGuides()
-  ])
-  await initialMeasures()
-  loaded.value = true
-  loadModel(fuseModel)
-  custom.showLeftPano = true
-}
-initialSys()
-defTitle.value = ''
-initialScenes()
+    initialGuides(),
+  ]);
+  await initialMeasures();
+  loaded.value = true;
+  await loadModel(fuseModel);
+  sdk.hideGrid();
+  custom.showLeftPano = true;
+};
+initialSys();
+defTitle.value = "";
+initialScenes();
 
 watchEffect((onCleanup) => {
   if (loaded.value && appEl.value && scenes.value.length && !fuseModels.value.length) {
-      loadModel(scenes.value[0] as any)
-      custom.showLeftPano = true
+    loadModel(scenes.value[0] as any);
+    custom.showLeftPano = true;
   }
-})
+});
 </script>
 
 <style>
@@ -80,6 +84,8 @@ watchEffect((onCleanup) => {
 
 .hideLeft {
   --editor-menu-left: calc(-1 * var(--editor-menu-width));
-  --left-pano-left: calc(var(--editor-menu-left) + var(--editor-menu-width) - var(--left-pano-width)) !important
+  --left-pano-left: calc(
+    var(--editor-menu-left) + var(--editor-menu-width) - var(--left-pano-width)
+  ) !important;
 }
-</style>
+</style>

+ 138 - 121
src/sdk/association/fuseMode.ts

@@ -1,220 +1,237 @@
-import { 
-  SDK, 
-  SceneModel, 
-  ModelAttrRange,  } from '../sdk'
-import { toRaw, watch, reactive } from 'vue'
-import { 
-  custom, 
-  getResource 
-} from '@/env'
-import { 
-  diffArrayChange, 
-  shallowWatchArray, 
+import { SDK, SceneModel, ModelAttrRange } from "../sdk";
+import { toRaw, watch, reactive } from "vue";
+import { custom, getResource } from "@/env";
+import {
+  diffArrayChange,
+  shallowWatchArray,
   arrayChildEffectScope,
   showLoad,
   hideLoad,
   deepIsRevise,
   round,
-} from '@/utils'
-import { 
+} from "@/utils";
+import {
   dynamicAddedModelIds,
-  fuseModels, 
-  getFuseModelShowVariable, 
+  fuseModels,
+  getFuseModelShowVariable,
   SceneType,
   SceneStatus,
-  FuseModel, FuseModels
-} from '@/store'
-import { currentLayout, RoutesName } from '@/router'
-import { isUnSet, unSet } from '@/utils/unset'
-
-
+  FuseModel,
+  FuseModels,
+} from "@/store";
+import { currentLayout, RoutesName } from "@/router";
+import { isUnSet, unSet } from "@/utils/unset";
 
 // -----------------模型关联--------------------
 
-export const modelRange: ModelAttrRange  = {
+export const modelRange: ModelAttrRange = {
   opacityRange: { min: 0, max: 100, step: 0.1 },
   bottomRange: { min: -30, max: 70, step: 0.1 },
-  scaleRange: { min: 0, max: 200, step: 0.1 }
-}
+  scaleRange: { min: 0, max: 200, step: 0.1 },
+};
 
-const sceneModelMap = reactive(new WeakMap<FuseModel, SceneModel>())
-export const getSceneModel = (model?: FuseModel | null) => model && sceneModelMap.get(toRaw(model))
+const sceneModelMap = reactive(new WeakMap<FuseModel, SceneModel>());
+export const getSceneModel = (model?: FuseModel | null) =>
+  model && sceneModelMap.get(toRaw(model));
 
 const setModels = (sdk: SDK, models: FuseModels, oldModels: FuseModels) => {
-  const { added, deleted } = diffArrayChange(models, oldModels)
+  const { added, deleted } = diffArrayChange(models, oldModels);
   for (const item of added) {
-
     if (getSceneModel(item)) {
       continue;
     }
 
     if (item.status !== SceneStatus.SUCCESS) {
-      item.error = true
-      item.loaded = true
+      item.error = true;
+      item.loaded = true;
       continue;
     }
 
-    const itemRaw = toRaw(item)
-    let sceneModel: SceneModel
+    const itemRaw = toRaw(item);
+    let sceneModel: SceneModel;
     try {
       sceneModel = sdk.addModel({
         ...itemRaw,
         ...modelRange,
-        mode: RoutesName.signModel === currentLayout.value! ? 'single' : 'many',
-        isDynamicAdded: dynamicAddedModelIds.value.some(id => itemRaw.id === id),
-        type: [SceneType.SWSS, SceneType.SWYDSS].includes(item.type) ? 'laser' : item.modelType,
-        url: [SceneType.SWSS, SceneType.SWYDSS].includes(item.type) ? item.url : item.url && getResource(item.url),
-        fromType: item.type
-      })
-    } catch(e) {
-      console.error('模型加载失败', e)
-      item.error = true
+        mode: RoutesName.signModel === currentLayout.value! ? "single" : "many",
+        isDynamicAdded: dynamicAddedModelIds.value.some(
+          (id) => itemRaw.id === id
+        ),
+        type: [SceneType.SWSS, SceneType.SWYDSS].includes(item.type)
+          ? "laser"
+          : item.modelType,
+        url: [SceneType.SWSS, SceneType.SWYDSS].includes(item.type)
+          ? item.url
+          : item.url && getResource(item.url),
+        fromType: item.type,
+      });
+    } catch (e) {
+      console.error("模型加载失败", e);
+      item.error = true;
       return;
     }
 
-    sceneModelMap.set(itemRaw, sceneModel)
+    sceneModelMap.set(itemRaw, sceneModel);
 
-    let changeId: NodeJS.Timeout
-    sceneModel.bus.on('transformChanged', transform => {
-      clearTimeout(changeId)
+    let changeId: NodeJS.Timeout;
+    sceneModel.bus.on("transformChanged", (transform) => {
+      clearTimeout(changeId);
 
       changeId = setTimeout(() => {
-        transform = { ...transform }
+        transform = { ...transform };
         if (transform.rotation) {
           transform.rotation = {
             x: round(transform.rotation.x, 5),
             y: round(transform.rotation.y, 5),
             z: round(transform.rotation.z, 5),
-          }
+          };
         }
         if (transform.position) {
           transform.position = {
             x: round(transform.position.x, 5),
             y: round(transform.position.y, 5),
             z: round(transform.position.z, 5),
-          }
+          };
         }
-        delete transform.bottom
+        delete transform.bottom;
         // if (transform.bottom) {
         //   transform.bottom = round(transform.bottom, 2)
         // }
         if (transform.scale) {
-          transform.scale = round(transform.scale, 2)
+          transform.scale = round(transform.scale, 2);
         }
 
-        const updateKeys = Object.keys(transform)
-        const update: any = {}
+        const updateKeys = Object.keys(transform);
+        const update: any = {};
         for (const key of updateKeys) {
-          update[key] = (item as any)[key]
+          update[key] = (item as any)[key];
         }
-        
+
         if (deepIsRevise(update, transform)) {
-          unSet(() => Object.assign(item, transform))
+          unSet(() => Object.assign(item, transform));
         }
-      }, 16)
-    })
+      }, 16);
+    });
 
-    sceneModel.bus.on('changeSelect', select => {
+    sceneModel.bus.on("changeSelect", (select) => {
       unSet(() => {
-        if (custom.currentModel === item && !select) {
-          custom.currentModel = null
-        } else if (custom.currentModel !== item && select) {
-          custom.currentModel = item
+        if (custom.showMode === "fuse") {
+          if (custom.currentModel === item && !select) {
+            custom.currentModel = null;
+          } else if (custom.currentModel !== item && select) {
+            custom.currentModel = item;
+          }
         }
-      })
-    })
-    showLoad()
-    sceneModel.bus.on('loadDone', () => {
-      item.loaded = true
-      hideLoad()
-    })
-    sceneModel.bus.on('loadError', () => {
-      item.error = true
-      item.show = false
-      
-      custom.showModelsMap.delete(item)
-      hideLoad()
-    })
-    sceneModel.bus.on('loadProgress', progress => item.progress = progress)
+      });
+    });
+    showLoad();
+    sceneModel.bus.on("loadDone", () => {
+      item.loaded = true;
+      hideLoad();
+    });
+    sceneModel.bus.on("loadError", () => {
+      item.error = true;
+      item.show = false;
+
+      custom.showModelsMap.delete(item);
+      hideLoad();
+    });
+    sceneModel.bus.on("loadProgress", (progress) => (item.progress = progress));
   }
   for (const item of deleted) {
-    console.error('销毁', item)
-    getSceneModel(item)?.destroy()
+    console.error("销毁", item);
+    getSceneModel(item)?.destroy();
   }
-}
-
+};
 
 export const associationModels = (sdk: SDK) => {
-  const getModels = () => fuseModels.value
-    .filter(model => getSceneModel(model) || getFuseModelShowVariable(model).value)
-  
+  watch(
+    () => ({
+      showMode: custom.showMode,
+      active: custom.currentModel,
+    }),
+    (status, _, onCleanup) => {
+      if (status.showMode !== "pano" || !status.active) return;
+      const sceneModel = getSceneModel(status.active);
+      sceneModel?.flyInPano();
+
+      onCleanup(() => {
+        sceneModel?.flyOutPano();
+      });
+    }
+  );
+
+  const getModels = () =>
+    fuseModels.value.filter(
+      (model) => getSceneModel(model) || getFuseModelShowVariable(model).value
+    );
+
   shallowWatchArray(getModels, (models, oldModels) => {
-    setModels(sdk, models, oldModels)
-  })
-  
-  arrayChildEffectScope(getModels, item => {
+    setModels(sdk, models, oldModels);
+  });
+
+  arrayChildEffectScope(getModels, (item) => {
     const stopLoadedWatch = watch(
       () => item.loaded,
       (loaded) => {
         if (loaded) {
-          const modelShow = getFuseModelShowVariable(item)
+          const modelShow = getFuseModelShowVariable(item);
           watch(
-            () => item.bottom, 
-            () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom), 
+            () => item.bottom,
+            () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom)
             // { immediate: true }
-          )
+          );
           watch(
-            () => item.opacity, 
-            () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity), 
+            () => item.opacity,
+            () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity)
             // { immediate: true }
-          )
+          );
           watch(
-            () => item.scale, 
-            () => isUnSet || getSceneModel(item)?.changeScale(item.scale), 
+            () => item.scale,
+            () => isUnSet || getSceneModel(item)?.changeScale(item.scale)
             // { immediate: true }
-          )
+          );
           watch(
-            () => item.position, 
+            () => item.position,
             () => {
               if (!isUnSet) {
-                getSceneModel(item)?.changePosition(item.position)
+                getSceneModel(item)?.changePosition(item.position);
               }
-            }, 
+            }
             // { immediate: true }
-          )
+          );
           watch(
-            () => item.rotation, 
+            () => item.rotation,
             () => {
               if (!isUnSet) {
-                getSceneModel(item)?.changeRotation(item.rotation)
+                getSceneModel(item)?.changeRotation(item.rotation);
               }
-            }, 
+            }
             // { immediate: true }
-          )
+          );
           watch(
-            () => modelShow.value, 
+            () => modelShow.value,
             () => {
-              const sceneModel = getSceneModel(item)
+              const sceneModel = getSceneModel(item);
               if (!isUnSet && sceneModel) {
-                sceneModel.changeSelect(false)
-                sceneModel.changeShow(modelShow.value)
+                sceneModel.changeSelect(false);
+                sceneModel.changeShow(modelShow.value);
               }
-            }, 
+            },
             { immediate: true }
-          )
+          );
 
           watch(
             () => custom.currentModel === item,
             (selected) => {
-              isUnSet || console.log(item.title, selected, getSceneModel(item))
-              isUnSet || getSceneModel(item)?.changeSelect(selected)
+              isUnSet || getSceneModel(item)?.changeSelect(selected);
             }
-          )
+          );
 
-          stopLoadedWatch()
+          stopLoadedWatch();
         }
-      },
+      }
       // { immediate: true }
-    )
-  })
-}
+    );
+  });
+};

+ 44 - 7
src/sdk/cover/index.js

@@ -38,7 +38,7 @@ export const enter = ({dom, mapDom, isLocal, lonlat, scenes }) => {
     
     let {THREE} = Potree.mergeEditStart(dom, mapDom)
     let MergeEditor = viewer.modules.MergeEditor
-    
+    Potree.settings.unableNavigate = false
     Potree.settings.showCesium = true
     if(Potree.settings.showCesium){ 
         
@@ -721,10 +721,16 @@ export const enter = ({dom, mapDom, isLocal, lonlat, scenes }) => {
                     setTimeout(()=>{
                         MergeEditor.focusOn([model], 1000, true, true)
                     },1) 
+                } 
+                if(props.fromType == 6){ 
+                    Potree.load4dkkPanos(props.url, model,()=>{
+                        bus.emit('loadDone')
+                    })
+                }else{
+                    bus.emit('loadDone')
                 }
-
                 
-                bus.emit('loadDone')
+                
                 
                 //console.log('loadDone' )
             }
@@ -958,14 +964,37 @@ export const enter = ({dom, mapDom, isLocal, lonlat, scenes }) => {
                 flyInPano(){//  飞入全景图
                     let pano = viewer.images360.findNearestPano(null,model.panos)
                     if(pano){
-                        Potree.settings.displayMode = 'showPanos'
-                        viewer.images360.flyToPano(pano)
-                        Potree.Utils.updateVisible(viewer.objs, 'showPanos', false)
+                        viewer.images360.panos.forEach(pano=>{
+                            pano.setEnable(pano.pointcloud == model )
+                        })
+                        viewer.setControls(viewer.fpControls)
+                        viewer.images360.flyToPano(pano) 
+                        viewer.images360.addEventListener('endChangeMode',()=>{ 
+                            Potree.Utils.updateVisible(viewer.objs, 'showPanos', false)
+                        },{once:true})
+                        
+                        Potree.settings.displayMode = 'showPanos' 
+                        
                     }
                 },
                 flyOutPano(){//  飞出全景图(就是切换到正常融合视角)
-                    Potree.settings.displayMode = 'showPointCloud'
+                    let panoPos = viewer.images360.position.clone()
                     Potree.Utils.updateVisible(viewer.objs, 'showPanos', true)
+                    setTimeout(()=>{//在下一帧再变,因为3dtiles需要更新一下才会显示tiles
+                        Potree.settings.displayMode = 'showPointCloud'
+                    },20) 
+                    let camera_changed = (e)=>{
+                        if (e.viewport.name == 'MainView' && e.changeInfo.positionChanged ) {
+                            //viewer.mainViewport.camera.position
+                            viewer.mainViewport.view.radius = 0.1 //使pivot在面前一丢丢距离
+                            viewer.setControls(viewer.orbitControls)
+                            viewer.removeEventListener('camera_changed',camera_changed)
+                        }
+                    }
+                    viewer.addEventListener('camera_changed',camera_changed)
+                        
+                   
+                    
                 },
                 destroy(){
                     model && MergeEditor.removeModel(model) 
@@ -1168,4 +1197,12 @@ export const enter = ({dom, mapDom, isLocal, lonlat, scenes }) => {
     return sdk 
 }
 
+ 
+/* 
+
+    暂定不同场景间的漫游点不能互通。虽然它们可能是摆放正确的,如果是组成一整个场景的话还是要打通……
+    不互通的方法是设置pano.enable
+
+ */
+
 export default enter

+ 4 - 0
src/sdk/sdk.ts

@@ -32,6 +32,10 @@ export type SceneModel = ToChangeAPI<SceneModelAttrs>
     leaveAlignment: () => void
     enterScaleSet:() => ScaleSet
     leaveScaleSet: () => void
+
+    supportPano: () => boolean;
+    flyInPano: () => void;
+    flyOutPano: () => void;
   }
 
 export interface ScaleSet {

+ 5 - 4
src/utils/stack.ts

@@ -20,21 +20,21 @@ export const stackFactory = <T>(initVal?: T, debug?: boolean): Stack<T> => {
     push(raw: T) {
       stack.push(raw);
       if (debug) {
-        console.warn('push', raw)
+        console.warn("push", raw);
       }
       return () => {
         const index = stack.indexOf(raw);
         ~index && stack.splice(index, 1);
         if (debug) {
-          console.warn('pop', raw)
-          console.warn('current', stack)
+          console.warn("pop", raw);
+          console.warn("current", stack);
         }
       };
     },
     pop() {
       let ret = stack[stack.length-- - 1];
       if (debug) {
-        console.warn('pop current', stack)
+        console.warn("pop current", stack);
       }
       return ret;
     },
@@ -69,6 +69,7 @@ export const flatStacksValue = <T extends { [key in any]: Stack<any> }>(
       } else {
         (stacks[key].current.value as any) = val;
       }
+      console.error("set", stacks[key].current.value.value, val);
       return true;
     },
   });