图 15 一个线性参考空间对象的例子
对于如图 15的例子,Oracle Spatial中需要通过如下的SQL语句进行创建:
SQL> select SDO_GEOMETRY(3302, NULL, NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(5,10,0, 20,5,NULL, 35,10,NULL, 55,10,100)) shape from dual;
SHAPE(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
------------------------------------------------------------------------------------------------------------------------
SDO_GEOMETRY(3302, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 2, 1), SDO_ORDINATE_ARRAY(5, 10, 0, 20, 5, NULL, 35, 10, NULL, 55, 10, 100))
同时,如果要在Oracle Spatial中可以使用这个空间数据,除了在相应的空间表中插入这些记录之外,还需要在元数据表中插入相关记录,插入元数据信息示例如下:
INSERT INTO user_sdo_geom_metadata(TABLE_NAME,COLUMN_NAME,DIMINFO,SRID)
VALUES('SDO_TEST,'SHAPE',
SDO_DIM_ARRAY (
SDO_DIM_ELEMENT('X', 0, 20, 0.005),
SDO_DIM_ELEMENT('Y', 0, 20, 0.005),
SDO_DIM_ELEMENT('M', 0, 100, 0.005)),
NULL);
正常情况下,在USER_SDO_GEOM_METADATA表中可以查到相关的信息(关于USER_SDO_GEOM_METADATA表的作用及定义可以回顾《II.1索引类型SPATIAL_INDEX》):
SQL> select * from user_sdo_geom_metadata where table_name='SDO_ROUTES';
TABLE_NAME COLUMN_NAME
-------------------------------------
DIMINFO(SDO_DIMNAME, SDO_LB, SDO_UB, SDO_TOLERANCE) SRID
------------------------------------------------------------------------------------------------------------------------
SDO_ROUTES SHAPE
SDO_DIM_ARRAY(SDO_DIM_ELEMENT(NULL, 2389694, 2569011.02, .0000005), SDO_DIM_ELEMENT(NULL, 581586.917, 760268.123, .0000005), SDO_DIM_ELEMENT('M', -1000, 267435.456, .0000005))
对于线性参考的空间对象,就可以根据线性参考来定位对象上的点,比如上述例子中图 15的对象,如果我们要获得在线方向上位于中点的点坐标,我们可以这样做:
SQL> select SDO_LRS.LOCATE_PT(SDO_GEOMETRY(3302, NULL, NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(5,10,0, 20,5,NULL, 35,10,NULL, 55,10,100)), 50) from dual;
SDO_LRS.LOCATE_PT(SDO_GEOMETRY(3302,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(5,10,0,20,5,NULL,35,10,NULL,
------------------------------------------------------------------------------------------------------------------------
SDO_GEOMETRY(3301, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1, 1), SDO_ORDINATE_ARRAY(29.486833, 8.16227766, 50))
图 16 线性参考的线中点
其中SDO_LRS包的LOCATE_PT函数原型如下:
SDO_LRS.LOCATE_PT(
geom_segment IN SDO_GEOMETRY,
measure IN NUMBER
[, offset IN NUMBER
) RETURN SDO_GEOMETRY;
注意到这里还可以指定一个offset值,这个值代表查找的定位点可以和线性参考的几何对象有一定的偏移。比如,如果上面的例子中这条线代表一条公路,现在我们想找到离公路中点一边(沿线的右手边)距离为5的某个点,那就可以使用这个offset值,注意,沿线左侧为正、右侧为负:
SQL> select SDO_LRS.LOCATE_PT(SDO_GEOMETRY(3302, NULL, NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(5,10,0, 20,5,NULL, 35,10,NULL, 55,10,100)), 50, -5) from dual;
SDO_LRS.LOCATE_PT(SDO_GEOMETRY(3302,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(5,10,0,20,5,NULL,35,10,NULL,
------------------------------------------------------------------------------------------------------------------------
SDO_GEOMETRY(3301, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1, 1), SDO_ORDINATE_ARRAY(31.0679718, 3.41886117, 50))
图 17 线性参考的线中点右侧距离5的点
对于如图 15的例子,ArcSDE中如果需要通过SQL语句进行创建可以采用以下的方式:
SQL> select sde.st_astext(sde.st_geometry ('linestring m(5 10 0, 20 5 16.67, 35 10 33.33, 55 10 53.33)', 0)) from dual;
SDE.ST_ASTEXT(SDE.ST_GEOMETRY('LINESTRINGM(5100,20516.67,351033.33,551053.33)',0
--------------------------------------------------------------------------------
LINESTRING M ( 5.00000000 10.00000000 0.00000000, 20.00000000 5.00000000 16.67000000, 35.00000000 10.00000000 33.33000000, 55.00000000 10.00000000 53.33000000)
ArcSDE对线性参考几何对象的操作并不在数据库层面实现,而是在各种ArcGIS的产品中的ArcObjects进行操作,下面演示了采用ArcGIS Server的ArcObjects进行同上定位的操作:
ServerConnection conn = new ServerConnection();
conn.connect("localhost", "*", "arcgismanager", "passwd");
IServerObjectManager som = conn.getServerObjectManager();
IServerContext serverContext = som.createServerContext(null , null );
try {
Polyline pl = (Polyline)serverContext.createObject(Polyline.getClsid ());
Point pt = null ;
pt = (Point) serverContext.createObject(Point.getClsid ());
pt.setX(5); pt.setY(10); pt.setM(0);
pl.addPoint(pt, null , null );
pt = (Point) serverContext.createObject(Point.getClsid ());
pt.setX(20); pt.setY(5); pt.setM(16.67);
pl.addPoint(pt, null , null );
pt = (Point) serverContext.createObject(Point.getClsid ());
pt.setX(35); pt.setY(10); pt.setM(33.33);
pl.addPoint(pt, null , null );
pt = (Point) serverContext.createObject(Point.getClsid ());
pt.setX(55); pt.setY(10); pt.setM(53.33);
pl.addPoint(pt, null , null );
pl.setMAware(true );
Multipoint mp = (Multipoint)pl.getPointsAtM(26.67, 0);
IPoint ptM = mp.getPoint(0);
System.out .println(ptM.getX() + "," + ptM.getY());
} catch (Exception ex) {
ex.printStackTrace();
} finally {
serverContext.releaseContext();
}
这样的代码可以得到中点的坐标(29.0036,8.0012),这个结果和Oracle Spatial中基本相符(这里为了简便采用了0-16.67-33.33-53.33这样不同的分段)。下面通过修改getPointsAtM()方法的参数查找线中点一边距离为5的点,btw,这里的offset参数的正负规则和Oracle Spatial中是恰恰相反的:
Multipoint mp = (Multipoint)pl.getPointsAtM(26.67, 5);
这样可以得到结果坐标为(30.5847,3.2578)。