美文网首页开源
Cesium中空间计算 、坐标转换、相机姿态

Cesium中空间计算 、坐标转换、相机姿态

作者: 宿州刘德华 | 来源:发表于2020-06-23 10:10 被阅读0次
    /**
     * 获取当前相机姿态信息
     * 包括经度、纬度、高程、Heading、Pitch、Roll
     * @param viewer
     */
    let getCameraInfo = (viewer) => {
      if (viewer && viewer.camera && viewer.camera.position && viewer.camera.heading) {
        let p = toDegrees(viewer.camera.position);
        let heading = Cesium.Math.toDegrees(viewer.camera.heading);
        let pitch = Cesium.Math.toDegrees(viewer.camera.pitch);
        let roll = Cesium.Math.toDegrees(viewer.camera.roll);
        return {
          heading: parseFloat(heading).toFixed(5),
          pitch: parseFloat(pitch).toFixed(5),
          roll: parseFloat(roll).toFixed(5),
          lng: parseFloat(p.lng).toFixed(7),
          lat: parseFloat(p.lat).toFixed(7),
          alt: parseFloat(p.alt).toFixed(2)
        }
      } else {
        throw new Error("Error in Parameter!");
      }
    };
    
    /**
     * 距离(米)转换为纬度  一米对应的纬度为定值
     * @param meter 距离多少米
     * @returns {number}
     */
    let meter2Lat = (meter) => {
      if (!meter) {
        throw new Error("Error in Parameter!");
      }
      let pi = Math.PI;
      let lngInMeter = (6371 * 2 * pi) / 360;
      return (meter / lngInMeter) / 1000;
    };
    
    /**
     * 距离(米)转换为经度  不同纬度下一米对应的经度不同
     * @param meter 距离
     * @param lat 所在纬度
     * @returns {number}
     */
    let meter2Lng = (meter, lat) => {
      if ((!meter) || (!lat)) {
        throw new Error("Error in Parameter!");
      }
      let pi = Math.PI;
      let latInMeter = (Math.cos(lat * pi / 180) * 6371 * 2 * pi) / 360;
      return (meter / latInMeter) / 1000;
    };
    
    /**
     * 判断该点是否是经纬度或者笛卡尔坐标
     * @param point
     */
    let isDegreesOrCartesian = (point) => {
      if (!point) {
        throw new Error("Error in Parameter!");
      }
      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;
    };
    
    /**
     * 转化成经纬度
     * @param point
     */
    let toDegrees = (point) => {
      if (isDegreesOrCartesian(point)) {
        /**
         * 笛卡尔坐标转地理坐标
         * @param point
         */
        let toDegreesFromCartesian = (point) => {
          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(8)),
            lat: parseFloat(Cesium.Math.toDegrees(cartographic.latitude).toFixed(8)),
            alt: parseFloat(cartographic.height.toFixed(8))
          };
    
        };
        if (point.x) {
          point = toDegreesFromCartesian(point);
        }
        return point;
      }
    };
    
    /**
     * 转化成笛卡尔坐标
     * @param point
     */
    let toCartesian = (point) => {
      if (isDegreesOrCartesian(point)) {
        /**
         * 地理坐标转笛卡尔坐标
         * @param point
         */
        let toCartesianFromDegrees = (point) => {
          return Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt || 0);
        };
        if (point.lng) {
          point = toCartesianFromDegrees(point);
        }
        return point;
      }
    };
    
    /**
     * 转屏幕坐标
     * @param point
     * @param viewer
     */
    let toWindowCoordinates = (point, viewer) => {
      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(point));
      } else {
        throw new Error("Error in Parameter!");
      }
    };
    
    /**
     * 点到线段的最短距离
     * @param a 线段端点
     * @param b 线段端点
     * @param s 该点到ab的最短距离
     * @returns {number}
     */
    let point2LineDistance = (a, b, s) => {
      a = toCartesian(a);
      b = toCartesian(b);
      s = toCartesian(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;
      }
    };
    
    /**
     * 求多边形的面积
     * @param arr
     * @returns {*}
     */
    let countArea = (arr) => {
      if ((!arr) || (arr.length < 3)) {
        throw new Error("Error in Parameter!");
      } 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(p1);
          p2 = toCartesian(p2);
          area += p1.x * p2.y;
          area -= p1.y * p2.x;
        }
        area /= 2;
        return Math.abs(area);
      }
    };
    
    /**
     * 求三角形面积;返回-1为不能组成三角形;
     * @param a
     * @param b
     * @param c
     * @returns {*}
     */
    let countAreaByThreePoints = (a, b, c) => {
      a = toCartesian(a);
      b = toCartesian(b);
      c = toCartesian(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 p1
     * @param p2
     * @returns {null|number}
     */
    let getDistance = (p1, p2) => {
      if ((!p1) || (!p2)) {
        throw new Error("Error in Parameter!");
      }
      p1 = toCartesian(p1);
      p2 = toCartesian(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 p1
     * @param p2
     * @param p3
     * @returns {{x: number, y: number, z: number}}
     */
    let getNormal = (p1, p2, p3) => {
      p1=toCartesian(p1);
      p2=toCartesian(p2);
      p3=toCartesian(p3);
      let x = ((p2.y - p1.y) * (p3.z - p1.z) - (p2.z - p1.z) * (p3.y - p1.y));
      let y = ((p2.z - p1.z) * (p3.x - p1.x) - (p2.x - p1.x) * (p3.z - p1.z));
      let z = ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x));
      return {"x": x, "y": y, "z": z};
    };
    
    /**
     * 求线面交点 线面平行返回undefined //参考网址[https://blog.csdn.net/abcjennifer/article/details/6688080]
     * @param planeVector 平面的法线向量
     * @param planePoint 平面经过的一点坐标
     * @param lineVector 直线的方向向量
     * @param linePoint 直线经过的一点坐标
     * @returns {Array}  返回交点坐标
     * @constructor
     */
    let countIntersectionOfLineAndPlane = (planeVector, planePoint, lineVector, linePoint) => {
      let vp1, vp2, vp3, n1, n2, n3, v1, v2, v3, m1, m2, m3, t, vpt;
      vp1 = planeVector.x;
      vp2 = planeVector.y;
      vp3 = planeVector.z;
      n1 = planePoint.x;
      n2 = planePoint.y;
      n3 = planePoint.z;
      v1 = lineVector.x;
      v2 = lineVector.y;
      v3 = lineVector.z;
      m1 = linePoint.x;
      m2 = linePoint.y;
      m3 = linePoint.z;
      vpt = v1 * vp1 + v2 * vp2 + v3 * vp3;
      //首先判断直线是否与平面平行
      let result = {};
      if (vpt === 0) {
        return undefined;
      } else {
        t = ((n1 - m1) * vp1 + (n2 - m2) * vp2 + (n3 - m3) * vp3) / vpt;
        result.x = m1 + v1 * t;
        result.y = m2 + v2 * t;
        result.z = m3 + v3 * t;
      }
      return result;
    };
    
    /**
     * 求交点 线面相交 求交点
     * @param line
     * @param polygon
     * @returns {boolean|Array}
     */
    let getPointInPolygon = (line, polygon) => {
      let normal = getNormal(polygon[0], polygon[1], polygon[2]);
      let lineX = line[0].x - line[1].x;
      let lineY = line[0].y - line[1].y;
      let lineZ = line[0].z - line[1].z;
      let lineNormal = {"x": lineX, "y": lineY, "z": lineZ};
      let result = countIntersectionOfLineAndPlane(normal, polygon[1], lineNormal, line[0]);
      if (result) {
        return result;
      }
      return false;
    };
    
    /**
     * 判断点是否在四边形内部(只针对凸多边形)
     * @param point
     * @param quadrilateral
     */
    let isPointInQuadrilateral = (point, quadrilateral) => {
      let s1, s2, s3, s4, s5, s6;//s1 s2是将四边形分为两个三角形的面积  s3 s4 s5 s6代表四边形四个顶点到目标点组成的四个三角形的面积
      let ab, bc, ac, cd, da;//四边形的边长和对角线ac的长度
      ab = getDistance(quadrilateral[0], quadrilateral[1]);
      bc = getDistance(quadrilateral[1], quadrilateral[2]);
      ac = getDistance(quadrilateral[0], quadrilateral[2]);
      cd = getDistance(quadrilateral[2], quadrilateral[3]);
      da = getDistance(quadrilateral[3], quadrilateral[4]);
      //海伦公式 计算出四边形中两个三角形的面积
      let p_abc = (ab + bc + ac) / 2;
      let p_acd = (ac + cd + da) / 2;
      s1 = Math.sqrt(p_abc * (p_abc - ab) * (p_abc - bc) * (p_abc - ac));
      s2 = Math.sqrt(p_acd * (p_acd - ac) * (p_acd - cd) * (p_acd - da));
      let ap, bp, cp, dp;//四边形到目标点之间的距离
      ap = getDistance(point, quadrilateral[0]);
      bp = getDistance(point, quadrilateral[1]);
      cp = getDistance(point, quadrilateral[2]);
      dp = getDistance(point, quadrilateral[3]);
      let p_abp = (ab + ap + bp) / 2;
      let p_bcp = (bc + bp + cp) / 2;
      let p_cdp = (cd + cp + dp) / 2;
      let p_dap = (da + dp + ap) / 2;
      s3 = Math.sqrt(p_abp * (p_abp - ab) * (p_abp - ap) * (p_abp - bp));
      s4 = Math.sqrt(p_bcp * (p_bcp - bc) * (p_bcp - bp) * (p_bcp - cp));
      s5 = Math.sqrt(p_cdp * (p_cdp - cd) * (p_cdp - cp) * (p_cdp - dp));
      s6 = Math.sqrt(p_dap * (p_dap - da) * (p_dap - dp) * (p_dap - ap));
      if (Math.abs((s3 + s4 + s5 + s6) - (s1 + s2)) > 0.0001) {
        return false
      }
      return true;
    };
    
    /**
     * 判断点是否在平面内部
     * @param point
     * @param polygon
     * @returns {boolean}
     * @constructor
     */
    let JudgePointInPolygon = (point, polygon) => {
      /**
       * 两个向量的叉积和
       * @param n
       * @param m
       * @returns {number}
       * @constructor
       */
      let VectorMultiplication = (n, m) => {
        return (n.y * m.z - m.y * n.z) + (n.z * m.x - n.x * m.z) + (n.x * m.y - n.y * m.x);
      };
    
      let p1 = polygon[0];
      let p2 = polygon[1];
      let p3 = polygon[2];
      let p4 = polygon[3];
      let n1, n2, n3, n4, n5, n6, n7, n8;
      n1 = {"x": p2.x - p1.x, "y": p2.y - p1.y, "z": p2.z - p1.z};
      n2 = {"x": point.x - p1.x, "y": point.y - p1.y, "z": point.z - p1.z};
      n3 = {"x": p4.x - p3.x, "y": p4.y - p3.y, "z": p4.z - p3.z};
      n4 = {"x": point.x - p3.x, "y": point.y - p3.y, "z": point.z - p3.z};
      n5 = {"x": p3.x - p2.x, "y": p3.y - p2.y, "z": p3.z - p2.z};
      n6 = {"x": point.x - p2.x, "y": point.y - p2.y, "z": point.z - p2.z};
      n7 = {"x": p4.x - p1.x, "y": p4.y - p1.y, "z": p4.z - p1.z};
      n8 = {"x": point.x - p4.x, "y": point.y - p4.y, "z": point.z - p4.z};
      return !(VectorMultiplication(n1, n2) * VectorMultiplication(n3, n4) >= 0 && VectorMultiplication(n5, n6) * VectorMultiplication(n7, n8) >= 0);
    };
    
    /**
     * 盘算点是否在线段上
     * @param point
     * @param polyline
     * @returns {boolean}
     * @constructor
     */
    let JudgePointInPolyline = (point, polyline) => {
      let lineLength = Math.sqrt(Math.pow((polyline[0].x - polyline[1].x), 2) + Math.pow((polyline[0].y - polyline[1].y), 2) + Math.pow((polyline[0].z - polyline[1].z), 2));
      let one = Math.sqrt(Math.pow((point.x - polyline[1].x), 2) + Math.pow((point.y - polyline[1].y), 2) + Math.pow((point.z - polyline[1].z), 2));
      let two = Math.sqrt(Math.pow((point.x - polyline[0].x), 2) + Math.pow((point.y - polyline[0].y), 2) + Math.pow((point.z - polyline[0].z), 2));
      let di = one + two - lineLength;
      if (di * 10000 < 1) {
        return true;
      }
      return false;
    
    };
    
    /**
     * 根据3个点,计算空间平面的方程
     * Ax+By+Cz+D=0
     * 输入参数:point3fArray---空间中3个点的坐标,大小为3;输入点>3时,只取前3个点
     * 输出参数A,B,C,D
     * 返回值:true---计算成功;false----计算失败
     * @param point3fArray
     * @returns {{A: number, B: number, C: number, D: number}}
     * @constructor
     */
    let GetPanelEquation = (point3fArray) => {
      if (point3fArray.length < 3) {
        return undefined;
      }
      let A, B, C, D;
      A = point3fArray[0].y * (point3fArray[1].z - point3fArray[2].z) +
        point3fArray[1].y * (point3fArray[2].z - point3fArray[0].z) +
        point3fArray[2].y * (point3fArray[0].z - point3fArray[1].z);
      B = point3fArray[0].z * (point3fArray[1].x - point3fArray[2].x) +
        point3fArray[1].z * (point3fArray[2].x - point3fArray[0].x) +
        point3fArray[2].z * (point3fArray[0].x - point3fArray[1].x);
      C = point3fArray[0].x * (point3fArray[1].y - point3fArray[2].y) +
        point3fArray[1].x * (point3fArray[2].y - point3fArray[0].y) +
        point3fArray[2].x * (point3fArray[0].y - point3fArray[1].y);
      D = -point3fArray[0].x * (point3fArray[1].y * point3fArray[2].z - point3fArray[2].y * point3fArray[1].z) -
        point3fArray[1].x * (point3fArray[2].y * point3fArray[0].z - point3fArray[0].y * point3fArray[2].z) -
        point3fArray[2].x * (point3fArray[0].y * point3fArray[1].z - point3fArray[1].y * point3fArray[0].z);
      return {A: A, B: B, C: C, D: D};
    };
    
    
    
    export default {
      getCameraInfo,
      meter2Lat,
      meter2Lng,
      isDegreesOrCartesian,
      toDegrees,
      toCartesian,
      toWindowCoordinates,
      point2LineDistance,
      countArea,
      countAreaByThreePoints,
      getDistance,
      getNormal,
      countIntersectionOfLineAndPlane,
      getPointInPolygon,
      isPointInQuadrilateral,
      JudgePointInPolygon,
      JudgePointInPolyline,
      GetPanelEquation,
    }
    
    

    相关文章

      网友评论

        本文标题:Cesium中空间计算 、坐标转换、相机姿态

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