I. 線性參考
· Oracle Spatial
1. 建立線性參考的空間對象
圖
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))
2. 根據線性參考錨點
對於線性參考的空間對象,就可以根據線性參考來定位對象上的點,比如上述例子中圖 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的點
· ArcSDE
1. 建立線性參考的空間對象
對於 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)
2. 根據線性參考錨點
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)。