import * as turf from '@turf/turf';
import { Message } from 'element-ui'

// geom转cesium坐标数组
export function geomToCartesian3(geom) {
    const positions = [];
    const geojson = wkt.parse(geom);
    const { type, coordinates } = geojson;
    if (type === 'Point') {
        const [x, y, z] = coordinates;
        positions.push(Cesium.Cartesian3.fromDegrees(x, y, z));
    } else if (type === 'LineString') {
        coordinates.forEach(element => {
            const [x, y, z] = element;
            positions.push(Cesium.Cartesian3.fromDegrees(x, y, z));
        });
    } else if (type === 'Polygon') {
        coordinates.forEach(element => {
            element.forEach(item => {
                const [x, y, z] = item;
                positions.push(Cesium.Cartesian3.fromDegrees(x, y, z));
            });
        });
    }
    return {
        type,
        positions,
    };
}

// 点位转WKTString
export function positionToGeom(wgs84Obj) {
    const { type, positions } = wgs84Obj;
    let geom = '';
    if (type === 'Point') {
        geom = wkt.convert({
            type: 'Point',
            coordinates: positions[0],
        });
    } else if (type === 'LineString') {
        geom = wkt.convert({
            type: 'LineString',
            coordinates: positions,
        });
    } else if (type === 'Polygon') {
        geom = wkt.convert({
            type: 'Polygon',
            coordinates: [positions],
        });
    }
    return geom;
}

// cesium坐标转WGS84坐标
export function simpleCartesian3ToWGS84(viewer, position) {
    const { ellipsoid } = viewer.scene.globe;
    const wgs84 = ellipsoid.cartesianToCartographic(position);
    let lng;
    let lat;
    let alt;
    // 弧度转经度
    lng = Cesium.Math.toDegrees(wgs84.longitude);
    lat = Cesium.Math.toDegrees(wgs84.latitude);
    alt = wgs84.height;
    return new Cesium.Cartesian3(lng, lat, alt);
}

// Cartesian3ToWGS84
export function cartesian3ToWGS84(viewer, cartesian3Obj) {
    const { type, positions } = cartesian3Obj;
    let wgs84Positions;
    if (type === 'Point') {
        wgs84Positions = Array.prototype.map.call(positions, item => {
            const wgs84 = simpleCartesian3ToWGS84(viewer, item);
            return [wgs84.x, wgs84.y, wgs84.z];
        });
    } else if (type === 'LineString') {
        wgs84Positions = Array.prototype.map.call(positions, item => {
            const wgs84 = simpleCartesian3ToWGS84(viewer, item);
            return [wgs84.x, wgs84.y, wgs84.z];
        });
    } else if (type === 'Polygon') {
        wgs84Positions = Array.prototype.map.call(positions, item => {
            const wgs84 = simpleCartesian3ToWGS84(viewer, item);
            return [wgs84.x, wgs84.y, wgs84.z];
        });
        wgs84Positions.push(wgs84Positions[0]);
    }
    return {
        type,
        positions: wgs84Positions,
    };
}

// 获取实体中心点
export function computePositionsCenter(wgs84Obj) {
    const { type, positions } = wgs84Obj;
    let turfPositions;
    let positionCenter;
    if (type === 'LineString') {
        turfPositions = turf.lineString(positions);
        positionCenter = turf.centerOfMass(turfPositions);
    } else if (type === 'Polygon') {
        turfPositions = turf.polygon([positions]);
        positionCenter = turf.centerOfMass(turfPositions); // 中心点计算
    }
    return positionCenter;
}

// 颜色格式调整
export function agbrToRgba(color) {
    return color.substring(2, 8) + color.substring(0, 2);
}
// 颜色格式调整
export function hexArgbToHexAbgr(color) {
    return `${color.slice(0, 2)}${color.slice(6, 8)}${color.slice(4, 6)}${color.slice(2, 4)}`;
}

// 颜色转换
export function fromCssColorString(param) {
    if (typeof param === 'object') {
        const { r, g, b, a } = param;
        return Cesium.Color.fromCssColorString(`rgba(${r}, ${g}, ${b}, ${a})`);
    }
    const r = Number.parseInt(param.substring(0, 2), 16);
    const g = Number.parseInt(param.substring(2, 4), 16);
    const b = Number.parseInt(param.substring(4, 6), 16);
    const a = Number.parseInt(param.substring(6, 8), 16);
    return Cesium.Color.fromBytes(r, g, b, a);
}

