[postgis-users] Topology: cannot delete slivers (or gaps)

Sandro Santilli strk at keybit.net
Wed Nov 5 03:03:25 PST 2014


On Tue, Nov 04, 2014 at 03:08:15PM -0800, Guillaume Drolet wrote:

> But because I'm stubborn and never give up, I still want to succeed on
> fixing TopoGeometry objects in PostGIS (bear with me, what follows is a bit
> long):

I like you ! :)

> First, I looked at faces NOT taking part in the composition of any
> TopoGeometry object:
> 
> /SELECT face_id FROM de_20k_topo.face WHERE face_id NOT IN (SELECT
> element_id
> 		                                                                       
> FROM de_20k_topo.relation);/
> face_id
> 0
> 2418
> 2650
> 2663
> 2766
> 3077
> 3118
> 3146
> 3267
> 3270
> 
> None of these 10 faces are involved with my three remaining slivers... And
> when I look at them, they ARE related to edges, as a next_face or a
> right_face. Is there any useful information in that for my purpose?

Except face 0, which is the "universe" face, all the others
should be "gaps" in your topology. You can zoom to the face's
bounding box ("mbr" field) to take a closer look (do you have qgis
set up by now?).

What you could do programmatically is for each face to fetch the list
of edges bounding it and pick the face on the other side as a candidate;
then for each candidate face you find TopoGeometry objects containing
it in their definition and pick one to assign that orphaned face
(you could use smaller TopoGeometry, or larger, or whatever).

It might be better first to deal with the faces that are associated
with multiple TopoGeometry, just to avoid assigning an orphaned face
to a TopoGeometry based on it's containing a face which will later
be removed from the definition because duplicated.

> Second, I tried to work along the lines suggested by Sandro, using a new
> topology (tolerance 2.0 m). As in one of my previous attempts, I
> successfully fixed 20 of the 23 slivers using ST_RemEdgeModFace. For the
> remaining three slivers, however, I tried modyfying TopoGeometry objects but
> with no success. I must admit I'm a bit lost and not too sure if I really
> understand what TopoGeometry objects are:

Eh, that part is a still a bit weak in documantation, maybe.
A TopoGeometry is a Geometry defined by its components.

In your case (areal TopoGeometry objects) it is a (multi)Polygon
defined by a set of faces. Note that QGIS is also able to
show you the TopoGeometry objects, and lets you edit them "spatially"
(less robust than editing them by adding/removing components but with
some care easier to use).

> For example, let's look at problematic face_id: 2227
> (https://dl.dropboxusercontent.com/u/5196336/example_2227.bmp). In this
> case, the light grey line is where a single edge should be. Blue edges 6381
> and 6341 should not be there. The light grey line should start from the node
> at the bottom right and connect at its other end somewhere in the middle of
> edge 6340:

Uhm, edge identifiers are missing from that dump.
I take it 6381 is the lower blue and 6341 the upper blue.

> I thought, let's first remove edge 6346, which should not exist in the first
> place, and then split edge 6340 with a node and connect it to node 4753 on
> the lower right corner of the image:
> 
> SELECT ST_RemEdgeModFace('de_20k_topo', 6346); 
> 
> As in my previous post, this yields:
> 
> ERROR:  TopoGeom 1546 in layer 1 (syshiera.de_20k.topogeom) cannot be
> represented healing faces 2225 and 2227

I take it that edge 6346 is the one on the right of the yellow face.
The message is telling you that a TopoGeometry object exists (id=1546)
that is composed only by one of the two faces 2225 and 2227.

I suggest you load the TopoGeometry layer with qgis and see for yourself.
Unfortunately (that'd be useful to add in qgis) it won't be easy to
find TopoGeometry 1546 as extracting the id of a TopoGeometry requires
running an expression on the database: id(topogeom).

You could create a view selecting just that topoGeometry, or a subset
of them, or you could just load them all, hoping it won't be too expensive
(another spot where qgis support for postgis topology could be improved).

Chances are it would be enough to assign face 2227 to the TopoGeometry
with id 1546 (likely the one not-assigned). But as face 2227 was not
in your initial set (unassigned faces) I guess there's another TopoGeometry
which does have 2227 in his definition, but not the one on the right.
In that case you have to pick which of the two contending TopoGeometry
objects should get face 2227 assigned, before you drop it. Basically, which
TopoGeometry will get assigned the space occupied by that face.

Given QGIS editing support for TopoGeometry objects you should be able
to see all of this by loading the layer and setting 50% transparency.
Enabling topological editing and editing those two TopoGeometry objects
should help you with manual resolution of this issue.

> So I looked at TopoGeom 1546:
> 
> /SELECT * FROM de_20k_topo.relation WHERE topogeo_id = 1546;/
> 
> topogeo_id;layer_id;element_id;element_type
> 1546;1;2225;3
> 1546;1;2233;3
> 
> Edge 2227 is missing from TopoGeom 1546: Where is it?

You meant _face_ 2227.
Right, it's not assigned to TopoGeometry 1546,
but to another one.

> /SELECT * FROM de_20k_topo.relation WHERE element_id = 2227;/
> 
> topogeo_id;layer_id;element_id;element_type
> 1551;1;2227;3
>
> There it is, in TopoGeom 1551. What else is there:
> 
> /SELECT * FROM de_20k_topo.relation WHERE topogeo_id = 1551;/
> 
> topogeo_id;layer_id;element_id;element_type
> 1551;1;2225;3
> 1551;1;2234;3
> 1551;1;2227;3
> 
> So edges 2225 and 2227 are associated with TopoGeom 1551. Will change that:

Again, you mean faces (last number is element_type, 3==face).
So TopoGeometry objects 1546 and 1551 overlap, and their intersection
is the union of faces 2225 and 2227.

> UPDATE de_20k_topo.relation SET topogeo_id = 1546
> 	WHERE topogeo_id = 1551 AND element_id = 2227;/

There's already a record associating face 2227 with TopoGeometry 1546
so you don't need another record, just drop the one associating it
with TopoGeometry 1551:

  DELETE FROM de_20k_topo.relation 
  WHERE topogeo_id = 1551 AND element_id = 2227;

> And then again:
> 
> /SELECT ST_RemEdgeModFace('de_20k_topo', 6346); /
> 
> ERROR:  TopoGeom 1551 in layer 1 (syshiera.de_20k.topogeom) cannot be
> represented healing faces 2225 and 2227

Right, you only resolved the overlap of face 2227, but there's still
the overlap of face 2225 :)

  DELETE FROM de_20k_topo.relation 
  WHERE topogeo_id = 1551 AND element_id = 2225;

> Obviously, as mentionned above, I don't quite understand how TopoGeometry
> objects work and the link between TopoGeoms, geometries and primitives. I
> need a bit of education here.

It looks like you're on the right track so far.

> Thanks a lot for your patience and your help.

Thank you for your stubbornnes in using PostGIS Topology !

--strk; 

  ()   Free GIS & Flash consultant/developer
  /\   http://strk.keybit.net/services.html


More information about the postgis-users mailing list