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

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
}

欢迎各位给出宝贵意见

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容