3

I am new to the GIS world but I have experience in programming. I am trying to build an app where users draw circles on a leaflet map and it returns the zipcodes "touched", but I think the right term is overlapped, by the circles. I have a table in PostGIS where I have uploaded the US census zipcodes; the column to query is a geometry type which return something like this when transformed as GeoJSON:

{"type":"MultiPolygon","crs":{"type":"name","properties":{"name":"EPSG:4269"}},"coordinates":[[[[-64.903808,17.679739],[-64.903804,17.679763],[-64.903799,17.679801],[-64.903796,17.67988],[-64.903793,17.679919],[-64.903788,17.679997],[-64.90377,17.680077],[-64.903756,17.680154],[-64.903744,17.680199],[-64.903729,17.68024],[-64.9037,17.68031]...}

This is the table: enter image description here

And this is an example of the map with a circle drawn where I console log its radius and center coordinates (lat, lng):

enter image description here

So far I have tried this query:

SELECT * 
FROM tl_2019_us_zcta510 AS b
WHERE ST_DWithin(b.geom,
  ST_Transform(
    ST_SetSrid(
      ST_MakePoint(lat_from_leaflet,lng_from_leaflet)
      ,4269)
    ,4269)
,radius_from_leaflet);

This isn't returning the correct zipcodes because when I try with a small circle, for example, it doesn't return any row, but I am expecting at least one row.

1
  • 1
    Geometry is created {X,Y} and latitude is a Y. It should be {lon,lat}
    – Vince
    Commented Mar 30, 2023 at 15:48

1 Answer 1

2

Two issues:

  • almost everywhere in OGC supported environments, coordinate order is {X, Y} | {lon, lat}
  • your radius seems to be given in meter, while ST_DWithin (as almost all functions in PostGIS) assume the primary unit of the CRS of the given geometry - which is degree for EPSG:4269! In order to calculate proximity with meter as reference unit you'd need to either use a suitable projection, or the GEOGRAPHY type with a defined geographic CRS; I assume here that the input values are referenced in EPSG:4326:
    SELECT
      *
    FROM
      <table> AS t
    WHERE
      ST_DWithin(
        t.geom::GEOGRAPHY(GEOMETRY, 4269),
        ST_Transfrom(ST_SetSRID(ST_MakePoint(<lon>, <lat>), 4326), 4269)::GEOGRAPHY(GEOMETRY, 4269),
        <radius_in_meter>
      )
    ;
    
    You'd want to have this covered by an appropriate index:
    CREATE INDEX ON <table> USING GIST (( geom::GEOGRAPHY(GEOMETRY, 4269) ));
    
7
  • Thank you so much for your help! When I try to run the query I get this error: ERROR: Invalid geometry type modifier: 4269 LINE 7: t.geom::GEOGRAPHY(4269), ^ SQL state: 22023 Do you have any advise how to debug this?
    – RmCs
    Commented Mar 30, 2023 at 17:45
  • @RmCs Try adding the geometry type, e.g. GEOGRAPHY(POINT, 4269)
    – geozelot
    Commented Mar 30, 2023 at 17:52
  • I tried this: SELECT * FROM tl_2019_us_zcta510 AS t WHERE ST_DWithin( t.geom::GEOGRAPHY(POINT, 4269), ST_Transfrom(ST_SetSRID(ST_MakePoint(-73.94633531570436, 40.787819679697904), 4326), 4269)::GEOGRAPHY(4269), 162 ); but I got the same error. Do I need to install specific extensions? Many thanks!
    – RmCs
    Commented Mar 30, 2023 at 18:01
  • @RmCs you need to specify the geometry type in both casts; if you are not sure which type your data is, use the generic GEOMETRY type (this is not the data type GEOMETRY!) - see my updated query above. Here is a db<>fiddle showing some options for casts.
    – geozelot
    Commented Mar 30, 2023 at 19:50
  • It worked! Thank you so much! One last question: how should I update the indexing query? I tried this: CREATE INDEX us_zcta_index ON tl_2019_us_zcta510 USING GIST (geom::GEOGRAPHY(GEOMETRY, 4269); but I got this error ERROR: syntax error at or near "::" LINE 3: USING GIST (geom::GEOGRAPHY(GEOMETRY, 4269);
    – RmCs
    Commented Mar 31, 2023 at 15:16

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.