Configurable Buffer: JTS and Oracle

In the Version History notes for the latest release 1.12 of the Java Topology Suite is the following:

Added ability to compute Single-Sided Buffers (invoked via BufferOp and BufferParameters)

Now, this is worth investigating.

What I have done is taken the GEOPROCESS package I have been describing recently and exposed both the JTS Buffer capability and also these new parameters that control things like sideways buffering.

Here are the additional functions (see SC4O Package Documentation for a full description) I have added to the Spatial Companion For Oracle (SC4O) package:

 CREATE OR REPLACE PACKAGE SC4O
 AUTHID CURRENT_USER
 AS
 .
   TYPE refcur_t IS REF Cursor;
 .
   -- For Buffer, some constants
   --
   CAP_ROUND  CONSTANT NUMBER := 1;
   CAP_BUTT   CONSTANT NUMBER := 2;
   CAP_SQUARE CONSTANT NUMBER := 3;
 .
   JOIN_ROUND CONSTANT NUMBER := 1;
   JOIN_MITRE CONSTANT NUMBER := 2;
   JOIN_BEVEL CONSTANT NUMBER := 3;
 .
   QUADRANT_SEGMENTS CONSTANT NUMBER := 8;
 .
 ...
 .
   /**
   * ST_Buffer
   * Buffer a geometry using variety of parameters including single siding.
   *
   * @param p_geom             : sdo_geometry : first geometry subject to overlay action
   * @param p_distance         : number : buffer distance
   * @param p_precision        : int : number of decimal places of precision
   * @param p_endCapStyle      : int : One of BufferParameters.CAP_ROUND,BufferParameters.CAP_BUTT, BufferParameters.CAP_SQUARE
   * @param p_joinStyle        : int : One of BufferParameters.JOIN_ROUND, BufferParameters.JOIN_MITRE, or BufferParameters.JOIN_BEVEL
   * @param p_quadrantSegments : int : Stroking of curves
   * @param p_singleSided      : int : If 1(true), p_distance > 0 means LEFT sided buffer else right sided
   * @return SDO_GEOMETRY      : Result of buffer
   * @history Simon Greener, August 2011, Original Coding
   */
   FUNCTION ST_Buffer(p_geom             IN mdsys.sdo_geometry,
                   p_distance         IN NUMBER,
                   p_precision        IN NUMBER,
                   p_endCapStyle      IN NUMBER  DEFAULT GEOPROCESS.CAP_ROUND,
                   p_joinStyle        IN NUMBER  DEFAULT GEOPROCESS.JOIN_ROUND,
                   p_quadrantSegments IN NUMBER  DEFAULT GEOPROCESS.QUADRANT_SEGMENTS,
                   p_singleSided      IN BOOLEAN DEFAULT FALSE)
     RETURN mdsys.sdo_geometry
            Deterministic;
 .
   FUNCTION ST_Buffer(p_geom             IN mdsys.sdo_geometry,
                   p_distance         IN NUMBER,
                   p_precision        IN NUMBER,
                   p_endCapStyle      IN NUMBER,
                   p_joinStyle        IN NUMBER,
                   p_quadrantSegments IN NUMBER,
                   p_singleSided      IN NUMBER )
     RETURN mdsys.sdo_geometry
            Deterministic;
 .
 END Geoprocess;

The following parameters “expose” the additional buffering capabilities:

  • p_endCapStyle : One of BufferParameters.CAP_ROUND, BufferParameters.CAP_BUTT, BufferParameters.CAP_SQUARE
  • p_joinStyle : One of BufferParameters.JOIN_ROUND, BufferParameters.JOIN_MITRE, or BufferParameters.JOIN_BEVEL
  • p_quadrantSegments : Stroking of curves
  • p_singleSided : If 1(true), p_distance > 0 means LEFT sided buffer else right sided

Best to show each of these by actual examples.

1. 15m Buffer with _Round_ End Cap and Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          1 /*CAP_ROUND*/,
                          1 /*JOIN_ROUND*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like ….

2. 15m Buffer with Square End Cap and Bevel Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          3 /*CAP_SQUARE*/,
                          3 /*JOIN_BEVEL*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like…

3. 15m Buffer with SQUARE End Cap and ROUND Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          3 /*CAP_SQUARE*/,
                          1 /*JOIN_ROUND*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like ….

4. 15m Buffer with BUTT End Cap and ROUND Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          2 /*CAP_BUTT*/,
                          1 /*JOIN_ROUND*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like….

5. 15m Buffer with BUTT End Cap and MITRE Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          2 /*CAP_BUTT*/,
                          2 /*JOIN_MITRE*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like…

6. 15m Buffer with BUTT End Cap and BEVEL Join Style

 SELECT SC4O.ST_Buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)),15.0,2,
                          2 /*CAP_BUTT*/,
                          3 /*JOIN_BEVEL*/,
                          8 /*QUADRANT_SEGMENTS*/,
                          0 /*FULL BUFFER*/) AS buf
   FROM dual;

Which looks like….

7. Left and Right Buffer (15m) with all three Join Styles

NOTE: Changing End Cap Style makes no difference.

 SELECT SC4O.ST_Buffer(line,b.left_right_distance,2,1,c.join_type,8,1) AS buf
   FROM (SELECT sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(20,1,50,50,100,0,150,50)) AS line
           FROM dual
        ) a,
        (SELECT CASE WHEN level = 1 THEN -15.0 ELSE 15.0 END AS left_right_distance FROM dual CONNECT BY level < 3) b,
        (SELECT level AS join_type FROM dual CONNECT BY level < 4) c;

Which looks like this….

I hope this is of interest to my readers.