iModel 地理坐标系统

坐标是用来确定具体的位置,如屏幕坐标、象限坐标等。地理坐标顾名思义是用来表达真实世界中的具体位置信息,例如 x, y, z 值能确定真实世界中的唯一位置。

文本从地理坐标划分内容开始,介绍地理位置在 iTwin 中的应用,描述不同坐标类型在 iTwin 中的表达,最后给出常用的坐标转换关键代码,供大家参考学习。

坐标系统类型

通常将地理坐标系统分为以下两大类

1. 全局坐标系或球坐标系

也称为 地理坐标系统(Geographic Coordinate System,GCS),生活中常用的 经纬度 坐标即属于此类坐标,即指在球体上的具体坐标值。

经度和纬度是从地心到球体表面上某点的测量角,测量角度的单位通常以度或百分度。下图将地球显示为具有经度和纬度值的地球。

地理坐标

由于地球是一个不规则的球体,且各地的引力值(G)也不同,人们为了方便测量、提高测量的精确值往往采用不同的椭球体完成地球的拟合。即采用不同的椭球体形状,改变椭球体参数实现地球拟合以满足自身需求。

地球球体

常用的地理坐标主要有:

  • WGS84 -- EPSG:4326

    世界大地测量系统(World Geodetic System, WGS)是一种用于地图学、大地测量学和導航(包括全球定位系统)的大地测量系统标准。WGS 的最新版本为 WGS 84(也称作 WGS 1984、EPSG:4326),1984 年定义、最后修订于 2004 年。

    该坐标系统随着全球定位系统(GPS)的发展而广泛运用在各行业的定位与导航系统中。因此,人们也通常将此坐标系统作为坐标转换的中介参考。

    WGS84

  • CGCS2000 -- EPSG:4490

    2000 国家大地坐标系,是我国当前最新的国家大地坐标系(China Geodetic Coordinate System 2000, CGCS2000)。

    按照国务院要求,到 2016 年我国将完成现行国家大地坐标系向 CGCS2000 的过渡,2018 年将停止使用 1954 北京坐标系和 1980 西安坐标系。

    CGCS2000

2. 投影坐标系

投影指将三维球体投射到二维笛卡尔坐标的过程,而投影坐标是指在二维笛卡尔坐标系统的坐标值。在投影坐标系中,通过格网上的 x,y 坐标来标识位置,其原点位于格网中心。每个位置均具有两个值,这两个值是相对于该中心位置的坐标。一个指定其水平位置,另一个指定其垂直位置。这两个值称为 x 坐标和 y 坐标。采用此标记法,原点坐标是 x = 0 和 y = 0。

在将球体投影到二维平面时,由于弯曲的地球表面与平面不是等距的,因此,保留形状不可避免地会导致比例尺的变化,从而导致区域的非比例表现。

Project

我国 CGCS2000 采用的投影类型选择的是 高斯-克吕格 投影。为减少投影变形,高斯-克吕格投影分为 3° 带和 6° 带投影。

Mercator

MicroStation 软件中默认采用 EPSG:3152 坐标系统,坐标适用 瑞典区域 范围,非此区域的模型选择该坐标可能出现模型打开错误、模型丢失等异常情况。

EPSG3152

常见三维笛卡尔坐标系

地心地固坐标系 (Earth-Centered, Earth-Fixed,ECEF) -- 简称地心坐标系

ECEF 坐标系是以地心为原点的 3D 右手笛卡尔坐标系,原点 O (0,0,0)为地球几何中心(地球质心),z 轴与地轴平行指向北极点,x 轴指向本初子午线与赤道的交点,y 轴垂直于 xOz 平面(即东经 90 度与赤道的交点)构成右手坐标系。有关以地心坐标系表示的目标位置 T 的示例,请参见下图。

ecef

当地东北天坐标系(Local east, north, up, ENU)