export function getRandomColor() {
    const colors = [
        '8a2be250',
        'ff7f5050',
        'dc143c50',
        '008b8b50',
        '1e90ff50',
        'adff2f50',
        'ffa50050',
        'db709350',
        'ff634750',
        '48d1cc50',
        'f0e68c50',
        '6495ed50',
        '9370db50',
        'da70d650',
        '2e8b5750',
        'ff7f5050',
    ];
    return colors[Math.floor(Math.random() * colors.length)];
}

// 创建Cesium实体
export const createPolygon = (viewer, options) => {
    const { text, geom, color } = options;
    // geom转Cartesian3
    const cartesian3Obj = geomToCartesian3(geom);
    // 坐标转换
    const wgs84Obj = cartesian3ToWGS84(viewer, cartesian3Obj);
    // 获取中心点
    const positionsCenter = computePositionsCenter(wgs84Obj);


    const entity = new Cesium.Entity({
        position: Cesium.Cartesian3.fromDegrees(
            positionsCenter.geometry.coordinates[0],
            positionsCenter.geometry.coordinates[1],
            wgs84Obj.positions[0][2],
        ),
        polygon: {
            hierarchy: cartesian3Obj.positions,
            material: fromCssColorString(color),
            clampToGround: true,
        },
        label: {
            text,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(0, 0),
        },
    });

    viewer.entities.add(entity);

    return entity;
};

