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)
Finding centre and radius of a circular geometry
Here is a method for finding the centre of a circle and its radius from a polygon (x003) sdo_geometry.
CREATE OR REPLACE FUNCTION FindCircle (p_polygon IN mdsys.sdo_geometry) RETURN mdsys.sdo_point_type deterministic IS v_centre mdsys.sdo_point_type; v_pt1 mdsys.vertex_type; v_pt2 mdsys.vertex_type; v_pt3 mdsys.vertex_type; dA NUMBER; dB NUMBER; dC NUMBER; dD NUMBER; dE NUMBER; dF NUMBER; dG NUMBER; BEGIN IF (p_polygon IS NULL) THEN RETURN NULL; END IF; IF (p_polygon.get_gtype() NOT IN (3,7) ) THEN RETURN NULL; END IF; -- Grab first three vertices for checking -- v_pt1 := mdsys.sdo_util.getVertices(p_polygon)(1); v_pt2 := mdsys.sdo_util.getVertices(p_polygon)(2); v_pt3 := mdsys.sdo_util.getVertices(p_polygon)(3); dA := v_pt2.X - v_pt1.X; dB := v_pt2.Y - v_pt1.Y; dC := v_pt3.X - v_pt1.X; dD := v_pt3.Y - v_pt1.Y; dE := dA * (v_pt1.X + v_pt2.X) + dB * (v_pt1.Y + v_pt2.Y); dF := dC * (v_pt1.X + v_pt3.X) + dD * (v_pt1.Y + v_pt3.Y); dG := 2.0 * (dA * (v_pt3.Y - v_pt2.Y) - dB * (v_pt3.X - v_pt2.X)); -- If dG is zero then the three points are collinear and no finite-radius -- circle through them exists. IF ( dG = 0 ) THEN RETURN NULL; ELSE v_centre := NEW mdsys.sdo_point_type((dD * dE - dB * dF) / dG, (dA * dF - dC * dE) / dG, NULL); v_centre.Z := SQRT(POWER(v_pt1.X - v_centre.X,2) + POWER(v_pt1.Y - v_centre.Y,2) ); RETURN v_centre; END IF; END FindCircle;
Some examples:
SELECT codesys.findCircle(mdsys.sdo_geom.sdo_buffer(mdsys.sdo_geometry(2001,NULL,sdo_point_type(10,10,NULL),NULL,NULL),10,0.02)) AS centre FROM dual; . CENTRE ------------------------------ MDSYS.SDO_POINT_TYPE(10,10,10) . SELECT codesys.findCircle(SDO_GEOMETRY (2003, NULL, NULL, SDO_ELEM_INFO_ARRAY (1,1003,4),SDO_ORDINATE_ARRAY (15,145, 10,150, 20,150))) AS centre FROM dual; . CENTRE ------------------------------ MDSYS.SDO_POINT_TYPE(15,150,5) .
The SDO_UTIL.CIRCLE_POLYGON function is trickier because it generates 8307 longitude/latitude data. So the above function, based as it is on projected data, can only give us a basic approximation. The returned radius is going to be in decimal degrees so we need to convert it via SDO_GEOM.SDO_DISTANCE.
SELECT roundOrdinates(mdsys.sdo_util.CIRCLE_POLYGON(10,10,10,1),8) AS circle FROM dual; . CIRCLE -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2003,8307,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(10,9.99991007,10.00006457,9.99993641,10.00009132,10,10.00006457,10.00006359,10,10.00008993,9.99993543,10.00006359,9.99990868,10,9.99993543,9.99993641,10,9.99991007)) . SELECT round(a.centre.x,8) AS cx, round(a.centre.y,8) AS cy, round(sdo_geom.sdo_distance(mdsys.sdo_geometry(2001,8307,mdsys.sdo_point_type(a.centre.x, a.centre.y,NULL),NULL,NULL), mdsys.sdo_geometry(2001,8307,mdsys.sdo_point_type(a.centre.x+a.centre.z,a.centre.y,NULL),NULL,NULL), 0.005),3) AS radius FROM (SELECT findCircle(roundOrdinates(mdsys.sdo_util.CIRCLE_POLYGON(10,10,10,1),8)) AS centre FROM dual ) a; . CX CY RADIUS ----------- ----------- ------ 10.00000068 10.00000071 9.938 . -- Or..... SELECT round(f.centre.x,8) AS cx, round(f.centre.y,8) AS cy, round(f.centre.z,1) AS radius FROM (SELECT sdo_cs.transform(mdsys.sdo_geometry(2001,28355, mdsys.sdo_point_type(b.centre.x, b.centre.y, b.centre.z), NULL,NULL),8307).sdo_point AS centre FROM (SELECT a.geom,findCircle(sdo_cs.transform(a.geom,28355)) AS centre FROM (SELECT mdsys.sdo_util.CIRCLE_POLYGON(147,-32,10,1) AS geom FROM dual ) a ) b ) f; . CX CY RADIUS ------------ ------------ ------ 147.00000026 -31.99999978 10
I hope this is of help to someone.
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