123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- import { sdk } from './sdk'
- import { toRaw, ref, watch, nextTick, watchEffect, reactive } from 'vue'
- import {
- viewModeStack,
- showLeftPanoStack,
- custom,
- } from '@/env'
- import {
- mount,
- diffArrayChange,
- shallowWatchArray,
- arrayChildEffectScope,
- showLoad,
- hideLoad,
- deepIsRevise,
- round,
- togetherCallback,
- asyncTimeout
- } from '@/utils'
- import {
- dynamicAddedModelIds,
- fuseModels,
- taggings,
- isEdit,
- sysBus,
- getFuseModelShowVariable,
- SceneType,
- MeasureType,
- measures,
- fuseModelsLoaded,
- getMeasureIsShow,
- SceneStatus,
- setting,
- caseProject,
- getGuidePaths,
- guidePaths
- } from '@/store'
- import { currentLayout, RoutesName } from '@/router'
- import TaggingComponent from '@/components/tagging/list.vue'
- import type { FuseModel, Tagging, Measure, FuseModels, Guide } from '@/store'
- import type {
- SDK,
- SceneModel,
- SceneGuidePath,
- ModelAttrRange,
- Measure as SceneMeasure
- } from '.'
- import { SettingResourceType } from '@/api/setting-resource'
- let isUnSet = false
- const unSet = ((fn: () => void) => {
- isUnSet = true
- fn()
- nextTick(() => isUnSet = false)
- })
- // -----------------模型关联--------------------
- 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 }
- }
- const sceneModelMap = reactive(new WeakMap<FuseModel, SceneModel>())
- export const getSceneModel = (model?: FuseModel | null) => model && sceneModelMap.get(toRaw(model))
- const setModels = (models: FuseModels, oldModels: FuseModels) => {
- 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
- continue;
- }
- 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.C_SWSS, SceneType.SWSS, SceneType.SWYDSS].includes(item.type) ? 'laser' : item.modelType,
- url: [SceneType.C_SWSS,SceneType.SWSS, SceneType.SWYDSS].includes(item.type) ? item.url : item.url && item.url,
- fromType: item.type
- })
- } catch(e) {
- console.error('模型加载失败', e)
- item.error = true
- return;
- }
- sceneModelMap.set(itemRaw, sceneModel)
- let changeId: NodeJS.Timeout
- sceneModel.bus.on('transformChanged', transform => {
- clearTimeout(changeId)
- changeId = setTimeout(() => {
- 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
- // if (transform.bottom) {
- // transform.bottom = round(transform.bottom, 2)
- // }
- if (transform.scale) {
- transform.scale = round(transform.scale, 2)
- }
- const updateKeys = Object.keys(transform)
- const update: any = {}
- for (const key of updateKeys) {
- update[key] = (item as any)[key]
- }
-
- if (deepIsRevise(update, transform)) {
- unSet(() => Object.assign(item, transform))
- }
- }, 16)
- })
- sceneModel.bus.on('changeSelect', select => {
- unSet(() => {
- 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)
- }
- for (const item of deleted) {
- console.error('销毁', item)
- getSceneModel(item)?.destroy()
- }
- }
- const associationModels = (sdk: SDK) => {
- const getModels = () => fuseModels.value
- .filter(model => getSceneModel(model) || getFuseModelShowVariable(model).value)
-
- shallowWatchArray(getModels, (models, oldModels) => {
- setModels(models, oldModels)
- })
-
- arrayChildEffectScope(getModels, item => {
- const stopLoadedWatch = watch(
- () => item.loaded,
- (loaded) => {
- if (loaded) {
- const modelShow = getFuseModelShowVariable(item)
- watch(
- () => item.bottom,
- () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom),
- // { immediate: true }
- )
- watch(
- () => item.opacity,
- () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity),
- // { immediate: true }
- )
- watch(
- () => item.scale,
- () => isUnSet || getSceneModel(item)?.changeScale(item.scale),
- // { immediate: true }
- )
- watch(
- () => item.position,
- () => {
- if (!isUnSet) {
- getSceneModel(item)?.changePosition(item.position)
- }
- },
- // { immediate: true }
- )
- watch(
- () => item.rotation,
- () => {
- if (!isUnSet) {
- getSceneModel(item)?.changeRotation(item.rotation)
- }
- },
- // { immediate: true }
- )
- watch(
- () => modelShow.value,
- () => {
- const sceneModel = getSceneModel(item)
- if (!isUnSet && sceneModel) {
- 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)
- }
- )
- stopLoadedWatch()
- }
- },
- // { immediate: true }
- )
- })
- }
- // -----------------热点关联--------------------
- const associationTaggings = (el: HTMLDivElement) => {
- const getTaggings = () => taggings.value
- const taggingVMs = new WeakMap<Tagging, ReturnType<typeof mount>>()
- shallowWatchArray(getTaggings, (taggings, oldTaggings) => {
- const { added, deleted } = diffArrayChange(taggings, oldTaggings)
- for (const item of added) {
- taggingVMs.set(toRaw(item), mount(el, TaggingComponent, { tagging: item }))
- }
- for (const item of deleted) {
- const unMount = taggingVMs.get(toRaw(item))
- unMount && unMount()
- }
- })
- }
- // -----------------测量关联--------------------
- const sceneMeasureMap = reactive(new WeakMap<Measure , SceneMeasure>())
- export const getSceneMeasure = (measure?: Measure | null) => measure && sceneMeasureMap.get(toRaw(measure))
- export const getSceneMeasureDesc = (smMeasure: SceneMeasure, measure: Measure) => {
- const length = measure.type === MeasureType.area
- ? (smMeasure as unknown as SceneMeasure<MeasureType.area>).getArea()
- : (smMeasure as unknown as SceneMeasure<MeasureType.free>).getDistance()
- return round(length.value, 2).toString()
- }
- export const associationMessaure = <T extends MeasureType>(smMeasure: SceneMeasure<T>, measure: Measure<T>) => {
- smMeasure.bus.on('update', ([points, modelIds]) => {
- unSet(() => measure.positions = points.map((point, i) => ({ point, modelId: modelIds[i] })))
- })
- smMeasure.bus.on('highlight', selected => unSet(() => measure.selected = selected))
- }
- const associationMessaures = (sdk: SDK) => {
- const getMeasures = () => measures.value.filter(getMeasureIsShow)
- shallowWatchArray(getMeasures, (measures, oldMeasures) => {
- const { added, deleted } = diffArrayChange(measures, oldMeasures)
- for (const item of added) {
- const sceneMeasure = sdk.drawMeasure(
- item.type,
- item.positions.map(position => ({...position.point})),
- item.positions.map(position => position.modelId),
- )
- if (sceneMeasure.destroy) {
- sceneMeasureMap.set(toRaw(item), sceneMeasure)
- associationMessaure(sceneMeasure, item)
- }
- }
- for (const item of deleted) {
- const sceneMeasure = getSceneMeasure(item)
- sceneMeasure && sceneMeasure.destroy!()
- sceneMeasureMap.delete(toRaw(item))
- }
- })
- arrayChildEffectScope(getMeasures, measure => {
- watch(
- () => measure.selected,
- (selected = false) => isUnSet || getSceneMeasure(measure)?.changeSelect(selected)
- )
- watch(
- () => measure.positions,
- (positions) => isUnSet || getSceneMeasure(measure)?.setPositions(
- positions.map(position => ({...position.point})),
- positions.map(position => position.modelId),
- )
- )
- watch(
- () => custom.showMeasures,
- (show) => {
- if (!isUnSet) {
- const smMeasure = getSceneMeasure(measure)
- if (show) {
- smMeasure?.show()
- } else {
- smMeasure?.hide()
- }
- }
- },
- { immediate: true }
- )
- })
- }
- // -----------------导览关联--------------------
- const fullView = async (fn: () => void) => {
- const popViewMode = togetherCallback([
- viewModeStack.push(ref('full')),
- showLeftPanoStack.push(ref(false))
- ])
- let isFull = false;
- try {
- await document.documentElement.requestFullscreen()
- isFull = true;
- } catch {}
-
- const driving = () => document.fullscreenElement || fn()
- const stop = (ev: KeyboardEvent) => ev.key == "Escape" && fn()
- if (isFull) {
- document.addEventListener('fullscreenchange', driving)
- document.addEventListener('fullscreenerror', fn)
- } else {
- document.addEventListener("keyup", stop)
- }
- return () => {
- popViewMode()
- if (isFull) {
- document.fullscreenElement && document.exitFullscreen()
- document.removeEventListener('fullscreenchange', driving)
- document.removeEventListener('fullscreenerror', fn)
- } else {
- document.removeEventListener("keyup", stop)
- }
- }
- }
- export const recovery = async (guide: Guide) => {
- let rFuseModels: (FuseModel & {viewShow: boolean})[];
- try {
- if (!guide.recoveryContent) {
- throw "没有recovery";
- }
- rFuseModels = JSON.parse(guide.recoveryContent);
- } catch (e) {
- return () => {};
- }
- const initFuseModels = JSON.parse(JSON.stringify(fuseModels.value)) as FuseModels;
- const initViewShow = fuseModels.value.map(item => custom.showModelsMap.get(item))
- console.error(initFuseModels, rFuseModels)
- const setModels = async (models: (FuseModel & {viewShow: boolean})[]) => {
- for (let i = 0; i < models.length; i++) {
- const ndx = fuseModels.value.findIndex(({ modelId }) => modelId === models[i].modelId);
- if (~ndx) {
- Object.assign(fuseModels.value[ndx], models[i]);
- custom.showModelsMap.set(toRaw(fuseModels.value[ndx]), models[i].viewShow)
- } else {
- fuseModels.value.push(models[i]);
- custom.showModelsMap.set(toRaw(models[i]), models[i].viewShow)
- }
- }
- // console.log(models)
- for (let i = 0; i < fuseModels.value.length; i++) {
- const ndx = models.findIndex(({ modelId }) => modelId === fuseModels.value[i].modelId);
- if (!~ndx) {
- fuseModels.value.splice(i, 1);
- i--
- }
- }
- await asyncTimeout(100)
- await new Promise<void>((resolve) => {
- const stop = watchEffect(() => {
- if (fuseModelsLoaded.value) {
- setTimeout(() => stop())
- resolve()
- }
- })
- })
- };
-
-
- for (let i = 0; i < fuseModels.value.length; i++) {
- const ndx = rFuseModels.findIndex(({ modelId }) => modelId === fuseModels.value[i].modelId);
- if (!~ndx) {
- rFuseModels.push({...fuseModels.value[i], viewShow: false})
- }
- }
- await setModels(rFuseModels);
- return () =>
- setModels(initFuseModels.map((item, i) => ({...item, viewShow: initViewShow[i]!})));
-
- };
- export enum ScenePlayIngEnum {
- ing = 1,
- stop = 0,
- ready = 2
- }
- export const isScenePlayIng = ref<ScenePlayIngEnum>(ScenePlayIngEnum.stop)
- let pauseRecovery: () => void
- export const playSceneGuide = async (guide: Guide, changeIndexCallback?: (index: number) => void, forceFull = false, paths = getGuidePaths(guide)) => {
- console.log(guide, guidePaths.value)
- if (isScenePlayIng.value) {
- throw new Error('导览正在播放')
- }
- isScenePlayIng.value = ScenePlayIngEnum.ready
- pauseRecovery = await recovery(guide)
- isScenePlayIng.value = ScenePlayIngEnum.ing
- const sceneGuide = sdk.enterSceneGuide(paths)
- changeIndexCallback && sceneGuide.bus.on('changePoint', changeIndexCallback)
- const quitHandler = pauseSceneGuide
- const clearHandler = !forceFull && isEdit.value ? null : await fullView(quitHandler)
- if (!clearHandler) {
- sysBus.on('leave', quitHandler, { last: true })
- sysBus.on('save', quitHandler, { last: true })
- }
- sceneGuide.play()
- const reces = [
- new Promise(resolve => sceneGuide.bus.on('playComplete', resolve)),
- new Promise<void>(resolve => {
- const stop = watch(isScenePlayIng, () => {
- if (!isScenePlayIng.value) {
- resolve()
- sceneGuide.pause()
- stop()
- }
- })
- }),
- ]
- await Promise.race(reces)
- pauseSceneGuide()
-
- if (clearHandler) {
- clearHandler()
- } else {
- sysBus.off('leave', quitHandler)
- sysBus.off('save', quitHandler)
- }
- sceneGuide.clear()
- sceneGuide.bus.off('changePoint')
- }
- export const pauseSceneGuide = () => {
- console.error('pause?')
- isScenePlayIng.value = ScenePlayIngEnum.stop
- pauseRecovery && pauseRecovery()
- }
- // -----------------启动关联--------------------
- export const setupAssociation = (mountEl: HTMLDivElement) => {
- associationModels(sdk)
- const stopWatch = watchEffect(() => {
- if (fuseModelsLoaded.value && setting.value) {
- associationTaggings(mountEl)
- associationMessaures(sdk)
- setting.value?.pose && sdk.comeTo(setting.value.pose)
- setBackdrop(setting.value!.back, setting.value!.backType, { scale: setting.value!.scale, rotate: setting.value!.rotate});
- setMap(setting.value!.mapOpen, setting.value!.mapType)
- watchEffect(() => {
- sdk.setCameraFov && sdk.setCameraFov(setting.value!.fov)
- })
-
- ;(document.querySelector('#direction') as HTMLDivElement)!.style.display = setting.value!.openCompass ? 'block' : 'none';
- nextTick(() => stopWatch())
- }
- })
- }
- export const setBackdrop = (back: string, type: SettingResourceType, tb: {scale?: number, rotate?: number} = { scale: 1, rotate: 0 }) => {
- ;(document.querySelector('#scene-map') as HTMLDivElement)!.style.display = 'none';
- if (type === SettingResourceType.map) {
- if (!caseProject.value!.tmProject?.latlng) {
- return;
- }
-
- const latlng = caseProject.value!.tmProject?.latlng.split(',').map(i => Number(i))
- ;(document.querySelector('#scene-map') as HTMLDivElement)!.style.display = 'block';
- sdk.enableMap && sdk.enableMap(document.querySelector('#scene-map') as HTMLDivElement, latlng)
- sdk.switchMapType && sdk.switchMapType(back)
- // 'satellite' | 'standard'
- } else if (type!== SettingResourceType.icon) {
- setting.value?.back && sdk.setBackdrop(back, type, tb)
- } else {
- sdk.setBackdrop('none', type, {scale: 1, rotate: 0})
- }
- }
- let opened = false
- export const setMap = (open: boolean, type:string = 'satellite') => {
- if (!caseProject.value!.tmProject?.latlng) {
- ;(document.querySelector('#scene-map') as HTMLDivElement)!.style.display = 'none';
- return;
- }
- if (open) {
- ;(document.querySelector('#scene-map') as HTMLDivElement)!.style.display = 'block';
- } else {
- ;(document.querySelector('#scene-map') as HTMLDivElement)!.style.display = 'none';
- return;
- }
- if (!opened) {
- const latlng = caseProject.value!.tmProject?.latlng.split(',').map(i => Number(i))
- console.log('open map')
- sdk.enableMap && sdk.enableMap(document.querySelector('#scene-map') as HTMLDivElement, latlng)
- opened = true
- }
- sdk.switchMapType && sdk.switchMapType(type)
- }
|