SpatialDB Advisor
|
Current Oracle Spatial Blog Articles • isValid, isSimple, Dimension and CoordDim methods for SDO_Geometry • Line Merging or Collecting lines together: ST_LineMerger • ST_RemovePoint for Oracle SDO_Geometry based on Jaspa/JTS • 3D/4D and SRID aware Conversion functions for SDO_Geometry: WKT and EWKT • Topological vs Non-Topological Simplification/Generalization of Aggregated Area Geometies in Oracle • Filtering very short linestrings via bitmap function index • CENTROID For Oracle • Gridding a sdo_geometry line/polygon object (Oracle) • Finding centre and radius of a circular geometry • Constraining geometry type for sdo_geometry column in a table. • CASE Statements and SDO_GEOMETRY • The Power of Constraints and Indexes for Spatial Constraints: stopping duplicate points • SURVEY: The Future of GeoRaptor • Replacement for SDO_GEOM.RELATE - JTS Relate • Changing Oracle Spatial Index Parameters on existing index • Writing Excel Spreadsheets files from within the Oracle database using Java and PL/SQL • Writing xSV (eg csv) files from within the Oracle database using Java and PL/SQL • A simple spike finder for Spatial/Locator • JTS Java class compilation for 11g and above • Random Spatial Search Procedure • Geometry Snapping using JTS in Oracle • Exposing JTS's MinimumBoundingCircle functionality • Exposing JTS's Densifier functionality • Using JTS's Comparison Functions - HausdorffSimilarityMeasure & AreaSimilarityMeasure with SDO_GEOMETRY • Free JTS-based Area/Length Functions • Handy way of systematically fixing polygon geometries with 13349 and other errors • Standalone CENTROID package now available for download • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 4 Processing Geodetic data • Configurable Buffer: JTS and Oracle • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 3 • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 2 • Free Union, Intersection, Xor and Difference Functions for Oracle Locator - Part 1 • Building Lines into Polygons in Oracle Locator • Saving Storage Space Part 1: Storage Effects of Sdo_Geometry Coordinate Precision • Finding Intersection Points between Line and Polygon • SDO2GeoJSON • Free version of sdo_length • Alternative to my SQL based GetNumRings function • External Tables and SDO_Geometry data. • layer_gtype keyword issue when indexing linear data on 11g • String Tokenizer for Oracle • Free Aggregate Method for Concatenating 2D Lines in Oracle Locator 10g • Reducing 5 Vertex Polygon to Optimized Rectangle • Square Buffer • GeoRaptor 3.0 Officially released. • Converting decimal seconds to string • SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT - 13356 Issues • Valid conversion unit values for Oracle sdo_geom.sdo_length() • Removing Steps in Gridded Vector Data - SmoothGrid for Oracle • Oracle Spatial DISJOINT search/filtering • Creating SDO_Geometry from geometric data recorded in the columns of a table • Concave Hull Geometries in Oracle 11gR2 • Projecting SDO_GEOM_METADATA DIMINFO XY ordinates • Instantiating MDSYS.VERTEX_TYPE • New PL/SQL Packages - Rotate oriented point • GeoRaptor Development Team • Fast Refreshing Materialized View Containing SDO_GEOMETRY and SDO_GEOM.SDO_AREA function • Performance of PL/SQL Functions using SQL vs Pure Code • Implementing the BEST VicGrid Projection in Oracle 10gR2 • Making Sdo Geometry Metadata Update Generic Code • ORA-13011 errors when using SDO_GEOM.VALIDATE_LAYER_WITH_CONTEXT() • Extract Polygons from Compound Polygon • Detecting sdo_geometries with compound (3-point Arcs) segments • GEOMETRY_COLUMNS for Oracle Spatial • Convert GML to SDO_Geometry in Oracle 10gR2 • Spatial Sorting of Data via Morton Key • Swapping Ordinates in an SDO_GEOMETRY object • New To_3D Function • Extend (Reduce/Contract/Skrink) Function for Oracle • Loading and Processing GPX 1.1 files using Oracle XMLDB • Loading Spatial Data from an external CSV file in Oracle • Calling the Oracle Spatial shapefile loader from within the Oracle database itself • Converting Google Earth Formatted Longitude/Latitude points to decimal degrees • Implementing SDO_VertexUpdate/ST_VertexUpdate for Oracle • Implementing SDO_RemovePoint/ST_RemovePoint for Oracle • Implementing SDO_AddPoint/ST_AddPoint for Oracle • ESRI ArcSDE Exverted and Inverted Polygons and Oracle Spatial • Funky Fix Ordinates By Formula • Implementing a SetPoint/ST_SetPoint function in Oracle • Implementing an ST_SnapToGrid (PostGIS) function for Oracle Spatial • Generating random point data • Implementing an Affine/ST_Affine function for Oracle Spatial • Implementing a Scale/ST_Scale function for Oracle Spatial • Implementing a Parallel/ST_Parallel function for linestring data for Oracle Spatial • Implementing a Rotate/ST_Rotate function for Oracle Spatial • Limiting table list returned when connecting to Oracle Database using ODBC • Filtering Rings (Oracle Spatial) • ST_Azimuth for Oracle: AKA Cogo.Bearing • Implementing a Translate/ST_Translate/Move function for Oracle Spatial • Elem_Info_Array Processing: An alternative to SDO_UTIL.GetNumRings and querying SDO_ELEM_INFO itself • Minumum Bounding Rectangle (MBR) Object Type for Oracle • How to extract elements from the result of an sdo_intersection of two polygons. • How to restart a database after failed parameter change • Fixing failed spatial indexes after import using data pump • generate_series: an Oracle implementation in light of SQL Design Patterns • Multi-Centroid Shootout • Oracle Spatial Centroid Shootout • On the use of ROLLUP in Oracle SELECT statements • Surrounding Parcels • Spatial Pipelining • Using Oracle's SDO_NN Operator - Some examples • Converting distances and units of measure in Oracle Locator • Split Sdo_Geometry Linestring at a known point • Forcing an Sdo_Geometry object to contain only points, lines or areas • Unpacking USER_SDO_GEOM_METADATA's DIMINFO structure using SQL • Generating multi-points from single point records in Oracle Spatial • Object Tables of Sdo_Geometry • Oracle Locator vs Oracle Spatial: A Reflection on Oracle Licensing of the SDO_GEOM Package • FAST REFRESHing of Oracle Materialized Views containing Sdo_Geometry columns • Australian MGA/AMG Zone Calculation from geographic (longitude/latitude) data • Loading Shapefiles (SHP) into Oracle Spatial • Oracle Spatial Mapping and Map Rendering Performance Tips • The significance of sdo_lb/sdo_ub in USER_SDO_GEOM_METDATA: Do I need it? • Oracle Spatial Forum - Melbourne April 2007 • Layer_GTypes for spatial indexes • Oracle's SQL/MM Compliant Types • Tips and Tricks
|
This little article was occasioned by someone emailing me and asking:
Well, there is nothing to be embarrassed about because you did this before you had Oracle Spatial (actually all the functionality used below is available to Locator users – thanks Oracle)! What I will do is outline the Oracle functionality that can do what the person wanted and give a practical example I used recently to solve a particular problem. First off the function we need in Oracle is the SDO_NN spatial operator. (My preference for everything I do in Oracle is to try and push as much processing into a SQL statement before launching into PL/SQL ie programming.) The Oracle documentation on SDO_NN is quite thorough so I recommend that you read it in consort with this article: For example, the only thing I will say say about the SDO_NN_DISTANCE ancillary operator (used in the first example) is that it returns the actual distance Oracle computed between the searched for object and the search object supplied to the SDO_NN operator. The examples below will clarify its use. For a detailed discussion on the operators read the documentation. For now, I will limit myself to a few comments and examples. SDO_BATCH_SIZE vs SDO_NUM_RES One of the first things to understand is use of the sdo_batch_size and sdo_num_res parameters. (Again the documentation is quite thorough on these parameters.) simply returns exactly N nearest objects to the search object. So, in the example that follows the nearest object only is returned.
(The script to create the STORE table can be accessed here.) Note that the store is a SHOE store. Let’s “widen” the search a little (note the use of the ORDER BY clause):
So, what if we only want the nearest three SHOE stores to our search point? Can we just add the “storetype = ‘SHOE’”?
No this will not do what we want. Why? Because the sdo_num_res parameter returns the objects based on their geometry not their attributes: the 5 stores returned by SDO_NN with sdo_num_res=5 are the 5 nearest. No more are returned. These 5 objects are then passed to the added predicate resulting in only 2 of the 5 passing the test. Can we move the predicate around? No because the SDO_NN will still only return the same 5 objects to the SELECT statement. We have to find a way to increase the set that can be returned by SDO_NN. Why not just increase the sdo_num_res to, say, 10?
Yes, it works, but it is subject to one guessing a value for sdo_num_res that will work in all cases. For example, sdo_num_res=10 does not work for COMPUTER stores:
See, we only got two! Sure, we would increase the sdo_num_res batch size again but we are playing a guessing game. This is why the sdo_batch_size parameter exists. It exists, as the documentation says,“If any geometries in the table might be nearer than the geometries specified in the WHERE clause”. We know SHOE stores in the table are nearer than our COMPUTER stores but it is COMPUTER stores that we want.
A correct result. I will leave you to read up on sdo_batch_size parameter value setting in the documentation. How do we find the 3 nearest SHOE stores to every SHOE store in the STORE table? As follows?
Anyone spot the error? The rownum < 4 is applied to the final rowset and not to each s.store and its 3 nearest neighbours! What we need to do is order the query such that the rownum test is applied to the neighbours of each and every store. One way to do this is via a correlated subquery as follows:
A correct result. Note: Because of limitations with returned values from correlated sub-queries, we cannot access any sdo_nn_distance() values so we simply use the sdo_geom.sdo_distance function to get out required distance. If I can come up with a better query (or perhaps my readers may have a better approach) I will amend this blog posting. Quality of Returned Distance What I want to turn to the types of distances SDO_NN calculates. It is an approximation to the actual geometric distance done so that the speed of the SDO_NN operator remains fast (which it is) through mainly RTree processing or is it computed by looking at the actual geometries? All I will do is conduct a very simple test using a point and a line. In the Codesys.ProjLine2D table there is a simple, straight line geometry with linetype of ‘STRAIGHTVERTEX’ as follows:
You will note that it is a horizontal line of length 60,000 meters. If I search this feature using two points to show that the SDO_NN distance calculation is quite accurate.
So, SDO_NN must look at the geometries of the objects it deals with to calculate its distances and not rely on MBRs and object vertices. Hints You will have noted that that all the queries above that involve a single table require no hints (as expected). However, the query against the two STORE tables above used the ORDERED and USE_NL (USE_Nested_Loops) hints. Why is this? Occasionally, queries just won’t run. For example, here is a query that does not work for the data I ship with my free PL/SQL packages on the copy of XE (10gr) I am running:
I have note that this can happen where a non-spatial attribute used in a predicate has its own index (and sometimes not). This issue is documented in the Spatial Operators chapter of the Oracle Spatial documentation and also in the excellent book Pro Oracle Spatial. The recommended solution is to include hints. Sometimes adding the /*+ORDERED*/ hint on its own can work but in other cases not. The ones recommended in the book involve knowing about the name of the RTRee and ordinary indexes over the CODESYS.PROJLINE2D table (/*+INDEX*/). Similarly for the documentation though it does suggested the LEADING hint in cases involving a join between the two tables in the FROM clause used in the SDO_NN operator. I have found that, at times, the ORDERED, INDEX and NO_INDEX hints are not enough: I have had to specify the LEADING or USE_NL (USE_Nested_Loops) hints as in the following examples:
You should read the documentation and be prepared to experiment with different hints. A Real Example Finally, I thought I would leave you with a real example derived from something I had to do for a customer recently. What we will do is find the nearest vertex-to-vertex segment (greater than 5 meters in length) of a land parcel polygon to a road centreline with the same name. Here is a picture of some data and a road centreline. Note that the distance to the road centreline will be the same for a parcel side boundary where it joins a front boundary as both share the same (corner) vertex. To get around this we will use the mid-point of each segment.
The identifiers of the hightlighted land parcels are: oid in ( 26388, 26386, 26387, 26392, 26390, 26391, 26389 ) Here is a query that achieves what we want to do.
But we want the nearest vector for each OID. The SQL is:
Finally, while we could use the MIN function with an appropriate GROUP BY clause to return the vector with the minimum distance to the road centreline, we cannot easily return the midpoint of the nearest vector of each OID using these operators. To do so requires some tricky SQL using a rank/partition analytic to find the first vector whose distance to the road centreline is the minimum of all vectors that make up any one land parcel (rank = 1). Here is the final result.
Mapping these midpoints (large gray circles) produces the following.
Given Thomas’s comments below I thought I would show an image of the solution I created from a new algorithm that is much improved algorithm over the one above. Here the requirement is to place a centroid point 3 meters inside the road boundary of a land parcel: if possible the centroid should be in the middle of the road frontage. If anyone is interested in using this algorithm (encapsulated inside a fairly short PL/SQL Procedure), please contact me, but generally the algorithm:
Here is the finaly image after processing (I know it is a bit garish but I have deliberately coloured the parcel and road centrelines by their road name to show how the algorithm correctly finds the land parcel frontage closest to its named road).
If you reached the end of this article, thanks for persevering with the material. I hope you got something out of it. ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]()
![]()
![]() |
Comment [5]
Thanks the article was very enlightening.I have a question though, is there any way of doing what you have done using SQL2008.what spatial function would be equivalent to the oracle SDO_NN.I have a tracking system running on SQL2008 and using Navteq RDF data.I would like to be able to get a location and its speed limit given GPS coordinates.Thank you
— Doreen · 26 September 2008, 19:13 · #
Here is one way to do a nearest neighbour search in SQL Server 2008. If I get time I will investigate faster, more flexible methods.
SELECT TOP 5 g1.id, g3.id As nn_id, g3.geom.STDistance(g1.geom) as dist FROM (SELECT TOP 100 id,geom FROM dbo.my_points ORDER BY id) g1 CROSS APPLY (SELECT g2.* FROM dbo.my_points As g2 WHERE g1.id <> g2.id AND g2.geom.STIntersects(g1.geom.STBuffer(300)) = 1) g3 ORDER BY g3.geom.STDistance(g1.geom);
I hope this helps.
regards
Simon
— Simon Greener · 14 November 2008, 10:27 · #
Simon – great article, I’ve been looking at implimenting something along these lines to automatically generate the locations of street address points. One thing that I’ve noticed is that unlike your example we have a lot of parcels that the frontage is made up of a ‘densified arc’ or that plus a ‘straight’ line segment – is there a simple way to select the largest segment in the parcel_vector to determine the required midpoint?
— Thomas Baxter · 25 March 2009, 09:34 · #
Simon,
Great article, the best I’ve seen that clearly explains this subject – especially to me, a novice on the subject.
My question is: I’ve created a table of lat/long sdo_geometry points that list the N/S/E/West points in a zipcode. I want the distince from N to S, E to W. My query doesn’t work though, I get the Ora-13249 error.
Here is the simple query:
select ZIP5,zip4,north,south, sdo_nn_distance (1) distance
from zip4_bounds
where zip5=‘01001’ and zip4=‘1717’ and
sdo_nn (south, north,‘unit=mile sdo_num_res=1’, 1) = ‘TRUE’
I’m basically trying to find the distance from North to South in zip 01001-1717, both geo fields stored on 1 row. It keeps failing though. Can this even be done? On the few occasions I get this working with 2 tables, the results are scattered and incorrect. Very strange.
Thanks,
Dan
— Dan Ostertag · 31 October 2009, 08:20 · #
Simon,
Could you give mo more details how to create the point 3 meters inside the boundary ?
— Kamil Frymus · 8 December 2009, 23:22 · #