cesium地图,通过多点成面,显示框出来的面,计算面积

<template>
    <div>
        <CesiumSelect @select="handleSelect" :modelValue="value" />
        <div id="cesiumContainer"></div>
        <button @click="draw('Polyline')">标点测距</button>
        <button @click="draw('Polygon')">标点测面</button>
        <button @click="clearAllDrawn()">清空数据</button>

    </div>
</template>
  
<script setup>
import { ref, onMounted } from "vue";
import * as Cesium from "cesium";
import { useRouter } from "vue-router";
import CesiumSelect from "../../components/cesium-select.vue";
const router = useRouter();
const value = ref('cesium-gird');
const handleSelect = (value) => {
    router.push({ name: value });
};

var tempEntities = []
var pointNum = 0
var floatingPoint = null
var activeShape = null
var viewer = null

onMounted(() => {
    // var viewer = new Cesium.Viewer("cesiumContainer", {
    //     //imageryProvider:使用的图像提供程序
    //     imageryProvider: new Cesium.UrlTemplateImageryProvider({
    //         url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
    //     }),
    // });
    // //通过imageryLayers获取图层列表集合
    // var layers = viewer.scene.imageryLayers;
    // //图层列表集合的addImageryProvider方法:
    // //两个参数,第一参数是一个ImageryProvider函数,这个函数的作用是新建一个图层;第二个参数是index,Number类型,作用是指定新插入图层在图层列表集合中的索引(位置),若不指定,默认新图层添加在最上层
    // //返回值是新添加到图层列表集合中的图层
    // var blackMarble = layers.addImageryProvider(
    //     new Cesium.UrlTemplateImageryProvider({
    //         url: "http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
    //     })
    // );
    // //get或set图层透明度,范围是0-1
    // blackMarble.alpha = 1.0;

    // //get或set图层亮度,小于1图层更暗,大于1更亮
    // blackMarble.brightness = 1.0;

    // ==============================================
    viewer = new Cesium.Viewer("cesiumContainer", {
        //imageryProvider:使用的图像提供程序
        imageryProvider: new Cesium.UrlTemplateImageryProvider({
            url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
            subdomains: ['0', '1', '2', '3'],
            tilingScheme: new Cesium.WebMercatorTilingScheme()
        })
    });
    viewer.camera.lookAt(
        Cesium.Cartesian3.fromDegrees(116.41667, 39.91667, 1000.0),
        new Cesium.Cartesian3(0.0, 0.0, 5000.0)
    )
    viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
    // //通过imageryLayers获取图层列表集合
    // var layers = viewer.scene.imageryLayers;
    // //图层列表集合的addImageryProvider方法:
    // //两个参数,第一参数是一个ImageryProvider函数,这个函数的作用是新建一个图层;第二个参数是index,Number类型,作用是指定新插入图层在图层列表集合中的索引(位置),若不指定,默认新图层添加在最上层
    // //返回值是新添加到图层列表集合中的图层
    // var blackMarble = layers.addImageryProvider(
    //     new Cesium.UrlTemplateImageryProvider({
    //         url: "http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
    //     })
    // );
    // //get或set图层透明度,范围是0-1
    // blackMarble.alpha = 1.0;

    // //get或set图层亮度,小于1图层更暗,大于1更亮
    // // blackMarble.brightness = 1.0;
    //     return


});
const getLength = (start, end) => {
    // 将起点与终点位置信息从笛卡尔坐标形式转换为Cartographic形式
    let startCartographic = Cesium.Cartographic.fromCartesian(start)
    let endCartographic = Cesium.Cartographic.fromCartesian(end)
    // 初始化测地线
    let geodesic = new Cesium.EllipsoidGeodesic()
    // 设置测地线起点和终点,EllipsoidGeodesic中setEndPoints常与surfaceDistance搭配使用
    geodesic.setEndPoints(startCartographic, endCartographic)
    // 获取起点和终点之间的表面距离,单位为km,规定四舍五入保留两位小数
    // surfaceDistance返回number 单位为m,带小数
    // console.log((geodesic.surfaceDistance / 1000).toFixed(2))
    return (geodesic.surfaceDistance / 1000).toFixed(2)
}
/* 空间两点计算中点函数 */
const getMidpoint = (start, end) => {
    let startPoint = Cesium.Cartographic.fromCartesian(start)
    let endPoint = Cesium.Cartographic.fromCartesian(end)
    let geodesic = new Cesium.EllipsoidGeodesic()
    geodesic.setEndPoints(startPoint, endPoint)
    let geoPoint = geodesic.interpolateUsingFraction(0.5)
    console.log(Cesium.Ellipsoid.WGS84.cartographicToCartesian(geoPoint))
    return Cesium.Ellipsoid.WGS84.cartographicToCartesian(geoPoint)
}
const addLabel = (midPoint, labelLength) => {
    // let viewer = this.viewer
    return viewer.entities.add({
        name: '中点',
        position: midPoint,
        label: {
            text: labelLength + 'km',
            font: '20px sans-serif',
            fillColor: Cesium.Color.WHITE,
            outlineWidth: 2,
            backgroundColor: Cesium.Color.BLACK,
            showBackground: true,
            style: Cesium.LabelStyle.FILL,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            disableDepthTestDistance: Number.POSITIVE_INFINITY
        }
    })
}
/* 测量空间面积 */
// 方向
const Bearing = (from, to) => {
    let fromCartographic = Cesium.Cartographic.fromCartesian(from)
    let toCartographic = Cesium.Cartographic.fromCartesian(to)
    let lat1 = fromCartographic.latitude
    let lon1 = fromCartographic.longitude
    let lat2 = toCartographic.latitude
    let lon2 = toCartographic.longitude
    let angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2))
    if (angle < 0) {
        angle += Math.PI * 2.0
    }
    return angle
}
// 角度
const pointAngle = (point1, point2, point3) => {
    let bearing21 = Bearing(point2, point1)
    let bearing23 = Bearing(point2, point3)
    let angle = bearing21 - bearing23
    if (angle < 0) {
        angle += Math.PI * 2.0
    }
    return angle
}
const getArea = (positions) => {
    let res = 0
    for (let i = 0; i < positions.length - 2; i++) {
        let j = (i + 1) % positions.length
        let k = (i + 2) % positions.length
        let totalAngle = pointAngle(positions[i], positions[j], positions[k])
        let tempLength1 = getLength(positions[j], positions[0])
        let tempLength2 = getLength(positions[k], positions[0])
        res += tempLength1 * tempLength2 * Math.sin(totalAngle) / 2
    }
    res = res.toFixed(2)
    // console.log(res)
    res = parseFloat(res)
    // console.log(Math.abs(res))
    return Math.abs(res)
}
const addArea = (area, positions) => {
    // let viewer = this.viewer
    return viewer.entities.add({
        name: '多边形面积',
        position: positions[positions.length - 1],
        label: {
            text: area + '平方公里',
            font: '20px sans-serif',
            fillColor: Cesium.Color.WHITE,
            outlineWidth: 2,
            backgroundColor: Cesium.Color.BLACK,
            showBackground: true,
            style: Cesium.LabelStyle.FILL,
            pixelOffset: new Cesium.Cartesian2(60, -60),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            disableDepthTestDistance: Number.POSITIVE_INFINITY
        }
    })
}
/* 绘制函数 */
const drawPointLabel = (position, pointNum) => {
    // let viewer = this.viewer
    // 本质上就是添加一个点的实体
    return viewer.entities.add({
        name: '点几何对象',
        position: position,
        point: {
            color: Cesium.Color.WHEAT,
            pixelSize: 5,
            outlineWidth: 3,
            disableDepthTestDistance: Number.POSITIVE_INFINITY, //
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 规定贴地
        },
        label: {
            text: pointNum,
            font: '30px sans-serif',
            fillColor: Cesium.Color.WHITE,
            outlineWidth: 2,
            backgroundColor: Cesium.Color.BLACK,
            showBackground: true,
            style: Cesium.LabelStyle.FILL,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER
        }
    })
}
const drawPoint = (position) => {
    // let viewer = this.viewer
    // 本质上就是添加一个点的实体
    return viewer.entities.add({
        position: position,
        point: {
            color: Cesium.Color.WHEAT,
            pixelSize: 5,
            outlineWidth: 3,
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 规定贴地
        }
    })
}
const drawPolyline = (positions) => {
    // let viewer = this.viewer
    if (positions.length < 1) return
    return viewer.entities.add({
        name: '线几何对象',
        polyline: {
            positions: positions,
            width: 5.0,
            material: new Cesium.PolylineGlowMaterialProperty({
                // eslint-disable-next-line new-cap
                color: Cesium.Color.WHEAT
            }),
            depthFailMaterial: new Cesium.PolylineGlowMaterialProperty({
                // eslint-disable-next-line new-cap
                color: Cesium.Color.WHEAT
            }),
            clampToGround: true
        }
    })
}
const drawPolygon = (positions) => {
    // let viewer = this.viewer
    if (positions.length < 2) return
    return viewer.entities.add({
        name: '面几何对象',
        polygon: {
            hierarchy: positions,
            // eslint-disable-next-line new-cap
            material: new Cesium.ColorMaterialProperty(
                Cesium.Color.WHEAT.withAlpha(0.4)
            )
        }
    })
}
/* 清除实体 */
const clearAllDrawn = () => {
    // let viewer = this.viewer
    tempEntities = []
    pointNum = 0
    viewer.entities.removeAll()
}

