vu3+vite+supermap(超图)实现可视域分析

<template>
    <div class="dialog-draggable">
        <el-dialog draggable destroy-on-close v-if="changeRangeVisibility" :modal="false" v-model="changeRangeVisibility"
            title="可视域分析" width="24%" :before-close="handleClose" @opened="getOpen()" :close-on-click-modal="false">
            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">方向(度)</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-slider v-model="viewedModel.direction" show-input :step="1" :min=0 :max=360  @change="directionChange"/>
                        </div>
                    </el-col>
                </el-row>
            </div>

            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">翻转(度)</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-slider v-model="viewedModel.pitch" show-input :min=-90 :max=90  @change="pitchChange"/>
                        </div>
                    </el-col>
                </el-row>
            </div>

            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">距离(米)</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-slider v-model="viewedModel.distance" show-input :min=1 :max=500 @change="distanceChange" />
                        </div>
                    </el-col>
                </el-row>
            </div>

            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">水平视场角</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-slider v-model="viewedModel.horizontalFov" show-input :min=1 :max=120 @change='horizontalFovChange' />
                        </div>
                    </el-col>
                </el-row>
            </div>

            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">垂直视场角</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-slider v-model="viewedModel.verticalFov" show-input :min=1 :max=90 @change='verticalFovChange'  />
                        </div>
                    </el-col>
                </el-row>
            </div>

            <!--可见颜色-->
            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">可见颜色</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <el-color-picker v-model="viewedModel.visibleAreaColor" />
                        </div>
                    </el-col>
                </el-row>
            </div>
            <!--不可见颜色-->
            <div class="el-h-line">
                <el-row :gutter="10">
                    <el-col :span="5">
                        <p class="font-big">不可见颜色</p>
                    </el-col>
                    <el-col :span="19">
                        <div class="slider-demo-block">
                            <div class="el-demo">
                                <el-color-picker v-model="viewedModel.invisibleAreaColor" />
                            </div>
                        </div>
                    </el-col>
                </el-row>
            </div>
            <template #footer>
                <span class="dialog-footer">
                    <el-button @click="drawViewshed">绘制分析</el-button>
                    <el-button type="primary" @click="clearViewshed" style="background-color: #1d888b;">
                        清除
                    </el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, unref, toRaw } from 'vue'
import { ElMessage } from 'element-plus'
// 组件传值
import emitter from "../../../utils/bus";
const changeRangeVisibility = ref<Boolean>(true)

// 定义参数类型
interface viewedModelValue {
    direction: number
    pitch: number
    distance: number
    horizontalFov: number
    verticalFov:number
    visibleAreaColor:string
    invisibleAreaColor:string
}
const viewedModel = ref<viewedModelValue>({
    direction: 0,
    pitch: -90,
    distance: 1,
    horizontalFov: 120,
    verticalFov: 90,
    visibleAreaColor: '#009eff',
    invisibleAreaColor: '#ffb200'
})
const viewPosition = ref()
const viewPointHandler = ref()
const viewshed3D = ref()
const viewEventHandler = ref()
const Cesium = window.Cesium

const handleClose = (done: () => void) => {
    done()
    clearViewshed()
}

// 接受layoutMenu传过来的值
emitter.on("rangeState", (data: any) => {
    changeRangeVisibility.value = data
});