export const createBillboard = (viewer, options) => {
    const { position, text, image } = options;

    const entity = new Cesium.Entity({
        position,
        billboard: {
            image,
            width: 32,
            height: 32,
            // scale: 0.6,
            // eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -64.0)
            // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
        label: {
            text,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian3(0.0, 32, 0.0),
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            zIndex: 5000,
        },
    });
    viewer.entities.add(entity);
    return entity;
};

export const createPolyline = (viewer, options) => {
    const { positions, color = Cesium.Color.YELLOWGREEN, width = 5 } = options;
    const entity = new Cesium.Entity({
        polyline: new Cesium.PolylineGraphics({
            positions,
            width,
            material: color,
            // clampToGround: true,
            zIndex: 5000,
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
        }),
    });
    viewer.entities.add(entity);
    viewer.flyTo(entity);
    return entity;
};

export const createGeomToPoint = (viewer, geom, image, title) => {
    const { positions } = geomToCartesian3(geom);

    const entity = new Cesium.Entity({
        position: positions[0],
        billboard: {
            image,
            width: 32,
            height: 32,
            // scale: 0.6,
            // eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -64.0)
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
        label: {
            text: title,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian3(0.0, 32, 0.0),
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            zIndex: 5000,
        },
    });
    viewer.entities.add(entity);
    return entity;
};

export const createGeomToPolyline = (viewer, geom, style, title) => {
    const styleObj = JSON.parse(style);
    const styleJson = convert.xml2json(styleObj.GeoSymbolXml, { compact: true, spaces: 4 });
    const styles = JSON.parse(styleJson);
    const color = `0x${hexArgbToHexAbgr(styles.CurveSymbol._attributes.Color)}`;
    const width = Math.abs(styles.CurveSymbol._attributes.Width);
    const clampToGround = styleObj.HeightStyle !== '1';
    const cartesian3Obj = geomToCartesian3(geom); // geom转Cartesian3
    const { positions } = cartesian3Obj;
    // const wgs84Obj = cartesian3ToWGS84(viewer, cartesian3Obj) // 坐标转换
    // const positionsCenter = computePositionsCenter(wgs84Obj)  // 获取中心点
    // 获取中心点
    const polyCenter = Cesium.BoundingSphere.fromPoints(positions).center;

    const entity = new Cesium.Entity({

        // position: Cesium.Cartesian3.fromDegrees(positionsCenter.geometry.coordinates[0], positionsCenter.geometry.coordinates[1], positions[0][2]),
        position: polyCenter,
        label: {
            text: title,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 5000),
            pixelOffset: new Cesium.Cartesian2(0, 0),
            // clampToGround: clampToGround,
            // disableDepthTestDistance: Number.POSITIVE_INFINITY
        },
        polyline: {
            positions,
            width,
            material: Cesium.Color.fromRgba(color),
            clampToGround,
            zIndex: 5000,
        },
    });
    viewer.entities.add(entity);
    return entity;
};

export const createGeomToPolygon = (viewer, geom, style, title) => {
    const styleObj = JSON.parse(style);
    const styleJson = convert.xml2json(styleObj.GeoSymbolXml, { compact: true, spaces: 4 });
    const styles = JSON.parse(styleJson);
    const color = `0x${hexArgbToHexAbgr(styles.SurfaceSymbol._attributes.Color)}`;
    const outlineColor = `0x${hexArgbToHexAbgr(styles.SurfaceSymbol.CurveSymbol._attributes.Color)}`;
    const width = Math.abs(styles.SurfaceSymbol.CurveSymbol._attributes.Width);
    const clampToGround = styleObj.HeightStyle !== '1';
    const cartesian3Obj = geomToCartesian3(geom); // geom转Cartesian3
    const { positions } = cartesian3Obj;
    const wgs84Obj = cartesian3ToWGS84(viewer, cartesian3Obj); // 坐标转换
    const positionsCenter = computePositionsCenter(wgs84Obj); // 获取中心点
    // const polyCenter = Cesium.BoundingSphere.fromPoints(positions).center
    // console.log(color, outlineColor, width)

    const point = Cesium.Cartographic.fromDegrees(
        positionsCenter.geometry.coordinates[0],
        positionsCenter.geometry.coordinates[1],
    );

    const height = viewer.scene.sampleHeight(point);


    const entity = new Cesium.Entity({

        position: Cesium.Cartesian3.fromDegrees(
            positionsCenter.geometry.coordinates[0],
            positionsCenter.geometry.coordinates[1],
            height,
        ),
        // position: polyCenter,
        label: {
            text: title,
            font: '18pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            // eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 32.0),
            pixelOffset: new Cesium.Cartesian2(0, 0),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
        polygon: {
            hierarchy: positions,
            // material: fromCssColorString(color),
            material: Cesium.Color.fromRgba(color),
            outline: true,
            outlineWidth: width,
            // outlineColor: fromCssColorString(outlineColor),
            outlineColor: Cesium.Color.fromRgba(outlineColor),
            clampToGround,
            perPositionHeight: !clampToGround,
        },
    });
    viewer.entities.add(entity);
    return entity;
};

// 空间两点距离计算函数
export function getSpaceDistance(positions) {
    let distance = 0;
    for (let i = 0; i < positions.length - 1; i++) {

        const point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
        const point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
        /** 根据经纬度计算出距离* */
        const geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        let s = geodesic.surfaceDistance;
        // console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
        // 返回两点之间的距离
        s = Math.sqrt(
            Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2),
        );
        distance += s;
    }
    return distance.toFixed(2);
}

// 空间面积计算
export function getSpaceArea(positions) {
    const col = getCoordinates(positions);
    const newCol = col.concat(col.slice(0, 1));
    const polygongeojson = turf.polygon([newCol]);
    const area = turf.area(polygongeojson);
    return area.toFixed(2);
}

const getCoordinates = t => {
    const e = [];
    for (let i = 0; i < t.length; i++) {
        const n = Cesium.Cartographic.fromCartesian(t[i]);
        const r = Number(Cesium.Math.toDegrees(n.longitude).toFixed(6));
        const o = Number(Cesium.Math.toDegrees(n.latitude).toFixed(6));
        const a = Number(n.height.toFixed(1));
        e.push([r, o, a]);
    }
    return e;
};

// 以下三个方法为官方绘制demo
const createPoint = (viewer, drawingMode, worldPosition, activeShapePoints) => {
    let distance = 0;
    let textDisance = '';
    if (activeShapePoints.length > 2 && drawingMode === 'line') {
        distance = getSpaceDistance(activeShapePoints);
        textDisance = `${distance}米`;
    }

    const point = viewer.entities.add({
        position: worldPosition,
        point: {
            color: Cesium.Color.RED,
            pixelSize: 5,
            // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND // 开启后点贴地
        },
        label: {
            text: textDisance,
            font: '18px sans-serif',
            fillColor: Cesium.Color.GOLD,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(20, -20),
        },
    });
    return point;
};

const createLabel = (viewer, positionData) => {
    const col = getCoordinates(positionData);
    const newCol = col.concat(col.slice(0, 1));
    const polygongeojson = turf.polygon([newCol]);
    const area = turf.area(polygongeojson);
    const textArea = `${area.toFixed(2)}平方米`;
    // const centerPoint = turf.centerOfMass(polygongeojson)
    // 获取中心点
    const polyCenter = Cesium.BoundingSphere.fromPoints(positionData).center;

    const label = viewer.entities.add({
        name: '多边形面积',
        // position: Cesium.Cartesian3.fromDegrees(centerPoint.geometry.coordinates[0], centerPoint.geometry.coordinates[1]),
        position: polyCenter,
        label: {
            text: textArea,
            font: '18px sans-serif',
            fillColor: Cesium.Color.GOLD,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(0, 0),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
    });
    return label;
};

export const drawShape = (viewer, drawingMode, positionData) => {
    let shape;
    if (drawingMode === 'line') {
        shape = viewer.entities.add({
            polyline: {
                positions: positionData,
                // clampToGround: true,
                material: Cesium.Color.RED.withAlpha(0.4),
                width: 3,
            },
        });
    } else if (drawingMode === 'polygon') {
        shape = viewer.entities.add({
            polygon: {
                hierarchy: positionData,
                material: new Cesium.ColorMaterialProperty(Cesium.Color.YELLOW.withAlpha(0.4)),
                // clampToGround: false,
            },
        });
    }
    return shape;
};

export const measure = function (viewer, drawingMode, callback) {
    if (!viewer.scene.pickPositionSupported) {
        window.alert('This browser does not support pickPosition.');
    }

    viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
    );

    let activeShapePoints = [];
    let activeShape = null;
    let floatingPoint = null;
    let backShapePoints = null;
    const backShapeEntities = [];
    if (drawingMode == 'line') {
        viewer.scene.globe.depthTestAgainstTerrain = false; // 开启地形深度检测
    } else {
        viewer.scene.globe.depthTestAgainstTerrain = true; // 开启地形深度检测

    }
    let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction(event => {
        // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
        // we get the correct point when mousing over terrain.
        // let earthPosition = viewer.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
        const earthPosition = viewer.scene.pickPosition(event.position);

        // `earthPosition` will be undefined if our mouse is not over the globe.
        if (Cesium.defined(earthPosition)) {
            if (!activeShapePoints || activeShapePoints.length === 0) {
                floatingPoint = createPoint(earthPosition);
                activeShapePoints.push(earthPosition);
                const dynamicPositions = new Cesium.CallbackProperty(() => {
                    if (drawingMode === 'polygon') {
                        return new Cesium.PolygonHierarchy(activeShapePoints);
                    }
                    return activeShapePoints;
                }, false);
                activeShape = drawShape(dynamicPositions);
            }
            activeShapePoints.push(earthPosition);
            // createPoint(earthPosition)
            createPoint(earthPosition, activeShapePoints);
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    handler.setInputAction(event => {
        if (Cesium.defined(floatingPoint)) {
            const newPosition = viewer.scene.pickPosition(event.endPosition);
            if (Cesium.defined(newPosition)) {
                floatingPoint.position.setValue(newPosition);
                activeShapePoints.pop();
                activeShapePoints.push(newPosition);
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction(event => {
        const result = terminateShape();
        if (result) {
            // viewer.scene.globe.depthTestAgainstTerrain = false // 关闭地形深度检测
            callback(backShapePoints, backShapeEntities);
            handler.destroy() //关闭事件句柄
            handler = null
            viewer.scene.globe.depthTestAgainstTerrain = false; // 关闭地形深度检测
        }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    //点
    function createPoint(worldPosition, activeShapePoints) {
        let point;
        if (drawingMode === 'line' && Array.isArray(activeShapePoints)) {
            const distance = getSpaceDistance(activeShapePoints);
            point = viewer.entities.add({
                position: worldPosition,
                point: {
                    color: Cesium.Color.RED,
                    pixelSize: 20,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                },
                label: {
                    text: `${distance}米`,
                    font: '18px sans-serif',
                    fillColor: Cesium.Color.BLUE,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(20, -20),
                },
            });
        } else {
            point = viewer.entities.add({
                position: worldPosition,
                point: {
                    color: Cesium.Color.RED,
                    pixelSize: 20,
                    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                },
            });
        }
        backShapeEntities.push(point);
        return point;
    }

    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    function terminateShape() {
        activeShapePoints.pop();
        const result = drawShape(activeShapePoints);
        if (!result) return false;
        viewer.entities.remove(floatingPoint);
        viewer.entities.remove(activeShape);
        floatingPoint = undefined;
        activeShape = undefined;
        activeShapePoints = [];
        return true;
    }
    //画形状
    function drawShape(positionData) {
        backShapePoints = positionData;
        let shape;
        let label;
        if (drawingMode === 'line') {
            if (backShapePoints.length < 2) {
                new Message.warning({
                    message: "请最少选择两个点",
                    duration: 2000
                })
                //message.warning('请最少选择两个点');
                return false;
            }
            shape = viewer.entities.add({
                //线
                polyline: {
                    positions: positionData,
                    material: Cesium.Color.RED.withAlpha(0.7),
                    clampToGround: true,
                    width: 3,
                },
            });
        } else if (drawingMode === 'polygon') {
            if (backShapePoints.length < 3) {
                new Message.warning({
                    message: "请最少选择三个点",
                    duration: 2000
                })
                return false;
            }
            shape = viewer.entities.add({
                polygon: {
                    hierarchy: positionData,
                    material: new Cesium.ColorMaterialProperty(Cesium.Color.BLUE.withAlpha(0.4)),
                },
            });
        }

        if (drawingMode === 'polygon' && Array.isArray(positionData)) {
            if (backShapePoints.length < 3) {
                new Message.warning({
                    message: "请最少选择三个点",
                    duration: 2000
                })
                return false;
            }
            const wgs84Obj = cartesian3ToWGS84(viewer, {
                type: 'Polygon',
                positions: positionData,
            });
            // 获取中心点
            const positionsCenter = computePositionsCenter(wgs84Obj);
            const point = Cesium.Cartographic.fromDegrees(
                positionsCenter.geometry.coordinates[0],
                positionsCenter.geometry.coordinates[1],
            );
            const height = viewer.scene.sampleHeight(point);
            const polyCenter = Cesium.Cartesian3.fromDegrees(
                positionsCenter.geometry.coordinates[0],
                positionsCenter.geometry.coordinates[1],
                height,
            );
            // const polyCenter = Cesium.BoundingSphere.fromPoints(positionData).center

            const col = getCoordinates(positionData);
            const newCol = col.concat(col.slice(0, 1));
            const polygongeojson = turf.polygon([newCol]);
            const area = turf.area(polygongeojson);
            // console.log(area)

            label = viewer.entities.add({
                position: polyCenter,
                label: {
                    text: `${area.toFixed(2)}平方米`,
                    font: '18px sans-serif',
                    fillColor: Cesium.Color.GOLD,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(20, -20),
                    eyeOffset: new Cesium.Cartesian3(0, 0, -10),
                },
            });
        }
        backShapeEntities.push(shape);
        backShapeEntities.push(label);

        return shape;
    }

    return handler;
};

export const measureElevation = (viewer, callback) => {
    if (!viewer.scene.pickPositionSupported) {
        window.alert('This browser does not support pickPosition.');
    }

    viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
    );

    let activeShapePoints = [];
    let activeShape;
    let floatingPoint;
    let backShapePoints = [];
    const backShapeEntities = [];

    viewer.scene.globe.depthTestAgainstTerrain = true; // 开启地形深度检测
    let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction((event) => {
        // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
        // we get the correct point when mousing over terrain.
        // let earthPosition = viewer.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
        const earthPosition = viewer.scene.pickPosition(event.position);
        // `earthPosition` will be undefined if our mouse is not over the globe.
        if (Cesium.defined(earthPosition)) {
            if (activeShapePoints.length === 0) {
                floatingPoint = createPoint(earthPosition);
                activeShapePoints.push(earthPosition);
                const dynamicPositions = new Cesium.CallbackProperty((() =>
                    // if (drawingMode === "polygon") {
                    //   return new Cesium.PolygonHierarchy(activeShapePoints)
                    // }
                    activeShapePoints
                ), false);
                activeShape = drawShape(dynamicPositions);
            }
            activeShapePoints.push(earthPosition);
            // createPoint(earthPosition)
            createPoint(earthPosition, activeShapePoints);

            if (activeShapePoints.length >= 3) {
                terminateShape();
                // viewer.scene.globe.depthTestAgainstTerrain = false // 关闭地形深度检测
                callback(backShapePoints, backShapeEntities);
                handler.destroy(); // 关闭事件句柄
                handler = null;
                // backShapeEntities.forEach(item => {
                //   // viewer.entities.removeById(item)
                //   viewer.entities.remove(item)
                // })
                // measureElevation(viewer, callback)
            }
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    handler.setInputAction((event) => {
        if (Cesium.defined(floatingPoint)) {
            const newPosition = viewer.scene.pickPosition(event.endPosition);
            if (Cesium.defined(newPosition)) {
                floatingPoint.position.setValue(newPosition);
                activeShapePoints.pop();
                activeShapePoints.push(newPosition);
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction((event) => {
        terminateShape();
        // viewer.scene.globe.depthTestAgainstTerrain = false // 关闭地形深度检测
        callback(backShapePoints, backShapeEntities);
        // handler.destroy() //关闭事件句柄
        // handler = null
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    function createPoint(worldPosition, activeShapePoints) {
        let point;
        if (Array.isArray(activeShapePoints)) {
            // let distance = getSpaceDistance(activeShapePoints)

            // var cartographic1 = Cesium.Cartographic.fromCartesian(activeShapePoints[0]);
            const height1 = Cesium.Cartographic.fromCartesian(activeShapePoints[0]).height;
            // var cartographic1 = Cesium.Cartographic.fromCartesian(cartesian);
            const height2 = Cesium.Cartographic.fromCartesian(activeShapePoints[1]).height;
            const distance = Math.abs(height1 - height2).toFixed(2);

            point = viewer.entities.add({
                position: worldPosition,
                point: {
                    color: Cesium.Color.RED,
                    pixelSize: 5,
                    // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 添加后显示点贴地
                },
                label: {
                    text: `${distance}米`,
                    font: '18px sans-serif',
                    fillColor: Cesium.Color.GOLD,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(20, -20),
                },
            });
        } else {
            point = viewer.entities.add({
                position: worldPosition,
                point: {
                    color: Cesium.Color.RED,
                    pixelSize: 8,
                    // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 添加后显示点贴地
                },
            });
        }
        backShapeEntities.push(point);
        return point;
    }

    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    function terminateShape() {
        activeShapePoints.pop();
        drawShape(activeShapePoints);
        viewer.entities.remove(floatingPoint);
        viewer.entities.remove(activeShape);
        floatingPoint = undefined;
        activeShape = undefined;
        activeShapePoints = [];
    }

    function drawShape(positionData) {
        backShapePoints = positionData;
        const shape = viewer.entities.add({
            polyline: {
                positions: positionData,
                material: Cesium.Color.RED.withAlpha(0.4),
                clampToGround: false,
                width: 3,
            },
        });

        backShapeEntities.push(shape);
        return shape;
    }

    return handler;
};

// 标注相关
export const createLabelPolyline = (viewer, options) => {
    const { positions, text, color, width = 5 } = options;
    // 获取中心点
    const polyCenter = Cesium.BoundingSphere.fromPoints(positions).center;
    const entity = new Cesium.Entity({
        position: polyCenter,
        label: {
            text,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(0, 0),
        },
        polyline: new Cesium.PolylineGraphics({
            positions,
            width,
            material: color ? fromCssColorString(color) : Cesium.Color.YELLOWGREEN,
            clampToGround: true,
            zIndex: 5000,
        }),
    });
    viewer.entities.add(entity);
    return entity;
};

export const createLabelPolygon = (viewer, options) => {
    const { text, positions, color } = options;
    // geom转Cartesian3
    // let cartesian3Obj = geomToCartesian3(geom)
    // 坐标转换
    const wgs84Obj = cartesian3ToWGS84(viewer, {
        type: 'Polygon',
        positions,
    });
    // 获取中心点
    // const polyCenter = Cesium.BoundingSphere.fromPoints(positions).center
    const positionsCenter = computePositionsCenter(wgs84Obj);
    const point = Cesium.Cartographic.fromDegrees(
        positionsCenter.geometry.coordinates[0],
        positionsCenter.geometry.coordinates[1],
    );
    const height = viewer.scene.sampleHeight(point);

    const entity = new Cesium.Entity({

        position: Cesium.Cartesian3.fromDegrees(
            positionsCenter.geometry.coordinates[0],
            positionsCenter.geometry.coordinates[1],
            height,
        ),
        // position: polyCenter,
        label: {
            // text,
            // font: '14pt monospace',
            // style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            // outlineWidth: 2,
            // eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            // verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            // pixelOffset: new Cesium.Cartesian2(0, 0),
            // disableDepthTestDistance: Number.POSITIVE_INFINITY,

            text,
            font: '14pt monospace',
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 2,
            eyeOffset: new Cesium.Cartesian3(0.0, 0.0, -10),
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            // pixelOffset: new Cesium.Cartesian2(0, 0),
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,

            pixelOffset: new Cesium.Cartesian2(20, -20),
        },
        polygon: {
            hierarchy: positions,
            // perPositionHeight: true,
            material: fromCssColorString(color),
            outline: true,
            outlineColor: Cesium.Color.BLACK,
            clampToGround: true,
            perPositionHeight: false,
        },
    });

    viewer.entities.add(entity);

    return entity;
};

/**
 * 32位色值转rgba
 * @param {*} hex 例如：ffff0000 (顺序：argb)
 * @returns
 */
export function hexToRgba(hex) {
    return {
        a: parseInt(`0x${hex.slice(0, 2)}`) / 255,
        r: parseInt(`0x${hex.slice(2, 4)}`),
        g: parseInt(`0x${hex.slice(4, 6)}`),
        b: parseInt(`0x${hex.slice(6, 8)}`),
    };
}

/**
 * rgba转32位色值
 * @param rgba { r: 255, g: 0, b: 0, a: 1 }
 * @returns hex 例如：ffff0000 (顺序：argb)
 */
export function rgbaToHex(rgba) {
    let r;
    let g;
    let b;
    let a;
    a = `0${Math.floor(rgba.a * 255).toString(16)}`.slice(-2);
    r = `0${parseInt(rgba.r).toString(16)}`.slice(-2);
    g = `0${parseInt(rgba.g).toString(16)}`.slice(-2);
    b = `0${parseInt(rgba.b).toString(16)}`.slice(-2);
    return (a + r + g + b).toUpperCase();
}

// 根据经纬度获取高度
export function getHeigthByLonLat(viewer, lon = 87.5968, lat = 43.8084) {
    // viewer.scene.globe.depthTestAgainstTerrain = true // 开启地形深度检测
    const positions = Cesium.Cartographic.fromDegrees(lon, lat);
    const height = viewer.scene.sampleHeight(positions);
    // var height = viewer.scene.globe.getHeight(positions)
    // let promise = viewer.scene.sampleHeightMostDetailed([positions]);
    // promise.then(function (updatedPosition) {
    //   // positions[0].height and positions[1].height have been updated.
    //   // updatedPositions is just a reference to positions.
    //   console.log("zhang", lon, lat, updatedPosition[0].height)
    // })
    // let promise = new Cesium.sampleTerrain(viewer.terrainProvider, 13, [positions])
    // promise = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, positions)
    // Cesium.when(new Cesium.sampleTerrain(viewer.terrainProvider, 13, [positions]), function (updatedPositions) {
    // 	console.log("zhang",lon,lat,updatedPositions[0].height)
    // })
}

// 获取XML style
export function getXMLStyle(type, width, height, hex, fillHex) {
    let cmObj;
    let cmXml;
    let style = '';
    if (type === 'polyline') {
        cmObj = {
            CurveSymbol: {
                _attributes: {
                    Color: hex,
                    RepeatLength: '1.000000',
                    Width: width,
                    DashStyle: 'DashSolid',
                },
            },
        };
    } else if (type === 'polygon') {
        cmObj = {
            SurfaceSymbol: {
                _attributes: {
                    Color: fillHex,
                    EnableLight: 'false',
                    RepeatLengthU: '1.000000',
                    RepeatLengthV: '1.000000',
                    Rotation: '0.000000',
                },
                CurveSymbol: {
                    _attributes: {
                        Color: hex,
                        RepeatLength: '1.000000',
                        Width: width,
                        DashStyle: 'DashSolid',
                    },
                },
            },
        };
    }

    cmXml = convert.js2xml(cmObj, { compact: true, spaces: 4 });
    style = JSON.stringify({
        HeightStyle: height,
        GeoSymbolXml: cmXml,
        TextSymbolXml: '',
    });
    return style;
}

/**
 * 方量计算中使用
 * @param points 顶点坐标
 */
// 计算多边形面积
export function getArea(points) {
    const radiansPerDegree = Math.PI / 180.0; // 角度转化为弧度(rad)
    const degreesPerRadian = 180.0 / Math.PI; // 弧度转化为角度

    /* 角度 */
    function Angle(p1, p2, p3) {
        const bearing21 = Bearing(p2, p1);
        const bearing23 = Bearing(p2, p3);
        let angle = bearing21 - bearing23;
        if (angle < 0) {
            angle += 360;
        }
        return angle;
    }

    /* 方向 */
    function Bearing(from, to) {

        from = Cesium.Cartographic.fromCartesian(from);

        to = Cesium.Cartographic.fromCartesian(to);

        const lat1 = from.latitude;
        const lon1 = from.longitude;
        const lat2 = to.latitude;
        const lon2 = to.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;
        }
        angle *= degreesPerRadian; // 角度
        return angle;
    }

    function distance(point1, point2) {

        const point1cartographic = Cesium.Cartographic.fromCartesian(point1);

        const point2cartographic = Cesium.Cartographic.fromCartesian(point2);
        /** 根据经纬度计算出距离* */
        const geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        let s = geodesic.surfaceDistance;
        // console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
        // 返回两点之间的距离
        s = Math.sqrt(
            Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2),
        );
        return s;
    }

    let res = 0;
    // 拆分三角曲面

    for (let i = 0; i < points.length - 2; i++) {
        const j = (i + 1) % points.length;
        const k = (i + 2) % points.length;
        const totalAngle = Angle(points[i], points[j], points[k]);

        const dis_temp1 = distance(points[j], points[0]);
        const dis_temp2 = distance(points[k], points[0]);
        res += (dis_temp1 * dis_temp2 * Math.sin(totalAngle)) / 2;
        // console.log(res);
    }

    // if (res < 1000000) {
    //   
    //   res = Math.abs(res).toFixed(4) + " 平方米";
    // } else {
    //   
    //   res = Math.abs((res / 1000000.0).toFixed(4)) + " 平方公里";
    // }

    return Math.abs(res);
}

export const measureTypes = {
    HORL: 'horizontal',
    VERL: 'vertical',
    AREA: 'area',
    VOLUME: 'volume',
};

export function drawGraphic(viewer, drawingMode, callback) {
    if (!viewer.scene.pickPositionSupported) {
        window.alert("This browser does not support pickPosition.")
    }

    viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
    )

    let activeShapePoints = []
    let activeShape = null
    let floatingPoint = null
    let backShapePoints = []
    const backShapeEntities = []

    viewer.scene.globe.depthTestAgainstTerrain = true // 开启地形深度检测
    let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
    handler.setInputAction((event) => {
        // We use `viewer.scene.pickPosition` here instead of `viewer.camera.pickEllipsoid` so that
        // we get the correct point when mousing over terrain.
        // let earthPosition = viewer.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
        const earthPosition = viewer.scene.pickPosition(event.position)

        // try {
        //   let ellipsoid = viewer.scene.globe.ellipsoid
        //   cartesian3 = ellipsoid.cartographicToCartesian(earthPosition)
        // } catch (e) {
        //   console.log(e)
        // }
        // if (!earthPosition) {
        //   earthPosition = viewer.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
        // }

        // `earthPosition` will be undefined if our mouse is not over the globe.
        if (Cesium.defined(earthPosition)) {
            if (activeShapePoints.length === 0) {
                floatingPoint = createPoint(earthPosition)
                if (drawingMode === "point") {
                    handler.destroy() // 关闭事件句柄
                    handler = null
                    callback([earthPosition], [floatingPoint])
                    return
                }

                activeShapePoints.push(earthPosition)
                const dynamicPositions = new Cesium.CallbackProperty((() => {
                    if (drawingMode === "polygon") {
                        return new Cesium.PolygonHierarchy(activeShapePoints)
                    }
                    return activeShapePoints
                }), false)
                if (drawingMode !== 'point') {
                    activeShape = drawShape(dynamicPositions)
                }
            }

            activeShapePoints.push(earthPosition)
            createPoint(earthPosition)
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

    handler.setInputAction((event) => {
        if (Cesium.defined(floatingPoint)) {
            const newPosition = viewer.scene.pickPosition(event.endPosition)
            if (Cesium.defined(newPosition)) {
                floatingPoint.position.setValue(newPosition)
                activeShapePoints.pop()

                activeShapePoints.push(newPosition)
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    handler.setInputAction((event) => {
        terminateShape()
        viewer.scene.globe.depthTestAgainstTerrain = false // 关闭地形深度检测
        callback(backShapePoints, backShapeEntities)
        handler.destroy() // 关闭事件句柄
        handler = null
        // viewer.entities.remove(floatingPoint)
        // viewer.entities.remove(activeShapePoints)
        // viewer.entities.remove(activeShape)
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

    function createPoint(worldPosition) {
        const point = viewer.entities.add({
            position: worldPosition,
            point: {
                color: Cesium.Color.RED,
                pixelSize: 5,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        })

        backShapeEntities.push(point)
        return point
    }

    // Redraw the shape so it's not dynamic and remove the dynamic shape.
    function terminateShape() {
        activeShapePoints.pop()
        drawShape(activeShapePoints)
        viewer.entities.remove(floatingPoint)
        viewer.entities.remove(activeShape)
        floatingPoint = undefined
        activeShape = undefined
        activeShapePoints = []
    }

    function drawShape(positionData) {
        backShapePoints = positionData
        let shape
        if (drawingMode === "line") {
            shape = viewer.entities.add({
                polyline: {
                    positions: positionData,
                    clampToGround: true,
                    width: 3,
                    material: new Cesium.ColorMaterialProperty(
                        Cesium.Color.RED.withAlpha(0.5)
                    )
                },
            })
        } else if (drawingMode === "polygon") {
            shape = viewer.entities.add({
                polygon: {
                    hierarchy: positionData,
                    material: new Cesium.ColorMaterialProperty(
                        Cesium.Color.YELLOWGREEN.withAlpha(0.5)
                    ),
                },
            })
        }

        backShapeEntities.push(shape)
        return shape
    }
}