Cesium 绘制点、线、面和测距

  本文基于ES6,采用React+Cesium的Webgis前端开发框架,目前threejs和cesium的结合正在研究中。此段代码采用原生javascript,可能过程中用到了es6的扁平化语法,如()=>{},list.map方法。

废话不多说了,直接上代码。

import Cesium from 'cesium/Source/Cesium';
import monitor from '../style/images/monitor.jpeg';

const ECesium = {
    version: '0.1',
    description: '自定义cesium组件',
    copyright: '2018-enbo'
};

ECesium.Tools = function (viewer, callback) {
    this.viewer = viewer;
    this.init();
};

ECesium.Tools.prototype.init = function (back) {
    //初始化事件
    const viewer = this.viewer;
    const scene = viewer.scene;
    this.drawingMode = null;
    this.measureMode = null;
    this.geodesic = new Cesium.EllipsoidGeodesic();
    this.handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    this.dataSource = new Cesium.CustomDataSource('test1');
    viewer.dataSources.add(this.dataSource);
    console.log(viewer.dataSources.indexOf(this.dataSource));
};

ECesium.Tools.prototype.draw = function (type) {
    if (!this.viewer) return console.error('this.viewer 未定义');
    this.deactivate();
    this.drawingMode = type;
    switch (type) {
        case this.DRAW_TYPE.Point:
            this.DrawPoint();
            break;
        case this.DRAW_TYPE.PolyLine:
        case this.DRAW_TYPE.Polygon:
            this.DrawGraphics();
            break;
        default:
            break;
    }
};