/* 根据类型绘制对象
* @param type point polyline polygon */
const draw = (type) => {
    let that = this
    // let viewer = this.viewer
    // let pointNum = pointNum
    // console.log(pointNum)
    // let tempEntities = tempEntities
    // let floatingPoint = floatingPoint
    // let activeShape = activeShape
    let position = []
    let tempPoints = []
    let activeShapePoints = []
    // 开启深度检测
    viewer.scene.globe.depthTestAgainstTerrain = true
    // 创建场景的HTML canvas元素
    let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    switch (type) {
        // 绘制线
        case 'Polyline':
            // 取消鼠标双击事件
            viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
            // 监听鼠标移动
            handler.setInputAction(function (movement) {
                if (Cesium.defined(floatingPoint)) {
                    let newPosition = viewer.scene.pickPosition(movement.endPosition)
                    if (Cesium.defined(newPosition)) {
                        floatingPoint.position.setValue(newPosition)
                        activeShapePoints.pop()
                        activeShapePoints.push(newPosition)
                    }
                }
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
            // 左键单击开始画线
            handler.setInputAction(function (click) {
                let earthPosition = viewer.scene.pickPosition(click.position)
                if (Cesium.defined(earthPosition)) {
                    floatingPoint = drawPoint(earthPosition)
                }
                // 获取位置信息
                // 从相机位置创建一条射线,这条射线通过世界中movement.position像素所在的坐标,返回Cartesian3坐标
                let ray = viewer.camera.getPickRay(click.position)
                // 找到射线与渲染的地球表面之间的交点。射线必须以世界坐标给出。返回Cartesian3坐标
                position = viewer.scene.globe.pick(ray, viewer.scene)
                tempPoints.push(position) // 记录点位
                pointNum += 1
                let tempLength = tempPoints.length // 记录点数
                // 调用绘制点的接口
                let point = drawPointLabel(tempPoints[tempPoints.length - 1], JSON.stringify(pointNum))
                tempEntities.push(point)
                // 存在超过一个点时
                if (tempLength > 1) {
                    // 绘制线
                    let pointLength = getLength(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1])
                    let midPosition = getMidpoint(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1])
                    let pointline = drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
                    let pointLabel = addLabel(midPosition, pointLength)
                    tempEntities.push(pointline) // 保存记录
                    tempEntities.push(pointLabel)
                }
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
            // 右键单击结束画线
            handler.setInputAction(function (click) {
                console.log(pointNum)
                activeShapePoints.pop()
                viewer.entities.remove(activeShapePoints)
                viewer.entities.remove(floatingPoint)
                tempPoints = [] // 清空点位记录
                handler.destroy()
                handler = null
                floatingPoint = undefined
                activeShape = undefined
                activeShapePoints = []
                console.log(pointNum)
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
            break
        // 绘制面
        case 'Polygon':
            // 取消鼠标双击事件
            viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
            // 监听鼠标移动
            handler.setInputAction(function (movement) {
                if (Cesium.defined(floatingPoint)) {
                    let newPosition = viewer.scene.pickPosition(movement.endPosition)
                    if (Cesium.defined(newPosition)) {
                        floatingPoint.position.setValue(newPosition)
                        activeShapePoints.pop()
                        activeShapePoints.push(newPosition)
                    }
                }
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
            // 左键单击开始画线
            handler.setInputAction(function (click) {
                let earthPosition = viewer.scene.pickPosition(click.position)
                if (Cesium.defined(earthPosition)) {
                    if (activeShapePoints.length === 0) {
                        floatingPoint = drawPoint(earthPosition)
                        activeShapePoints.push(earthPosition)
                        const dynamicPositions = new Cesium.CallbackProperty(function () {
                            return new Cesium.PolygonHierarchy(activeShapePoints)
                        }, false)
                        activeShape = drawPolygon(dynamicPositions)
                    }
                    activeShapePoints.push(earthPosition)
                }
                // 获取位置信息
                let ray = viewer.camera.getPickRay(click.position)
                position = viewer.scene.globe.pick(ray, viewer.scene)
                tempPoints.push(position) // 记录点位
                let tempLength = tempPoints.length // 记录点数
                pointNum += 1
                // 调用绘制点的接口
                let point = drawPointLabel(tempPoints[tempPoints.length - 1], JSON.stringify(pointNum))
                tempEntities.push(point)
                // 存在超过一个点时
                if (tempLength > 1) {
                    // 绘制线
                    let pointline = drawPolyline([tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1]])
                    tempEntities.push(pointline) // 保存记录
                }
            },
                Cesium.ScreenSpaceEventType.LEFT_CLICK)
            // 右键单击结束画面
            handler.setInputAction(function (click) {
                // 选择一个椭球或地图
                let cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid)
                if (cartesian) {
                    let tempLength = tempPoints.length
                    if (tempLength < 3) {
                        alert('闭合操作需要至少3个点嗷')
                    } else {
                        // 闭合最后一条线
                        let pointline = drawPolyline([tempPoints[0], tempPoints[tempPoints.length - 1]])
                        tempEntities.push(pointline)
                        drawPolygon(tempPoints)
                        let pointArea = getArea(tempPoints)
                        addArea(JSON.stringify(pointArea), tempPoints)
                        tempEntities.push(tempPoints)
                        handler.destroy()
                        handler = null
                    }
                }
                activeShapePoints.pop()
                viewer.entities.remove(activeShapePoints)
                viewer.entities.remove(floatingPoint)
                floatingPoint = undefined
                activeShapePoints = []
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
            break
    }
}
</script>
  
<style scoped>
#cesiumContainer {
    width: 100%;
    height: 100%;
    margin: 0px;
    padding: 0px;
    overflow: hidden;
}
</style>
  

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值