Encontrar la geometría más cercana en PostGIS

15

He estado revisando la "API" de funciones de PostGIS, y me doy cuenta de que la mayoría de ellas toman dos elementos para comparar. Por ejemplo, la función ST_Distance toma dos elementos de geometría / geografía para encontrar la distancia.

No hay ninguna función para hacer algo como: "Dada una geometría G, dame la geometría más cercana GClosest en la Tabla T donde G.id < > GClosest.id"

Me doy cuenta de que podría escribir una función PL / PgSQL para iterar sobre la tabla y llamar a ST_Distance en cada elemento, pero espero que haya una solución mejor y más eficiente.

    
pregunta Jmoney38 08.09.2011 - 21:47

2 respuestas

7

Su pregunta también puede responderse mediante una consulta única (aunque compleja) como la siguiente, que devuelve todo el registro y la distancia a la geometría de referencia. Tenga en cuenta que si más de un registro coincide con la distancia mínima, son todos devueltos.

SELECT 
  i.*,
  md.min_distance
FROM
  address AS i, 
  (SELECT 
     ga.address_geom,
     min( ST_Distance(
            ga.address_geom,
            gb.address_geom)
        ) AS min_distance
   FROM
     address AS ga,
     address AS gb 
   WHERE 
     ga.id <> gb.id 
   AND 
     ga.id = 3
   GROUP BY 
     ga.address_geom
  ) AS md 
WHERE 
  ST_Distance( i.address_geom, md.address_geom) = md.min_distance;

He probado esta consulta en la tabla de direcciones y funciona. En la consulta anterior, estoy buscando el punto más cercano a ese con id = 3.

    
respondido por el unicoletti 08.09.2011 - 22:31
8

George MacKerron ha escrito una función sencilla del vecino más cercano que he encontrado bastante útil . Esta función devuelve el ID del vecino más cercano a una función determinada:

create or replace function 
  nn(nearTo                   geometry
   , initialDistance          real
   , distanceMultiplier       real 
   , maxPower                 integer
   , nearThings               text
   , nearThingsIdField        text
   , nearThingsGeometryField  text)
 returns integer as $$
declare 
  sql     text;
  result  integer;
begin
  sql := ' select ' || quote_ident(nearThingsIdField) 
      || ' from '   || quote_ident(nearThings)
      || ' where st_dwithin($1, ' 
      ||   quote_ident(nearThingsGeometryField) || ', $2 * ($3 ^ $4))'
      || ' order by st_distance($1, ' || quote_ident(nearThingsGeometryField) || ')'
      || ' limit 1';
  for i in 0..maxPower loop
     execute sql into result using nearTo              -- $1
                                , initialDistance     -- $2
                                , distanceMultiplier  -- $3
                                , i;                  -- $4
    if result is not null then return result; end if;
  end loop;
  return null;
end
$$ language 'plpgsql' stable;

Ejemplo de uso:

SELECT id, nn(pt_geom,0.00001,2,100,'nw_node','node_id','node_geom') FROM my_point_table;

... selecciona el nodo más cercano en la tabla nw_node para cada entrada en my_point_table.

También hay una función más genérica en el sitio de Boston GIS .

    
respondido por el underdark 08.09.2011 - 21:57

Lea otras preguntas en las etiquetas