是定义在地表正切平面的局部坐标系。如下图所示,它以站心点的纬线方向(指东)为 X 轴,以站心点的经线方向(指北)为 Y 轴,以站心点的法线(指上)为 Z 轴。

ecef

ECEF 与 ENU 坐标相互转换

  • ECEF 转 ENU 由于 ENU 坐标系定义在局部坐标系下,所以转换前需要知道 ENU 局部坐标系的原点的 ECEF 坐标(Xr,Yr,Zr),以及原点的经度 ϕ 和纬度 λ。计算式为: ECEF to ENU
  • ENU 转 ECEF 是 ECEF 转 ENU 的逆方法,即二者矩阵互为逆矩阵。 ENU to ECEF

iTwin 地理坐标

iTwin 中的地理坐标是关于将笛卡尔点坐标转换为地球上的制图坐标。转换的方法依据原始数据可以分为三种:

  • 未知
  • 线性
  • 投影

未知

当原始数据(模型)没有包含地理位置信息时,则无法在 iTwin 中进行地理坐标的标识与转换。可通过 iModelConnection.isGeoLocated 方法进行判断。

线性转换

对于厂房、建筑物、变电站甚至校园等结构的 iModel,z 轴通常表示高于底层或某些其他基点的高度。那么,Z=0 是一个无限平面,不考虑地球的曲率(即 Z 方向的直线不一定指向地球的中心)。显然,这样的 iModel 只能包含一小部分区域,因此地球的曲率实际上并不重要——通常只有几公里。从笛卡尔{x,y,z}坐标到制图{lat,long,height}坐标的转换是通过一个单点的线性变换完成的。源应用程序(如 Bentley 的 Open Building Designer、OpenPlant 和 Revit)使用线性地理定位创建 iModel。

投影转换

对于根据地图数据创建的 iModel,z 轴通常表示高于地球表面的某种形式的高度(例如,海平面、地形、椭球体等),因此 iModel 中的 z=0 平面投影地球的椭球体,z 方向的直线始终指向地球的中心(椭圆质心)。笛卡尔{x,y,z}值通过非线性地图投影转换为制图{lat,long,height}坐标,其描述作为地理坐标系存储在 iModel 中。源应用程序,如 Bentley Map、OpenRoads、Civil 3D、GIS 应用程序等,使用投影地理位置创建 iModel。


常用坐标转换代码示例

1. 经纬度度分秒转为十进制

// 以 120°30'36.6" 为例
const degree = 120;
const minutes = 30;
const seconds = 36.6;
const decimalDegree = degree + minutes / 60 + seconds / 3600;
console.log("十进制结果为: ", decimalDegree);

2. iModel 在地面投影的项目范围

/** get a 5 point shape of Cartographic points that encloses the project on the ground plane. */
public async convertExtentsToCartographicShape(iModel: IModelConnection): Promise<Cartographic[]> {
  const shape: Cartographic[] = [];

  // convert extents to an 8 point array
  const pts = Frustum.fromRange(iModel.projectExtents).points;

  // the first 4 points are on the front plane
  for (let i = 0; i < 4; ++i) {
    shape[i] = await iModel.spatialToCartographic(pts[i]);
    shape[i].height = 0; // set at ground level
  }

  shape[4] = shape[0]; // close shape
  return shape;
}

3. iModel 的空间范围

/** get the low and high Cartographic range of this iModel */
public async getProjectMinMaxCartographic(iModel: IModelConnection) {
  let low: Cartographic | undefined;
  let high: Cartographic | undefined;

  const pts = Frustum.fromRange(iModel.projectExtents).points;
  for (const pt of pts) {
    const geoPt = await iModel.spatialToCartographic(pt);
    if (undefined === low || undefined === high) {
      low = geoPt;
      high = geoPt.clone();
      continue;
    }
    low.latitude = Math.min(low.latitude, geoPt.latitude);
    low.longitude = Math.min(low.longitude, geoPt.longitude);
    low.height = Math.min(low.height, geoPt.height);
    high.latitude = Math.max(high.latitude, geoPt.latitude);
    high.longitude = Math.max(high.longitude, geoPt.longitude);
    high.height = Math.max(high.height, geoPt.height);
  }

  return { min: low!, max: high! };
}

