[postgis-users] Landtype minus parcels ?

Brian Hamlin maplabs at light42.com
Sat Feb 18 17:56:25 PST 2012


Hi Birgit-

   thank you for the reply.. I admit that I have not compared your  
solution to my own carefully,
but instead have written a lot more code, and solved the problem.

   using psycopg2 and python's threading and Queue , I built a multi- 
core parallel version.
Since the logic loops through each large landtype geometry, and  
INSERTs the results
into one table, it is naturally parallelizable.  The psuedo-code goes  
something like this:

tSQL_primediff =
     INSERT into destination_table
       SELECT desired_fields,
          CASE when st_difference(
               landtype_poly, parcels
           ) is null then landtype_poly
          ELSE st_difference(
               landtype_poly, parcels )
          END as tgeom
FROM
     landtype_poly  INNER JOIN parcels
      ON st_intersects( landtype_poly, parcels)
WHERE
      landtype_poly id = tIND
GROUP BY
     landtype_poly id, landtype_poly

##---------------------------------------------
create a thread_UnitofWork subclass
     def run()
          get an id_start, id_end from queue msg
          SELECT landtype IDs >= start && <= end
          for each ID:
               cursor.execute(  tSQL_primediff )

          conn.commit()
          thread.done()

##----------------------------------------------------
      build a Queue
      SELECT landtype_id ORDER BY landtype_id
      count them and decide on a division per thread

      for the number of threads:
          build a queue entry
          fire the thread task

     wait for all threads to complete
###-------------------------------------------------------------
## last trick

tSQL_pre =
     SELECT lt_id FROM landtypes
       LEFT JOIN result_table  ON (lt_id = res.id )
     WHERE
        id_lt == NULL

tSQL_test =
    SELECT
       parcels_id
    FROM
       landtypes INNER JOIN parcels
         ON st_intersect( landtype, parcel)
    WHERE
         landtype_id = tIND

tSQL_alt =
     INSERT into result_table
      SELECT desired_fields, geom
      FROM landtypes
      WHERE landtypes_id = tIND


execute tSQL_pre, get a list of IDs
for each ID
    execute tSQL_test
    if  len(result_list) > 0: continue

    execute tSQL_alt  ## copy whole landtype into result

##----
the reason for this last step is that the way the program ran,
if a landtype was not at all touching any parcels, it was not copied
but you do not want to copy landtypes that were completely covered..

So you get the difference of landtype IDs in the input, and the ones  
that were
copied to the result, and check each one for the number of  
intersections of parcels.
Only if there were no intersections of parcels to that landtype, copy  
it to the result.

##-----
the final program uses 12 cores on a 16 core linux machine,  
processing sets of
landtypes in parallel.. It runs quite quickly on approximately  
850,000 parcels
against 14,000 landtype polys.

   thanks for the pointers and guidance.. perhaps I will get a chance  
to clean this up
at some later date..

==
Brian Hamlin
GeoCal
OSGeo California Chapter
415-717-4462 cell





On Feb 15, 2012, at 12:00 PM, postgis-users- 
request at postgis.refractions.net wrote:

>
> Message: 19
> Date: Wed, 15 Feb 2012 10:04:01 +0100
> From: Birgit Laggner <birgit.laggner at vti.bund.de>
> Subject: Re: [postgis-users] Landtype minus parcels ?
> To: PostGIS Users Discussion <postgis-users at postgis.refractions.net>
> Message-ID: <4F3B7501.2040000 at vti.bund.de>
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
>
> Hi Brian,
>
> you could try this query:
>
> SELECT st_difference(l.wkb_geometry,
>           case when st_union(p.wkb_geometry) is null
>             then st_collect(p.wkb_geometry)
>             else st_union(p.wkb_geometry)
>           end)
>         as tgeom
> from
>    big_landtypes l
>    inner join
>    small_parcels p
>    on st_intersects(l.wkb_geometry, p.wkb_geometry)
> where l.pkey = 1
> group by l.pkey, l.wkb_geometry;
>
> You are getting more than one result per landtype geometry because  
> they
> intersect with more then one parcel geometry. For each intersect case
> there is a result row. You are unioning all parcel geometries which  
> are
> anywhere intersecting any landtype geometry, which is probably  
> resulting
> in a big geometry. I would assume, the proposed query would do better,
> but you would have to try :-) I also added a CASE WHEN with st_collect
> as an alternative for st_union, because, sometimes st_union fails and
> results in a NULL geometry. In this case st_collect could take over  
> and
> as for the st_difference, st_union or st_collect have the same impact.
>
> Hope that helps,
>
> Birgit.
>
>
>
> Am 14.02.2012 20:42, schrieb Brian Hamlin:
>> SELECT distinct on (tgeom)
>>      st_difference(
>>        l.wkb_geometry,
>>
>>        (select st_union(p.wkb_geometry )
>>        from
>>          big_landtypes l,
>>          small_parcels p
>>        where st_intersects(
>>          l.wkb_geometry, p.wkb_geometry) AND
>>          l.pkey = 1)
>>        ) tgeom
>>      FROM
>>        big_landtypes l,
>>        small_parcels p
>>      WHERE
>>        l.pkey = 1
>>      ORDER BY
>>        tgeom;
>




More information about the postgis-users mailing list