美文网首页开源Cesium技术
Cesium 拖拽坐标轴调整模型位置(entity)ts

Cesium 拖拽坐标轴调整模型位置(entity)ts

作者: 宿州刘德华 | 来源:发表于2022-05-06 10:33 被阅读0次

    turn.ts

    
    /* eslint-disable no-unused-vars */
    /**
     * 距离(米)转换为经度  一米对应的经度与所在有关纬度
     * @param meter 距离
     * @param lat 所在纬度
     * @returns {number}
     */
    export const meter2Lng = (meter: number, lat: number): number => {
      let pi = Math.PI;
      let latInMeter = (Math.cos((lat * pi) / 180) * 6371 * 2 * pi) / 360;
      return meter / latInMeter / 1000;
    };
    
    /**
     * 距离(米)转换为纬度  一米对应的纬度为定值
     * @param meter 距离多少米
     * @returns {number}
     */
    export const meter2Lat = (meter: number) => {
      let pi = Math.PI;
      let lngInMeter = (6371 * 2 * pi) / 360;
      return meter / lngInMeter / 1000;
    };
    
    /**
     * 判断该点是否是经纬度或者笛卡尔坐标
     * @param point
     */
    export const isDegreesOrCartesian = (point: any) => {
      if (!point) {
        throw "参数错误!";
      }
      if (
        "number" === typeof point.x &&
        "number" === typeof point.y &&
        "number" === typeof point.z
      ) {
        return true;
      }
      if ("number" === typeof point.lng && "number" === typeof point.lat) {
        return true;
      }
      return false;
    };
    /**
     * 笛卡尔坐标转WGS84
     * @param Cartesian3 单个点或点数组
     */
    export const Cartesian3ToWGS84 = ({ Cesium, viewer }: any, Cartesian3: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (!Cartesian3 || !Cartesian3.x) {
        throw "Error in parameters";
      }
      let _cartesian3 = new Cesium.Cartesian3(
        Cartesian3.x,
        Cartesian3.y,
        Cartesian3.z
      );
      let _cartographic = Cesium.Cartographic.fromCartesian(_cartesian3);
      let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
      let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
      let _alt = _cartographic.height;
      return { lng: _lng, lat: _lat, alt: _alt };
    };
    /**
     * 世界坐标系转屏幕坐标
     * @param point
     * @param viewer
     */
    export const toWindowCoordinates = ({ Cesium, viewer }: any, point: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (viewer && point && point.x && point.y && point.z) {
        return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, point);
      } else if (viewer && point.lng && point.lat && point.alt) {
        return Cesium.SceneTransforms.wgs84ToWindowCoordinates(
          viewer.scene,
          toCartesianFromDegrees({ Cesium, viewer }, point)
        );
      } else {
        throw "参数错误!";
      }
    };
    
    /**
     * 笛卡尔坐标转世界坐标
     * @param point
     */
    export const toDegreesFromCartesian = ({ Cesium, viewer }: any, point: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (point.x && point.y && point.z) {
        let cartesian33 = new Cesium.Cartesian3(point.x, point.y, point.z);
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian33);
        return {
          lng: parseFloat(
            Cesium.Math.toDegrees(cartographic.longitude).toFixed(10)
          ),
          lat: parseFloat(Cesium.Math.toDegrees(cartographic.latitude).toFixed(10)),
          alt: parseFloat(cartographic.height.toFixed(5)),
        };
      } else {
        throw "参数错误!";
      }
    };
    
    /**
     * 世界坐标转笛卡尔坐标
     * @param point
     */
    export const toCartesianFromDegrees = ({ Cesium, viewer }: any, point: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (point.lng && point.lat) {
        return Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt || 0);
      } else {
        throw "参数错误!";
      }
    };
    /**
     * 转化成经纬度
     * @param point
     */
    export const toDegrees = ({ Cesium, viewer }: any, point: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (isDegreesOrCartesian(point)) {
        if (point.x && point.y && point.z) {
          point = toDegreesFromCartesian({ Cesium, viewer }, point);
        }
        return point;
      } else {
        throw "参数错误!";
      }
    };
    
    /**
     * 转化成笛卡尔坐标
     * @param point
     */
    export const toCartesian = ({ Cesium, viewer }: any, point: any) => {
      if (!Cesium || !viewer) {
        return;
      }
      if (isDegreesOrCartesian(point)) {
        if (point.lng && point.lat) {
          point = toCartesianFromDegrees({ Cesium, viewer }, point);
        }
        return point;
      } else {
        throw "参数错误!";
      }
    };
    
    /**
     * 获取两点之间的距离
     * @param p1
     * @param p2
     * @returns {*}
     */
    export const getDistance = ({ Cesium, viewer }: any, p1: any, p2: any) => {
      p1 = toCartesian({ Cesium, viewer }, p1);
      p2 = toCartesian({ Cesium, viewer }, p2);
      return Math.sqrt(
        Math.pow(p1.x - p2.x, 2) +
        Math.pow(p1.y - p2.y, 2) +
        Math.pow(p1.z - p2.z, 2)
      );
    };
    
    /**
     * 点到线段的最短距离
     * @param a 线段上一点
     * @param b 线段上另一个点
     * @param s 该点到ab的最短距离
     * @returns {number}
     */
    export const point2LineMinDistance = ({ Cesium, viewer }: any, a: any, b: any, s: any) => {
      a = toCartesian({ Cesium, viewer }, a);
      b = toCartesian({ Cesium, viewer }, b);
      s = toCartesian({ Cesium, viewer }, s);
      let ab = Math.sqrt(
        Math.pow(a.x - b.x, 2.0) +
        Math.pow(a.y - b.y, 2.0) +
        Math.pow(a.z - b.z, 2.0)
      );
      let as = Math.sqrt(
        Math.pow(a.x - s.x, 2.0) +
        Math.pow(a.y - s.y, 2.0) +
        Math.pow(a.z - s.z, 2.0)
      );
      let bs = Math.sqrt(
        Math.pow(s.x - b.x, 2.0) +
        Math.pow(s.y - b.y, 2.0) +
        Math.pow(s.z - b.z, 2.0)
      );
      let cos_A =
        (Math.pow(as, 2.0) + Math.pow(ab, 2.0) - Math.pow(bs, 2.0)) / (2 * ab * as);
      let sin_A = Math.sqrt(1 - Math.pow(cos_A, 2.0));
      let t =
        ((a.x - s.x) * (a.x - b.x) +
          (a.y - s.y) * (a.y - b.y) +
          (a.z - s.z) * (a.z - b.z)) /
        (Math.pow(a.x - b.x, 2.0) +
          Math.pow(a.y - b.y, 2.0) +
          Math.pow(a.z - b.z, 2.0));
      if (t < 0) {
        return as;
      } else if (t <= 1 && t >= 0) {
        return as * sin_A;
      } else if (t > 1) {
        return bs;
      }
    };
    
    /**
     * 求三角形面积;返回-1为不能组成三角形;
     * @param a
     * @param b
     * @param c
     * @returns {*}
     */
    export const countTriangleArea = ({ Cesium, viewer }: any, a: any, b: any, c: any) => {
      a = toCartesian({ Cesium, viewer }, a);
      b = toCartesian({ Cesium, viewer }, b);
      c = toCartesian({ Cesium, viewer }, c);
      let area = -1;
      let side = []; //存储三条边的长度;
      side[0] = Math.sqrt(
        Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2) + Math.pow(a.z - b.z, 2)
      );
      side[1] = Math.sqrt(
        Math.pow(a.x - c.x, 2) + Math.pow(a.y - c.y, 2) + Math.pow(a.z - c.z, 2)
      );
      side[2] = Math.sqrt(
        Math.pow(c.x - b.x, 2) + Math.pow(c.y - b.y, 2) + Math.pow(c.z - b.z, 2)
      );
      //不能构成三角形;
      if (
        side[0] + side[1] <= side[2] ||
        side[0] + side[2] <= side[1] ||
        side[1] + side[2] <= side[0]
      ) {
        return area;
      }
      //利用海伦公式。area =sqr(p*(p-a)(p-b)(p-c));
      let p = (side[0] + side[1] + side[2]) / 2; //半周长;
      area = Math.sqrt(p * (p - side[0]) * (p - side[1]) * (p - side[2]));
      return area;
    };
    
    /**
     * 获取多边形的中心(根据经纬度,不包括高程)
     * @param path  数组 [{lng:123,lat:32},...]
     * @returns {{lng: number, lat: number}}
     */
    export const getPolygonCenterByDegree = (path: any) => {
      if (!path || path.length < 3 || !path[0].lng) {
        throw "Error in parameters";
      }
      let x = 0.0;
      let y = 0.0;
      for (let i = 0; i < path.length; i++) {
        x = x + parseFloat(path[i].lng);
        y = y + parseFloat(path[i].lat);
      }
      x = x / path.length;
      y = y / path.length;
      return {
        lng: x,
        lat: y,
      };
    };
    
    /**
     * 求多边形的面积
     * @param arr
     * @returns {*}
     */
    export const countArea = ({ Cesium, viewer }: any, arr: any) => {
      if (!arr || arr.length < 3) {
        throw "参数错误!";
      } else {
        let area = 0;
        for (let i = 0; i < arr.length; i++) {
          let j = (i + 1) % arr.length;
          let p1 = arr[i],
            p2 = arr[j];
          p1 = toCartesian({ Cesium, viewer }, p1);
          p2 = toCartesian({ Cesium, viewer }, p2);
          area += p1.x * p2.y;
          area -= p1.y * p2.x;
        }
        area /= 2;
        return Math.abs(area);
      }
    };
    
    
    

    run.ts

    import { meter2Lng, meter2Lat, toDegrees, toCartesian } from "@/assets/tools/turn/turn"
    
    /**
     * 拖拽坐标轴调整实体位置
     * @param Cesium 
     * @param viewer 
     * @param activeModelEntity 要移动的实体
     * @param arrowLength 坐标轴长度(米) 默认200
     */
    let dragEntity: any = (Cesium: any, viewer: any, activeModelEntity: any, arrowLength: number) => {
        let MoveEntity = (() => {
            let leftDownFlag = false;//左键是否按下 作为可拖拽的依据
            let pointDraged: any = null;//左键按下之后拾取到的东西
            let viewer: any;
            let Cesium: any;
            let handler: any;
            let activeModelEntity: any;//要拖动的实体
            let arrowLength: number;//单位米
            let lastMaterial: any;// 坐标轴原本的材质
            let activePolyLineEntity: any;//选中的线实体
            let activePolyLineMaterial: any;//坐标轴选中之后的材质
            let lastEndPosition: any;//鼠标移动上次的位置
            let ConstructMoveEntity = (options: any) => {
                viewer = options.viewer;
                Cesium = options.Cesium;
                activeModelEntity = options.activeModelEntity;
                arrowLength = options.arrowLength || 200;
                handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
                Init();
                addOrUpdateAxis(null, null);
                viewer.scene.globe.depthTestAgainstTerrain = true;//开启深度检测
                activePolyLineMaterial = new Cesium.PolylineArrowMaterialProperty(Cesium.Color.YELLOW)
            }
    
            let addOrUpdateAxis = (pickedId: any = null, activePolyLineMaterial: any = null) => {
                if (activeModelEntity && arrowLength) {
                    let startPosition = activeModelEntity.position.getValue(viewer.clock.currentTime);
                    let p_p = toDegrees({ Cesium: Cesium, viewer: viewer }, startPosition)
                    // console.log(p_p) //打印位置
                    let endLng = toCartesian({ Cesium: Cesium, viewer: viewer }, { lng: p_p.lng + meter2Lng(arrowLength, p_p.lat), lat: p_p.lat, alt: p_p.alt })
                    let endLat = toCartesian({ Cesium: Cesium, viewer: viewer }, { lng: p_p.lng, lat: p_p.lat + meter2Lat(arrowLength), alt: p_p.alt })
                    let endAlt = toCartesian({ Cesium: Cesium, viewer: viewer }, { lng: p_p.lng, lat: p_p.lat, alt: p_p.alt + arrowLength })
    
    
                    let AxisLng = viewer.entities.getOrCreateEntity("AxisLng")
                    AxisLng.polyline = {
                        positions: new Cesium.CallbackProperty(function () {
                            return [startPosition, endLng];
                        }, false),
                        width: 10,
                        material: pickedId === "AxisLng" ? activePolyLineMaterial : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED),
                    }
    
                    let AxisLat = viewer.entities.getOrCreateEntity("AxisLat")
                    AxisLat.polyline = {
                        positions: new Cesium.CallbackProperty(function () {
                            return [startPosition, endLat];
                        }, false),
                        width: 10,
                        material: pickedId === "AxisLat" ? activePolyLineMaterial : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.GREEN),
                    }
    
                    let AxisAlt = viewer.entities.getOrCreateEntity("AxisAlt")
                    AxisAlt.polyline = {
                        positions: new Cesium.CallbackProperty(function () {
                            return [startPosition, endAlt];
                        }, false),
                        width: 10,
                        material: pickedId === "AxisAlt" ? activePolyLineMaterial : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.BLUE),
                    }
                }
            }
    
            let Init = () => {
                // 左键按下 
                handler.setInputAction((movement: any) => {
                    pointDraged = viewer.scene.pick(movement.position);//选取当前的entity
                    leftDownFlag = true;
                    if (pointDraged) {
                        viewer.scene.screenSpaceCameraController.enableRotate = false;//锁定相机
                        //当前实体Entity的polyline坐标属性信息暂存
                        if (pointDraged.id.polyline) {
                            activePolyLineEntity = pointDraged.id//记录正在活动的线实体
                            lastMaterial = activePolyLineEntity.polyline.material//线实体材质
                            activePolyLineEntity.polyline.material = activePolyLineMaterial
                        }
                    }
                }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
    
                // 左键抬起
                handler.setInputAction(() => {
                    leftDownFlag = false;
                    pointDraged = null;
                    viewer.scene.screenSpaceCameraController.enableInputs = true;
                    viewer.scene.screenSpaceCameraController.enableRotate = true;//锁定相机
    
                    if (activePolyLineEntity && lastMaterial) {
                        activePolyLineEntity.polyline.material = lastMaterial
                        activePolyLineEntity = null;
                    }
                    lastEndPosition = null;
                }, Cesium.ScreenSpaceEventType.LEFT_UP);
                // 鼠标移动
                handler.setInputAction((movement: any) => {
                    if (leftDownFlag === true && pointDraged != null && activePolyLineEntity && activeModelEntity) {
    
                        let endPosition = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
                        if (!endPosition) {
                            return
                        }
    
                        let cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(endPosition);
                        let cartographic2: any;
                        if (endPosition && lastEndPosition) {
                            cartographic2 = viewer.scene.globe.ellipsoid.cartesianToCartographic(lastEndPosition);
                        }
                        let nowPosition_Cartesian = activeModelEntity.position.getValue(viewer.clock.currentTime);//模型当前位置
                        let nowPosition_Degree = toDegrees({ Cesium: Cesium, viewer: viewer }, nowPosition_Cartesian)
                        let temp = 0.5;//这个可以通过传参来搞
                        let pickedId = pointDraged.id.id
    
                        if (!(["AxisAlt", "AxisLng", "AxisLat"].includes(pickedId))) {
                            return
                        }
                        if (pickedId === "AxisAlt") {
                            //高度调整
                            let pixel_difference = movement.endPosition.y - movement.startPosition.y
                            //pixel_difference > 0高度减少  pixel_difference < 0 高度增加
                            nowPosition_Degree.alt = nowPosition_Degree.alt - (temp * pixel_difference)
                        } else if (pickedId === "AxisLng") {
                            //经度调整
                            if (cartographic2 && cartographic) {
                                let lng = Cesium.Math.toDegrees(cartographic.longitude);//鼠标拾取的经度
                                let lng2 = Cesium.Math.toDegrees(cartographic2.longitude);
                                nowPosition_Degree.lng -= (lng2 - lng);
                            }
    
                        } else if (pickedId === "AxisLat") {
                            //纬度调整
                            if (cartographic2 && cartographic) {
                                let lat = Cesium.Math.toDegrees(cartographic.latitude);//鼠标拾取的纬度
                                let lat2 = Cesium.Math.toDegrees(cartographic2.latitude);
                                nowPosition_Degree.lat -= (lat2 - lat);
                            }
    
                        }
                        lastEndPosition = endPosition
                        let r = toCartesian({ Cesium: Cesium, viewer: viewer }, nowPosition_Degree)
                        activeModelEntity.position.setValue(r);
                        addOrUpdateAxis(pickedId, activePolyLineMaterial)
                    }
                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    
                // 右键结束
                handler.setInputAction(() => {
                    handler.destroy();
                }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
            }
            return ConstructMoveEntity;
        })();
        MoveEntity({ Cesium: Cesium, viewer: viewer, activeModelEntity: activeModelEntity, arrowLength: arrowLength })
    }
    
    export {
        dragEntity
    }
    

    欢迎各位给出宝贵意见

    相关文章

      网友评论

        本文标题:Cesium 拖拽坐标轴调整模型位置(entity)ts

        本文链接:https://www.haomeiwen.com/subject/wabayrtx.html