Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
Geometry Snapping using JTS in Oracle
In my exploration of the possibilities of using Java Topology Suite’s (JTS) robust algorithms with Oracle SDO_GEOMETRY I have moved to expose three methods within JTS’s GeometrySnapper (com.vividsolutions.jts.operation.overlay.snap) class:
- snap – Snaps two geometries to each other with both being able to move.
- snapTo – Snaps the vertices of the source geometry to the vertices of the given snap geometry.
- snapToSelf – Snaps the vertices of the source geometry to itself.
The following examples not not exhaust the possibilities in the implementation. I leave it up to you to install try each function on your own data. Note: I do not test geodetic data though the functions to snap geometries through use of sdo_cs.transform are in the package.
All the functions are accessed by the Spatial Companion For Oracle (SC4O) PLSQL package.
1. Snap Two Lines to Each Other
This example might be of use with GPS track logs.
Before Image
WITH q_geoms AS ( SELECT MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0.2,0.4,9.8,10.5,19.7,-0.2,30.2,9.6)) AS geom1, MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0,0,10,10,20,0,30,10)) AS snapGeom FROM dual ) SELECT SC4O.ST_Snap(geom1,snapgeom,1.0,3) AS SnappedLines FROM q_geoms; SNAPPEDLINES ----------------------------------------------------------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2004,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1),MDSYS.SDO_ORDINATE_ARRAY(0,0,10,10,20,0,30,10,0,0,10,10,20,0,30,10))
After Image
2. Snap One Line to Another
In the first image above, the red line will be snapped to the blue line.
-- Snap first line to second WITH q_geoms AS ( SELECT MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0.2,0.4,9.8,10.5,19.7,-0.2,30.2,9.6)) AS line1, MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0,0,10,10,20,0,30,10)) AS snapGeom FROM dual ) SELECT SC4O.ST_SnapTo(line1,snapgeom,1.0,3) AS SnappedLine1 FROM q_geoms; SNAPPEDLINE1 ------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0,0,10,10,20,0,30,10))
After Image
3. Snap a Point To a Polygon
Before Image
-- Point to Area WITH q_geoms AS ( SELECT MDSYS.SDO_GEOMETRY(2001,NULL,MDSYS.SDO_POINT_TYPE(-7.091,1.347,NULL),NULL,NULL) AS point, MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(-8.369,14.803,-8.191,8.673,-8.072,0.400,5.737,0.400,5.142,14.922,-8.369,14.803)) AS snapGeom FROM dual ) SELECT SC4O.ST_SnapTo(point,snapgeom,2.0,3) AS snappedPoint FROM q_geoms; SNAPPEDPOINT ---------------------------------- MDSYS.SDO_GEOMETRY(2001,NULL,MDSYS.SDO_POINT_TYPE(-8.072,0.4,NULL),NULL,NULL)
After Image
4. Snap a Line To a Polygon
Before Image
-- Snap a line to an area WITH q_geoms AS ( SELECT MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(-8.339,-1.553,-8.682,8.496,-8.476,16.728)) AS line, MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(-8.369,14.803,-8.191,8.673,-8.072,0.400,5.737,0.400,5.142,14.922,-8.369,14.803)) AS snapGeom FROM dual ) SELECT SC4O.ST_SnapTo(line,snapgeom,0.75,3) AS snappedLine FROM q_geoms; SNAPPEDLINE -------------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(-8.339,-1.553,-8.072,0.4,-8.191,8.673,-8.369,14.803,-8.476,16.728))
After Image
In this image both the before and after lines are shown.
5. Snap One Polygon To Another
Before Image
The gaps between the three “adjoining” vertices are as shown in the following images.
Top | Middle | Bottom |
---|---|---|
!http://www.spatialdbadvisor.com/images/141.png! | !http://www.spatialdbadvisor.com/images/142.png! | !http://www.spatialdbadvisor.com/images/140.png! |
Knowing these gaps we can set a suitable snapping tolerance to bring snap the left polygon to the right one.
-- Snap one area to another WITH q_geoms AS ( SELECT MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(-24.089,0.348,-8.339,0.553,-8.682,8.496,-8.476,14.728,-24.020,14.522,-24.089,0.348)) AS poly, MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(-8.369,14.803,-8.191,8.673,-8.072,0.400,5.737,0.400,5.142,14.922,-8.369,14.803)) AS snapPoly FROM dual ) SELECT SC4O.ST_SnapTo(poly,snapPoly,0.75,3) AS snappedPoly FROM q_geoms; SNAPPEDPOLY -------------------------------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(-24.089,0.348,-8.072,0.4,-8.191,8.673,-8.369,14.803,-24.02,14.522,-24.089,0.348))
The resultant polygon after snapping is shown below.
After Image
I think you will agree that this stuff is pretty cool! Well done JTS and Martin Davis! Now, coupled with the JTS PolygonBuilder functionality, and the geometry editing functions in my GEOM package, we have the basis of some pretty useful editing of geometries. Those functions are:
FUNCTION Move( p_geometry IN MDSYS.SDO_GEOMETRY, p_tolerance IN NUMBER, p_deltaX IN NUMBER, p_deltaY IN NUMBER, p_deltaZ IN NUMBER := NULL, p_mbr IN &&defaultSchema..MBR := NULL, p_filter_geom IN MDSYS.SDO_GEOMETRY := NULL, p_filter_mask IN VARCHAR2 := 'INSIDE' ) RETURN MDSYS.SDO_GEOMETRY Deterministic; FUNCTION Scale( p_geometry IN MDSYS.SDO_GEOMETRY, p_diminfo IN MDSYS.SDO_DIM_ARRAY, p_XFactor IN NUMBER, p_YFactor IN NUMBER, p_ZFactor IN NUMBER := NULL ) RETURN MDSYS.SDO_GEOMETRY Deterministic; FUNCTION Rotate ( p_geometry IN MDSYS.SDO_Geometry, p_dimarray IN MDSYS.SDO_Dim_Array, p_X IN NUMBER, p_Y IN NUMBER, p_rotation IN NUMBER := 0) RETURN MDSYS.SDO_Geometry deterministic; FUNCTION Affine(p_geom IN mdsys.sdo_geometry, p_a NUMBER, p_b NUMBER, p_c NUMBER, p_d NUMBER, p_e NUMBER, p_f NUMBER, p_g NUMBER, p_h NUMBER, p_i NUMBER, p_xoff NUMBER, p_yoff NUMBER, p_zoff NUMBER) RETURN mdsys.sdo_geometry deterministic; FUNCTION Densify( p_geometry IN MDSYS.SDO_Geometry, p_tolerance IN NUMBER, p_distance IN NUMBER ) RETURN MDSYS.SDO_Geometry deterministic; PROCEDURE Split( p_line IN mdsys.sdo_geometry, p_point IN mdsys.sdo_geometry, p_tolerance IN NUMBER, p_out_line1 OUT nocopy mdsys.sdo_geometry, p_out_line2 OUT nocopy mdsys.sdo_geometry ); FUNCTION removeDuplicateCoordinates (p_geometry IN MDSYS.SDO_Geometry, p_diminfo IN MDSYS.SDO_Dim_Array) RETURN MDSYS.SDO_Geometry deterministic; FUNCTION Roundordinates( P_Geometry IN Mdsys.Sdo_Geometry, P_X_Round_Factor IN NUMBER, P_Y_Round_Factor IN NUMBER := NULL, P_Z_Round_Factor IN NUMBER := NULL, p_m_round_factor IN NUMBER := NULL) RETURN Mdsys.Sdo_Geometry Deterministic; FUNCTION Parallel(p_geometry IN mdsys.sdo_geometry, p_distance IN NUMBER, p_tolerance IN NUMBER, p_curved IN NUMBER := 0) RETURN mdsys.sdo_geometry DETERMINISTIC; FUNCTION SDO_AddPoint(p_geometry IN MDSYS.SDO_Geometry, p_point IN MDSYS.Vertex_Type, p_position IN NUMBER ) RETURN MDSYS.SDO_Geometry Deterministic; FUNCTION SDO_RemovePoint(p_geometry IN MDSYS.SDO_Geometry, p_position IN NUMBER) RETURN MDSYS.SDO_Geometry Deterministic; FUNCTION SDO_SetPoint(p_geometry IN MDSYS.SDO_Geometry, p_point IN MDSYS.Vertex_Type, p_position IN NUMBER ) RETURN MDSYS.SDO_Geometry Deterministic; FUNCTION SDO_VertexUpdate(p_geometry IN MDSYS.SDO_Geometry, p_old_point IN MDSYS.Vertex_Type, p_new_point IN MDSYS.Vertex_Type) RETURN MDSYS.SDO_Geometry Deterministic; FUNCTION fix_ordinates(p_geometry IN mdsys.sdo_geometry, p_x_formula IN varchar2, p_y_formula IN varchar2, p_z_formula IN varchar2 := NULL, p_w_formula IN varchar2 := NULL) RETURN mdsys.SDO_GEOMETRY Deterministic; FUNCTION Extend( p_geom IN mdsys.sdo_geometry, p_extension IN NUMBER, p_tolerance IN NUMBER, p_end IN varchar2 DEFAULT 'START' ) RETURN mdsys.sdo_geometry deterministic; FUNCTION SwapOrdinates( p_geom IN mdsys.sdo_geometry, p_pair IN varchar2 DEFAULT 'XY' /* Can be XY, XZ, XM, YZ, YM, ZM */ ) RETURN mdsys.sdo_geometry deterministic;
I hope this article is of interest to someone out there.
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions