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)
Some Oriented Point Functions
A reader asked me for some help constructing and querying oriented points a few months back. The functions I created for him were one to create an oriented point from an normal point and a supplied whole circle bearing (0-360 degrees); the other was one that, given an oriented point, computed what they orientation angle was.
Here are those functions.
CREATE OR REPLACE FUNCTION Point2oriented(P_Point IN Mdsys.Sdo_Geometry, P_Degrees IN NUMBER, P_Dec_Digits IN INTEGER DEFAULT 5) RETURN mdsys.sdo_geometry AS V_Dx NUMBER; V_Dy NUMBER; V_Dec_Digits INTEGER := Nvl(P_Dec_Digits,5); v_vertices mdsys.vertex_set_type; BEGIN IF (p_point IS NULL OR p_point.get_gtype() != 1) THEN RETURN p_point; END IF; -- p_degrees is bearing clockwise from north. V_Dx := Round(Sin(Cogo.Radians(P_Degrees)),V_Dec_Digits); v_dy := Round(cos(cogo.radians(p_degrees)),v_dec_digits); v_vertices := mdsys.sdo_util.getVertices(p_point); RETURN mdsys.sdo_geometry(p_point.sdo_gtype, p_point.sdo_srid, NULL, mdsys.sdo_elem_info_array(1,1,1, p_point.get_dims()+1,1,0), CASE p_point.get_dims() WHEN 2 THEN Mdsys.Sdo_Ordinate_Array(V_Vertices(1).X,V_Vertices(1).Y,V_Dx,V_Dy) WHEN 3 THEN Mdsys.Sdo_Ordinate_Array(V_Vertices(1).X,V_Vertices(1).Y,V_Vertices(1).Z,V_Dx,V_Dy,V_Vertices(1).Z) WHEN 4 THEN mdsys.sdo_ordinate_array(v_vertices(1).x,v_vertices(1).Y,v_vertices(1).z,v_vertices(1).w,v_dx,v_dy,v_vertices(1).z,v_vertices(1).w) ELSE mdsys.sdo_ordinate_array(v_vertices(1).x,v_vertices(1).Y,v_dx,v_dy) END ); END Point2oriented; / SHOW errors -- -- CREATE OR REPLACE FUNCTION orientation(p_oriented_point IN mdsys.sdo_geometry) RETURN NUMBER deterministic AS -- Examines an oriented point and returns the angle of the orientation. v_vertices mdsys.vertex_set_type; v_dims NUMBER; BEGIN IF (p_oriented_point IS NULL) THEN RETURN NULL; END IF; IF ( NOT codesys.geom.isOrientedPoint(p_oriented_point.sdo_elem_info)) THEN RETURN NULL; END IF; v_vertices := mdsys.sdo_util.getVertices(p_oriented_point); IF (v_vertices IS NULL OR v_vertices.COUNT != 2) THEN RETURN NULL; END IF; v_dims := p_oriented_point.get_dims(); RETURN codesys.cogo.bearing(v_vertices(1).x, v_vertices(1).y, v_vertices(1).x + v_vertices(2).x, v_vertices(1).y + v_vertices(2).y); END orientation; / SHOW errors
Now let’s test them.
First create 10 random points and orientation angles and supply them to the Point2Oriented function.
SELECT substr(Sdo_Geom.Validate_Geometry(Oriented_point,0.005),1,6) AS valid, Orientation_Angle, Oriented_point FROM (SELECT Orientation_Angle, Point2oriented(Point,Orientation_Angle,3) AS Oriented_point FROM (SELECT Round(Dbms_Random.VALUE(0,359.9),1) AS Orientation_Angle, sdo_geometry(3001,NULL, SDO_POINT_TYPE( ROUND(dbms_random.VALUE(358880 - ( 10000 / 2 ), 358880 + ( 10000 / 2 )),2), ROUND(dbms_random.VALUE(5407473 - ( 5000 / 2 ), 5407473 + ( 5000 / 2 )),2), ROUND(dbms_random.VALUE(1,1000),1) ), NULL,NULL) AS point FROM Dual CONNECT BY Level <= 10 ) F ) g; Valid Orientation_Angle Oriented_point ----- ----------------- -------------------------------------------------------------------------------------------------------------------------------- TRUE 128.4 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(361032.79,5407813.53,347.8,0.784,-0.621,347.8)) TRUE 82.9 SDO_GEOMETRY(3001,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,1,1,4,1,0),SDO_ORDINATE_ARRAY(362761.18,5405102.74,933.4,0.992,0.124,933.4)) TRUE 341.7 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(361807.1,5408334.49,872.7,-0.314,0.949,872.7)) TRUE 185.3 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(361067.44,5405260.26,872.6,-0.092,-0.996,872.6)) TRUE 203.4 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(360077.7,5406661.86,250,-0.397,-0.918,250)) TRUE 31.5 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(362073.68,5406605.41,788.5,0.522,0.853,788.5)) TRUE 96.9 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(355304.54,5408247.13,346.8,0.993,-0.12,346.8)) TRUE 249.6 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(362476.09,5409435.45,716,-0.937,-0.349,716)) TRUE 60.6 Sdo_Geometry(3001,NULL,NULL,Sdo_Elem_Info_Array(1,1,1,4,1,0),Sdo_Ordinate_Array(355431.23,5409586.01,155.8,0.871,0.491,155.8)) TRUE 291.8 SDO_GEOMETRY(3001,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,1,1,4,1,0),SDO_ORDINATE_ARRAY(359221.46,5406013.39,728.3,-0.928,0.371,728.3)) 10 ROWS selected
Now create 10 random oriented points and query the result using the orientation function to discover the orientation angle and compare it to the supplied angle.
SELECT orientation_angle, round(cogo.degrees(orientation(Point2oriented(Point,Orientation_Angle,3))),1) AS Opoint FROM (SELECT ROUND(dbms_random.VALUE(0,359.9),1) AS orientation_Angle, sdo_geometry(2001,NULL, SDO_POINT_TYPE( ROUND(dbms_random.VALUE(358880 - ( 10000 / 2 ), 358880 + ( 10000 / 2 )),2), ROUND(dbms_random.VALUE(5407473 - ( 5000 / 2 ), 5407473 + ( 5000 / 2 )),2), NULL), NULL,NULL) AS point FROM Dual CONNECT BY Level <= 10 ) F; ORIENTATION_ANGLE OPOINT ----------------- ------ 80.5 80.5 147.6 147.6 16.3 16.3 309 309 176.8 176.8 69.5 69.5 41.4 41.4 308.9 308.9 312.6 312.6 22.5 22.5 10 ROWS selected
I hope these are useful to someone out there.
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