CENTROID Package now returns centroid of multi-linestring

My original CENTROID package’s sdo_centroid() functions, when supplied with a multilinestring sdo_geometry, would “explode” the multilinestring into its component linestrings and calculate the centroid (mid-point) of the largest linestring.

Some users have asked for the centroid package to return the centroid (midpoint) of the whole multilinestring. While the LINEAR package can do this, I have modified the CENTROID package so that it can return either via an option called p_line_explode.
If p_line_explode is set to 1 then the sdo_centroid() function will operate as it always has, but if set to 0, then the midpoint (at half-length) of the entire multipoint is returned.

  /* ----------------------------------------------------------------------------------------
   * @function   : SDO_Centroid
   * @precis     : Generates centroid for a polygon.
   * @version    : 1.0
   * @description: The standard MDSYS.SDO_GEOM.SDO_GEOMETRY function does not guarantee
   *               that the centroid it generates falls inside the polygon.   Nor does it
   *               generate a centroid for a multi-part polygon shape.
   *               This function ensures that the centroid of any arbitrary polygon
   *               falls within the polygon.
   * @usage      : Function Do_Centroid(
   *                 p_geometry     IN MDSYS.SDO_GEOMETRY,
   *                 p_dimarray     IN MDSYS.SDO_DIM_ARRAY,
   *                 p_area         IN NUMBER,
   *                 p_line_explode IN NUMBER)
   *                 RETURN MDSYS.SDO_GEOMETRY DETERMINISTIC;
   * @param      : p_geometry  : MDSYS.SDO_GEOMETRY : The geometry object.
   * @param      : p_tolerance    : Number : Tolerance used when processing vertices.
   *                                         Expressed in dataset units eg decimal degrees if 8311.
   *                                         See Convert_Distance for method of converting distance in meters to dataset units.
   * @param      : p_area         : Number : Whether largest part in a multi-part polygon should be chosen as part with largest
   *                                         area (1) or with largest MBR (not 1)
   * @param      : p_line_explode : Number : Whether largest part in a multi-linestring should be used for centroid or chose
   *                                         centroid based on 50% of length across all parts.
   * @return     : centroid    : MDSYS.SDO_GEOMETRY : The centroid.
   * @requires   : GetVector()
   * @requires   : tolerance
   * @note       : Does not check if passed shape is a polygon.
   * @history    : Simon Greener - Mar 2008 - Total re-write of algorithm following on from cases the original algorithm didn't handle.
   *                                          The new algorithm does everything in a single SQL statement which can be run outside of this function if needed.
   *                                          The algorithm is based on a known method for filling a polygon which counts the type and number of crossings of a
   *                                          "ray" (in this case a vertical line) across a polygon boundary. The new algorithm also has improved handling of
   *                                          multi-part geometries and also generates a starting X ordinate for the vertical "ray" using vertex averaging
   *                                          rather than the mid point of a part's MBR. This is to try and "weight" the centroid more towards where detail exists.
   *               Simon Greener - Jul 2008 - Standalone version with no dependencies other than the need for external object types.
   * @copyright  : Free for public use
   **/
   FUNCTION sdo_centroid (
     p_geometry     IN MDSYS.SDO_Geometry,
     p_tolerance    IN NUMBER,
     p_area         IN NUMBER := 1,
     p_line_explode IN NUMBER := 1)
     RETURN MDSYS.SDO_Geometry deterministic;
   /**
   * Overload of main sdo_centroid function
   **/
   FUNCTION Do_Centroid(
     p_geometry     IN MDSYS.SDO_GEOMETRY,
     p_dimarray     IN MDSYS.SDO_DIM_ARRAY,
     p_area         IN NUMBER := 1,
     p_line_explode IN NUMBER := 1)
     RETURN MDSYS.SDO_Geometry deterministic;

Example

 SELECT CODESYS.centroid.sdo_centroid(MDSYS.SDO_GEOMETRY(2006, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), MDSYS.SDO_ORDINATE_ARRAY(50.0, 15.0, 55.0, 15.0, 60.0, 15.0, 65.0, 15.0)),0.005,1,1) AS mcentroid,
        CODESYS.centroid.sdo_centroid(MDSYS.SDO_GEOMETRY(2006, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), MDSYS.SDO_ORDINATE_ARRAY(50.0, 15.0, 55.0, 15.0, 60.0, 15.0, 65.0, 15.0)),0.005,1,0) AS centroid
   FROM dual;
 MCENTROID                                                                  CENTROID
 -------------------------------------------------------------------------- ------------------------------------------------------------------------
 MDSYS.SDO_GEOMETRY(2001,NULL,MDSYS.SDO_POINT_TYPE(52.5,15,NULL),NULL,NULL) MDSYS.SDO_GEOMETRY(2001,NULL,MDSYS.SDO_POINT_TYPE(55,15,NULL),NULL,NULL)

Visually

I hope this is of help to someone.

Leave a Reply

Your email address will not be published. Required fields are marked *