区域可视域分析示例
这个示例演示如何使用 DMap3D SDK 进行区域可视域分析,展示观察点的视锥体范围内可见和不可见区域。
效果预览
用户在场景中点击设置观察点,通过视锥体分析区域的可见性,支持动态调整水平/垂直视场角。
完整代码
src/components/ViewshedAreaAnalysis.tsx
import { useEffect, useRef, useState } from 'react'
import * as Cesium from 'cesium'
import DMap3D from 'dmap3d'
import './ViewshedAreaAnalysis.css'
function ViewshedAreaAnalysis() {
const containerRef = useRef<HTMLDivElement>(null)
const viewerRef = useRef<Cesium.Viewer | null>(null)
const toolRef = useRef<any>(null)
const [isActive, setIsActive] = useState(false)
const [fovx, setFovx] = useState(90)
const [fovy, setFovy] = useState(60)
useEffect(() => {
if (!containerRef.current) return
Cesium.Ion.defaultAccessToken = 'your-cesium-ion-token'
const viewer = new Cesium.Viewer(containerRef.current, {
animation: false,
fullscreenButton: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
selectionIndicator: false,
timeline: false,
navigationHelpButton: false,
infoBox: false,
baseLayerPicker: false,
terrain: Cesium.Terrain.fromWorldTerrain(),
})
viewerRef.current = viewer
// 加载 3DTiles
const loadTileset = async () => {
const tileset = await Cesium.Cesium3DTileset.fromUrl(
'/3DTiles/model/tileset.json'
)
viewer.scene.primitives.add(tileset)
viewer.zoomTo(tileset)
}
loadTileset()
// 创建区域可视域分析工具
const tool = new DMap3D.analysis.viewshedArea(viewer, {
fovx: 90,
fovy: 60,
visibleColor: '#00ff00',
invisibleColor: '#ff0000',
visibleColorAlpha: 0.5,
invisibleColorAlpha: 0.5,
heightOffset: 1.8,
showFrustumRefLines: true,
})
toolRef.current = tool
return () => {
tool.destroy()
viewer.destroy()
}
}, [])
const handleStart = () => {
toolRef.current?.startAnalysis()
setIsActive(true)
}
const handleClear = () => {
const tool = toolRef.current
if (tool) {
tool.destroy()
// 重新创建
const viewer = viewerRef.current
if (viewer) {
const newTool = new DMap3D.analysis.viewshedArea(viewer, {
fovx, fovy,
visibleColor: '#00ff00',
invisibleColor: '#ff0000',
visibleColorAlpha: 0.5,
invisibleColorAlpha: 0.5,
heightOffset: 1.8,
showFrustumRefLines: true,
})
toolRef.current = newTool
}
}
setIsActive(false)
}
const handleFovxChange = (value: number) => {
setFovx(value)
if (toolRef.current) {
toolRef.current.fovx = value
}
}
const handleFovyChange = (value: number) => {
setFovy(value)
if (toolRef.current) {
toolRef.current.fovy = value
}
}
return (
<div className="viewshed-area-analysis">
<div ref={containerRef} className="cesium-container" />
<div className="control-panel">
<h3>区域可视域分析</h3>
<p>点击设置观察点,拖动调整方向</p>
<div className="buttons">
<button onClick={handleStart} disabled={isActive}>
{isActive ? '分析中...' : '开始分析'}
</button>
<button onClick={handleClear}>清除</button>
</div>
<div className="settings">
<h4>参数设置</h4>
<div className="setting-item">
<label>水平视场角: {fovx}°</label>
<input type="range" min="1" max="130" value={fovx}
onChange={(e) => handleFovxChange(Number(e.target.value))} />
</div>
<div className="setting-item">
<label>垂直视场角: {fovy}°</label>
<input type="range" min="1" max="179" value={fovy}
onChange={(e) => handleFovyChange(Number(e.target.value))} />
</div>
</div>
<div className="legend">
<div className="legend-item">
<span className="color-box" style={{background: '#00ff00'}}></span>
<span>可视区域</span>
</div>
<div className="legend-item">
<span className="color-box" style={{background: '#ff0000'}}></span>
<span>不可视区域</span>
</div>
</div>
</div>
</div>
)
}
export default ViewshedAreaAnalysis
样式文件
src/components/ViewshedAreaAnalysis.css
.viewshed-area-analysis { position: relative; width: 100%; height: 100vh; }
.cesium-container { width: 100%; height: 100%; }
.control-panel {
position: absolute; top: 20px; right: 20px;
background: rgba(255, 255, 255, 0.95); padding: 20px;
border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); min-width: 260px;
}
.control-panel h3 { margin: 0 0 10px 0; font-size: 18px; }
.control-panel p { margin: 0 0 15px 0; color: #666; font-size: 14px; }
.buttons { display: flex; gap: 10px; margin-bottom: 15px; }
.buttons button {
flex: 1; padding: 8px 16px; border: none; border-radius: 4px;
background: #1890ff; color: white; cursor: pointer; font-size: 14px;
}
.buttons button:hover { background: #40a9ff; }
.buttons button:disabled { background: #d9d9d9; cursor: not-allowed; }
.settings { border-top: 1px solid #e8e8e8; padding-top: 15px; margin-bottom: 15px; }
.settings h4 { margin: 0 0 12px 0; font-size: 14px; color: #666; }
.setting-item { margin-bottom: 12px; }
.setting-item label { display: block; font-size: 13px; color: #333; margin-bottom: 4px; }
.setting-item input[type="range"] { width: 100%; }
.legend-item { display: flex; align-items: center; gap: 8px; margin: 4px 0; font-size: 14px; }
.color-box { width: 20px; height: 12px; border-radius: 2px; }
关键代码说明
1. 创建区域可视域工具
const tool = new DMap3D.analysis.viewshedArea(viewer, {
fovx: 90, // 水平视场角(1-130°)
fovy: 60, // 垂直视场角(1-179°)
visibleColor: '#00ff00', // 可视区域颜色
invisibleColor: '#ff0000', // 不可视区域颜色
heightOffset: 1.8, // 观察点高度偏移(米)
showFrustumRefLines: true, // 显示视锥体参考线
})
2. 动态调整参数
// 直接修改属性即时生效
tool.fovx = 120
tool.fovy = 90
tool.visibleColor = '#00ff00'
tool.invisibleColor = '#ff0000'
tool.heightOffset = 2.0
3. 与单点可视域的区别
| 特性 | viewshed | viewshedArea |
|---|---|---|
| 分析范围 | 射线检测 | 视锥体区域 |
| 参数调节 | 固定 | 支持动态调节 |
| 视场角 | 无 | fovx + fovy |
| 适用场景 | 快速判断 | 精确分析 |
扩展功能
- 多观察点 - 同时分析多个观察点
- 最佳位置 - 计算最佳观察位置
- 视域覆盖 - 统计区域可视覆盖率
- 动态分析 - 随相机移动实时更新分析