CREATE OR REPLACE package Centroid
AUTHID CURRENT_USER
IS
TYPE t_numbers IS TABLE OF NUMBER;
TYPE t_Vectors IS TABLE OF &&defaultSchema..t_Vector;
/** @NOTE : The schema owning this package, and all calling schemas (see AUTHID above) MUST have
* direct SELECT permissions on DBA_REGISTRY for this package to compile and run properly.
* SQL> connect sys/****@sid
* SQL> GRANT SELECT ON DBA_REGISTRY TO &&defaultSchema.;
* @NOTE : These packages assume a minimum of 9iR2 as the SDO_MBR function uses SDO_AGGR_MBR for
* Locator users. If you are on 9iR1 then modify the SDO_MBR function to uncomment out
* the SQL that doesn't use SDO_AGGR_MBR and comment out the SDO_AGGR_MBR SQL.
* @NOTE : This package uses &&defaultSchema..T_VERTEX_TYPE which Oracle changed the definition of at 10g
* by adding an ID field. If you want to compile the package on 9i, manually change the
* code in ConvertGeometry so that it does not reference the last, ID, field.
* @NOTE : If sdo_geometry linestrings or polygons contain circular arcs they must be "stroked" before
* Calling the SDO_CENTROID function. If you have SPATIAL you can use sdo_geom.sdo_arc_densify().
* If not use this package's ConvertGeometry() function.
* SDO_GEOM.SDO_ARC_DENSIFY() function before calling sdo_centroid.
* @NOTE : SDO_Area does not work for non-2D geometries.
**/
/** ----------------------------------------------------------------------------------------
* @function : Generate_Series
* @precis : Function that generates a series of numbers mimicking PostGIS's function with
* the same name
* @version : 1.0
* @usage : Function generate_series(p_start pls_integer,
* p_end pls_integer,
* p_step pls_integer := 1)
* Return centroid.t_integers Pipelined;
* eg SELECT s.* FROM TABLE(generate_series(1,1000,10)) s;
* @param : p_start : Starting value
* @paramtype : p_start : Integer
* @param : p_end : Ending value.
* @paramtype : p_end : Integer
* @return : p_step : The step value of the increment between start and end
* @rtnType : p_step : Integer
* @history : Simon Greener - June 2008 - Original coding.
* @copyright : Free for public use
**/
FUNCTION generate_series(p_start IN pls_integer,
p_end IN pls_integer,
p_step IN pls_integer := 1 )
RETURN &&defaultSchema..centroid.t_numbers Pipelined;
/** ----------------------------------------------------------------------------------------
* @function : SDO_MBR
* @precis : Returns Minimum Bounding Rectangle of a given geometry.
* @version : 1.0
* @usage : Function SDO_MBR ( p_geometry IN MDSYS.SDO_GEOMETRY )
* Return MDSYS.SDO_GEOMETRY Deterministic;
* @example : SELECT sdo_mbr(a.geom,0.01)
* FROM ProjCompound2D a,
* TABLE( &&defaultSchema..geom.GetElemInfo( a.geom ) ) ei
* WHERE a.geom is not null;
* @param : p_geometry : A shape.
* @paramtype : p_geomery : MDSYS.SDO_GEOMETRY
* @param : p_tolerance : Dimarray sdo_tolerance value
* @paramtype : p_tolerance : number
* @return : geometry : A 2003 vertex described polygon
* @rtnType : sdo_geometry : MDSYS.SDO_GEOMETRY
* @note : Function is pipelined
* @history : Simon Greener - Jul 2008 - Original coding.
* @copyright : Free for public use
**/
FUNCTION SDO_MBR( p_geometry IN MDSYS.SDO_GEOMETRY )
RETURN MDSYS.SDO_GEOMETRY Deterministic;
/** ----------------------------------------------------------------------------------------
* @function : SDO_Length
* @precis : Function which computes length of linestrings or boundaries of polygons.
* @version : 1.0
* @description: These are wrapper functions over SDO_3GL.LENGTH_AREA procedures that are
* not mentioned in Oracle's licensing as being functions limited to Spatial (EE)
* @usage : Function SDO_Length ( p_geometry IN MDSYS.SDO_GEOMETRY,
* p_tolerance IN Number
* p_units IN VarChar2 )
* Return Number Deterministic;
* eg fixedShape := &&defaultSchema..geom.length(shape,diminfo);
* @param : p_geometry : A valid sdo_geometry.
* @paramtype : p_geomery : MDSYS.SDO_GEOMETRY
* @param : p_tolerance : The dimarray describing the shape.
* @paramtype : p_tolerance : MDSYS.SDO_DIM_ARRAY
* @param : p_units : The units in which the length is to be calculated eg meters, miles etc
* @paramtype : p_units : varchar2
* @return : length : Length of linestring or boundary of a polygon in required unit of measure
* @rtnType : length : Number
* @note : Supplied p_units should exist in mdsys.SDO_UNITS_OF_MEASURE
* @history : Simon Greener - Oct 2007 - Original coding.
* @copyright : Free for public use
**/
FUNCTION SDO_Length( p_geometry IN mdsys.sdo_geometry,
p_tolerance IN NUMBER,
p_units IN varchar2 := 'Meter' )
RETURN NUMBER deterministic;
/** ----------------------------------------------------------------------------------------
* @function : SDO_AREA
* @precis : Function which computes area of a polygon.
* @version : 1.0
* @description: These are wrapper functions over SDO_3GL.LENGTH_AREA procedures that are
* not mentioned in Oracle's licensing as being functions limited to Spatial (EE)
* @usage : Function SDO_Area ( p_geometry IN MDSYS.SDO_GEOMETRY,
* p_dimarray IN MDSYS.SDO_DIM_ARRAY
* p_units IN VarChar2 )
* Return Number Deterministic;
* eg fixedShape := sdo_area(shape,tolerance);
* @param : p_geometry : A valid sdo_geometry.
* @paramtype : p_geomery : MDSYS.SDO_GEOMETRY
* @param : p_tolerance : The vertex tolerance .
* @paramtype : p_tolerance : NUMBER
* @return : area : Area of a polygon in required unit of measure
* @rtnType : area : Number
* @note : Supplied p_units should exist in mdsys.SDO_UNITS_OF_MEASURE
* @history : Simon Greener - Oct 2007 - Original coding.
* @copyright : Free for public use
**/
FUNCTION SDO_Area( p_geometry IN mdsys.sdo_geometry,
p_tolerance IN NUMBER,
p_units IN varchar2 := 'Square Meter' )
RETURN NUMBER Deterministic;
/** ----------------------------------------------------------------------------------------
* @function : ConvertGeometry
* @precis : Function which converts optimized rectangle components in a polygon to their
* stroked equivalent.
* @version : 1.0
* @description: The centroid algorithm works with vector representations of the sides
* of a polygon generated by GetVector. Optimized rectangle are not directly
* supported in either the GetVector or sdo_centroid functions. If these exist
* the sdo_geometry should be put through this function before calling sdo_centroid.
* @usage : Function Converte_Geometry ( p_geometry IN MDSYS.SDO_GEOMETRY )
* Return MdSys.Sdo_Geometry Deterministic;
* eg centroid := centroid.sdo_centroid(centroid.ConvertGeometry(shape),tolerance);
* @param : p_geometry : A valid sdo_geometry.
* @paramtype : p_geomery : MDSYS.SDO_GEOMETRY
* @param : p_Arc2Chord : ArcToChord separation expressed in dataset units for converting arcs to stroked lines.
* @paramtype : p_Arc2Chord : Number
* @return : geometry : Converted, valid, geometry
* @rtnType : sdo_geometry : MDSYS.SDO_GEOMETRY
* @note : Oracle changed the definition of T_VERTEX_TYPE at 10g by adding and ID field. If you
* compiling on 9i manually change the code in ConvertGeometry so that it does not
* reference the ID field.
* @history : Simon Greener - July 2008 - Original coding.
* @copyright : Free for public use
**/
FUNCTION ConvertGeometry(p_geometry IN mdsys.sdo_geometry,
p_Arc2Chord IN NUMBER := 0.1)
RETURN mdsys.sdo_geometry Deterministic;
FUNCTION SDO_ARC_DENSIFY(p_geometry IN mdsys.sdo_geometry,
p_Arc2Chord IN NUMBER := 0.1)
RETURN mdsys.sdo_geometry Deterministic;
/** ----------------------------------------------------------------------------------------
* @function : GetVector
* @precis : Places a geometry's coordinates into a pipelined vector data structure.
* @version : 3.0
* @description: Loads the coordinates of a linestring, polygon geometry into a
* pipelined vector data structure for easy manipulation by other functions
* such as geom.SDO_Centroid.
* @usage : select *
* from myshapetable a,
* table(centroid.GetVector(a.shape));
* @param : p_geometry : MDSYS.SDO_GEOMETRY : A geographic shape.
* @return : geomVector : VectorSetType : The vector pipelined.
* @requires : Global data types coordRec, vectorRec and VectorSetType
* @history : Simon Greener - July 2006 - Original coding from GetVector
* @history : Simon Greener - July 2008 - Re-write to be standalone of other packages eg GF
* @history : Simon Greener - October 2008 - Removed 2D limits
* @copyright : Free for public use
**/
FUNCTION GetVector(P_Geometry IN Mdsys.Sdo_Geometry)
RETURN &&defaultSchema..CENTROID.t_Vectors pipelined;
/** =================== CENTROID Functions ====================== **/
/* ----------------------------------------------------------------------------------------
* @function : centroid_p
* @precis : Generates centroid for a point (itself) or multipoint.
* @version : 1.3
* @description: This function creates centroid of multipoint via averaging of ordinates.
* @param : p_geometry : MDSYS.SDO_GEOMETRY : The geometry object.
* @param : p_round_x : Number : Ordinate rounding precision for X ordinates.
* @param : p_round_y : Number : Ordinate rounding precision for Y ordinates.
* @param : p_round_z : Number : Ordinate rounding precision for Z ordinates.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroid.
* @requires : GetVector()
* @history : Simon Greener - Jul 2008 - Original coding of centroid_p as internal function
* @history : Simon Greener - Jan 2012 - Exposed internal function.
* @copyright : Free for public use
**/
FUNCTION centroid_p(p_geometry IN mdsys.sdo_geometry,
p_round_x IN NUMBER := 3,
p_round_y IN NUMBER := 3,
p_round_z IN NUMBER := 2)
RETURN MDSYS.SDO_GEOMETRY DETERMINISTIC;
/* ----------------------------------------------------------------------------------------
* @function : Centroid_A
* @precis : Generates centroid for a polygon.
* @version : 1.3
* @description: The standard MDSYS.SDO_GEOM.SDO_CENTROID function does not guarantee
* that the centroid it generates falls inside the polygon.
* This function ensures that the centroid of any arbitrary polygon falls within the polygon.
* @param : p_geometry : MDSYS.SDO_GEOMETRY : The geometry object.
* @param : p_start : Number : 0 = Use average of all Area's vertices for starting X centroid calculation
* 1 = Use centre X of MBR
* 2 = User supplied starting seed X
* @param : p_seed_x : Number : Starting X ordinate for which a Y that is inside the polygon is returned.
* @param : p_round_x : Number : Ordinate rounding precision for X ordinates.
* @param : p_round_y : Number : Ordinate rounding precision for Y ordinates.
* @param : p_round_z : Number : Ordinate rounding precision for Z ordinates.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroid.
* @requires : GetVector()
* @history : Simon Greener - Jul 2008 - Original coding of centroid_a as internal function
* @history : Simon Greener - Jan 2012 - Exposed internal function. Added p_seed_x support.
* @copyright : Free for public use
**/
FUNCTION centroid_a(p_geometry IN mdsys.sdo_geometry,
p_start IN NUMBER := 1,
p_seed_x IN NUMBER := NULL,
p_round_x IN NUMBER := 3,
p_round_y IN NUMBER := 3,
p_round_z IN NUMBER := 2)
RETURN MDSYS.SDO_GEOMETRY DETERMINISTIC;
/* ----------------------------------------------------------------------------------------
* @function : Centroid_1
* @precis : Generates centroid for a linestring.
* @version : 1.3
* @description: The standard MDSYS.SDO_GEOM.SDO_CENTROID function does not guarantee
* that the centroid it generates falls inside the polygon.
* This function ensures that the centroid of any arbitrary polygon falls within the polygon.
* @param : p_geometry : MDSYS.SDO_GEOMETRY : The geometry object.
* @param : p_position_as_ratio : Number : Position along multi-line/line where "centroid" created.
* @param : p_round_x : Number : Ordinate rounding precision for X ordinates.
* @param : p_round_y : Number : Ordinate rounding precision for Y ordinates.
* @param : p_round_z : Number : Ordinate rounding precision for Z ordinates.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroid.
* @requires : GetVector()
* @history : Simon Greener - Jul 2008 - Original coding of centroid_l as internal function
* @history : Simon Greener - Jan 2012 - Exposed internal function.
* @copyright : Free for public use
**/
FUNCTION centroid_l(p_geometry IN mdsys.sdo_geometry,
p_position_as_ratio IN NUMBER := 0.5,
p_round_x IN NUMBER := 3,
p_round_y IN NUMBER := 3,
p_round_z IN NUMBER := 2)
RETURN MDSYS.SDO_GEOMETRY DETERMINISTIC;
/* ----------------------------------------------------------------------------------------
* @function : SDO_Centroid
* @precis : Generates centroid for a polygon.
* @version : 1.5
* @description: The standard MDSYS.SDO_GEOM.SDO_CENTROID 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. Also provides centroid functions for multipoints and linestrings.
* @param : p_geometry : MDSYS.SDO_GEOMETRY : The geometry object.
* @param : p_start : Number : 0 = Use average of all Area's vertices for starting X centroid calculation
* 1 = Use centre X of MBR
* @param : p_largest : Number : 0 = Use smallest of any multipart geometry.
* 1 = Use largest of any multipart geometry.
* @param : p_round_x : Number : Ordinate rounding precision for X ordinates.
* @param : p_round_y : Number : Ordinate rounding precision for Y ordinates.
* @param : p_round_z : Number : Ordinate rounding precision for Z ordinates.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroid.
* @requires : GetVector()
* @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_start IN NUMBER := 1,
p_largest IN NUMBER := 1,
p_round_x IN NUMBER := 3,
p_round_y IN NUMBER := 3,
p_round_z IN NUMBER := 2)
RETURN MDSYS.SDO_GEOMETRY DETERMINISTIC;
/**
* Overload of main sdo_centroid function
* @param : p_tolerance : Number : Single tolerance for use with all ordinates.
* Expressed in dataset units eg decimal degrees if 8311.
* See Convert_Distance for method of converting distance in meters to dataset units.
**/
FUNCTION sdo_centroid (
p_geometry IN MDSYS.SDO_Geometry,
p_start IN NUMBER := 1,
p_tolerance IN NUMBER )
RETURN MDSYS.SDO_Geometry deterministic;
/**
* Overload of main sdo_centroid function
* @param : p_dimarray : Number : Supplies all tolerances when processing vertices.
* Note that the function requires the sdo_tolerances inside the diminfo to be expressed in dataset
* units eg decimal degrees if 8311. But for Oracle this is in meters for long/lat and dataset units otherwise.
* Thus use of this wrapper for geodetic data IS NOT RECOMMENDED.
* See Convert_Distance for method of converting distance in meters to dataset units.
**/
FUNCTION Sdo_Centroid(
p_geometry IN MDSYS.SDO_GEOMETRY,
p_start IN NUMBER := 1,
p_dimarray IN MDSYS.SDO_DIM_ARRAY)
RETURN MDSYS.SDO_Geometry deterministic;
/* ----------------------------------------------------------------------------------------
* @function : Sdo_Multi_Centroid
* @precis : Generates centroids for a all parts of a multi-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 generates a point for every part of a 2007 multi-part polygon..
* @param : p_geometry : MDSYS.SDO_GEOMETRY : The polygon shape.
* @param : p_start : Number : 0 = Use average of all Area's vertices for starting X centroid calculation
* 1 = Use centre X of MBR
* @param : p_round_x : Number : Ordinate rounding precision for X ordinates.
* @param : p_round_y : Number : Ordinate rounding precision for Y ordinates.
* @param : p_round_z : Number : Ordinate rounding precision for Z ordinates.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroids of the parts as a multi-part shape.
* @history : Simon Greener - Jun 2006 - Original coding.
* @copyright : Free for public use
**/
FUNCTION SDO_Multi_Centroid(
p_geometry IN MDSYS.SDO_Geometry,
p_start IN NUMBER := 1,
p_round_x IN NUMBER := 3,
p_round_y IN NUMBER := 3,
p_round_z IN NUMBER := 2)
RETURN MDSYS.SDO_Geometry deterministic;
/**
* Overload of main sdo_multi_centroid function
* @param : p_geometry : MdSys.Sdo_Geometry : The sdo_geometry object.
* @param : p_start : Number : 0 = Use average of all Area's vertices for starting X centroid calculation
* 1 = Use centre X of MBR
* @param : p_tolerance : Number : Tolerance used when processing vertices.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroids of the parts as a multi-part shape.
* @history : Simon Greener - Jun 2006 - Original coding.
* @copyright : Free for public use
**/
FUNCTION sdo_multi_centroid(
p_geometry IN MDSYS.SDO_Geometry,
p_start IN NUMBER := 1,
p_tolerance IN NUMBER)
RETURN MDSYS.SDO_Geometry deterministic;
/**
* Overload of main sdo_multi_centroid function
* @param : p_geometry : MdSys.Sdo_Geometry : The sdo_geometry object.
* @param : p_start : Number : 0 = Use average of all Area's vertices for starting X centroid calculation
* 1 = Use centre X of MBR
* @param : p_dimarray : Number : Supplies all tolerances when processing vertices.
* Note that the function requires the sdo_tolerances inside the diminfo to be expressed in dataset
* units eg decimal degrees if 8311. But for Oracle this is in meters for long/lat and dataset units otherwise.
* Thus use of this wrapper for geodetic data IS NOT RECOMMENDED.
* See Convert_Distance for method of converting distance in meters to dataset units.
* @return : centroid : MDSYS.SDO_GEOMETRY : The centroids of the parts as a multi-part shape.
* @history : Simon Greener - Jun 2006 - Original coding.
* @copyright : Free for public use
**/
FUNCTION sdo_multi_centroid(
p_geometry IN MDSYS.SDO_Geometry,
p_start IN NUMBER := 1,
p_dimarray IN MDSYS.SDO_Dim_Array)
RETURN MDSYS.SDO_Geometry deterministic;
END Centroid;
Comment [4]
Hi Simon, I was trying your package but I get:
“ORA-06553: PLS-306: wrong number or types of arguments in call to ‘OGC_CENTROID’”
My db is a 11.2.0.2… any idea? Thanks! Stefano
— Stefano · 30 May 2012, 01:21 · #
Not unless you give me a LOT more information.
S
— Simon Greener · 30 May 2012, 11:38 · #
Hi, I have the same problem.
The SQL:
SELECT codesys.centroid.sdo_multi_centroid(my_polygon, 1, 0.005) FROM my_table;
The error message:
SQL1.sql: Error (1501,1): ORA-06553: PLS-306: wrong number or types of arguments in call to ‘OGC_CENTROID’
ORA-06512: at “CODESYS.CENTROID”, line 1501
ORA-06512: at “CODESYS.CENTROID”, line 1519
ORA-06512: at “CODESYS.CENTROID”, line 1583
ORA-06512: at line 1
— Keeper · 1 February 2013, 03:41 · #
Note my previous requirements:
1. Function (DONE)
2. How (DONE – EXCEPT THAT I CAN’T REPLICATE THE ERROR BECAUSE YOU HAVE NOT PROVIDED ME WITH THE ACTUAL GEOMETRY)
3. LINE (DONE)
So, can you please supply me with the test geometry (email me it if you wish) as I cannot see how my CENTROID package even uses OGC_CENTROID….
regards
Simon
— Simon Greener · 1 February 2013, 12:07 · #