const drawViewshed = (): void => {
    if (!window.scene.pickPositionSupported) {
        ElMessage({
            showClose: true,
            message: '不支持深度纹理,可视域分析功能无法使用(无法添加观测)!',
            type: 'error',
        })
        return
    }
    // 先将此标记置为true,不激活鼠标移动事件中对可视域分析对象的操作
    window.scene.viewFlag = true
    if (!viewPointHandler.value) {
        viewPointHandler.value = new Cesium.DrawHandler(
            window.viewer,
            Cesium.DrawMode.Point
        )
    }
    if (!viewshed3D.value) {
        viewshed3D.value = new Cesium.ViewShed3D(window.scene)
    }
    Cesium.knockout.track(toRaw(unref(viewedModel)))
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'direction')
        .subscribe((newValue: string) => {
            viewshed3D.value.direction = parseFloat(newValue)
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'pitch')
        .subscribe((newValue: string) => {
            viewshed3D.value.pitch = parseFloat(newValue)
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'distance')
        .subscribe((newValue: string) => {
            viewshed3D.value.distance = parseFloat(newValue)
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'verticalFov')
        .subscribe((newValue: string) => {
            viewshed3D.value.verticalFov = parseFloat(newValue)
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'horizontalFov')
        .subscribe((newValue: string) => {
            viewshed3D.value.horizontalFov = parseFloat(newValue)
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'visibleAreaColor')
        .subscribe((newValue: string) => {
            var color = Cesium.Color.fromCssColorString(newValue)
            viewshed3D.value.visibleAreaColor = color
        })
    Cesium.knockout
        .getObservable(toRaw(unref(viewedModel)), 'invisibleAreaColor')
        .subscribe((newValue: string) => {
            var color = Cesium.Color.fromCssColorString(newValue)
            viewshed3D.value.hiddenAreaColor = color
        })
    if (!viewEventHandler.value) {
        viewEventHandler.value = new Cesium.ScreenSpaceEventHandler(
            window.scene.canvas
        )
    }
    viewEventHandler.value.setInputAction((e: object) => {
        // 若此标记为false,则激活对可视域分析对象的操作
        if (!window.scene.viewFlag) {
            // 获取鼠标屏幕坐标,并将其转化成笛卡尔坐标
            var position = e.endPosition
            var last = window.scene.pickPosition(position)

            // 计算该点与视口位置点坐标的距离
            var distance = Cesium.Cartesian3.distance(viewPosition.value, last)

            if (distance > 0) {
                // 将鼠标当前点坐标转化成经纬度
                var cartographic = Cesium.Cartographic.fromCartesian(last)
                var longitude = Cesium.Math.toDegrees(cartographic.longitude)
                var latitude = Cesium.Math.toDegrees(cartographic.latitude)
                var height = cartographic.height
                // 通过该点设置可视域分析对象的距离及方向
                viewshed3D.value.setDistDirByPoint([longitude, latitude, height])
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    viewEventHandler.value.setInputAction((e: any) => {
        // 鼠标右键事件回调,不再执行鼠标移动事件中对可视域的操作
        window.scene.viewFlag = true
        viewedModel.value.direction = viewshed3D.value.direction
        viewedModel.value.pitch = viewshed3D.value.pitch
        viewedModel.value.distance = viewshed3D.value.distance
        viewedModel.value.horizontalFov = viewshed3D.value.horizontalFov
        viewedModel.value.verticalFov = viewshed3D.value.verticalFov
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    viewPointHandler.value.drawEvt.addEventListener((result: any) => {
        var point = result.object
        var position = point.position
        viewPosition.value = position

        // 将获取的点的位置转化成经纬度
        var cartographic = Cesium.Cartographic.fromCartesian(position)
        var longitude = Cesium.Math.toDegrees(cartographic.longitude)
        var latitude = Cesium.Math.toDegrees(cartographic.latitude)
        var height = cartographic.height
        point.position = Cesium.Cartesian3.fromDegrees(
            longitude,
            latitude,
            height
        )

        if (window.scene.viewFlag) {
            // 设置视口位置
            viewshed3D.value.viewPosition = [longitude, latitude, height]
            viewshed3D.value.hiddenAreaColor = Cesium.Color.fromCssColorString(viewedModel.value.invisibleAreaColor)
            viewshed3D.value.visibleAreaColor = Cesium.Color.fromCssColorString(viewedModel.value.visibleAreaColor)
            viewshed3D.value.build()
            // 将标记置为false以激活鼠标移动回调里面的设置可视域操作
            window.scene.viewFlag = false
        }
    })
    if (viewPointHandler.value.active) {
        return
    }
    // 先清除之前的可视域分析
    window.viewer.entities.removeAll()
    viewshed3D.value.distance = 1
    window.scene.viewFlag = true
    // 激活绘制点类
    viewPointHandler.value.activate()
}

const clearViewshed = (): void => {
    window.viewer.entities.removeAll()
    if (viewshed3D.value) {
        viewshed3D.value.distance = 0.1
    }
    window.scene.viewFlag = true
    //viewPointHandler.value = undefined
    // 清除观察点
    if (viewPointHandler.value) {
        viewPointHandler.value.clear()
    }
    // 初始化属性面板
    viewedModel.value.direction = 0
    viewedModel.value.pitch = -90
    viewedModel.value.distance = 1
    viewedModel.value.horizontalFov = 120
    viewedModel.value.verticalFov = 90
    viewedModel.value.visibleAreaColor = '#009eff',
    viewedModel.value.invisibleAreaColor = '#ffb200'
}


// 初始化进入路由页面时传穿透
onMounted(() => {
    onDialog()
});
// 弹框打开之后的回调再次穿透页面
const getOpen = () => {
    onDialog()
}


//方向变化
const directionChange = (val:number) =>{
    viewedModel.value.direction = val
}
// 翻转(度)
const pitchChange = (val:number) =>{
    viewedModel.value.pitch = val
}
// 距离
const distanceChange = (val:number)=>{
    viewedModel.value.distance = val
}
// 水平视场角
const horizontalFovChange = (val:number)=>{
    viewedModel.value.horizontalFov = val
}
// 垂直是仰角
const verticalFovChange = (val:number) =>{
    viewedModel.value.verticalFov =val
}

onBeforeUnmount(() => {
    clearViewshed()
    viewPosition.value = undefined
    viewPointHandler.value = undefined
    viewshed3D.value = undefined
    viewEventHandler.value = undefined
})

// 解决弹框打开时可操作操作其他Dom的问题
const onDialog = () => {
    var box = document.querySelector(".el-overlay-dialog");
    // 获取.el-overlay-dialog父级
    var boxa = box.parentNode;
    //  使用pointerEvents 进行页面穿透
    boxa.style.pointerEvents = "none";
}
</script>
  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸥总

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值