[postgis-users] ST_CreateTopoGeo

paul.malm at lfv.se paul.malm at lfv.se
Fri Feb 28 04:29:49 PST 2020


Hi again,
I can see in the edge data of topo2 that the main polygon of Egypt intersects with an island next to the main polygon. If I delete the island in the original layer before running the SQL sequence the main polygon of Egypt is included in the result layer. Is there any solution of this problem?

Kind regards,
Paul

-----Ursprungligt meddelande-----
Från: postgis-users [mailto:postgis-users-bounces at lists.osgeo.org] För Malm, Paul (Operations AIM)
Skickat: den 28 februari 2020 11:36
Till: postgis-users at lists.osgeo.org; strk at kbt.io
Ämne: Re: [postgis-users] ST_CreateTopoGeo

Thanks, Sandro!
It worked with your LOOP! Great!
The problem I can see on the result (I'm simplifying country polygons) is that the large polygon of Finland, Germany, Italy and Egypt is missing.
I've tried to change the different tolerances (Simplify tolerance and your loop snap-tolerance). If I use simplifying tolerance 2500 m the missing polygons are there, but not when using 5000 m. The countries included in the  original layer is from Sweden, Norway and Finland down to Jordan, Egypt, Libya and Tunisia.
Ref sys =WGS 84_UTM-33N


If you have the time and want to look at the SQL sequence, here it is;
Thank you,
Paul

CREATE TABLE "simple_countries2nd" as (
       SELECT "NAME_ZH", "OGR_STYLE", fid, (st_dump(the_geom)).*
       FROM "countries2nd");

CREATE INDEX "simple_countries2nd_geom_gist" ON "simple_countries2nd" USING gist(geom);

ALTER TABLE "simple_countries2nd" ADD COLUMN simple_geom geometry(POLYGON, 32633);

SELECT topology.CreateTopology('topo1', 32633);

DO $$
DECLARE
  rec RECORD;
BEGIN
  FOR rec in SELECT "NAME_ZH", "OGR_STYLE", "fid", (ST_Dump(the_geom)).geom FROM "countries2nd"
  LOOP
    BEGIN
      IF GeometryType(rec.geom) = 'POLYGON' THEN
         PERFORM topology.TopoGeo_AddPolygon('topo1', rec.geom, 400);
      ELSIF GeometryType(rec.geom) = 'LINESTRING' THEN
        PERFORM topology.TopoGeo_AddLinestring('topo1', rec.geom, 400);
      ELSIF GeometryType(rec.geom) = 'POINT' THEN
        PERFORM topology.TopoGeo_AddPoint('topo1', rec.geom, 400);
      END IF;
    EXCEPTION WHEN OTHERS THEN
      RAISE WARNING 'For geometry % we got exception % (%)', rec.id, SQLERRM, SQLSTATE;
    END;
  END LOOP;
END;
$$ LANGUAGE 'plpgsql';

SELECT topology.CreateTopology('topo2', 32633);

SELECT topology.ST_CreateTopoGeo('topo2', "the_geom")
FROM (
       SELECT ST_Collect(st_simplifyPreserveTopology(geom, 5000)) as "the_geom"
       FROM topo1.edge_data
) AS foo;
						 
with simple_face AS (
       SELECT topology.st_getFaceGeometry('topo2', face_id) as "the_geom"
       FROM topo2.face
       WHERE face_id > 0
) UPDATE "simple_countries2nd" d SET geom = sf."the_geom"
FROM simple_face sf
WHERE st_intersects(d.geom, sf."the_geom")
AND st_area(st_intersection(sf."the_geom", d.geom))/st_area(sf."the_geom") > 0.5;
	

-----Ursprungligt meddelande-----
Från: postgis-users [mailto:postgis-users-bounces at lists.osgeo.org] För Sandro Santilli
Skickat: den 25 februari 2020 15:38
Till: PostGIS Users Discussion
Ämne: Re: [postgis-users] ST_CreateTopoGeo

On Tue, Feb 25, 2020 at 01:22:39PM +0000, paul.malm at lfv.se wrote:
> Hi,
> Where do you mean I can play with the tolerance?

In TopoGeo_addLinestring
https://postgis.net/docs/manual-3.1/TopoGeo_AddLineString.html

> This is what I have done before the ST_createTopoGeo
> SELECT topology.CreateTopology('topo1', 4326)";
> SELECT topology.ST_CreateTopoGeo('topo1', ST_Collect(geom)) from "countries_first";
> Btw, I'm intending to simplify later on in my SQL command list.

You could do something like this:

  DO $$
    DECLARE
      rec RECORD;
      tol FLOAT8;
    BEGIN
      tol := 0;
      FOR rec in SELECT gid, (ST_Dump(geom)).geom FROM countries_first
      LOOP
        BEGIN
          IF GeometryType(rec.geom) = 'POLYGON' THEN
            PERFORM topology.TopoGeo_AddPolygon('topo1', rec.geom, tol);
          ELSIF GeometryType(rec.geom) = 'LINESTRING' THEN
            PERFORM topology.TopoGeo_AddLinestring('topo1', rec.geom, tol);
          ELSIF GeometryType(rec.geom) = 'POINT' THEN
            PERFORM topology.TopoGeo_AddPoint('topo1', rec.geom, tol);
          END IF;
        EXCEPTION WHEN OTHERS THEN
          RAISE WARNING 'For geometry % we got exception % (%)', rec.id, SQLERRM, SQLSTATE;
        END;
      END LOOP;
    END;
  $$ LANGUAGE 'plpgsql';

You can tweak the above to do something different rather than raising
a WARNING (for example store ID of offending geoms in a table).
Then you can look at the offending geometries in isolation, possibly
tweaking the "tol" variable.

--strk;
_______________________________________________
postgis-users mailing list
postgis-users at lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/postgis-users
_______________________________________________
postgis-users mailing list
postgis-users at lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/postgis-users


More information about the postgis-users mailing list