Go to content Go to navigation and search

Home

Current Oracle Spatial Blog Articles


Search

Browse

RSS / Atom

Email me

textpattern

Creative Commons License
All Blog Articles, Data Models and Free Source Code by Simon Greener, The SpatialDB Advisor is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

Geometry Snapping using JTS in Oracle

Thursday September 15 2011 at 17:23

Keywordssnap point line polygon oracle spatial locator sdo_geometry jts ST_Snap ST_SnapTo ST_SnapToSelf
Summary

This article shows how to snap sdo_geometry points, lines and polygons together via the Java Topology Suite deployed within the Oracle database Jvm and accessible via Pl/Sql.

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.

1. Snap Two Lines to Each Other

This example might be of use with GPS track logs.

Before Image

  1. WITH q_geoms AS (
  2.    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,
  3.           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
  4.      FROM dual
  5. )
  6. SELECT JTS.ST_Snap(geom1,snapgeom,1.0,3) AS SnappedLines
  7.   FROM q_geoms;
  8. ==<nbsp/> ==
  9. SNAPPEDLINES
  10. -----------------------------------------------------------------------------------------------------------------------------
  11. 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.

  1. -- Snap first line to second
  2. WITH q_geoms AS (
  3.    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,
  4.           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
  5.      FROM dual
  6. )
  7. SELECT JTS.ST_SnapTo(line1,snapgeom,1.0,3) AS SnappedLine1
  8.   FROM q_geoms;
  9. ==<nbsp/> ==
  10. SNAPPEDLINE1
  11. -------------------------------------------------------------------------
  12. 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

  1. -- Point to Area
  2. WITH q_geoms AS (
  3. SELECT MDSYS.SDO_GEOMETRY(2001,NULL,MDSYS.SDO_POINT_TYPE(-7.091,1.347,NULL),NULL,NULL) AS point,
  4.        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
  5.   FROM dual
  6. )
  7. SELECT JTS.ST_SnapTo(point,snapgeom,2.0,3) AS snappedPoint
  8.   FROM q_geoms;
  9. ==<nbsp/> ==
  10. SNAPPEDPOINT
  11. ----------------------------------
  12. 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

  1. -- Snap a line to an area
  2. WITH q_geoms AS (
  3. 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,
  4.        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
  5.   FROM dual
  6. )
  7. SELECT JTS.ST_SnapTo(line,snapgeom,0.75,3) AS snappedLine
  8.   FROM q_geoms;
  9. ==<nbsp/> ==
  10. SNAPPEDLINE
  11. --------------------------------------------------------------------------------
  12. 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

