cesium坐标转换

603 阅读5分钟

1、坐标系统

cesium常用坐标系包括地理坐标、世界坐标和屏幕坐标三种。

1)地理坐标:

默认使用WGS84作为空间参考,分为经纬度和弧度两种表达方式。通常用来进行位置表达。Cesium中默认使用Cartographic表示弧度制的WGS84地理坐标系,new Cesium.Cartographic(longitude, latitude, height),这里的参数也叫longitude、latitude,就是经度和纬度。

2)世界坐标(X,Y,Z):

又称笛卡尔空间坐标,原点为椭球中心。Cesium中用Cartesian3变量表示,可通过new Cesium.Cartesian3(x, y, z)创建,主要是用来做空间位置的变化如平移、旋转和缩放等。

image.png

3)屏幕坐标:

即二维笛卡尔平面坐标,我们通过鼠标点击直接获取的坐标就是屏幕坐标了,单位是像素值,也可以通过new Cesium.Cartesian2(x, y)创建,主要用来做用户交互。

image.png

2、坐标拾取

在 Cesium 的场景组织中,构成三维世界的有如下三个容器:

Ellipsoid:一个数学公式所定义的旋转椭球体,代表一个纯粹的地球椭球形状;

Globe:包括了 Ellipsoid,还包括了所有的影像图层、地形瓦片,可以算是椭球体上面的皮肤;

Scene:包括了 Globe,除了 Globe 的元素外,还加上了 Primitive、Entity、DataSource 等三维物体。

鼠标点击获取对象,就是在scene的canvas对象上进行操作。cesium常见的坐标拾取方法如下:

1)viewer.scene.pick(获取Cartesian2):

通过坐标位置,拾取 Entity 实体、 Primitive(图元)、3D-Tiles(Cesium3DTileFeature)瓦片数据、数据源datasource对象。

let pickObject = viewer.scene.pick(windowPosition, width , height );

scene.pick 只能获取一个对象,并且获取的是最顶部的对象。如果拾取点没有对象,则为undefined。

2)viewer.scene.drillPick(穿透拾取,获取所有对象):

穿透拾取,是从当前拾取位置获取所有对象的对象列表(entity的集合),列表按其在场景中的视觉顺序(从前到后)排序(通过for循环可以获取当前坐标下的所有entity)。

let pickObject = viewer.scene.drillPick (windowPosition, limit , width , height )

drillPick 和 Pick 不同,Pick 只能拾取一个对象,而 drillPick 可以拾取多个对象,并且 drillPick 可以设置 limit 参数,limit 参数可以控制获取几个对象,超出的就不获取了。

3)viewer.scene.pickPosition(获取Cartesian3):

拾取对应位置的世界坐标,适用于模型表面位置的选取,拾取三维物体的坐标等。

let cartesian3 = viewer.scene.pickPosition (windowPosition)

一定要开启深度检测(viewer.scene.globe.depthTestAgainstTerrain = true;),否则在没有3dTile模型的情况下,会出现空间坐标不准的问题,如果不开启深度检测,只能在3dTile模型上获取准确的空间坐标。

4、viewer.scene.globe.pick(获取加载地形后的经纬度(弧度)和高程):

适用于拾取有地形高程的点,但不包括模型、倾斜摄影等表面高度。需要开启深度测试viewer.scene.globe.depthTestAgainstTerrain = true。

const ray = viewer.camera.getPickRay(windowCoordinates); 
const intersection = viewer.scene.globe.pick(ray, viewer.scene);

与scene.pickPosition区别:

globe.pick只能求交地形,结果相对稳定准确,不论地形深度检测开启与否,不论加载的是默认地形还是别的地形数据;

scene.pickPosition不仅可以求交地形,还可以求交除地形以外其他所有写深度的物体。只有在开启地形深度检测,且不使用默认地形时是准确的。

5、 viewer.scene.camera.pickEllipsoid:

返回的是椭圆球体表面的一个Cartesian3坐标。适用于裸球表面的选取,是基于数学模型的椭圆球体。

let cartesian3 = viewer.scene.camera.pickEllipsoid(movement.position, ellipsoid);

pickEllipsoid在加载地形的情况下有误差,地形凹凸程度越大,误差越大,所以不要用来获取有地形的坐标。使用此方法,需关掉深度测试。

