19 votos

Encontrar la geometría más cercana en PostGIS

He estado revisando la "API" de funciones de PostGIS, y me he dado 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 así: "Dada una geometría G, dame la geometría GClosest más cercana 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.

10voto

Celso Puntos 66

Su pregunta también puede responderse con una única consulta (aunque compleja) como la siguiente, que devuelve el registro completo 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 devuelto.

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.

9voto

tobes Puntos 19

George MacKerron ha escrito un función simple de vecino más próximo que me ha resultado bastante útil. Esta función devuelve el ID del vecino más cercano a una característica dada:

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 un función más genérica en el sitio del SIG de Boston .

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X