import _ from 'lodash'
|
import { boxTransformScale } from '@/utils/turfFunc'
|
import { MAP_LEVEL } from '@/const/drc'
|
import * as Cesium from 'cesium'
|
import { PolyGradientMaterial } from '@/utils/cesium/Material'
|
import { useStore } from 'vuex'
|
import { getDeviceRegion, getDeviceRegionCount } from '@/api/home/aggregation'
|
import userStore from '@/store/modules/user'
|
import { areaCodeToArr, getContourByCode } from '@/utils/cesium/mapUtil'
|
// import { getEllipse } from '@/hooks/useSingleDroneMap/useSingleDroneMap'
|
import getBaseConfig from '@/buildConfig/config'
|
import { getDroneStatusImage } from '@/utils/stateToImageMap/drone'
|
import {
|
GroundCirclePrimitiveManager
|
} from '@/utils/mapUtils'
|
|
const { VITE_APP_BASE, VITE_APP_ENV, VITE_APP_REGION_URL } = import.meta.env
|
// const { singleDockSystem } = getBaseConfig()
|
const { singleDockSystem } = getBaseConfig()
|
|
|
|
/**
|
* 使用通用的边界
|
* @param viewer
|
* @param options
|
*/
|
export const useBoundary = (viewer, options = {}) => {
|
const { multiple = 1.4, dockOptions = {}, boundaryChange, boundaryColor, dockRangeType, useDockHeight = false } = options
|
const { scrollShowDock = false, showDock = false } = dockOptions
|
|
const manager = new GroundCirclePrimitiveManager()
|
manager.init(viewer)
|
|
// 缩放判断list(包含省市县的轮廓边界散点数据)
|
let scalingJudgment = _.cloneDeep(MAP_LEVEL).map(i => ({ ...i, gJson: null, show: false, outline: {} }))
|
let active = null
|
const defaultDir = `${VITE_APP_REGION_URL}/100000/`
|
const userAreaCode = userStore.state.userInfo.detail.areaCode
|
const selectedAreaCode = userStore.state.selectedAreaCode
|
const dockSource = new Cesium.CustomDataSource('dockSource')
|
const outlineSource = new Cesium.CustomDataSource('outlineSource')
|
const minOutlineSource = new Cesium.CustomDataSource('minOutlineSource')
|
|
viewer.dataSources.add(dockSource)
|
viewer.dataSources.add(outlineSource)
|
viewer.dataSources.add(minOutlineSource)
|
let initDockList = []
|
let showDockSnList = null
|
|
if (scrollShowDock || showDock) {
|
getDeviceRegionFun().then(list => {
|
initDockList = list
|
if (showDock && !scrollShowDock) droneSplashed()
|
})
|
}
|
|
// 获取设备列表
|
async function getDeviceRegionFun () {
|
const res = await getDeviceRegion({ areaCode: selectedAreaCode })
|
return res?.data?.data || []
|
}
|
|
// 确定缩放比例
|
const determineScaling = () => {
|
if (!viewer) return
|
let height = viewer.camera.positionCartographic.height
|
// 根据高度展示对应的 gJson
|
for (let [index, item] of scalingJudgment.entries()) {
|
if (!item.show) return
|
if (height > item.heightRange[0] && height <= item.heightRange[1]) {
|
if (active === item.name) return
|
boundaryChange?.(item?.gJson?.features)
|
active = item.name
|
removeBoundary()
|
renderOutline(item)
|
scrollShowDock && removeDockCover()
|
item.gJson || (scrollShowDock && droneSplashed(item))
|
break
|
}
|
}
|
}
|
|
const removeBoundary = () => {
|
minOutlineSource?.entities.removeAll()
|
outlineSource?.entities?.removeAll()
|
}
|
const removeAllEntities = () => {
|
removeBoundary()
|
removeDockCover()
|
}
|
|
const removeDockCover = () => {
|
dockSource?.entities?.removeAll()
|
manager?.removeAll()
|
}
|
|
const getFiler = async url => {
|
const res = await fetch(url)
|
return await res.json()
|
}
|
|
// 无人机散点渲染
|
const droneSplashed = () => {
|
let showDockList = showDockSnList === null
|
? _.cloneDeep(initDockList)
|
: initDockList.filter(item => showDockSnList.includes(item.device_sn))
|
|
showDockList.forEach((item, index) => {
|
let polyline = {}
|
|
if (dockRangeType === 2) {
|
manager.addCircleOutline({
|
data: {
|
lng: item.longitude,
|
lat: item.latitude
|
},
|
frameColor: Cesium.Color.fromCssColorString('#7FFFD4')
|
})
|
} else {
|
manager.addCircle({
|
data: {
|
lng: item.longitude,
|
lat: item.latitude
|
},
|
materialColor: Cesium.Color.CORNFLOWERBLUE.withAlpha(0.3)
|
})
|
}
|
|
if (useDockHeight) {
|
polyline = {
|
positions: new Cesium.CallbackProperty(() => {
|
const pointPosition = Cesium.Cartesian3.fromDegrees(+item.longitude, +item.latitude, +item.height)
|
if (!pointPosition) return []
|
// 获取点的位置
|
const cartographic = Cesium.Cartographic.fromCartesian(pointPosition)
|
// 获取地形高度
|
const terrainHeight = viewer.scene.globe.getHeight(cartographic) || 0
|
// 创建地面点位置
|
const groundPosition = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, terrainHeight)
|
|
return [pointPosition, groundPosition]
|
}, false),
|
width: 0.5,
|
material: Cesium.Color.WHITE,
|
}
|
}
|
|
dockSource.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(+item.longitude, +item.latitude, !useDockHeight ? 0 : +item.height),
|
polyline,
|
billboard: {
|
image: getDroneStatusImage(item.status),
|
width: 60,
|
height: 60,
|
eyeOffset: new Cesium.Cartesian3(0, 0, -5)
|
},
|
})
|
})
|
}
|
|
// 渲染各个独立的轮廓
|
const renderOutline = item => {
|
// 加载大边界
|
item.outline &&
|
Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => {
|
const entities = dataSource.entities.values
|
entities.forEach((entity, index) => {
|
// 创建独立折线作为轮廓
|
const positions = entity.polygon.hierarchy.getValue().positions
|
const randomInt = Math.floor(Math.random() * 5) + 1
|
let polygon = {}
|
if (item.name === '县' && !scalingJudgment[0].outline) {
|
let material = new PolyGradientMaterial({
|
color: Cesium.Color.fromCssColorString(arrColor[randomInt]),
|
opacity: 0.7,
|
alphaPower: 1.3,
|
})
|
entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || 1) * 500
|
entity.polygon.material = material
|
polygon = entity.polygon
|
entity.polygon.outline = false // 显示边框
|
}
|
outlineSource.entities.add({
|
polyline: {
|
positions: positions,
|
width: 5, // 直接设置宽度
|
clampToGround: true,
|
material: Cesium.Color.fromCssColorString(boundaryColor)
|
},
|
polygon,
|
})
|
})
|
})
|
|
if (!item.gJson) return
|
// 加载小边界
|
Cesium.GeoJsonDataSource.load(item.gJson).then(dataSource => {
|
// 获取数据源中的实体
|
const entities = dataSource.entities.values
|
entities.forEach(entity => {
|
const positions = entity.polygon.hierarchy.getValue().positions
|
minOutlineSource.entities.add({
|
polyline: {
|
positions: positions,
|
width: 1, // 直接设置宽度
|
clampToGround: true,
|
material: Cesium.Color.fromCssColorString(boundaryColor)
|
},
|
})
|
})
|
})
|
}
|
|
const findFun = (featItem, numItem) => Number(featItem.region_code.slice(0, 6)) === numItem.properties.adcode
|
|
// 打开边界
|
const openContour = async () => {
|
const areaCode = selectedAreaCode || userAreaCode
|
viewer.scene.postRender.removeEventListener(determineScaling)
|
if (!areaCode) return
|
const hierarchy = areaCodeToArr(areaCode.slice(0, 6))
|
const jsonPath = hierarchy.join('/')
|
scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true }))
|
scalingJudgment[0].gJson = null
|
active = null
|
const res = await getDeviceRegionCount({ areaCode })
|
const list = res?.data?.data || []
|
try {
|
// 省市县三级
|
if (hierarchy.length === 1) {
|
const gJson1 = await getFiler(`${defaultDir}${jsonPath}/indexDistrict.json`)
|
const gJson2 = await getFiler(`${defaultDir}${jsonPath}/index.json`)
|
scalingJudgment[1].gJson = {
|
...gJson1,
|
features: gJson1.features.map(item => {
|
const findData = list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item))
|
return { ...item, data: { ...findData } }
|
}),
|
}
|
scalingJudgment[2].gJson = gJson2
|
}
|
// 市县两级
|
if (hierarchy.length === 2) {
|
scalingJudgment[2].gJson = null
|
scalingJudgment[2].show = false
|
scalingJudgment[1].gJson = await getFiler(`${defaultDir}${jsonPath}/index.json`)
|
}
|
// 区县一级
|
if (hierarchy.length === 3) {
|
scalingJudgment[1].gJson = null
|
scalingJudgment[1].show = false
|
scalingJudgment[2].gJson = null
|
scalingJudgment[2].show = false
|
}
|
// 轮廓
|
const outlineGJson = await getContourByCode(areaCode.slice(0, 6))
|
scalingJudgment.forEach(item => item.show && (item.outline = outlineGJson))
|
renderOutline(scalingJudgment[(hierarchy.length - 3) * -1])
|
} catch (e) { }
|
viewer.scene.postRender.addEventListener(determineScaling)
|
}
|
|
// 关闭边界
|
function closeContour () {
|
removeAllEntities()
|
viewer.scene.postRender.removeEventListener(determineScaling)
|
}
|
|
// 飞向边界
|
async function flyToBoundary () {
|
// 单机巢系统
|
if (singleDockSystem) {
|
if (!initDockList.length) {
|
initDockList = await getDeviceRegionFun()
|
}
|
viewer?.camera.flyTo({
|
destination: Cesium.Cartesian3.fromDegrees(initDockList[0].longitude, initDockList[0].latitude, 24000),
|
duration: 0,
|
})
|
return
|
}
|
const areaCode = selectedAreaCode || userAreaCode
|
const gJson = await getContourByCode(areaCode.slice(0, 6))
|
const dataSource = await Cesium.GeoJsonDataSource.load(gJson)
|
if (!dataSource) return
|
viewer.dataSources.add(dataSource)
|
|
dataSource.entities.values.forEach(function (entity) {
|
if (entity.polygon) {
|
// 获取多边形的边界球
|
// const boundingSphere = entity.polygon.hierarchy.getValue(viewer.clock.currentTime).boundingSphere
|
let curPolygonPosition = entity.polygon.hierarchy._value.positions.map(item => {
|
let cartographic = Cesium.Cartographic.fromCartesian(item)
|
let lng = Cesium.Math.toDegrees(cartographic.longitude) // 经度
|
let lat = Cesium.Math.toDegrees(cartographic.latitude) // 纬度
|
|
return [_.round(lng, 6), _.round(lat, 6)]
|
})
|
|
const newBox = boxTransformScale(curPolygonPosition, multiple)
|
|
viewer.camera.flyTo({
|
destination: Cesium.Rectangle.fromDegrees(...newBox),
|
offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0),
|
duration: 0.5,
|
})
|
}
|
})
|
|
dataSource.entities.values.forEach(entity => {
|
entity.polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.YELLOW.withAlpha(0))
|
entity.polygon.outline = new Cesium.ConstantProperty(false) // 显示边框
|
entity.polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.AQUAMARINE.withAlpha(0))
|
})
|
}
|
|
/**
|
* 设置要显示的机巢列表
|
* @param dockSns - 要显示的机巢设备序列号数组。如果为 undefined,则显示所有已初始化的机巢;如果为空数组,则不显示任何机巢。
|
*/
|
function setShowDock (dockSns) {
|
if (dockSns === undefined) {
|
showDockSnList = null
|
} else if (dockSns.length === 0) {
|
showDockSnList = []
|
} else {
|
showDockSnList = dockSns
|
}
|
|
removeDockCover()
|
|
if (active === '县') droneSplashed()
|
}
|
|
onBeforeUnmount(() => {
|
manager.destroy()
|
})
|
|
|
return {
|
openContour,
|
closeContour,
|
flyToBoundary,
|
setShowDock
|
}
|
}
|