前言
今天我们分享的是怎么样用前端来实现像水淹分析和限高分析这样子的一个效果,水淹分析这个功能可以非常直观的看出如果水流进入到了我们城市里会出现什么样的一个状况,到底哪些地方会被水面覆盖,这样我们在防水防洪的时候就能提供一个有效的参考。限高分析就可以很直观的看出,到底那些建筑超出了我们限制的一个高度,在飞机航线或者无人机的航线设计的时候可以参考这个来设计。快来看看我们是如何实现的吧。


水淹分析
需求
当我们点击水淹分析的时候,出现水淹分析的ui控制组件,然后可以控制我们三维场景水面的一个高度,当点击开始水淹分析时,水面自动上升,并且实时展示水面高度,滑块可以对水面进行控制。
思路
想要实现水淹分析功能可以有两种方式,一个是添加动态水面的方式,然后不断的去更新他的一个高度,使用的类是DynamicWater类,提供动态水面相关的操作。还有一种方式是通过调用我们的水淹分析功能,这个类叫做FloodFill 提供水淹分析相关的操作。这个类与前面的类不同点就是提供了一个出水点一个参数,所以这次我们使用水淹分析的功能,主要涉及的是flooding这个组件。
首先当点击水淹分析按钮时,需要将我们的视角抬高到合适位置,然后需要创建一个水面,设置一下出水点,然后调用飞渡的api即可
arduino
onMounted(async () => {
fdapi.camera.set([565152.817539, 3466707.845645, 200.902441, -5.784357, 167.227448, 2])
addFloodFillLayer()
})
const addFloodFillLayer = async () => {
const point = [565905.55, 3466376.64]
let o = {
id: 'floodFill',
min: [point[0] - 5000, point[1] - 5000], //水淹分析范围min
max: [point[0] + 5000, point[1] + 5000], //水淹分析范围max
seed: point, //出水点 注意:出水点一定要在水淹分析范围[min~max]内,否则接口会报错
elevation: elevation.value, //水位高度
color: '#173a49', //水颜色
precision: 0.6 //水淹模拟精度
}
await fdapi.floodFill.add(o)
}
然后当我们点击开始水淹分析按钮,水面自动抬升,使用的是floodFill.update()方法去控制三维水面的变化,里面有一个参数为z值。包括组件面板需要展示当前水面的高度,这里我们可以用到滑块和定时器一起完成,并且在使用滑块的地方,我们对函数进行一个防抖的优化。在退出水淹分析时,需要对实例进行删除。
scss
//开始水淹分析
const startFloodFill = () => {
if (curActiveBtn.value) return
if (Number(elevation.value) >= Number(height.value)) {
elevation.value = minheight.value
}
curActiveBtn.value = true
FloodFillInterval = setInterval(() => {
if (Number(elevation.value) >= Number(height.value)) {
stopFloodFill()
}
elevation.value = Number(elevation.value) + 0.2
}, 200)
}
// 更新水面高度
const updateFloodFill = async () => {
const z = Number(elevation.value)
fdapi.floodFill.update({
id: 'floodFill',
elevation: z
})
}
watch(elevation, debounce(updateFloodFill, 100))
//停止水淹分析
const stopFloodFill = () => {
curActiveBtn.value = false
if (FloodFillInterval) clearInterval(FloodFillInterval)
}
onBeforeUnmount(async () => {
fdapi.floodFill.delete('floodFill')
})
涉及的飞渡api
- 添加一个水面-fdapi.floodFill.add(o)
- 更新水面-fdapi.floodFill.update()
- 删除水面-fdapi.floodFill.delete('floodFill')
限高分析
需求
当我们点击限高分析时,开启限高分析功能,超过设定高度的建筑部分为红色,进行一个高亮提示,没有超过的部分为灰色。并且可以控制超出高度部分建筑的颜色,不透明度,并且可以控制是否展示限高面这样一个功能。
思路
首先我们需要书写这样一个控制组件,当选择限高分析按钮时,展示这个控制组件,所以在这个控制组件的挂载时同样需要调整我们的相机视角到合适位置。
scss
onMounted(() => {
fdapi.camera.set(565555.903828, 3466773.747764, 536.138906, -12.565546, 170.855652, 2)
addHighlightAreaLayer()
})
然后就是限高分析的初始化了,首先我们先添加一个灰色的面作为我们的限高面,我们可以用行政边界的范围作为需要限高的范围,通过api获取他的一些点位信息,然后通过polygon这个类去绘制限高面,然后我们可以使用HighlightArea(高亮区域)相关的操作这个类去添加高亮区域,这个区域我们同样可以使用到这个范围,在add方法里面有一个color和heightRange参数可以调节。
typescript
const addHighlightAreaLayer = async () => {
const { data } = await getAdministrativeDivisionCity()
const coordinates = data.features[0].geometry.coordinates[0][0]
coordinates_polygon = coordinates
let o = {
id: 'highlightArea',
coordinates: coordinates,
coordinateType: 0, //坐标系类型,取值范围:0为Projection类型,1为WGS84类型,2为火星坐标系(GCJ02),3为百度坐标系(BD09),默认值:0
color: toColorArr(color.value, opacity.value), //多边形高亮颜色
heightRange: [elevation.value, 1000], //高亮染色区域可以限定一个高度范围,也就是Z坐标的区间,只有Z值这这个区间的模型才会被染色
intensity: 1.0, //高亮颜色的强度
depthTest: true //深度检测
}
await fdapi.highlightArea.add(o)
let p1 = {
id: 'highlight_polygon',
coordinates: coordinates.map((c: number[]) => [c[0], c[1], Number(elevation.value)]),
coordinateType: 0, //坐标系类型,取值范围:0为Projection类型,1为WGS84类型,2为火星坐标系(GCJ02),3为百度坐标系(BD09),默认值:0
range: [1, 10000], //可视范围:[近裁距离, 远裁距离],取值范围: [任意负值, 任意正值]
color: [1, 1, 0, 0.2], //多边形的填充颜色
intensity: 1, //亮度
style: 0, //单色 请参照API开发文档选取枚举
depthTest: true, //是否做深度检测 开启后会被地形高度遮挡
priority: 1 //显示优先级 值越大显示越靠上
}
await fdapi.polygon.add(p1)
}
在HighlightArea里面提供了setColor方法可以设置他的颜色,我们通过利用一些第三方的方法,将颜色和透明度转为16进制,这样就能适配我们的接口了,当我们调节颜色和透明度时,通过watch监听加上防抖,然后调用飞渡的highlightArea.setColor方法即可。
css
/**
* 16进制颜色转[1,0,0,0],附上透明度
* @param sColor 16进制颜色
* @param opacity 透明度
* @returns {*[]|*}
*/
const toColorArr = (sColor: string, opacity: number) => {
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
var sColorNew = '#'
for (var i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
}
sColor = sColorNew
}
//处理六位的颜色值
var sColorChange = []
for (var i = 1; i < 7; i += 2) {
sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)) / 255)
}
sColorChange.push(opacity)
return sColorChange
} else {
return sColor
}
}
// 设置颜色
const setColor = () => {
fdapi.highlightArea.setColor('highlightArea', toColorArr(color.value, opacity.value))
}
watch(color, debounce(setColor, 100))
watch(opacity, debounce(setColor, 100))
接下来就是滑块控制限制面高度了,同样也是通过添加防抖和监听,需要调整限高面的高度,限高面高度建筑高亮。
scss
// 设置高度范围
const setHeightRange = () => {
fdapi.highlightArea.setHeightRange('highlightArea', [Number(elevation.value), 1000])
fdapi.polygon.setCoordinates(
'highlight_polygon',
coordinates_polygon.map((c: number[]) => [c[0], c[1], Number(elevation.value)])
)
}
watch(elevation, debounce(setHeightRange, 100))
然后就是调整是否展示限高面这个功能了,在polygon里面有一个额根据id来控制是否显示和隐藏面的方法,我们可以通过这个方法来实现这个功能。
dart
// 设置限高面显隐
const setPolygonShow = () => {
if (areaShow.value) {
fdapi.polygon.show('highlight_polygon')
} else {
fdapi.polygon.hide('highlight_polygon')
}
}
watch(areaShow, debounce(setPolygonShow, 100))
最后就是当我们组件销毁前进行一些清理操作了
go
onBeforeUnmount(() => {
fdapi.highlightArea.delete('highlightArea')
fdapi.polygon.delete('highlight_polygon')
})
涉及的飞渡api
-
添加高亮区域-fdapi.highlightArea.add(o)
-
设置高亮区域颜色-fdapi.highlightArea.setColor()
-
设置高亮区域高度-fdapi.highlightArea.setHeightRange()
-
删除高亮区域-fdapi.highlightArea.delete('highlightArea')
-
添加面-fdapi.polygon.add()
-
展示面-fdapi.polygon.show('highlight_polygon')
-
隐藏面- fdapi.polygon.hide('highlight_polygon')