3、坐标转换

1、弧度和经纬度转换

Cesuim中没有具体的经纬度对象,要得到经纬度首先需要计算为弧度,再进行转换。

//经纬度转弧度 
let radians = Cesium.Math.toRadians(degrees); 
//弧度转经纬度 
let degrees=Cesium.Math.toDegrees(radians);

2、笛卡尔空间坐标与经纬度转换

//数据格式化方法 
const formatNum = (num, digits) =>{ 
    return Number(num.toFixed(digits || 0)); 
} 
//1、笛卡尔空间坐标转经纬度 
const cartesian2lonlat = (cartesian) =>{ 
    let carto = Cesium.Cartographic.fromCartesian(cartesian); //弧度 
    if (carto == null) return null; 
    let x = formatNum(Cesium.Math.toDegrees(carto.longitude), 6); 
    let y = formatNum(Cesium.Math.toDegrees(carto.latitude), 6); 
    let z = formatNum(carto.height, 2); 
    return [x, y, z];
} 
//2、经纬度转笛卡尔空间坐标 
const lonlat2cartesian = (coord, defHeight) =>{ 
    if (!coord || coord.length < 2) return null;
    return Cesium.Cartesian3.fromDegrees(coord[0], coord[1], coord[2] || defHeight || 0); 
}

3、屏幕坐标与笛卡尔空间坐标转换

//1、屏幕坐标转笛卡尔空间坐标--屏幕坐标一定要在球上,否则生成出的cartesian对象是undefined 
let cartesian3 = scene.globe.pick(viewer.camera.getPickRay(windowPostion),scene ); 
//2、笛卡尔空间坐标转屏幕坐标--结果是Cartesian2对象,取出X,Y即为屏幕坐标。 
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, Cartesian3);

4、笛卡尔空间坐标与墨卡托投影坐标转换

//1、笛卡尔空间坐标转墨卡托投影坐标 
const cartesian2mercator = (position) => { 
    if (!position) return null; 
    let lonlat = cartesian2lonlat(position); //笛卡尔空间坐标转经纬度坐标 
    return lonlat2mercator(lonlat); //经纬度坐标转墨卡托 
} 
//2、墨卡托投影坐标转笛卡尔空间坐标 
const mercator2cartesian = (point) => { 
    if (isNaN(point[0]) || isNaN(point[1])) return null; 
    let lonlat = mercator2lonlat(point); //墨卡托转经纬度 
    return lonlat2cartesian(lonlat); //经纬度装笛卡尔空间坐标 
}

5、墨卡托投影坐标与经纬度转换

//1、web墨卡托转经纬度 
const mercator2lonlat = (point) => { 
    let lng = Number(point[0]); 
    let lat = Number(point[1]);
    let x = lng / 20037508.34 * 180; 
    let y = lat / 20037508.34 * 180; 
    y = 180 / PI * (2 * Math.atan(Math.exp(y * PI / 180)) - PI / 2); 
    x = Number(x.toFixed(6)); 
    y = Number(y.toFixed(6));
    return [x, y, point[2] || 0]; 
}; 
//2、经纬度转Web墨卡托 
const lonlat2mercator = (point) =>{
    let lng = Number(point[0]); 
    let lat = Number(point[1]); 
    let x = lng * 20037508.34 / 180; 
    let y = Math.log(Math.tan((90 + lat) * PI / 360)) / (PI / 180); 
    y = y * 20037508.34 / 180; //+ 7.081154553416204e-10; 
    x = Number(x.toFixed(2)); 
    y = Number(y.toFixed(2)); 
    return [x, y, arrdata[2] || 0]; 
};

4、空间位置变换(平移、旋转、缩放)

只有转换到笛卡尔空间坐标系后才能进行空间位置变换如平移旋转缩放。Cesium提供的几种常用变换工具类如下:

  • Cesium.Cartesian3(相当于Point3D)
  • Cesium.Matrix3(3x3矩阵,用于描述旋转变换)
  • Cesium.Matrix4(4x4矩阵,用于描述旋转加平移变换)
  • Cesium.Quaternion(四元数,用于描述围绕某个向量旋转一定角度的变换)
  • Cesium.Transforms (包含将位置转换为各种参考系的功能)

项目地址:github.com/DLFouge/vue…

欢迎指正与star