Knowing these gaps we can set a suitable snapping tolerance to bring snap the left polygon to the right one.

  1. -- Snap one area to another
  2. WITH q_geoms AS (
  3. 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,
  4.        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
  5.   FROM dual
  6. )
  7. SELECT JTS.ST_SnapTo(poly,snapPoly,0.75,3) AS snappedPoly
  8.   FROM q_geoms;
  9. ==<nbsp/> ==
  10. SNAPPEDPOLY
  11. --------------------------------------------------------------------------------------------------
  12. 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:

  1.   FUNCTION Move( p_geometry    IN MDSYS.SDO_GEOMETRY,
  2.                  p_tolerance   IN NUMBER,
  3.                  p_deltaX      IN NUMBER,
  4.                  p_deltaY      IN NUMBER,
  5.                  p_deltaZ      IN NUMBER             := NULL,
  6.                  p_mbr         IN &&defaultSchema..MBR := NULL,
  7.                  p_filter_geom IN MDSYS.SDO_GEOMETRY := NULL,
  8.                  p_filter_mask IN VARCHAR2           := 'INSIDE'
  9.                 )
  10.     RETURN MDSYS.SDO_GEOMETRY Deterministic;
  11. ==<nbsp/> ==
  12.   FUNCTION Scale( p_geometry    IN MDSYS.SDO_GEOMETRY,
  13.                   p_diminfo     IN MDSYS.SDO_DIM_ARRAY,
  14.                   p_XFactor     IN NUMBER,
  15.                   p_YFactor     IN NUMBER,
  16.                   p_ZFactor     IN NUMBER  := NULL
  17.                 )
  18.     RETURN MDSYS.SDO_GEOMETRY Deterministic;
  19. ==<nbsp/> ==
  20.   FUNCTION Rotate ( p_geometry IN MDSYS.SDO_Geometry,
  21.                     p_dimarray IN MDSYS.SDO_Dim_Array,
  22.                     p_X        IN NUMBER,
  23.                     p_Y        IN NUMBER,
  24.                     p_rotation IN NUMBER := 0)
  25.     RETURN MDSYS.SDO_Geometry deterministic;
  26. ==<nbsp/> ==
  27.   FUNCTION Affine(p_geom IN mdsys.sdo_geometry,
  28.                   p_a NUMBER,
  29.                   p_b NUMBER,
  30.                   p_c NUMBER,
  31.                   p_d NUMBER,
  32.                   p_e NUMBER,
  33.                   p_f NUMBER,
  34.                   p_g NUMBER,
  35.                   p_h NUMBER,
  36.                   p_i NUMBER,
  37.                   p_xoff NUMBER,
  38.                   p_yoff NUMBER,
  39.                   p_zoff NUMBER)
  40.     RETURN mdsys.sdo_geometry deterministic;
  41. ==<nbsp/> ==
  42.   FUNCTION Densify( p_geometry  IN MDSYS.SDO_Geometry,
  43.                     p_tolerance IN NUMBER,
  44.                     p_distance  IN NUMBER )
  45.            RETURN MDSYS.SDO_Geometry deterministic;
  46. ==<nbsp/> ==
  47.   PROCEDURE Split( p_line      IN mdsys.sdo_geometry,
  48.                    p_point     IN mdsys.sdo_geometry,
  49.                    p_tolerance IN NUMBER,
  50.                    p_out_line1 OUT nocopy mdsys.sdo_geometry,
  51.                    p_out_line2 OUT nocopy mdsys.sdo_geometry );
  52. ==<nbsp/> ==
  53.   FUNCTION removeDuplicateCoordinates (p_geometry IN MDSYS.SDO_Geometry,
  54.                                        p_diminfo  IN MDSYS.SDO_Dim_Array)
  55.     RETURN MDSYS.SDO_Geometry deterministic;
  56. ==<nbsp/> ==
  57.   FUNCTION Roundordinates( P_Geometry        IN Mdsys.Sdo_Geometry,
  58.                            P_X_Round_Factor  IN NUMBER,
  59.                            P_Y_Round_Factor  IN NUMBER := NULL,
  60.                            P_Z_Round_Factor  IN NUMBER := NULL,
  61.                            p_m_round_factor  IN NUMBER := NULL)
  62.     RETURN Mdsys.Sdo_Geometry Deterministic;
  63. ==<nbsp/> ==
  64.   FUNCTION Parallel(p_geometry   IN mdsys.sdo_geometry,
  65.                     p_distance   IN NUMBER,
  66.                     p_tolerance  IN NUMBER,
  67.                     p_curved     IN NUMBER := 0)
  68.     RETURN mdsys.sdo_geometry DETERMINISTIC;
  69. ==<nbsp/> ==
  70.   FUNCTION SDO_AddPoint(p_geometry   IN MDSYS.SDO_Geometry,
  71.                         p_point      IN MDSYS.Vertex_Type,
  72.                         p_position   IN NUMBER )
  73.     RETURN MDSYS.SDO_Geometry Deterministic;
  74. ==<nbsp/> ==
  75.   FUNCTION SDO_RemovePoint(p_geometry  IN MDSYS.SDO_Geometry,
  76.                            p_position  IN NUMBER)
  77.     RETURN MDSYS.SDO_Geometry Deterministic;
  78. ==<nbsp/> ==
  79.   FUNCTION SDO_SetPoint(p_geometry   IN MDSYS.SDO_Geometry,
  80.                         p_point      IN MDSYS.Vertex_Type,
  81.                         p_position   IN NUMBER )
  82.     RETURN MDSYS.SDO_Geometry Deterministic;
  83. ==<nbsp/> ==
  84.   FUNCTION SDO_VertexUpdate(p_geometry  IN MDSYS.SDO_Geometry,
  85.                             p_old_point IN MDSYS.Vertex_Type,
  86.                             p_new_point IN MDSYS.Vertex_Type)
  87.     RETURN MDSYS.SDO_Geometry Deterministic;
  88. ==<nbsp/> ==
  89.   FUNCTION fix_ordinates(p_geometry IN mdsys.sdo_geometry,
  90.                          p_x_formula IN varchar2,
  91.                          p_y_formula IN varchar2,
  92.                          p_z_formula IN varchar2 := NULL,
  93.                          p_w_formula IN varchar2 := NULL)
  94.     RETURN mdsys.SDO_GEOMETRY Deterministic;
  95. ==<nbsp/> ==
  96.   FUNCTION Extend( p_geom      IN mdsys.sdo_geometry,
  97.                    p_extension IN NUMBER,
  98.                    p_tolerance IN NUMBER,
  99.                    p_end       IN varchar2 DEFAULT 'START' )
  100.     RETURN mdsys.sdo_geometry deterministic;
  101. ==<nbsp/> ==
  102.   FUNCTION SwapOrdinates( p_geom IN mdsys.sdo_geometry,
  103.                           p_pair IN varchar2 DEFAULT 'XY' /* Can be XY, XZ, XM, YZ, YM, ZM */ )
  104.     RETURN mdsys.sdo_geometry deterministic;

I hope this article is of interest to someone out there.

Creative Commons License

post this at del.icio.uspost this at Diggpost this at Technoratipost this at Redditpost this at Farkpost this at Yahoo! my webpost this at Windows Livepost this at Google Bookmarkspost this to Twitter

Comment