{"id":5595,"date":"2016-06-10T07:30:24","date_gmt":"2016-06-10T10:30:24","guid":{"rendered":"http:\/\/www.fernandoquadro.com.br\/html\/?p=5595"},"modified":"2016-08-12T15:15:19","modified_gmt":"2016-08-12T18:15:19","slug":"criando-um-aplicativo-de-rotas-com-pgrouting-parte-3","status":"publish","type":"post","link":"https:\/\/www.fernandoquadro.com.br\/html\/2016\/06\/10\/criando-um-aplicativo-de-rotas-com-pgrouting-parte-3\/","title":{"rendered":"Criando um aplicativo de rotas com pgRouting \u2013 Parte 3"},"content":{"rendered":"<p>Al\u00e9m de ter uma conex\u00e3o de rede, precisamos saber o &#8220;custo&#8221; de viajar sobre qualquer uma das esta\u00e7\u00f5es. O custo depende da aplica\u00e7\u00e3o: Pode ser um manipulador de custo real (tal como um medidor de tarifa); a dist\u00e2ncia total percorrida; tempo; ou qualquer outra m\u00e9trica quando se desloca de um ponto a outro.<\/p>\n<p>Em nossa aplica\u00e7\u00e3o, vamos suportar tanto a dist\u00e2ncia quanto o tempo como m\u00e9trica de custos. Para melhorar o desempenho, vamos pr\u00e9-calcular o tempo para viajar de carro em todas as nossas entradas na tabela <i>edges_noded<\/i>. O tempo ser\u00e1 calculado com base no tipo de estrada; consultando nosso banco de dados ele nos mostra os diferentes tipos de rodovias cadastradas.<\/p>\n<pre>SELECT DISTINCT(type) from edges_noded;\r\n    type\r\n----------------\r\n motorway\r\n motorway_link\r\n steps\r\n secondary\r\n tertiary\r\n trunk\r\n secondary_link\r\n path\r\n unclassified\r\n proposed\r\n cycleway\r\n trunk_link\r\n primary\r\n track\r\n tertiary_link\r\n raceway\r\n residential\r\n construction\r\n primary_link\r\n service\r\n footway<\/pre>\n<p>Alguns deles (steps, path, footway, cycleway, proposed and construction) claramente n\u00e3o s\u00e3o adequados para ve\u00edculos por isso para estes vamos setar um custo de -1 (n\u00fameros negativos o pgRouting interpreta como sendo segmentos intransit\u00e1veis). Para o restante, vamos precisar atribuir uma velocidade m\u00e9dia e usar esse tempo para preencher uma nova coluna na nossa tabela. N\u00f3s vamos adicionar uma coluna dist\u00e2ncia para economizar no c\u00e1lculo do comprimento dos nossos segmentos em cada solicita\u00e7\u00e3o.<\/p>\n<pre>ALTER TABLE edges_noded ADD distance FLOAT8;\r\nALTER TABLE edges_noded ADD time FLOAT8;\r\nUPDATE edges_noded SET distance = ST_Length(ST_Transform(the_geom, 4326)::geography) \/ 1000;<\/pre>\n<p>Com base na dist\u00e2ncia, tipo e a superf\u00edcie agora pode-se estimar a quantidade de tempo necess\u00e1rio para percorrer cada aresta. O site OpenStreetMap nos d\u00e1 alguma indica\u00e7\u00e3o sobre a velocidade relativa para v\u00e1rios tipos de rodovia.<\/p>\n<pre>UPDATE&nbsp;edges_noded&nbsp;SET\r\n&nbsp;&nbsp;time&nbsp;=\r\n&nbsp;&nbsp;CASE&nbsp;type\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'steps'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'path'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'footway'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'cycleway'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'proposed'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'construction'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'raceway'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;100\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'motorway'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;70\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'motorway_link'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;70\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'trunk'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;60\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'trunk_link'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;60\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'primary'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;55\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'primary_link'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;55\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'secondary'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;45\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'secondary_link'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;45\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'tertiary'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;45\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'tertiary_link'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;40\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'unclassified'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;35\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'residential'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;30\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'living_street'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;30\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'service'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;30\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'track'&nbsp;THEN&nbsp;distance&nbsp;\/&nbsp;20\r\n&nbsp;&nbsp;&nbsp;&nbsp;ELSE&nbsp;distance&nbsp;\/&nbsp;20\r\n&nbsp;&nbsp;END;<\/pre>\n<p>Dividindo a dist\u00e2ncia por nossas estimativas de velocidade para cada estrada digite o n\u00famero de horas necess\u00e1rias para viajar ao longo desse segmento. Vamos tamb\u00e9m definir a dist\u00e2ncia para o valor especial de -1 aos tipos de arestas que n\u00e3o queremos que os ve\u00edculos circulem.<\/p>\n<pre>UPDATE&nbsp;edges_noded&nbsp;SET\r\n&nbsp;&nbsp;distance&nbsp;=\r\n&nbsp;&nbsp;CASE&nbsp;type\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'steps'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'path'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'footway'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'cycleway'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'proposed'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;WHEN&nbsp;'construction'&nbsp;THEN&nbsp;-1\r\n&nbsp;&nbsp;&nbsp;&nbsp;ELSE&nbsp;distance\r\n&nbsp;&nbsp;END;<\/pre>\n<p>Podemos testar o funcionamento da rota usando a fun\u00e7\u00e3o <em>pgr_dijkstra <\/em>(que implementa o algoritmo <em>Dijkstra<\/em>) para encontrar o caminho mais curto entre quaisquer dois v\u00e9rtices da rede. V\u00e9rtices s\u00e3o identificados pela coluna id na tabela<em> edges_noded_vertices_pgr<\/em>, gerada automaticamente. Selecione quaisquer dois n\u00fameros do ID de tabela e execute a seguinte consulta. Iremos utilizar neste exemplo os v\u00e9rtices 757 e 1000.<\/p>\n<pre>SELECT\r\n&nbsp;&nbsp;id1&nbsp;AS&nbsp;vertex,\r\n&nbsp;&nbsp;id2&nbsp;AS&nbsp;edge,\r\n&nbsp;&nbsp;cost\r\nFROM&nbsp;pgr_dijkstra('SELECT&nbsp;id,&nbsp;source::INT4,&nbsp;target::INT4,&nbsp;time&nbsp;AS&nbsp;cost&nbsp;FROM&nbsp;edges_noded',&nbsp;1000,&nbsp;757,&nbsp;false,&nbsp;false)\r\nORDER&nbsp;BY&nbsp;seq;\r\n\r\n&nbsp;vertex&nbsp;|&nbsp;edge&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cost\r\n--------+-------+---------------------\r\n&nbsp;&nbsp;&nbsp;1000&nbsp;|&nbsp;&nbsp;&nbsp;873&nbsp;|&nbsp;0.00862449481177354\r\n&nbsp;&nbsp;&nbsp;1001&nbsp;|&nbsp;11469&nbsp;|&nbsp;&nbsp;0.0946329838309096\r\n&nbsp;&nbsp;11548&nbsp;|&nbsp;11468&nbsp;|&nbsp;&nbsp;0.0411391925170661\r\n&nbsp;&nbsp;11510&nbsp;|&nbsp;11418&nbsp;|&nbsp;&nbsp;0.0130258077805629\r\n&nbsp;&nbsp;11511&nbsp;|&nbsp;11452&nbsp;|&nbsp;&nbsp;&nbsp;0.010555359038939\r\n&nbsp;&nbsp;11536&nbsp;|&nbsp;11453&nbsp;|&nbsp;&nbsp;0.0500946880163133\r\n&nbsp;&nbsp;11537&nbsp;|&nbsp;11454&nbsp;|&nbsp;&nbsp;0.0128158392635584\r\n&nbsp;&nbsp;11538&nbsp;|&nbsp;11455&nbsp;|&nbsp;&nbsp;&nbsp;0.225115465905455\r\n&nbsp;&nbsp;&nbsp;&nbsp;757&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;-1&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0\r\n<\/pre>\n<p>Note como passamos uma sub-consulta como um argumento para <em>pgr_dijkstra<\/em>. Isto \u00e9, estamos dizendo para o <em>pgRouting <\/em>qual rede usar quando procurar a rota, e \u00e9 um SQL, que podemos refinar o tipo de rota a procurar. Poder\u00edamos, por exemplo, dizer ao <em>pgRouting <\/em>para ignorar todas as highways ao procurar uma rota, adicionando a seguinte cl\u00e1usula WHERE: WHERE type = <i>&#8216;highway&#8217;<\/i>. O melhor de tudo, isso pode ser feito de forma din\u00e2mica, para que possamos mudar os par\u00e2metros de roteamento com cada solicita\u00e7\u00e3o.<\/p>\n<p>Para nossos prop\u00f3sitos, devemos notar que, se substituirmos o tempo pela dist\u00e2ncia na sub-consulta, isto dir\u00e1 ao pgRouting para encontrar a rota mais curta, em vez da rota mais r\u00e1pida (lembre-se que voc\u00ea ter\u00e1 de viajar mais lento em determinados tipos de estradas).<\/p>\n<p>At\u00e9 agora n\u00e3o temos estradas de sentido \u00fanico. O mesmo algoritmo pode lidar com estradas de sentido \u00fanico se somarmos a coluna reverse_cost. Como antes, precisamos definir o custo -1 quando n\u00e3o queremos permitir que uma aresta seja usada; Portanto, vamos usar -1 como o reverse_cost quando o atributo de sentido \u00fanico for sim. Se a estrada n\u00e3o for unidirecional, usamos o mesmo custo na dire\u00e7\u00e3o de avan\u00e7o e revers\u00e3o.<\/p>\n<pre>SELECT\r\n&nbsp;&nbsp;id1&nbsp;AS&nbsp;vertex,\r\n&nbsp;&nbsp;id2&nbsp;AS&nbsp;edge,\r\n&nbsp;&nbsp;cost\r\nFROM&nbsp;pgr_dijkstra('SELECT&nbsp;id,&nbsp;source::INT4,&nbsp;target::INT4,&nbsp;time&nbsp;AS&nbsp;cost,&nbsp;CASE&nbsp;oneway&nbsp;WHEN&nbsp;''yes''&nbsp;THEN&nbsp;-1&nbsp;ELSE&nbsp;time&nbsp;END&nbsp;AS&nbsp;reverse_cost&nbsp;FROM&nbsp;edges_noded',&nbsp;1000,&nbsp;757,&nbsp;true,&nbsp;true)\r\nORDER&nbsp;BY&nbsp;seq;<\/pre>\n<p>Juntando os resultados dos n\u00f3s da consulta com os da tabela, podemos obter a informa\u00e7\u00e3o completa acerca da rota que deve ser tomada, em vez de apenas os n\u00fameros de pontos e v\u00e9rtices.<\/p>\n<pre>SELECT\r\n&nbsp;&nbsp;e.old_id&nbsp;AS&nbsp;id,\r\n&nbsp;&nbsp;e.name,&nbsp;e.type,\r\n&nbsp;&nbsp;e.oneway,\r\n&nbsp;&nbsp;sum(e.time)&nbsp;AS&nbsp;time,\r\n&nbsp;&nbsp;sum(e.distance)&nbsp;AS&nbsp;distance\r\nFROM\r\n&nbsp;&nbsp;pgr_dijkstra('SELECT&nbsp;id,&nbsp;source::INT4,&nbsp;target::INT4,&nbsp;time&nbsp;AS&nbsp;cost,&nbsp;CASE&nbsp;oneway&nbsp;WHEN&nbsp;''yes''&nbsp;THEN&nbsp;-1&nbsp;ELSE&nbsp;time&nbsp;END&nbsp;AS&nbsp;reverse_cost&nbsp;FROM&nbsp;edges_noded',&nbsp;753,&nbsp;756,&nbsp;true,&nbsp;true)&nbsp;AS&nbsp;r,\r\n&nbsp;&nbsp;edges_noded&nbsp;AS&nbsp;e\r\nWHERE&nbsp;r.id2&nbsp;=&nbsp;e.id\r\nGROUP&nbsp;BY&nbsp;e.old_id,&nbsp;e.name,&nbsp;e.type,&nbsp;e.oneway;\r\n\r\n&nbsp;id&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;oneway&nbsp;|&nbsp;&nbsp;time&nbsp;&nbsp;&nbsp;|&nbsp;distance\r\n-----+---------------------+-------------+--------+--------------------+\r\n&nbsp;203&nbsp;|&nbsp;Bunker&nbsp;Hill&nbsp;Terrace&nbsp;|&nbsp;residential&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;0.00790&nbsp;|&nbsp;0.23713\r\n&nbsp;210&nbsp;|&nbsp;Two&nbsp;Rod&nbsp;Road&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;residential&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;0.00537&nbsp;|&nbsp;0.16137\r\n&nbsp;225&nbsp;|&nbsp;Heritage&nbsp;Lane&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;residential&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;0.01131&nbsp;|&nbsp;0.33932\r\n&nbsp;224&nbsp;|&nbsp;Plymouth&nbsp;Drive&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;residential&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;0.00230&nbsp;|&nbsp;0.06914\r\n&nbsp;201&nbsp;|&nbsp;Colonial&nbsp;Drive&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;residential&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;0.00794&nbsp;|&nbsp;0.23829<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Al\u00e9m de ter uma conex\u00e3o de rede, precisamos saber o &#8220;custo&#8221; de viajar sobre qualquer uma das esta\u00e7\u00f5es. O custo depende da aplica\u00e7\u00e3o: Pode ser um manipulador de custo real (tal como um medidor de tarifa); a dist\u00e2ncia total percorrida;&#8230; <a class=\"more-link\" href=\"https:\/\/www.fernandoquadro.com.br\/html\/2016\/06\/10\/criando-um-aplicativo-de-rotas-com-pgrouting-parte-3\/\">Continue Reading &rarr;<\/a><\/p>\n","protected":false},"author":275,"featured_media":5069,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,24,132,11],"tags":[208,223,250,266,212],"class_list":["post-5595","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-geoserver","category-gis","category-openlayers","category-postgis","tag-geoserver","tag-gis","tag-openlayers","tag-pgrouting","tag-postgis"],"_links":{"self":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/5595","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/users\/275"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/comments?post=5595"}],"version-history":[{"count":13,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/5595\/revisions"}],"predecessor-version":[{"id":6213,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/5595\/revisions\/6213"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media\/5069"}],"wp:attachment":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media?parent=5595"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/categories?post=5595"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/tags?post=5595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}