【Cesium绘制扇形】

cesium绘制扇形区域,支持颜色、角度、半径调整,支持动态手动更新。


【Cesium绘制扇形】_第1张图片



class DrawFanShape {
    constructor(viewer, sourceName, config) {
        this._viewer = viewer
        let dataSourceList = viewer.dataSources.getByName(sourceName)
        if (!dataSourceList || dataSourceList.length === 0) {
            this._dataSource = new Cesium.CustomDataSource(sourceName)
            viewer.dataSources.add(this._dataSource) // 为扇形数据建立一个自定义数据源
        } else {
            this._dataSource = dataSourceList[0]
        }
        this._config = config || {
            color: Cesium.Color.RED,
            labelFont: '14px sans-serif',
            labelFillColor: Cesium.Color.BLACK,
            labelOutlineWidth: 1,
            labelOutlineColor: Cesium.Color.GOLD
        }
    }
    /**
     * @description 画扇形(从正北开始顺时针旋转)
     * @param {String} id 扇形ID
     * @param {Object} position 中心点位置
     * @param {Object} heading 航向
     * @param {Object} color 扇形颜色
     * @param {Number} radius 扇形半径
     * @param {Number} angle 角度大小
     * @param {String} type 类别-用于区分是否是同一个目标的扇形
     */
    drawSector(params) {
        // 通过圆心(经纬度)、航偏角度d1、d2(d1
        // d1、d2 可以通过此方法获取:假设当前目标航向角度A,d1 = A - 自定义扇形角度/2;d2 = A + 自定义扇形角度/2;
        let { id, position, heading, angle, color, type, radius, label } = params
        let A = Cesium.Math.toDegrees(heading.getValue()) // 弧度转角度
        let d1 = A - angle / 2 // 扇形第一个边的角度
        let d2 = A + angle / 2 // 扇形第二个边的角度
        let pos = this.cartesian2Degrees(position.getValue())
        let { lon, lat, height } = pos

        let box = this._dataSource.entities.add({
            id: id,
            polygon: {
                show: true,
                hierarchy: this.generateHierarchy(lon, lat, height, d1, d2, radius),
                material: color ? color.withAlpha(0.5) : this._config.color.withAlpha(0.5),
                outline: true,
                outlineWidth: 1,
                outlineColor: color ? color : this._config.color,
                zIndex: Math.floor(1000 / radius)
            },
            position: this.getLabelPos(lon, lat, height, A, radius), // Label显示需要位置
            label: {
                show: true,
                text: label,
                font: this._config.labelFont,
                fillColor: this._config.labelFillColor,
                outlineWidth: this._config.labelOutlineWidth,
                outlineColor: this._config.labelOutlineColor,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(0, 10),
                disableDepthTestDistance: 5e8,
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 6e6),
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER
            },
            type: type,
            customFields: { // 缓存一些字段方便查找
                position: position,
                heading: heading,
                color: color,
                angle: angle,
                radius: radius
            }
        })
        return box
    }
    /**
     * 生成label的position
     */
    getLabelPos(lon, lat, height, A, radius) {
        let point = this.getPointByProjection(lon, lat, height, (90 - A) * (Math.PI / 180), radius * 1000)
        let cartesian = Cesium.Cartesian3.fromDegrees(Number(point[0]), Number(point[1]), height)
        return cartesian
    }
    /**
     * 生成polygon线性环
     */
    generateHierarchy(lon, lat, height, d1, d2, radius) {
        let list = [Number(lon), Number(lat), Number(height)]
        //获取 航偏角d1 至 航偏角d2 弧段的点位信息
        for (let i = d1; i < d2; i += 1) {
            let point = this.getPointByProjection(lon, lat, height, (90 - i) * (Math.PI / 180), radius * 1000)
            list.push(Number(point[0]))
            list.push(Number(point[1]))
            list.push(height)
        }
        list.push(Number(lon))
        list.push(Number(lat))
        list.push(Number(height))
        return Cesium.Cartesian3.fromDegreesArrayHeights(list)
    }
    /**
     * @description 根据位置,方位,距离求经纬度
     * @param {int} lon 中心点经度
     * @param {*} lat 中心点纬度
     * @param {*} height 中心点高度
     * @param {*} direction 方向
     * @param {*} radius 半径
     */
    getPointByProjection(lon, lat, height, direction, radius) {
        // 观察点
        let cartesian = Cesium.Cartesian3.fromDegrees(lon, lat, height)
        // 世界坐标转为投影坐标
        let webMercatorProjection = new Cesium.WebMercatorProjection(
            this._viewer.scene.globe.ellipsoid
        )
        let viewPointWebMercator = webMercatorProjection.project(
            Cesium.Cartographic.fromCartesian(cartesian)
        )
        // 计算目标点
        let toPoint = new Cesium.Cartesian3(
            viewPointWebMercator.x + radius * Math.cos(direction),
            viewPointWebMercator.y + radius * Math.sin(direction),
            height
        )
        // 投影坐标转为世界坐标
        let cartographic = webMercatorProjection.unproject(toPoint)
        let point = [
            Cesium.Math.toDegrees(cartographic.longitude),
            Cesium.Math.toDegrees(cartographic.latitude),
        ]
        return point
    }
    /**
    * @description 更新扇形
    * @param {String} id 扇形ID
    * @param {Object} position 中心点位置
    * @param {Object} color 扇形颜色
    * @param {Number} radius 扇形半径
    * @param {Number} angle 扇形角度大小
    */
    updateSector(params) {
        let { id, color, radius, angle } = params
        let entity = this.getEntityById(id)
        if (entity) {
            if (color) {
                entity.polygon.material = color.withAlpha(0.5)
                entity.polygon.outlineColor = color
                entity.customFields.color = color
            }
            if (radius) {
                let customFields = this.getCustomFields(id)
                let pos = this.cartesian2Degrees(customFields.position.getValue())
                let lon = pos.lon
                let lat = pos.lat
                let height = pos.height
                let A = Cesium.Math.toDegrees(customFields.heading.getValue()) // 弧度转角度
                let d1 = A - customFields.angle / 2
                let d2 = A + customFields.angle / 2
                entity.polygon.hierarchy = this.generateHierarchy(lon, lat, height, d1, d2, radius)
                entity.customFields.radius = radius
                entity.position = this.getLabelPos(lon, lat, height, A, radius)
            }
            if (angle) {
                let customFields = this.getCustomFields(id)
                let pos = this.cartesian2Degrees(customFields.position.getValue())
                let lon = pos.lon
                let lat = pos.lat
                let height = pos.height
                let A = Cesium.Math.toDegrees(customFields.heading.getValue()) // 弧度转角度
                let d1 = A - angle / 2
                let d2 = A + angle / 2
                entity.polygon.hierarchy = this.generateHierarchy(lon, lat, height, d1, d2, customFields.radius)
                entity.customFields.angle = angle
            }
        }
    }
    // 外部接口 - 动态更新扇形位置(随目标运动)【不改变颜色、半径、角度大小】
    dynamicUpdate(id) {
        const change = (entity) => {
            let pos = this.cartesian2Degrees(entity.customFields.position.getValue())
            let A = Cesium.Math.toDegrees(entity.customFields.heading.getValue()) // 弧度转角度
            if (pos && A) {
                let lon = pos.lon
                let lat = pos.lat
                let height = pos.height
                let d1 = A - entity.customFields.angle / 2
                let d2 = A + entity.customFields.angle / 2
                entity.polygon.hierarchy = this.generateHierarchy(lon, lat, height, d1, d2, entity.customFields.radius)
                entity.position = this.getLabelPos(lon, lat, height, A, entity.customFields.radius)
            } else {
                this._dataSource.entities.remove(entity)
            }
        }
        if (id) {
            let entity = this.getEntityById(id)
            change(entity)
        } else {
            let entities = this.getAllEntities()
            entities.forEach(entity => {
                change(entity)
            })
        }
    }
    getEntityById(id) {
        return this._dataSource.entities.getById(id)
    }
    getEntitiesByType(type) {
        return this._dataSource.entities.values.filter(entity => entity.type === type)
    }
    getAllEntities() {
        return this._dataSource.entities.values
    }
    getLength() {
        if (this._dataSource.entities.values) {
            return this._dataSource.entities.values.length
        } else {
            return 0
        }
    }
    getCustomFields(id) {
        let entity = this.getEntityById(id)
        if (entity) {
            return entity.customFields
        } else {
            return {}
        }
    }
    clearById(id) {
        this._dataSource.entities.removeById(id)
    }
    clearByType(type) {
        let entities = this.getEntitiesByType(type)
        entities.forEach(entity => {
            this._dataSource.entities.remove(entity)
        })
    }
    clearAll() {
        this._dataSource.entities.removeAll()
    }
    // 笛卡尔坐标转经纬度
    cartesian2Degrees(cartesian) {
        if (cartesian) {
            let cartographic = this._viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian)
            let pos = {
                lon: Cesium.Math.toDegrees(cartographic.longitude), // 经纬度
                lat: Cesium.Math.toDegrees(cartographic.latitude),
                height: cartographic.height
            }
            return pos
        } else {
            return cartesian
        }
    }
}
export default DrawFanShape

你可能感兴趣的:(cesium,绘制扇形,cesium自定义扇形)