4. 获取当前相机的经纬度坐标

const cameraPoint = (vp!.view as ViewState3d).getEyePoint();
const cartLocation = await iModelConnection?.spatialToCartographic(cameraPoint);
// latitude of camera
console.log("latitude: ", cartLocation!.latitudeDegrees);
// longitude of camera
console.log("longitude: ", cartLocation!.longitudeDegrees);

5. 经纬度转世界坐标系

// 与参考椭球无关
// long:106.17960542126575 lat: 29.244371398709067 height: 258.2120626227443
const cart = Cartographic.fromRadians(
  Angle.degreesToRadians(106.17960542126575),
  Angle.degreesToRadians(29.244371398709067),
  258.2120626227443
);
const ecef = cart.toEcef();
// ECEF result: x: -1552043.45826556 y: 5349274.991556412 z: 3097688.8570909603
console.log("ecef 坐标: ", ecef);

6. 世界坐标转经纬度

// x y z 世界坐标
const x = -1552153.962272866;
const y = 5349655.839715691;
const z = 3097910.8913075076;

const origin = new Point3d(x, y, z);

const cart = Cartographic.fromEcef(origin);
// Result: longitude: 106.17960546453158, latitude: 29.24437142620322 height: 712.6989097656179
console.log(
  "经纬度坐标: ",
  cart?.longitudeDegrees,
  cart?.latitude,
  cart?.height
);

7. 经纬度转当前模型空间坐标

// 输入经纬度,以常见的 WGS84 为例
const center = Cartographic.fromRadians(
  Angle.degreesToRadians(106.17960542126573),
  Angle.degreesToRadians(29.244371398681867),
  258.21311713530514
);
// iModel 的坐标为 EPSG:3857, 不同的参考系算出的位置是不一样的
const spatial = await vp.iModel.cartographicToSpatial(center);
// Result: x: 11819859.608126009, y: 3406785.957360854, z: 258.21311713530514
console.log("iModel 空间坐标: ", spatial);

8. 从 iTwin 获取的坐标转换

// 坐标转换的结果依赖于当前 iTwin 采用的参考系
// 例如:鼠标拾取的坐标为 Point3d (x, y, z)
const iTwinPoint = {
  x: 12685971.712373149,
  y: 2576926.867955715,
  z: 12.96646845936883,
};
// ecef 坐标
const ecef = iModelConnection.spatialToEcef(iTwinPoint);
// 经纬度坐标
const cartLocation = await iModelConnection.spatialToCartographic(iTwinPoint);

9. Cesium 坐标到 iTwin 平台

// 由于 Cesium 默认采用 WGS84 坐标,因此在进行坐标转换时需考虑 iModel 的坐标系统是否为采用 WGS84 椭球体
// 可查看 https://cesium.com/learn/cesiumjs/ref-doc/GeographicProjection.html
// 常见的 WGS84 坐标有:EPSG4326, EPSG3857, EPSG900913, WGS84 UTM 等
// 在进行坐标数据互操作时,推荐采用 经纬度 数据作为中间交换数据

/*--------- iTwin 坐标导出 ------------- */
// (1) 从 iTwin 获取坐标,为 iTwin 空间坐标
const spatial = { x: 0.1, y: 0.1, z: 0.1 };
// (2) 通过调用以下方法将空间坐标转换为经纬度
const exchange = await iModelConnection.spatialToCartographic(spatial);

/*--------- Cesium 坐标导出 ------------- */
// (1) 从 Cesium 获取坐标,通常为空间坐标
var cartesian3 = new Cesium.Cartesian3(0.1, 0.1, 0.1);
// (2) 通过调用以下方法将空间坐标转换为经纬度
var cartLocation =
  viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);

results matching ""

    No results matching ""