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)
A simple spike finder for Spatial
This is an old article that uses older custom code e.g. Vector2Geom(). Because the principles in the code are correct, I will bring the code up to date if anyone shows any interest.
When investigating geometric or topological errors for linear or polygonal geometry objects, a range of tools are needed. Oracle has basic tools which can be used as the building blocks for additional tests. These are:
One test that is not clearly provided for is the discovery of “spikes” in the linestring defining an outer or inner ring of a polygon (or any linestring).
Dictionary definitions of a spike include:
noun
1. a nail-like fastener, 3 to 12 inches (7.6 to 30.5 cm) long and proportionately thicker than a common nail, for fastening together heavy timbers or railroad track.
2. something resembling such a nail; a stiff, sharp-pointed piece or part: to set spikes in the top of a cement wall.
3. a sharp-pointed piece of metal set with the point outward, as on a weapon.
4. an abrupt increase or rise: a chart showing a spike of unusual activity in the stock market; a sudden spike of electrical current.
5. a rectangular or nail-like metal projection on the heel and sole of a shoe for improving traction, as of a baseball player or a runner.
…
9. a pointed portion of a continuous curve or graph, usually rising above the adjacent portion: a spike in the value of the voltage.
Applying these to geographic/geometric linear objects we could say that a “spike” is:
is a sharp, abrupt and narrow deviation from the normal course of a linestring
Graphically:
How can we detect spikes?
One simple (the point of this article) method for finding a spike is to see if the gap between the two “vectors” that compose the spike collapse at the specified tolerance of a table’s geometry column (user_sdo_geom_metadata) causing a topological error (often 13349). Here are two examples of spikes.
| Spike 1 | Spike 2 |
|---|---|
|
|
A simple algorithm for finding spikes is to walk all the adjacent “vectors” of a linestring and send each pair into SDO_GEOM.RELATE with a “determine” mask. If the result is anything other than TOUCH we must have an error.
/** ----------------------------------------------------------------------------------------
* @function : FindSpikes
* @precis : Function that implements a simple "spike" finder.
* @version : 1.0
* @usage : SELECT b.* FROM test a, TABLE(FindSpikes(a.geom,0.005) b;
* @param : p_geometry : MDSYS.SDO_GEOMETRY : An sdo_geometry line or polygon object.
* @param : p_tolerance : NUMBER : Oracle sdo_tolerance value eg 0.005 meters for geodetic.
* @history : Simon Greener - October 2011 - Original coding.
* @copyright : Licensed under a Creative Commons Attribution-Share Alike 2.5 Australia License.
* http://creativecommons.org/licenses/by-sa/2.5/au/
**/
CREATE OR REPLACE
FUNCTION FindSpikes(p_geometry IN mdsys.sdo_geometry,
p_tolerance IN NUMBER DEFAULT 0.005)
RETURN CODESYS.SDO_ERROR.T_VectorSet pipelined
AS
v_vector CODESYS.t_vector;
v_vectors CODESYS.SDO_ERROR.T_VectorSet;
v_num_elements pls_integer;
v_element_no pls_integer;
v_element mdsys.sdo_geometry;
v_num_rings pls_integer;
v_ring_no pls_integer;
v_ring mdsys.sdo_geometry;
v_relate varchar2(100);
NULL_GEOMETRY EXCEPTION;
NOT_LINE_POLY EXCEPTION;
BEGIN
IF ( p_geometry IS NULL ) THEN
Raise NULL_GEOMETRY;
ElsIf ( p_geometry.get_gtype() NOT IN (2,5,3,7) ) THEN
RAISE NOT_LINE_POLY;
END IF;
-- Process Line/Multiline and Polygon/Multipolygon
--
v_num_elements := MDSYS.SDO_UTIL.GETNUMELEM(p_geometry);
<<Process_All_Elements>>
FOR v_element_no IN 1..v_num_elements LOOP
v_element := MDSYS.SDO_UTIL.EXTRACT(p_geometry,v_element_no,0);
IF ( v_element IS NOT NULL ) THEN
-- Polygons
-- Need to check for inner rings
--
IF ( v_element.get_gtype() = 3) THEN
-- Process all rings in this single polygon have?
v_num_rings := GetNumRings(v_element);
<<All_Rings>>
FOR v_ring_no IN 1..v_num_rings LOOP
v_ring := MDSYS.SDO_UTIL.EXTRACT(p_geometry,v_element_no,v_ring_no);
-- Now walk ring's vectors
--
IF ( v_ring IS NOT NULL ) THEN
-- Process 1st/2rd vectors looking for spike
SELECT CODESYS.T_Vector(v.id,V.Startcoord,V.Endcoord) AS vector
BULK COLLECT INTO V_Vectors
FROM TABLE(CODESYS.Sdo_Error.GetVector(v_ring)) V
ORDER BY v.id;
IF NOT ( V_Vectors IS NULL OR V_Vectors.COUNT = 0 ) THEN
FOR I IN V_Vectors.FIRST..V_Vectors.LAST Loop
IF ( i = V_Vectors.LAST ) THEN
v_vector := v_vectors(1);
ELSE
v_vector := v_vectors(i+1);
END IF;
-- Check if the interact in a way other than TOUCH
--
v_relate := mdsys.sdo_geom.relate(Vector2Geom(v_vectors(i),p_geometry.sdo_srid),
'DETERMINE',
Vector2Geom(v_vector,p_geometry.sdo_srid),p_tolerance);
IF ( v_relate <> 'TOUCH' ) THEN
PIPE ROW ( CODESYS.T_Vector(v_vectors(i).id,v_vectors(i).startCoord,v_vectors(i).endCoord) );
PIPE ROW ( CODESYS.T_Vector(v_vector.id,v_vector.startCoord,v_vector.endCoord) );
END IF;
END Loop;
END IF;
END IF;
END LOOP All_Rings;
-- Linestrings
--
ElsIf ( v_element.get_gtype() = 2) THEN
-- Process 1st/2rd vectors looking for spike
SELECT CODESYS.T_Vector(v.id,V.Startcoord,V.Endcoord) AS vector
BULK COLLECT INTO V_Vectors
FROM TABLE(CODESYS.Sdo_Error.GetVector(v_element)) V
ORDER BY v.id;
IF NOT ( V_Vectors IS NULL OR V_Vectors.COUNT = 0 ) THEN
FOR I IN V_Vectors.FIRST..(V_Vectors.Last-1) Loop
v_vector := v_vectors(i+1);
-- Check if the interact in a way other than TOUCH
--
v_relate := mdsys.sdo_geom.relate(Vector2Geom(v_vectors(i),p_geometry.sdo_srid),
'DETERMINE',
Vector2Geom(v_vector,p_geometry.sdo_srid),p_tolerance);
IF ( v_relate <> 'TOUCH' ) THEN
PIPE ROW ( CODESYS.T_Vector(v_vectors(i).id,v_vectors(i).startCoord,v_vectors(i).endCoord) );
PIPE ROW ( CODESYS.T_Vector(v_vector.id,v_vector.startCoord,v_vector.endCoord) );
END IF;
END Loop;
END IF;
END IF;
END IF;
END LOOP;
RETURN ;
EXCEPTION
WHEN NULL_GEOMETRY THEN
raise_application_error(c_i_null_geometry, c_s_null_geometry,TRUE);
RETURN;
WHEN NOT_LINE_POLY THEN
raise_application_error(c_i_not_line_poly, c_s_not_line_poly,TRUE);
RETURN ;
END FindSpikes;
Applying this function to the two spikes above we get.
| Linestring with Spike 1 | Linestring with Spike 2 |
|---|---|
|
|
I hope this is of use to someone.
Documentation
- GeoRaptor 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




