MapGuide空间参考系 API提供了一些非常易于使用的类,主要功能由以下四个类提供。
l MgCoordinateSystemFactory:这是一个工厂类,主要用于创建MgCoordinateSystem和MgCoordinateSystemTransform的实例。
l MgCoordinateSystem:代表一个空间参考系,主要用于获取空间参考系的定义信息,诸如获取空间参考系的类型、分类(Category)、基准面、椭球体、测量单位等。
l MgCoordinateSystemTransform:用于坐标转换和坐标变换。
l MgCoordinateSystemMeasure:用于测量两个坐标值间的距离,或给定一个初始坐标值、方位角和距离,计算得到新的坐标值。
需要注意的是,在开源版MapGuide 2.0和企业版MapGuide 2009中空间参考系 API有过较大变动,例如不再为类MgCoordinateSystemMeasure提供构造方法,而是使用类MgCoordinateSystemFactory创建MgCoordinateSystemMeasure的实例。本章中,所有的介绍和代码示例都是基于最新的空间参考系 API。
1.1.1 CS-MAP和PROJ4
PROJ4是一个著名的开源空间参考系工具,许多GIS开源软件都使用了PROJ4,例如GDAL、MapServer和PostGIS等。PROJ4现已加入OSGeo,它的主页为http://trac.osgeo.org/proj,它支持Windows和Linux,遵循MIT license。
CS-MAP是由Norm所创建的Mentor Software Inc.公司开发的一个空间参考系工具。2007年9月Autodesk通过收购了Mentor Software Inc.获得了CS-MAP的源代码,Norm由此成为了我的同事。2008年8月,Autodesk将CS-MAP捐赠给了开源社区,现在它的主页为http://trac.osgeo.org/csmap。相对于PROJ4,CS-MAP支持更多的空间参考系,现在它支持4000多个空间参考系,大约700种基准面,100种椭球体。而且,CS-MAP解决了一些PROJ4没有解决的问题,例如垂直基准面移位(Shifting)等。
在MapGuide开放源代码之前,一直使用的是CS-MAP。在MapGuide准备开放源代码时,Autodesk还没有收购CS-MAP,所以由于版权的问题,MapGuide不得不转而使用PROJ4。在MapGuide开源版2.1之后,Autodesk收购了CS-MAP,所以又开始使用CS-MAP。对于MapGuide企业版来说,一直使用的是CS-MAP。类MgCoordinateSystemFactory提供了一个方法GetBaseLibrary()用于获取当前所使用的空间参考系工具,当前此方法的返回值是“Mentor Coordinate System Library”。
CS-MAP为每一个支持的空间参考系提供了一个简称,我们称之为Mentor代码。加上EPSG代码,MapGuide共支持两种空间参考系代码,它们由类MgCoordinateSystemCodeFormat所定义。
l MgCoordinateSystemCodeFormat::EPSG
l MgCoordinateSystemCodeFormat::Mentor
1.1.2 MapGuide支持的空间参考系类型
类MgCoordinateSystemType定义了MapGuide支持的三种空间参考系类型。
l MgCoordinateSystemType::Arbitary:代表一个和地球无关的空间参考系统,WKT使用LOCAL_CS子句来定义此类型的空间参考系。
l MgCoordinateSystemType::Geographic:代表一个地理参考系统,WKT使用LOCAL_CS子句来定义此类型的空间参考系。
l MgCoordinateSystemType::Projected:代表一个地理参考系统,WKT使用PROJCS子句来定义此类型的空间参考系。
类MgCoordinateSystem提供了如下的方法用于获取空间参考系的类型,返回值是上述三种空间参考系类型之一。
int GetType();
1.1.3 创建空间参考系
MapGuide使用一个类MgCoordinateSystem的代表一个空间参考系,然而MapGuide并没有为类MgCoordianteSystem提供任何构造方法,这是因为MapGuide使用了类工厂(Class Factory)模式来创建MgCoordianteSystem的实例。工厂类MgCoordinateSystemFactory提供了如下的方法创建一个空间参考系。
MgCoordinateSystem Create(string srsWkt);
MgCoordinateSystem CreateFromCode(string code);
第一个方法使用一个WKT格式的字符串来创建一个空间参考系,第二个方法使用一个Mentor代码来创建一个空间参考系。目前,MapGuide空间参考系 API并不支持由EPSG代码创建一个空间参考系,但是可以通过将EPSG代码转换为Mentor代码或WKT来创建一个空间参考系。
下面的代码示意了如何使用WKT格式的字符串来创建一个投影空间参考系和一个地理空间参考系。
$wktProj = 'PROJCS["UTM Zone 18 (NAD 83)",
GEOGCS ["NAD 83 (Continental US)",
DATUM ["NAD 83 (Continental US)",
SPHEROID ["GRS 80", 6378137, 298.257222101]],
PRIMEM ["Greenwich", 0.000000],
UNIT ["Decimal Degree", 0.01745329251994330]],
PROJECTION ["Transverse Mercator"],
PARAMETER ["Scale_Factor", 0.999600],
PARAMETER ["Central_Meridian", -75.000000],
PARAMETER ["False_Easting", 500000.000000],
UNIT ["Meter", 1.000000000000]]';
$wktGeog = 'GEOGCS ["Longitude / Latitude (NAD 83)",
DATUM ["NAD 83",
SPHEROID ["GRS 80", 6378137, 298.257222101]],
PRIMEM ["Greenwich", 0.000000],
UNIT ["Decimal Degree", 0.01745329251994330]]';
$coordSysFactory = new MgCoordinateSystemFactory();
$coordSysProj = $coordSysFactory->Create($wktProj);
$coordSysGeog = $coordSysFactory->Create($wktGeog);
1.1.4 空间参考系表示方式之间的转换
MapGuide可以使用Mentor代码、EPSG代码和WKT代表一个空间参考系,类MgCoordinateSystemFactory提供了如下四个方法来实现这些三种表示方式之间的转换,前两个方法用于Mentor代码和WKT之间的相互转换,后两个方法用于EPSG代码和WKT之间的相互转换。
string ConvertWktToCoordinateSystemCode(string wkt);
string ConvertCoordinateSystemCodeToWkt(string code);
string ConvertEpsgCodeToWkt(int code);
int ConvertWktToEpsgCode(string wkt);
1.1.5 获取空间参考系的定义信息
类MgCoordinateSystem定义一个空间参考系,通过它可以得到一个空间参考系的定义信息,下表列出了类MgCoordinateSystem的部分方法及它们的功能。
方法名 | 描述 |
GetCode | 获取空间参考系的Mentor代码。 |
GetDatum | 获取空间参考系基准面的名称。 |
GetDatumDescription | 获取空间参考系基准面的描述信息。 |
GetDatumDefinition | 获取空间参考系的基准面定义。 |
GetDescription | 获取空间参考系的描述信息。 |
GetEllipsoid | 获取空间参考系椭球体的名称。 |
GetEllipsoidDefinition | 获取空间参考系的椭球体定义。 |
GetEllipsoidDescription | 获取空间参考系椭球体的描述信息。 |
GetMaxX | 获取空间参考系最大的X坐标值。 |
GetMaxY | 获取空间参考系最大的Y坐标值。 |
GetMinX | 获取空间参考系最小的X坐标值。 |
GetMinX | 获取空间参考系最小的Y坐标值。 |
GetProjection | 获取空间参考系投影的名称。 |
GetProjectionCode | 获取空间参考系投影的代码。 |
GetProjectionDescription | 获取空间参考系投影的描述信息。 |
GetProjectionParameter | 获取空间参考系投影的第n个参数。 |
GetProjectionParameterCount | 获取空间参考系投影的参数数目。 |
GetType | 获取空间参考系的类型。 |
GetUnits | 获取空间参考系的测量单位。 |
GetUnitScale | 获取空间参考系的测量单位与米之间的转换系数。 |
类MgCoordinateSystemDatum定义了一个基准面,调用类MgCoordinateSystem的方法GetDatumDefinition(…)可以得到一个MgCoordinateSystemDatum的实例,用于表示此空间参考系的基准面。类MgCoordinateSystemEllipsoid定义了一个椭球体,调用类MgCoordinateSystem的方法GetEllipsoidDefinition可以得到一个GetEllipsoidDefinition(…)的实例,用于表示此空间参考系的椭球体。
1.1.6 坐标转换
MapGuide使用类MgCoordinateSystemTransform进行坐标转换,然而MapGuide并没有为类MgCoordianteSystem提供任何构造方法。与类MgCoordinateSystem类似,我们需要使用类MgCoordinateSystemFactory的如下的方法创建MgCoordinateSystemTransform的实例,其中参数source用于指定源空间参考系,target用于指定目标空间参考系。
MgCoordinateSystemTransform GetTransform(MgCoordinateSystem source,
MgCoordinateSystem target);
MgCoordinateSystemTransform提供了如下五个方法对一个坐标值进行坐标转换,坐标值可以是XY、XYZ、XYM和XYZM。
MgCoordinate Transform(MgCoordinate coordinate);
MgCoordinate Transform(double x, double y, double z);
MgCoordinate Transform(double x, double y);
MgCoordinate TransformM(double x, double y, double z, double m);
MgCoordinate TransformM(double x, double y, double m);
但是,并不是任意两个空间参考系统之间可以成功地进行坐标转换的,所以在调用Transform(…)方法之后,需要调用方法GetLastTransformStatus()检测此操作是否成功执行。在调用Transform(…)方法之前,还可以调用如下方法以设置在坐标转换的时候是否忽略某些警告。
void IgnoreDatumShiftWarning(boolean ignoreDatumShiftWarning);
void IgnoreOutsideDomainWarning(boolean ignoreOutsideDomainWarning);
如下的代码示意了如何进行坐标转换。其中,$coordSys1是空间参考系“Longitude / Latitude (NAD 83)”, $coordSys2是空间参考系“UTM Zone 18 (NAD 83)”, $csTransform12用于将坐标从$coordSys1转换到$coordSys2,$csTransform21用于将坐标从$coordSys2转换到$coordSys1。
$csTransform12 = new MgCoordinateSystemTransform($coordSys1, $coordSys2);
$csTransform21 = new MgCoordinateSystemTransform($coordSys2, $coordSys1);
$coordinateArg = $geometryFactory->CreateCoordinateXY($xArg, $yArg);
$coordinate12 = $csTransform12->Transform($coordinateArg);
$x12 = $coordinate12->GetX();
$y12 = $coordinate12->GetY();
$coordinate21 = $csTransform21->Transform($coordinate12);
$x21 = $coordinate21->GetX();
$y21 = $coordinate21->GetY();
echo "$xArg: $xArg; $x21: $x21n";
echo "$yArg: $yArg; $y21: $y21n";
echo "$x12: $x12; $y12 : $y12n";
假设$xArg的值为-71.061342,$yArg的值为42.355892,执行上面的代码,输出如下所示:
xArg: -71.061342; x21: -71.061341999861
yArg: 42.355892; y21: 42.355891999573
x12: 824390.29381426; y12 : 4696809.9055963
如果坐标转换中源或目标空间参考系是WGS84,那么MgCoordinateSystem为我们提供了更为简单的方法,如下的两个方法分别可以将一个WGS84的经纬度坐标转换到MgCoordinateSystem代表的空间参考系坐标,将一个MgCoordinateSystem代表的空间参考系坐标转换到WGS84经纬度坐标。
MgCoordinate ConvertFromLonLat(MgCoordinate lonLat);
MgCoordinate ConvertToLonLat(MgCoordinate coordinate);
假设($xGeog, $yGeog)的值为(-71.061342, 42.355892),执行如下的代码可以将此经纬度坐标转换到指定的投影空间参考系,得到($xConv, $yConv)的值(824399.31463498, 4696596.0339483)。
$wktProj = 'PROJCS["UTM Zone 18 (NAD 83)",
GEOGCS ["NAD 83 (Continental US)",
DATUM ["NAD 83 (Continental US)",
SPHEROID ["GRS 80", 6378137, 298.257222101]],
PRIMEM [ "Greenwich", 0.000000 ],
UNIT ["Decimal Degree", 0.01745329251994330]],
PROJECTION ["Transverse Mercator"],
PARAMETER ["Scale_Factor", 0.999600],
PARAMETER ["Central_Meridian", -75.000000],
PARAMETER ["False_Easting", 500000.000000],
UNIT ["Meter", 1.000000000000]]';
$coordSysProj = $coordSysFactory->Create($wktProj);
$xGeog = -71.061342;
$yGeog = 42.355892;
$coordinate = $geometryFactory->CreateCoordinateXY($xGeog, $yGeog);
$convertedCoordinate = $coordSys->ConvertFromLonLat($coordinate);
$xConv = $convertedCoordinate->GetX();
$yConv = $convertedCoordinate->GetY();
echo "($xGeog, $yGeog) to ($xConv, $yConv)n";
1.1.7 测量距离
因为地球是一个椭球体,所以计算地理参考系或投影参考系中任意两个坐标值之间的距离需要使用大圆计算(Great Circle Calculation)。例如:MgGeometry::Buffer(…)和MgGeometry::Distance(…)都需要一个测量参数来定义所使用的大圆。如果这个参数为NULL,那么使用线性算法进行计算。
那么,如何创建一个测量参数呢?MapGuide使用类MgCoordinateSystemMeasure的实例来代表一个测量参数。它继承自MgMeasure,提供了测量两个坐标值间距离、方位角(Azimuth)的功能。给定一个初始坐标值、方位角和距离,MgCoordinateSystemMeasure还可以计算得到一个新的坐标值。但是,MapGuide并没有为类MgCoordinateSystemMeasure提供构造方法,必须调用类MgCoordinateSystem的方法GetMeasure()获取一个MgCoordinateSystemMeasure的实例。
MgCoordinateSystemMeasure GetMeasure();
如下的代码示意了如何获取一个类MgCoordinateSystemMeasure的实例。
$coordSysFactory = new MgCoordinateSystemFactory();
$coordSys = $coordSysFactory->Create(GEOGCS ["Longitude / Latitude (NAD 83)",
DATUM ["NAD 83",
SPHEROID ["GRS 80", 6378137, 298.257222101]],
PRIMEM ["Greenwich", 0.000000 ],
UNIT ["Decimal Degree", 0.01745329251994330]]");
$coordSysMeasure = $coordSys->GetMeasure();
从上面的代码,我们可以看到类MgCoordinateSystemMeasure的实例总是关联到一个坐标系。当计算距离的时候,坐标值使用的是此坐标系,大圆使用的此坐标系的椭球体。
调用方法GetDistance(…)可以获得两个坐标之间的距离,距离的单位总是使用米。
double GetDistance(MgCoordinate coord1, MgCoordinate coord2);
double GetDistance(double x1, double y1, double x2, double y2);
下面的代码中,第一个坐标$coord1是纽约市,第二个坐标$coord2是波士顿,计算得到的距离是361777.95418396。
$geometryFactory = new MgGeometryFactory();
$coord1 = $geometryFactory->CreateCoordinateXY(-74.806394, 40.714169);
$coord2 = $geometryFactory->CreateCoordinateXY(-71.061342, 42.355892);
$distance = $coordSysMeasure->GetDistance($coord1, $coord2);
也可以使用如下的代码,它们的计算结果是全相同的。
$distance = $coordSysMeasure->GetDistance(-74.806394, 40.714169,
-71.061342, 42.355892);
实际上,如果仅仅是想得到两个坐标之间的距离,还有一种更为简单的方法,类MgCoordinateSystem已经提供了如下的四个方法计算两个坐标之间的距离,无需通过类MgCoordinateSystemMeasure。
double MeasureGreatCircleDistance(double x1, double y1, double x2, double y2);
double MeasureGreatCircleDistance(MgCoordinate coord1, MgCoordinate coord2);
double MeasureEuclideanDistance(double x1, double y1, double x2, double y2);
double MeasureEuclideanDistance(MgCoordinate coord1, MgCoordinate coord2);
这四个方法都是返回单位为米的距离,前两个方法计算的是大圆距离,考虑到了地球是一个椭球体;后两个方法计算的是欧几里德距离,没有考虑到地球是一个椭球体。
1.1.8 计算方位角
类MgCoordinateSystem和MgCoordinateSystemMeasure都提供了如下两个方法用于计算两个坐标所组成的向量相对于方向北的夹角,即方位角, 这两个方法在这两个类中的函数签名完全一样,功能也完全一样。
double GetAzimuth(double x1, double y1, double x2, double y2);
double GetAzimuth(MgCoordinate coord1, MgCoordinate coord2);
假设$coordSys为类MgCoordinateSystem或MgCoordinateSystemMeasure的一个实例,如下的代码示意了如何计算方位角。
$x1Geog = -71.061342;
$y1Geog = 42.355892;
$x2Geog = -74.806394;
$y2Geog = 40.714169;
$azimuth = $coordSys->GetAzimuth($x2Geog, $y2Geog, $x1Geog, $y1Geog);
1.1.9 定位新坐标
给定一个初始坐标、方位角和距离,类MgCoordinateSystem和MgCoordinateSystemMeasure都提供了如下两个方法,计算得到沿着一个向量移动指定的距离后的坐标值。这两个方法在这两个类中的函数签名完全一样,功能也完全一样,距离都使用单位米。
MgCoordinate GetCoordinate(double xStart, double yStart, double azimuth, double distance);
MgCoordinate GetCoordinate(MgCoordinate *coord, double azimuth, double distance);
利用此功能我们可以验证计算得到的两个坐标之间的距离是否正确,具体步骤如下:
1) 计算得到两个坐标coordinate1和coordinate2的距离distance。
2) 计算从coordinate1到coordinate2的方位角azimuth12。
3) 计算从coordinate2到coordinate1的方位角azimuth21。
4) 给定coordinate1、azimuth12和distance,计算得到坐标coordinate12,coordinate12应该和coordinate2具有相同的坐标值。
5) 给定coordinate2、azimuth21和distance,计算得到坐标coordinate21,coordinate21应该和coordinate1具有相同的坐标值。
在下面的代码中,($x1,$y1)是纽约市的经纬度坐标,$azimuth是纽约市相对方向北的顺时针夹角,沿着$azimuth的方向移动361777.95418396米,得到了波士顿的经纬度坐标 (-71.061342, 42.355892)。
$x1 = -74.806394;
$y1 = 40.714169;
$coord1Geog = $geometryFactory->CreateCoordinateXY($x1Geog, $y1Geog);
$azimuth = 58.507421025167;
$distance = 361777.95418396;
$coord = $coordSysGeog->GetCoordinate($x1, $y1, $azimuth, $distance);
$x2 = $coord->GetX();
$y2 = $coord->GetY();
1.1.10单位转换
我们经常需要在空间参考系的测量单位和其它单位之间进行转换,例如上一节中计算得到的距离都使用单位米,我们可能需要将其转换为相应空间参考系的测量单位,类MgCoordinateSystem为此提供了许多方法。
如下这两个方法分别可以将一个指定的值从空间参考系的单位转换为单位米,将一个单位为米的值转换为空间参考系的单位。
double ConvertCoordinateSystemUnitsToMeters(double units);
double ConvertMetersToCoordinateSystemUnits(double meters);
如果仅仅是想得到空间参考系的单位转换为单位米的系数,可以使用如下方法。
double GetUnitScale();