ECesium.Tools.prototype.DrawPoint = function (callback) {
    const viewer = this.viewer;
    const this_ = this;
    this.drawingMode = "point";
    this.handler.setInputAction(function (evt) {
        const ray = viewer.camera.getPickRay(evt.position);
        const mapPosition = this_.getMapPoint(ray);
        if (!mapPosition) return;
        this_.dataSource.entities.add({
            id: '云台' + Math.random(),
            name: '林火监测点',
            position: Cesium.Cartesian3.fromDegrees(mapPosition.x, mapPosition.y, mapPosition.z),
            point: new Cesium.PointGraphics({
                color: Cesium.Color.SKYBLUE,
                pixelSize: 10,
                outlineColor: Cesium.Color.YELLOW,
                outlineWidth: 3,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
            }),
            description: `<img style="height: 200px;" src=${monitor}>`
        });
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};

ECesium.Tools.prototype.DrawGraphics = function (callback) {
    const viewer = this.viewer;
    const this_ = this;
    let activeShapePoints = [];
    let activeShape, floatingPoint;
    this.handler.setInputAction(function (event) {
        if (!Cesium.Entity.supportsPolylinesOnTerrain(viewer.scene)) {
            return console.log('This browser does not support polylines on terrain.');
        }
        const ray = viewer.camera.getPickRay(event.position);
        const earthPosition = viewer.scene.globe.pick(ray, viewer.scene);
        if (Cesium.defined(earthPosition)) {
            if (activeShapePoints.length === 0) {
                floatingPoint = this_.createPoint(earthPosition);
                activeShapePoints.push(earthPosition);
                const dynamicPositions = new Cesium.CallbackProperty(function () {
                    return activeShapePoints;
                }, false);
                activeShape = this_.drawShape(dynamicPositions);
            }

            activeShapePoints.push(earthPosition);
            this_.createPoint(earthPosition);
        }

    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    this.handler.setInputAction(function (event) {
        if (Cesium.defined(floatingPoint)) {
            const ray = viewer.camera.getPickRay(event.endPosition);
            const newPosition = viewer.scene.globe.pick(ray, viewer.scene);
            if (Cesium.defined(newPosition)) {
                floatingPoint.position.setValue(newPosition);
                activeShapePoints.pop();
                activeShapePoints.push(newPosition);
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    this.handler.setInputAction(function () {
        terminateShape();
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    function terminateShape() {
        activeShapePoints.pop();
        this_.drawShape(activeShapePoints);
        this.dataSource.entities.remove(floatingPoint);
        this.dataSource.entities.remove(activeShape);
        floatingPoint = undefined;
        activeShape = undefined;
        activeShapePoints = [];
    }
};

ECesium.Tools.prototype.getMapPoint = function (ray) {
    const viewer = this.viewer;
    const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
    if (!cartesian) {
        return null;
    }

    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    const lng = Cesium.Math.toDegrees(cartographic.longitude);//经度值
    const lat = Cesium.Math.toDegrees(cartographic.latitude);//纬度值
    //cartographic.height的值为地形高度。
    return {x: lng, y: lat, z: cartographic.height};
};

ECesium.Tools.prototype.createPoint = function (worldPosition) {
    return this.dataSource.entities.add({
        position: worldPosition,
        point: {
            color: Cesium.Color.WHITE,
            pixelSize: 5,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
        }
    });
};

ECesium.Tools.prototype.drawShape = function (positionData) {
    switch (this.drawingMode) {
        case this.DRAW_TYPE.PolyLine:
            return this.dataSource.entities.add({
                polyline: {
                    positions: positionData,
                    clampToGround: true,
                     3
                }
            });
        case this.DRAW_TYPE.Polygon:
            return this.dataSource.entities.add({
                polygon: {
                    hierarchy: positionData,
                    material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.7))
                }
            });
        default:
            return;
    }
};

ECesium.Tools.prototype.measure = function (type) {
    this.deactivate();
    this.measureMode = type;
    this.DrawMeasureGraphics();
};

ECesium.Tools.prototype.DrawMeasureGraphics = function () {
    const viewer = this.viewer;
    const this_ = this;
    let activeShapePoints = [];
    let activeShape, floatingPoint;
    let measureDistance = 0, floatDistance = 0;
    this.handler.setInputAction(function (event) {
        if (!Cesium.Entity.supportsPolylinesOnTerrain(viewer.scene)) {
            return console.log('This browser does not support polylines on terrain.');
        }
        const ray = viewer.camera.getPickRay(event.position);
        const earthPosition = viewer.scene.globe.pick(ray, viewer.scene);
        if (Cesium.defined(earthPosition)) {
            if (activeShapePoints.length === 0) {
                floatingPoint = this_.createMeasurePoint(earthPosition);
                if (this_.measureMode === this_.MEASURE_TYPE.MEASURE_DISTANCE) {
                    floatingPoint.label = {
                        text: new Cesium.CallbackProperty(function (time) {
                            let distance = floatDistance = this_.getLatestLength(activeShapePoints);
                            return ((distance + measureDistance) / 1000).toFixed(2) + ' km';
                        }, false),
                        showBackground: true,
                        backgroundColor: new Cesium.Color(0, 0, 0, 0.5),
                        backgroundPadding: new Cesium.Cartesian2(7, 5),
                        font: '16px sans-serif',
                    };

                    this_.createLabel(earthPosition, '起点')
                }
                activeShapePoints.push(earthPosition);
                const dynamicPositions = new Cesium.CallbackProperty(function () {
                    return activeShapePoints;
                }, false);
                activeShape = this_.drawMeasureShape(dynamicPositions);
            }

            if (activeShapePoints.length > 1 && this_.measureMode === this_.MEASURE_TYPE.MEASURE_DISTANCE) {
                measureDistance += floatDistance;
                this_.createLabel(earthPosition, (measureDistance / 1000).toFixed(2) + ' km');
            }

            activeShapePoints.push(earthPosition);
            this_.createMeasurePoint(earthPosition);
        }

    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    this.handler.setInputAction(function (event) {
        if (Cesium.defined(floatingPoint)) {
            const ray = viewer.camera.getPickRay(event.endPosition);
            const newPosition = viewer.scene.globe.pick(ray, viewer.scene);
            if (Cesium.defined(newPosition)) {
                floatingPoint.position.setValue(newPosition);
                activeShapePoints.pop();
                activeShapePoints.push(newPosition);
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    this.handler.setInputAction(function () {
        terminateShape();
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    function terminateShape() {
        activeShapePoints.pop();
        this_.drawMeasureShape(activeShapePoints);
        this_.dataSource.entities.remove(floatingPoint);
        this_.dataSource.entities.remove(activeShape);
        floatingPoint = undefined;
        activeShape = undefined;
        activeShapePoints = [];
        measureDistance = 0;
    }
};

ECesium.Tools.prototype.drawMeasureShape = function (positionData, callback) {
    console.log("draw shape");
    switch (this.measureMode) {
        case this.MEASURE_TYPE.MEASURE_DISTANCE:
            return this.dataSource.entities.add({
                polyline: {
                    positions: positionData,
                    clampToGround: true,
                     3
                }
            });
        case this.MEASURE_TYPE.MEASURE_AREA:
            return this.dataSource.entities.add({
                polygon: {
                    hierarchy: positionData,
                    material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.7))
                }
            });
        default:
            return;
    }
};

ECesium.Tools.prototype.getLatestLength = function (activeShapePoints) {
    const length = activeShapePoints.length;
    const endPoint = activeShapePoints[length - 1];
    const startPoint = activeShapePoints[length - 2];
    const startCartographic = Cesium.Cartographic.fromCartesian(startPoint);
    const endCartographic = Cesium.Cartographic.fromCartesian(endPoint);
    this.geodesic.setEndPoints(startCartographic, endCartographic);
    return Math.round(this.geodesic.surfaceDistance);
};

ECesium.Tools.prototype.createMeasurePoint = function (worldPosition, callback) {
    return this.dataSource.entities.add({
        position: worldPosition,
        point: {
            color: Cesium.Color.WHITE,
            pixelSize: 8,
            outlineColor: Cesium.Color.RED,
            outlineWidth: 3,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            scaleByDistance: new Cesium.NearFarScalar(0, 0, 1, 1)
        }
    });
};

ECesium.Tools.prototype.createLabel = function (worldPosition, text) {
    return this.dataSource.entities.add({
        position: worldPosition,
        label: {
            text: text,
            showBackground: true,
            backgroundColor: new Cesium.Color(1, 1, 1, 0.7),
            backgroundPadding: new Cesium.Cartesian2(7, 5),
            font: '16px sans-serif',
            fillColor: Cesium.Color.BLACK,
            outlineColor: Cesium.Color.BLACK,
            pixelOffset: new Cesium.Cartesian2(-15, -15)
        }
    });
};

ECesium.Tools.prototype.deactivate = function () {
    if (this.handler) {
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    this.drawingMode = null;
};

ECesium.Tools.prototype.DRAW_TYPE = {
    Point: 'Point',
    PolyLine: 'PolyLine',
    Polygon: 'Polygon'
};

ECesium.Tools.prototype.MEASURE_TYPE = {
    MEASURE_DISTANCE: 'MeasureTerrainDistance',
    MEASURE_AREA: 'MeasureTerrainArea'
};
export default ECesium;

   使用时直接实例化ECesium

this.tool = new ECesium.Tools(this.viewer);

   绘制图形

this.tool.draw('Point/PolyLine/Polygon');

   测距

this.tool.measure(MeasureTerrainDistance);

Tips*面积测量没有添加计算方法,后期会加上。

原文地址:https://www.cnblogs.com/zfygiser/p/10169312.html