Cesium 基于模型实现绘制面和编辑面

实现效果 
编辑
绘制
RailMange.js 全内容
import * as Cesium from 'cesium';
import PlotDrawTip from './PlotDrawTip';
export class RailManage {
    constructor() {
        this.viewer = window.mapViewer;
        this.entityCollection = [];
        this.labelEntity = null;
        this.pointsId = [];
        this.editPolygonShow = false;
        this.primitive = null;
        this.echEntites = null; //回显围栏
        this.plotDrawTip = null;
        this.entityPointList = [];
        this.handler = window.mapViewer.screenSpaceEventHandler;
    }

    flyToOverall() {
        this.viewer.scene.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(106.53873959614215, 37.730160351329395, 2000.9778139644488),
            orientation: new Cesium.HeadingPitchRange(Cesium.Math.toRadians(-17.0), Cesium.Math.toRadians(-90.0), 1),
        });
    }

    removeEchPolyGon() {
        if (this.echEntites) {
            this.viewer.entities.remove(this.echEntites);
        }
    }
    /**
     * 清除
     */
    destroy(callback) {
        for (let i = 0; i < this.entityCollection?.length; i++) {
            this.viewer.entities.remove(this.entityCollection[i]);
        }
        this.destoryAddPoint();
        this.destoryHandler();
        this.entityCollection = [];
        this.viewer.entities.remove(this.labelEntity);
        if (callback) {
            callback();
        }
        if (this.plotDrawTip != null) {
            this.plotDrawTip.remove();
            this.plotDrawTip = null;
        }
    }
    destoryHandler() {
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        if (this.pointsId) {
            for (let id of this.pointsId) {
                this.viewer.entities.removeById(id);
            }
        }
    }
    destoryAddPoint() {
        if (this.entityPointList.length) {
            for (let i = 0; i < this.entityPointList.length; i++) {
                this.viewer.entities.remove(this.entityPointList[i]);
            }
        }
    }

    // 添加wl
    addWLPolygon(callback) {
        let positions = [];
        let xyzPosition = [];
        let clickStatus = false;
        this.plotDrawTip = new PlotDrawTip(this.viewer);
        this.plotDrawTip.setContent([
            '当前绘制类型:普通墙体,最少需要2个点',
            '按下鼠标左键确定第1个点',
            '按下鼠标右键取消绘制',
        ]);

        // this.viewer.enableCursorStyle = false;
        // this.viewer._element.style.cursor = 'point';
        this.viewer.scene.globe.depthTestAgainstTerrain = false;
        this.handler.setInputAction((clickEvent) => {
            clickStatus = true;
            // 返回cartesian3坐标
            const { scene, camera } = this.viewer;
            let _cartesian = undefined;
            // if (scene.pickPosition(clickEvent.position)) {
            _cartesian = scene.pickPosition(clickEvent.position);
            // } else {
            //     _cartesian = camera.pickEllipsoid(clickEvent.position);
            // }
            // const _cartographic = Cesium.Cartographic.fromCartesian(
            //     _cartesian,
            //     scene.globe.ellipsoid,
            //     new Cesium.Cartographic()
            // )
            if (!_cartesian) {
                return false;
            }
            if (positions.length == 0) {
                positions.push(_cartesian.clone()); //鼠标左击 添加第1个点
                this.addPoint(_cartesian.clone());
                xyzPosition.push({
                    x: _cartesian.x,
                    y: _cartesian.y,
                    z: _cartesian.z,
                });
                this.plotDrawTip.updatePosition(_cartesian.clone());
                this.setTipContent(xyzPosition);

                this.handler.setInputAction((moveEvent) => {
                    let _moveEvent = undefined;
                    _moveEvent = scene.pickPosition(moveEvent.endPosition);
                    if (!_moveEvent) {
                        return false;
                    }

                    var screenPosition = new Cesium.Cartesian2(moveEvent.endPosition.x, moveEvent.endPosition.y);
                    // 获取屏幕坐标对应的地理坐标(笛卡尔坐标)
                    var ray = this.viewer.camera.getPickRay(screenPosition);
                    var cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);

                    this.plotDrawTip.updatePosition(cartesian);
                    this.setTipContent(xyzPosition);

                    if (positions.length == 1) {
                        positions.push(_moveEvent);
                    } else {
                        if (clickStatus) {
                            positions.push(_moveEvent);
                        } else {
                            positions.pop();
                            positions.push(_moveEvent);
                        }
                    }
                    clickStatus = false;
                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
            } else if (positions.length == 2) {
                if (!_cartesian) {
                    return false;
                }
                positions.pop();
                positions.push(_cartesian.clone()); // 鼠标左击 添加第2个点
                xyzPosition.push({
                    x: _cartesian.x,
                    y: _cartesian.y,
                    z: _cartesian.z,
                });
                this.plotDrawTip.updatePosition(_cartesian.clone());
                this.setTipContent(xyzPosition);

                this.addPoint(_cartesian);
                this.addPolyGon(positions);

                // 右击结束
                this.handler.setInputAction((clickEvent) => {
                    let _clickEvent = undefined;
                    _clickEvent = scene.pickPosition(clickEvent.position);
                    if (!_clickEvent) {
                        return false;
                    }
                    positions.pop();
                    positions.push(_clickEvent);
                    xyzPosition.push({
                        x: _clickEvent.x,
                        y: _clickEvent.y,
                        z: _clickEvent.z,
                    });

                    this.addPoint(_clickEvent);
                    this.viewer.scene.globe.depthTestAgainstTerrain = true;
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
                    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
                    this.viewer.entities.remove(this.labelEntity);
                    if (this.plotDrawTip) {
                        this.plotDrawTip.remove();
                        this.plotDrawTip = null;
                    }
                    this.destoryAddPoint();
                    if (callback) {
                        let res = tranformXyztoLonLat(this.viewer, xyzPosition);
                        callback(res, this.entityCollection);
                    }
                }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
            } else if (positions.length >= 3) {
                if (!_cartesian) {
                    return false;
                }
                positions.pop();
                positions.push(_cartesian.clone()); // 鼠标左击 添加第3个点
                xyzPosition.push({
                    x: _cartesian.x,
                    y: _cartesian.y,
                    z: _cartesian.z,
                });
                this.plotDrawTip.updatePosition(_cartesian.clone());
                this.setTipContent(xyzPosition);
                this.addPoint(_cartesian);
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    setTipContent(positions) {
        this.plotDrawTip.setContent([
            '当前绘制类型:面,最少需要3个点。',
            '已有' + positions.length + '个点,' + '按下鼠标左键确定第' + (positions.length + 1) + '个点',
            positions.length < 2 ? '' : '按下鼠标右键结束绘制',
        ]);
        // 按下鼠标右键取消绘制;
    }

    /**
     * 添加点
     * @param position
     */
    addPoint(position) {
        this.entityPointList.push(
            this.viewer.entities.add(
                new Cesium.Entity({
                    position: position,
                    point: {
                        color: Cesium.Color.fromCssColorString('#139e96'),
                        pixelSize: 15,
                        heightReference: Cesium.ClassificationType.CLAMP_TO_GROUND,
                        disableDepthTestDistance: position.z,
                    },
                })
            )
        );
    }
    /**
     * 添加面
     * @param positions
     */
    addPolyGon(positions) {
        let dynamicPositions = new Cesium.CallbackProperty(() => {
            return new Cesium.PolygonHierarchy(positions);
        }, false);
        let entities = this.viewer.entities.add(
            new Cesium.Entity({
                name: 'geopolygon',
                polygon: {
                    hierarchy: dynamicPositions,
                    material: Cesium.Color.BLUE.withAlpha(0.4),
                    // classificationType: Cesium.ClassificationType.BOTH, // 贴地表和贴模型,如果设置了,这不能使用挤出高度
                },
            })
        );
        this.entityCollection.push(entities);
        this.echEntites = entities;
    }

    echoPolyGon(positions, positionList) {
        if (!positions.length) return;
        let data = positions.flat().map((i) => {
            return Number(i);
        });
        this.echEntites = this.viewer.entities.add(
            new Cesium.Entity({
                name: 'geopolygon',
                polygon: {
                    // hierarchy: Cesium.Cartesian3.fromDegreesArray(positions),
                    hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(data),
                    material: Cesium.Color.BLUE.withAlpha(0.4),
                    classificationType: Cesium.ClassificationType.BOTH, // 贴地表和贴模型,如果设置了,这不能使用挤出高度
                },
            })
        );
        let center = getCenter(positions);
        // console.log(center);
        this.viewer.scene.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(...center, 1400),
        });
    }
    // 重绘
    resetDraw(callback) {
        this.viewer.scene.screenSpaceCameraController.enableRotate = true;
        this.viewer.scene.screenSpaceCameraController.enableZoom = true;
        this.destroy();
        this.removeEchPolyGon();
        this.addWLPolygon((res) => {
            callback(res);
        });
    }
    // 退出编辑
    endEditPolygon(callback) {
        this.editPolygonShow = false;
        // 获取多边形的层次结构信息
        var hierarchy = this.echEntites.polygon.hierarchy.getValue(Cesium.JulianDate.now());

        // 遍历多边形的坐标点
        let arr = [];
        var positions = hierarchy.positions;

        for (var i = 0; i < positions.length; i++) {
            var position = positions[i];
            // 获取坐标点的地理信息
            var cartographic = Cesium.Cartographic.fromCartesian(position);
            // 获取地理坐标的经度、纬度、高度
            var longitude = Cesium.Math.toDegrees(cartographic.longitude);
            var latitude = Cesium.Math.toDegrees(cartographic.latitude);
            var height = cartographic.height;
            arr.push([longitude, latitude, height]);
        }
        // arr.push(arr[0])
        this.viewer.scene.screenSpaceCameraController.enableRotate = true;
        this.viewer.scene.screenSpaceCameraController.enableZoom = true;
        for (let id of this.pointsId) {
            this.viewer.entities.removeById(id);
        }
        this.pointsId = [];
        callback(arr);
    }

    createPointEdit() {
        this.viewer.scene.globe.depthTestAgainstTerrain = true;
        let _this = this;
        if (this.echEntites) {
            this.pointsId = [];
            let hierarchy = this.echEntites.polygon.hierarchy;
            var positions = hierarchy.getValue(Cesium.JulianDate.now()).positions;
            let positionsList = positions.map((i) => {
                return {
                    x: Number(i.x),
                    y: Number(i.y),
                    z: Number(i.z) + 1,
                };
            });
            // 生成编辑点
            if (positionsList.length) {
                for (let i = 0; i < positionsList.length; i++) {
                    let cartesian3 = new Cesium.Cartesian3(positionsList[i].x, positionsList[i].y, positionsList[i].z);
                    let pointEntity = this.viewer.entities.add({
                        name: 'gon_point',
                        position: cartesian3,
                        point: {
                            color: Cesium.Color.WHITE,
                            pixelSize: 20,
                            outlineColor: Cesium.Color.BLACK.withAlpha(0.5),
                            outlineWidth: 5,
                            disableDepthTestDistance: positionsList[i].z,
                            // disableDepthTestDistance: 1000,
                            // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, positionsList[i].z + 2500),
                            // height: 0,
                            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                        },
                        // viewFrom: new Cesium.Cartesian3(-100, 0, 100),
                    });
                    this.pointsId.push(pointEntity.id);
                }
            }
        }
    }

    // 编辑面
    editWlPolygon() {
        this.viewer.scene.globe.depthTestAgainstTerrain = true;
        let currentPoint = undefined;
        this.editPolygonShow = true;
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
        let { scene } = this.viewer;
        this.viewer.scene.screenSpaceCameraController.enableRotate = false;
        // this.viewer.scene.screenSpaceCameraController.enableZoom = false;
        // 对鼠标按下事件的监听
        this.handler.setInputAction((event) => {
            let windowPosition = event.position;
            let pickedObject = this.viewer.scene.pick(windowPosition);
            if (Cesium.defined(pickedObject)) {
                let entity = pickedObject.id;
                if (entity?.name === 'gon_point') {
                    currentPoint = entity;
                }
            }
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
        // 对鼠标移动事件的监听
        this.handler.setInputAction((moveEnd) => {
            if (currentPoint) {
                let _cartesian = undefined;
                _cartesian = scene.pickPosition(moveEnd.endPosition);
                let points = [];
                if (!_cartesian) {
                    return;
                }
                currentPoint.position = _cartesian;
                for (let id of this.pointsId) {
                    let ent = this.viewer.entities.getById(id);
                    let pos = ent.position._value;
                    points.push(pos);
                }
                this.echEntites.polygon.hierarchy = new Cesium.CallbackProperty(() => {
                    return new Cesium.PolygonHierarchy([...points]);
                }, false);
                return;
            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
        // 对鼠标抬起事件的监听
        this.handler.setInputAction((event) => {
            currentPoint = undefined;
        }, Cesium.ScreenSpaceEventType.LEFT_UP);
    }
    removePrimitive() {
        if (this.primitive) {
            this.viewer.scene.primitives.remove(this.primitive);
        }
    }
}

//     xyz转经纬度
function tranformXyztoLonLat(viewer, positions) {
    let arr = [];
    for (let i = 0; i < positions?.length; i++) {
        let cartesian3 = new Cesium.Cartesian3(positions[i].x, positions[i].y, positions[i].z);
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
        let lat = Cesium.Math.toDegrees(cartographic.latitude);
        let lng = Cesium.Math.toDegrees(cartographic.longitude);
        // console.log(cartographic, 'cartographic')
        arr.push([lng, lat, cartographic.height]);
    }
    return arr;
}
export function getCenter(arr) {
    let centerLonLat = [];
    if (arr.length) {
        const lon = [];
        const lat = [];
        const poly = [];
        for (let i = 0, len = arr.length; i < len; i++) {
            lon.push(arr[i][0]);
            lat.push(arr[i][1]);
        }
        for (let i = 0, len = lon.length; i < len; i++) {
            poly.push({
                x: parseFloat(lon[i]),
                y: parseFloat(lat[i]),
                z: 0,
            });
        }
        const sortedLongitudeArray = poly.map((item) => item.x).sort();
        const sortedLatitudeArray = poly.map((item) => item.y).sort();
        const centerLongitude = (
            (parseFloat(sortedLongitudeArray[0]) + parseFloat(sortedLongitudeArray[sortedLongitudeArray.length - 1])) /
            2
        ).toFixed(14);
        const centerLatitude = (
            (parseFloat(sortedLatitudeArray[0]) + parseFloat(sortedLatitudeArray[sortedLatitudeArray.length - 1])) /
            2
        ).toFixed(14);
        centerLonLat = [Number(centerLongitude), Number(centerLatitude)];
    }
    return centerLonLat;
}
Tip.vue 样式文件 vue2适用 vue3不适用可以去除弹框
<template>
  <div class="plot-draw-tip-container">
    <div  v-for="(text,index) in contents" :key="index">{{text}}</div>
  </div>
</template>
<script>
export default {
  name: "PlotDrawTip",
  props: {
    contents: {
      type: Array
    }
  }
};
</script>

<style lang="css" scoped>
.plot-draw-tip-container {
  position: absolute;
  background: rgba(0, 0, 0, 0.637);
  padding: 6px;
  color: white;
    pointer-events: none;
}

.plot-draw-tip-container::before {
  position: absolute;
  content: "";
  top: calc(50% - 10px);
  left:  -10px;
  border-bottom: 10px solid transparent;
  border-top: 10px solid transparent;
  border-right: 10px solid rgba(0, 0, 0, 0.637);
}
</style>

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值