8

I'm trying to validate the topology of a shapefile. I managed to repair cases of overlap and gaps, but i can't resolve cases of spikes. The image shows one example of this situation.

enter image description here

I used the comand:

SELECT geom,
ST_Buffer(  ST_Buffer(  ST_Buffer(geom,0.00001, 'join=mitre'),-0.00002,                           
'join=mitre'),0.00001, 'join=mitre') AS geom_spike_removed
FROM repaired_polygons;

it works fine to remove the spikes, but changes the original form of the polygon. Comparing area and perimeter before and after, we can see that the perimeter changes because there is no more spikes, and the difference on area it's not absurd, but anyway it changes a little the geometry of the polygons, causing new cases of small overlaps and small gaps.

How can i remove this spikes without changing the original geometry of the polygon? Any suggestions?

3
  • does your spike have a width ? I would expect a large difference for the perimeter, but a very small one for the area. Also why do +1/-2/+1 and not -1/+1 with your buffer ?
    – radouxju
    Commented Dec 15, 2015 at 20:40
  • You are right, after running the buffer process the difference in the perimeter is significant, because there is no more spikes and that's ok. The difference in the area it's not huge, but is not zero too, that's my goal.
    – Roberto
    Commented Dec 16, 2015 at 12:35
  • 2
    you could also try ST_buffer -0.001/+0.002, then ST_intersect with the original. The original geometry will then be unchanged, but you will have a remain of your spike (length ~0.001)
    – radouxju
    Commented Dec 16, 2015 at 12:50

2 Answers 2

11

Here is a link to my PL/pgSQL function which does exactly what the OP is asking for: removing spikes from polygons and linestrings.

Here you can download it and read the documentation: PostGIS NormalizeGeometry.


As suggested in the comments, here is an example:

WITH temp (wkt) AS (
    VALUES
        ('LINESTRING(0 0, 2 2, 0 4, -5 4, 0 4.001, 2 6)'),
        ('POLYGON((0 0, 1 1, 2 1, 3 0.5, 2 -3, 3 0.499, 0 0))')
)
SELECT ST_AsText(normalize_geometry(ST_GeometryFromText(wkt), 0.5, 0.5, 0.005, 0.0001)) 
FROM temp;

-- Output
  LINESTRING(0 0, 2 2, 0 4, 2 6)
  POLYGON((0 0, 1 1, 2 1, 3 0.5 ,0 0))

Before:

Before

After:

After

4
  • 2
    Looks like a really good function. Maybe add an example of its use in your answer? This will make the answer more relevant to later interested users. Commented Jun 3, 2016 at 8:17
  • Thanks, I've just added an example. You can find a detailed explaination and more examples in the official documentation page. Cheers.
    – Eggplant
    Commented Jun 3, 2016 at 9:41
  • @Eggplant, this is great. But the spike, in general, is not a line, it has some small area. Once you remove it you know have a sliver between the neighboring polygons. Do you have a good solution to fill that? Commented Jul 17, 2018 at 17:10
  • @LucasMation We've been using this function in my Company for years and this is actually the typical use case. Those "sliver" or small holes" between polygons can be of 2 different kinds: 1) A removed spike protruding from a polygon corresponds to an "inner spike" inside another: this is fixed applying normalize_geometry to both of them. 2) An tiny "empty" area is created: decide which polygons are "more important" (eg. the biggest), extend them using a buffer and cut them on the neighbors boundaries (removing the part that intersects with surrounding polygons). WITH RECURSIVE comes in handy.
    – Eggplant
    Commented Jul 18, 2018 at 7:46
5

Someone may chime in with a more sophisticated, purpose-built solution, but to start I'd try generalizing your polygons. The Visvalingam-Whyatt algorithm is a very intuitive one, especially in this application. If you imagine that each vertex forms a triangle with its neighbors to either side, you call the algorithm by specifying the maximum triangle area that you wish to remove. The other vertices in your polygon will remain untouched.

The Visvalingam-Whyatt algorithm is available in PostGIS 2.2 (docs). You may be able to remove your spikes by calling ST_SimplifyVW with an small tolerance parameter.

You could also try experimenting with ST_SimplifyPreserveTopology (docs), which uses a modified Douglas-Peucker algorithm. The "preserve topology" bit means that it won't introduce self-intersections in your polygon, but it operates on one geometry at a time and may still cause gaps or overlaps between adjacent polygons.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.