Além de ter uma conexão de rede, precisamos saber o “custo” de viajar sobre qualquer uma das estações. O custo depende da aplicação: Pode ser um manipulador de custo real (tal como um medidor de tarifa); a distância total percorrida; tempo; ou qualquer outra métrica quando se desloca de um ponto a outro.

Em nossa aplicação, vamos suportar tanto a distância quanto o tempo como métrica de custos. Para melhorar o desempenho, vamos pré-calcular o tempo para viajar de carro em todas as nossas entradas na tabela edges_noded. O tempo será calculado com base no tipo de estrada; consultando nosso banco de dados ele nos mostra os diferentes tipos de rodovias cadastradas.

SELECT DISTINCT(type) from edges_noded;
    type
----------------
 motorway
 motorway_link
 steps
 secondary
 tertiary
 trunk
 secondary_link
 path
 unclassified
 proposed
 cycleway
 trunk_link
 primary
 track
 tertiary_link
 raceway
 residential
 construction
 primary_link
 service
 footway

Alguns deles (steps, path, footway, cycleway, proposed and construction) claramente não são adequados para veículos por isso para estes vamos setar um custo de -1 (números negativos o pgRouting interpreta como sendo segmentos intransitáveis). Para o restante, vamos precisar atribuir uma velocidade média e usar esse tempo para preencher uma nova coluna na nossa tabela. Nós vamos adicionar uma coluna distância para economizar no cálculo do comprimento dos nossos segmentos em cada solicitação.

ALTER TABLE edges_noded ADD distance FLOAT8;
ALTER TABLE edges_noded ADD time FLOAT8;
UPDATE edges_noded SET distance = ST_Length(ST_Transform(the_geom, 4326)::geography) / 1000;

Com base na distância, tipo e a superfície agora pode-se estimar a quantidade de tempo necessário para percorrer cada aresta. O site OpenStreetMap nos dá alguma indicação sobre a velocidade relativa para vários tipos de rodovia.

UPDATE edges_noded SET
  time =
  CASE type
    WHEN 'steps' THEN -1
    WHEN 'path' THEN -1
    WHEN 'footway' THEN -1
    WHEN 'cycleway' THEN -1
    WHEN 'proposed' THEN -1
    WHEN 'construction' THEN -1
    WHEN 'raceway' THEN distance / 100
    WHEN 'motorway' THEN distance / 70
    WHEN 'motorway_link' THEN distance / 70
    WHEN 'trunk' THEN distance / 60
    WHEN 'trunk_link' THEN distance / 60
    WHEN 'primary' THEN distance / 55
    WHEN 'primary_link' THEN distance / 55
    WHEN 'secondary' THEN distance / 45
    WHEN 'secondary_link' THEN distance / 45
    WHEN 'tertiary' THEN distance / 45
    WHEN 'tertiary_link' THEN distance / 40
    WHEN 'unclassified' THEN distance / 35
    WHEN 'residential' THEN distance / 30
    WHEN 'living_street' THEN distance / 30
    WHEN 'service' THEN distance / 30
    WHEN 'track' THEN distance / 20
    ELSE distance / 20
  END;

Dividindo a distância por nossas estimativas de velocidade para cada estrada digite o número de horas necessárias para viajar ao longo desse segmento. Vamos também definir a distância para o valor especial de -1 aos tipos de arestas que não queremos que os veículos circulem.

UPDATE edges_noded SET
  distance =
  CASE type
    WHEN 'steps' THEN -1
    WHEN 'path' THEN -1
    WHEN 'footway' THEN -1
    WHEN 'cycleway' THEN -1
    WHEN 'proposed' THEN -1
    WHEN 'construction' THEN -1
    ELSE distance
  END;

Podemos testar o funcionamento da rota usando a função pgr_dijkstra (que implementa o algoritmo Dijkstra) para encontrar o caminho mais curto entre quaisquer dois vértices da rede. Vértices são identificados pela coluna id na tabela edges_noded_vertices_pgr, gerada automaticamente. Selecione quaisquer dois números do ID de tabela e execute a seguinte consulta. Iremos utilizar neste exemplo os vértices 757 e 1000.

SELECT
  id1 AS vertex,
  id2 AS edge,
  cost
FROM pgr_dijkstra('SELECT id, source::INT4, target::INT4, time AS cost FROM edges_noded', 1000, 757, false, false)
ORDER BY seq;

 vertex | edge  |        cost
--------+-------+---------------------
   1000 |   873 | 0.00862449481177354
   1001 | 11469 |  0.0946329838309096
  11548 | 11468 |  0.0411391925170661
  11510 | 11418 |  0.0130258077805629
  11511 | 11452 |   0.010555359038939
  11536 | 11453 |  0.0500946880163133
  11537 | 11454 |  0.0128158392635584
  11538 | 11455 |   0.225115465905455
    757 |    -1 |                   0

Note como passamos uma sub-consulta como um argumento para pgr_dijkstra. Isto é, estamos dizendo para o pgRouting qual rede usar quando procurar a rota, e é um SQL, que podemos refinar o tipo de rota a procurar. Poderíamos, por exemplo, dizer ao pgRouting para ignorar todas as highways ao procurar uma rota, adicionando a seguinte cláusula WHERE: WHERE type = ‘highway’. O melhor de tudo, isso pode ser feito de forma dinâmica, para que possamos mudar os parâmetros de roteamento com cada solicitação.

Para nossos propósitos, devemos notar que, se substituirmos o tempo pela distância na sub-consulta, isto dirá ao pgRouting para encontrar a rota mais curta, em vez da rota mais rápida (lembre-se que você terá de viajar mais lento em determinados tipos de estradas).

Até agora não temos estradas de sentido único. O mesmo algoritmo pode lidar com estradas de sentido único se somarmos a coluna reverse_cost. Como antes, precisamos definir o custo -1 quando não queremos permitir que uma aresta seja usada; Portanto, vamos usar -1 como o reverse_cost quando o atributo de sentido único for sim. Se a estrada não for unidirecional, usamos o mesmo custo na direção de avanço e reversão.

SELECT
  id1 AS vertex,
  id2 AS edge,
  cost
FROM pgr_dijkstra('SELECT id, source::INT4, target::INT4, time AS cost, CASE oneway WHEN ''yes'' THEN -1 ELSE time END AS reverse_cost FROM edges_noded', 1000, 757, true, true)
ORDER BY seq;

Juntando os resultados dos nós da consulta com os da tabela, podemos obter a informação completa acerca da rota que deve ser tomada, em vez de apenas os números de pontos e vértices.

SELECT
  e.old_id AS id,
  e.name, e.type,
  e.oneway,
  sum(e.time) AS time,
  sum(e.distance) AS distance
FROM
  pgr_dijkstra('SELECT id, source::INT4, target::INT4, time AS cost, CASE oneway WHEN ''yes'' THEN -1 ELSE time END AS reverse_cost FROM edges_noded', 753, 756, true, true) AS r,
  edges_noded AS e
WHERE r.id2 = e.id
GROUP BY e.old_id, e.name, e.type, e.oneway;

 id  |        name         |    type     | oneway |  time   | distance
-----+---------------------+-------------+--------+--------------------+
 203 | Bunker Hill Terrace | residential |        | 0.00790 | 0.23713
 210 | Two Rod Road        | residential |        | 0.00537 | 0.16137
 225 | Heritage Lane       | residential |        | 0.01131 | 0.33932
 224 | Plymouth Drive      | residential |        | 0.00230 | 0.06914
 201 | Colonial Drive      | residential |        | 0.00794 | 0.23829