OSMBrasil / stable

Cópia filtrada segura e estável de dados oficiais do Brasil representados no OSM
Other
13 stars 5 forks source link

Agrupamento de segmentos de road #28

Closed ppKrauss closed 4 years ago

ppKrauss commented 4 years ago

Cada rua, ferrovia ou rodovia do OSM é composta de centenas de segmentos, cada qual com respectivas tags de name, ref, etc. repetidos. Por exemplo a Rodovia Raposo Tavares tem da ordem de 750 segmentos, repetindo ref="SP-270" em todos eles; e a rota BR-116 tem mais de 3000.

A tabela planet_osm_roads gerada pelo osm2pgsql é uma reprodução fiel dessa estrutura de segmentos construída pelos mapeadores do OSM, e formalizada no modelo XML OpenStreetMap com os elementos tipo way.

Neste repositorio git os segmentos foram armazenados em arquivos GeoJSON nas pastas dos municípios, com alguns poucos segmentos (menos de 0,01%) se repetindo quando participam da fronteira entre municípios, ou cruzam as mesmas.

Neste repositório tambem adotamos a estratégia de uso de caches para representações alternativas e para estatísticas, nas escalas estadual e federal:


Copia/cola das convenções para nome de arquivo da issue 15:

A seguir as sugestões de convenção a adotar nos algoritmos de cada caso.

Algoritmo para agrupamento de roads em quadrantes

Conforme convencionado o prefixo Geohash da road é determinado pelo valor prefGeohash, com 1 a 4 dígitos. O agrupamento em um mesmo arquivo GeoJSON do tipo collection se dá pelos seguintes critérios e ordem de precedência, supondo que o limite do número de itens na collection seja max_itens e o número de dígitos compatível com esse limite:

  1. Segmentso de via distintos dentro da mesma collection são ordenados conforme seu osm_id, primeiro os IDs de relation depois os IDs de way.

  2. Se os valores de prefGeohash forem iguais, são agrupados no mesmo arquivo.

  3. Se os valores de prefGeohash forem vizinhos (segue sequência relativa aos demais no último dígito), e o número de itens menor que max_itens, então agrupar;

  4. Se existir valor de prefGeohash com dígito a menos (quadrante pai), e o número de itens menor que max_itens, então agrupar com o pai;

A sequência de decisões pode se repetir recursivamente até que todos os arquivos tenham mais de um valor min_itens de itens.

Algoritmo para simplificação das roads estaduais e federais

Em SQL foi sugerido o seguinte algoritmo, que satisfaz todas os requisitos, supondo por exemplo a generalização da rodovia BR-116:

SELECT ST_SimplifyPreserveTopology(
          ST_Union( way ),
          0.0000001
        )  as "BR-116"
FROM planet_osm_roads
WHERE tags->>'ref' ~ '^BR\-116($|;)'

Se houverem muitas falhas de conectividade, algo como ST_ApproximateMedialAxis( ST_Union( ST_Buffer(way,r) ) )... Enfim, será empirico conforme amostragens, outros algorimos podem ser sugeridos, o mais razoável pode ser adotado como padrão, de modo a manter uma geometria estável nas próximas atualiações.

IgorEliezer commented 4 years ago

Para a criação de um banco de endereços, é bom que se faça a filtragem das vias por nome, e não por ref. Eu não me apoiaria em refs a não ser para "tampar buraco" nos casos de rodovias sem nome. Digo o porquê:

A tag ref refere-se à rota rodoviária e não ao nome. Uma rota pode ser composta de várias rodovias com nomes diferentes. Por exemplo a BR-116 começa em Fortaleza, segue para o sul até RJ, passa por SP e vai até RS. Ela possui uma dezena de denominações; só em SP é rodovia Dultra e rodovia Régis Bitencourt.

E ainda há as rotas estaduais e municipais.

Em São Paulo (estado), a SP-300 é composta pela Rodovia Dom Gabriel Paulino Bueno Couto, Rodovia Marechal Rondon e por uma série de ruas e avenidas nos trechos urbanos: https://www.openstreetmap.org/relation/9245672#map=14/-23.2539/-47.2919 (zoom na cidade de Itu onde a SP-300 muda várias vezes de nome)

Em Piracicaba (município), a PIR-260 é composta por cerca de 3 estradas e uma rua urbana: https://overpass-turbo.eu/s/RrC


Casos com ref=XX-001;XX-002

Há casos em que duas ou mais rotas rodoviárias de mesmo nível compartilham a mesma rodovia. É o caso das SP-191 e SP-304: https://www.openstreetmap.org/#map=13/-22.5706/-48.0169 (ref=SP-304;SP-191).

A SP-191 vem pelo leste e a SP-304 vem pelo Sudeste; e juntam em São Pedro; seguem para o oeste; e se separam em Santa Maria da Serra; a SP-191 segue para sudoeste e a SP-304 para noroeste.

Também pode ocorrer de ref nacionais se sobreporem ref estaduais. Exemplo BR-262: https://www.openstreetmap.org/#map=12/-20.7953/-51.6474

Casos com barra no ref

Vendo alguns lugares, a barra pode ser uso incorreto ou pode indicar ramal rodoviário.

Exemplo errado: Uma rodovia com ref=BR-070/163/364 (https://www.openstreetmap.org/way/33745763) é certeza que o ref foi digitado errado. O certo seria ref=BR-070;BR-163;BR-364 (como aqui: https://www.openstreetmap.org/way/180523426, também acho estranho colocar isso numa rotatória).

Exemplo certo: Uma rodovia com ref=SPA-253/300 significa rodovia de Acesso do km 253 da SP-300, como pode ser visto aqui http://www.der.sp.gov.br/WebSite/Arquivos/MalhaRodoviaria/codificacao.pdf, nas páginas 12 e 13.

Neste caso aqui https://www.openstreetmap.org/way/102050575, é certo que quem colocou o ref esqueceu de colocar SPA ao invés de SP. Compare com imagem do DataGEO-SP

Código de prefixo estadual de duas e três letras

Costuma-se usar a sigla do estado de duas letras (DF, SP, MG, RS, AM etc) como prefixo para indicar que a rota rodoviária é estadual e do tipo "eixo", uma forma técnica de dizer "troncal".

Já nas demais rotas rodoviárias "ramais", ou seja, as rodovias de acesso, trevos, (inter)ligações, marginais etc, se usa uma sigla de três letras.

Verifica-se que o formato de ref para rodovias "ramais" varia conforme o estado.

Também não confundir o código de três letras dos estados com o código municipal que é também de três letras. Exemplos: PIR = Piracicaba/SP; URA= Uberaba/MG; CDR = Caçador/SC etc.

ppKrauss commented 4 years ago

Obrigado @IgorEliezer, fica então pendente tarefa minha de tentar agrupar vias federais e estaduais da melhor forma possível, e então publicar apenas um ou dois trechos em GeoJSON simplificado para avaliarmos. Se for consistente, fazemos para todo o resto.

Se não, deixamos para versões futuras, depois de avaliar melhoras no Stable de 2020 (bom lembrar que ainda estamos analisando 2018) e interagir com a comunidade no sentido de pedir que corrijam e conferir se todos tem o mesmo entendimento.

ppKrauss commented 4 years ago

Antes de sair sujando o nosso repositório git com dados de teste, alguns resultados mais para discutir ou homologar decisões.

Estatisticas da BR-116

Na tabela abaixo (e depois sumarizo no git a estatística) percebemos que a hipótese que colocou não se confirma: a grande maioria tem ref, inclusive ref sem name. Para testar o inverso farei uma gambiarra que explico no final, e que comprova que "name sem ref" é muito raro nas rodovias mais conhecidas, tais como a BR-116... Lemrbando que estas estatísticas só serão feitas para escala federal e estadual.

Abaixo uma amostra de dados que descreve o que se passa com a BR-116, conforme a consulta

SELECT uf, tags->>'name' AS name, tags->>'ref' AS ref,
       count(*) n, min(osm_id) osm_id_amostra
FROM  stable.vw01_osm_roads_city_inside   -- sem UF basta planet_osm_roads
WHERE tags->>'ref' ~ '^BR\-116($|;)'   group by 1,2,3 order by 1,2,3;
uf name ref n osm_way_id
BA Anel Rodoviário Jadiel Matos BR-116 9 103014391
BA Anel Rodoviário Jadiel Matos Leste BR-116 23 42267150
BA Anel Rodoviário Jadiel Matos Oeste BR-116 22 104708732
BA Avenida Eduardo Froes da Mota BR-116 3 29199377
BA Avenida Integração BR-116 31 23921878
BA Avenida Juscelino Kubitscheck BR-116;BA-262 2 312274722
BA Avenida Presidente Jonh Kennedy BR-116 1 311572426
BA Avenida Presidente Vargas BR-116 1 311549221
BA Avenida Rio Bahia BR-116 1 311586713
... ... ... .. ...
BA Rodovia Régis Bittencourt BR-116 2 278263758
BA Rodovia Santos Dumont BR-116 184 8142706
BA Rodovia Santos Dumont BR-116;BA-262 2 312278245
BA Rodovia Santos Dumont / BR-116 BR-116 1 293536928
BA BR-116 11 42272600
BA BR-116;BR-030 1 31566208
CE Avenida José Humberto de Alcântara Gondim BR-116 1 31514473
CE Pista Marginal BR-116 6 23404107
CE Rodovia Estrada do Guarani BR-116 12 215126942
CE Rodovia Estrada do Guarani BR-116;CE-350 2 233599393
CE Rodovia Santos Dumont BR-116 106 24407291
CE BR-116 36 23342296
CE BR-116;CE-350 4 303895053
... ... ... .. ...
RS Avenida Zaida Jarros BR-116 4 288127010
RS Freeway BR-116;BR-290 17 27104056
RS Ponte do Canal Furado Grande BR-116;BR-290 2 29208310
RS Ponte do Guaíba BR-116;BR-290 7 29208969
RS Ponte do Retiro BR-116 2 414696438
RS Ponte do Retiro BR-116 2 414696438
RS Ponte do Saco da Alemoa BR-116;BR-290 2 29208284
RS Rodovia General Bento Gonçalves BR-116 215 20862007
RS Rodovia General Bento Gonçalves BR-116;BR-293 8 108139354
RS Rodovia General Bento Gonçalves BR-116;BR-293; 17 20865097
RS Rodovia General Bento Gonçalves BR-116;BR-470 1 298621186
RS Rodovia General Bento Gonçalves BR-116;ERS-350 13 119980797
RS Rodovia Presidente Getúlio Vargas BR-116 20 92109551
RS Rua Uruguai BR-116 8 46032826
RS Travessia Régis Bitencourt BR-116;BR-290 33 29207238
RS Viaduto Deputado Federal Júlio Redecker BR-116 2 294419369
RS Viaduto Manoel Luiz Nunes BR-116 2 58821590
RS BR-116 377 27090387
RS BR-116;BR-290 70 29207875
SC Trevo do Patussi BR-116 4 290097622
SC BR-116 193 35772174
SC BR-116;BR-477 3 37191866
SP Avenida Assis Chateaubriand (Expressa) BR-116 1 185797083
SP Avenida Otaviano Alves de Lima(Expressa) BR-116 1 469771940
SP Rodovia Salvador de Leone BR-116;SP-234 1 58683893
SP BR-116 1 58683572

A tabela acima mostra todos os nomes consistentes com ref="BR-116", a menos de alguns que filtrariamos como "Freeway". Segmentos de "Anel Rodoviário" criam geometria diferente da linha unica, mas por hora deixamos assim pois não afeta o GeoJSON. Mesmo a estranha "Rua Uruguai" está correta, é o rabicho da BR-116 que interliga a rota do Brasil com a rota do Uruguai.

Apesar de complexo é factivel puxar uma lista de nomes. A cado estado (UF), todos aqueles que iniciam por "Rodovia", são os mais frequentes.

-- create table t as
SELECT DISTINCT uf || '/'|| (tags->>'name') AS name_br116
FROM  stable.vw01_osm_roads_city_inside
WHERE tags->>'ref' ~ '^BR\-116($|;)' AND tags->>'name' iLIKE 'Rodovia%' order by 1;

BA/Rodovia Régis Bittencourt;   BA/Rodovia Santos Dumont;   BA/Rodovia Santos Dumont / BR-116;   BA/Rodovia Santos-Dumont CE/Rodovia Estrada do Guarani;   CE/Rodovia Santos Dumont MG/Rodovia Santos Dummont;   MG/Rodovia Santos Dumont PB/Rodovia Santos Dumont PE/Rodovia Régis Bittencourt;   PE/Rodovia Santos Dumont PR/Rodovia Régis Bittencourt RJ/Rodovia Presidente Dutra;   RJ/Rodovia Rio Magé;   RJ/Rodovia Rio-Magé; RJ/Rodovia Rio-Teresópolis;   RJ/Rodovia Santos Dumont;   RJ/Rodovia Teresópolis - Alem Paraíba;   RJ/Rodovia Washington Luiz;   RS/Rodovia General Bento Gonçalves;   RS/Rodovia Presidente Getúlio Vargas SP/Rodovia Salvador de Leone

Por fim, resultado estatístico de segmentos "só com ref" e "só com name":

SELECT COUNT(*) n_com_name_sem_ref
FROM  stable.vw01_osm_roads_city_inside
WHERE NOT(tags?'ref')
              AND uf || '/'|| (tags->>'name') IN (select name_br116 FROM t)
;  -- resultaram apenas 17
SELECT COUNT(*) n_com_ref
FROM  stable.vw01_osm_roads_city_inside
WHERE tags->>'ref' ~ '^BR\-116($|;)'
;  -- total 2733
SELECT COUNT(*) ngeral_com_ref
FROM planet_osm_roads           
WHERE tags->>'ref' ~ '^BR\-116($|;)'
;--  total 3018

Apenas 17 segmentos nesta condição (n_com_name_sem_ref). Representam ~20/3000= 0,6% do total de segmentos.

Conclusão: para gerar uma geometria simplificada (resumo visual) das rodovias federais, se seguirem o comportamento da BR-116, poderemos desprezar os segmentos sem ref.


PS: o objetivo dos dados do OSM-Stable não é a perfeição, é apenas filtrar o que desejamos controlar como "supostamente bom e estável", e dar um histórico rastreável das melhoras conquistadas a cada nova versão.

ppKrauss commented 4 years ago

Estatisticas da SP-191 e SP-304

Abaixo uma amostra de dados que descreve o que se passa com ambos, SP-191 e SP-304, conforme a consulta

SELECT tags->>'name' AS name, tags->>'ref' AS ref,
       count(*) n, min(osm_id) osm_id_amostra
FROM  planet_osm_roads
WHERE tags->>'ref' ~ '^SP\-(191|304)($|;)'  group by 1,2 order by 1,2;
name ref n osm_id_amostra
Avenida Antenor Marques SP-191 3 167081312
Avenida Italo Lorandi SP-191 3 191967176
Avenida do Contorno SP-191 1 167474935
Rodovia Cassio Primiano SP-304 20 133746978
Rodovia Deputado Amauri Barroso de Souza SP-304 35 154190553
Rodovia Deputado Leônidas Pacheco Ferreira SP-304 83 156799087
Rodovia Doutor Antônio Piva SP-304 3 128381099
Rodovia Dr. Antônio Piva SP-304 6 249256821
Rodovia Geraldo de Barros SP-191 30 128381077
Rodovia Geraldo de Barros SP-304 29 31588853
Rodovia Jornalista José Willibaldo de Freitas SP-304 25 133747003
Rodovia Luiz de Queiroz SP-304 2 88818571
Rodovia Luís de Queiroz SP-304 43 50149653
Rodovia Luíz de Queiroz SP-304 5 156129473
Rodovia Wilson Finardi SP-191 62 132101262
Rua Barão do Rio Branco SP-191 1 316695209
Rua Luiz Cruzatto SP-191 2 316695274
Rua Olavo Bilac SP-304 1 128447015
Via Piracicaba SP-191 1 491192765
  SP-191 54 128446995
  SP-304 38 75401853

O total na coluna n é 447.

Novamente juntando só nomes de "Rodovia":

-- create table t as
SELECT DISTINCT tags->>'name' AS name
FROM  planet_osm_roads
WHERE tags->>'ref' ~ '^SP\-(191|304)($|;)' AND tags->>'name' iLIKE 'Rodovia%' 
ORDER BY  1;

Rodovia Cassio Primiano; Rodovia Deputado Amauri Barroso de Souza; Rodovia Deputado Leônidas Pacheco Ferreira; Rodovia Doutor Antônio Piva; Rodovia Dr. Antônio Piva; Rodovia Geraldo de Barros; Rodovia Jornalista José Willibaldo de Freitas; Rodovia Luiz de Queiroz; Rodovia Luís de Queiroz; Rodovia Luíz de Queiroz; Rodovia Wilson Finardi.

Por fim, resultado estatístico de segmentos "só com ref" e "só com name":

SELECT COUNT(*) n_com_name_sem_ref
FROM  stable.vw01_osm_roads_city_inside
WHERE uf='SP' AND NOT(tags?'ref')
              AND (tags->>'name') IN (select name FROM t)
;  -- resultou em apenas 1 caso! num total de 447, são 0.2%

Conclusão: na escala estadual também podemos ignorar segmentos sem ref.

Outra conclusão é que não precisamos nos preocupar com as sobreposições, pois parecem já existir segmentos duplicados onde necessário (ver na tabela o nome "Rodovia Geraldo de Barros")... Ou duplicamos por algorirmo (função geradora do GeoJSON simplificado) quando vierem listados por ; na tag ref.


PS: claro que com toda essa análise vale fazer sugestões para a comunidade corrigir, por isso, principalmente na publicação de "versão testing" os relatórios (arquivos e pastas prefixo kx_) são importantes, e podem ser utilizados para a comunidade corrigir antes do lançamento da "versão stable"

ppKrauss commented 4 years ago

Descrição técnica do experimento final, para postar no branch testing do git. Resultados já na forma definitiva de GeoJSON sugerido.

--- nova stored procedure:
CREATE or replace FUNCTION stable.rota_tags2lexname(p_tags jsonb) RETURNS text AS $f$
  SELECT x FROM (
    SELECT stable.name2lex(coalesce(p_tags->>'official_name',p_tags->>'name'),true,true,true)
  ) t(x) WHERE substring(x,1,7) IN ('rodovia','estrada')
$f$ LANGUAGE SQL IMMUTABLE;
COMMENT ON FUNCTION stable.rota_tags2lexname 
  IS 'Normaliza nome de rodovia conforme sintaxe URN LEX.';

--- novas views:

CREATE VIEW stable.vw01item_roads_rota_federal AS
  SELECT ref, count(*) n, 
              array_agg(DISTINCT osm_id) AS members_osm_id,
              array_agg(DISTINCT lexname) AS members_lexname
  FROM (
    SELECT osm_id,
                 trim(regexp_split_to_table(tags->>'ref', ';')) AS ref,
                 stable.rota_tags2lexname(tags) AS lexname
    FROM planet_osm_roads
    WHERE tags->>'ref' ~ 'BR\-\d\d\d'
  ) t
  WHERE ref ~ '^BR\-\d\d\d$'
  GROUP BY 1 ORDER BY 1
;
COMMENT ON VIEW stable.vw01item_roads_rota_federal
  IS 'Isola rodovias de federais de planet_osm_roads com rótulo oficial de rota BR.'
;
CREATE MATERIALIZED VIEW stable.mvw01lexname_rota_federal AS
 SELECT * FROM ( 
  SELECT DISTINCT
     ref AS rota_ref,
     unnest(members_lexname) as lexname
   FROM stable.vw01item_roads_rota_federal
   where members_lexname is not null
  ) t 
  where lexname is not null
;
CREATE VIEW stable.vw01lexnames_rota_federal AS
    select rota_ref, array_agg(DISTINCT lexname)  as members_lexname
    from stable.mvw01lexname_rota_federal
    group by 1 order by 1
;
CREATE MATERIALIZED VIEW stable.mvw02geom_roads_rota_federal AS
  SELECT 
     f.ref AS rota_ref, 
     ST_SimplifyPreserveTopology(
       ST_Union( r.way ),
       0.0000005
     ) AS geom,
    count(*) members_n,
    round( SUM(ST_Length(r.way,true))/1000 ) comprimento_km,
    array_agg(r.osm_id) members_osm_id,
    min(r.osm_id) members_id_min,
    max(r.osm_id) members_id_max,
    (SELECT members_lexname FROM stable.vw01lexnames_rota_federal s  where s.rota_ref=f.ref) as members_lexname
  FROM planet_osm_roads r INNER JOIN (
    SELECT ref, unnest(members_osm_id) osm_id
    FROM stable.vw01item_roads_rota_federal
  ) f   
  ON f.osm_id=r.osm_id
  GROUP BY 1
  ORDER BY 1
; -- 156 rotas
COMMENT ON MATERIALIZED VIEW stable.mvw02geom_roads_rota_federal
  IS 'Isola rodovias de federais de planet_osm_roads com rótulo oficial de rota BR.'
;
/*
-- depois de git clone --single-branch --branch "test2018-10-02A" stable.git
SELECT file_put_contents( 
       '/tmp/pg_io/_rotas/'||rota_ref||'.geojson',
       jsonb_pretty(
            ST_AsGeoJSON(geom,6)::JSONb
           || jsonb_build_object('properties', jsonb_build_object( 
                'name',rota_ref,                'comprimento_km',comprimento_km,
                'members_osm_id',members_osm_id ',  'members_lexnames',members_lexnames
            ))
       ) -- falta properties
 ) as put 
FROM stable.vw03geom_roads_rota_federal
;
*/
ppKrauss commented 4 years ago

Pendências para encerrar análise e padronização das rotas federais:

IgorEliezer commented 4 years ago

Já estou dando uma olhada nas rotas rodoviárias. E adianto algo:

A BR-116 está faltando o trecho do estado de São Paulo onde há dois refs (e.g. BR-116;SP-260). Os trechos onde há só BR-116 foram importados.

ppKrauss commented 4 years ago

@IgorEliezer obrigado, não parece ser falha das refs, vou revisar a consulta do split (stable.vw01item_roads_rota_federal) e retorno. Se ver mais um caso (não precisa buscar outros além de um segundo) testo com com a BR-116 mais ele.

ppKrauss commented 4 years ago

Bug da "ref com BR no meio" resolvido, publicarei os mapas novamente. Não eram poucos os segmentos nesta situação:

SELECT count(*)  -- confere quantos não começam por BR
FROM planet_osm_roads
WHERE tags->>'ref' ~ 'BR\-\d\d\d' and not(tags->>'ref' ~ '^BR\-\d+($|;)')
; -- 4305

Entre estes ~4300 casos temos "SP-060;BR-116", "SP-015;BR-116", etc. Foi a convenção adotada por mapeadores do estado de SP. Se está estranho ou errado, vale a pena discutir na comunidade se o correto é manter a ordem alfabética e/ou ordem das jurisdições.


A correção já está aplicada acima no post do SQL. Na geração da geometria também já acrescentei um filtro filtro de qualidade: nenhuma das rotas, federais ou estaduais, pode ter menos de 2 km.
PS: se tiver menos de 200 km já é para desconfiar, mas aí fica a cargo da comunidade OSM conferir.

rota_ref members_n comprimento_km
BR-128 2 1
BR-151 1 0
BR-368 7 1

Estas outras não foram eliminadas mas são suspeitas (lembrando que é mapa de 2018 e pode ter sido corrigido), por não terem mais de 10 km ou 2 membros.

rota_ref members_n comprimento_km
BR-148 1 28
BR-363 10 7
BR-434 1 11
BR-436 14 10
BR-485 12 10
BR-504 3 10
IgorEliezer commented 4 years ago

Para registro: Os shapefiles das rotas federais, com trechos construídos e planejados, estão aqui http://www.dnit.gov.br/sistema-nacional-de-viacao/sistema-nacional-de-viacao

IgorEliezer commented 4 years ago

Para encerrar esse issue, deixo para registro:

  1. Foi detectado que segmentos de rodovias com duas refs não foram importados (ref: https://github.com/OSMBrasil/stable/issues/28#issuecomment-597591206). Já foi corrigido per https://github.com/OSMBrasil/stable/issues/28#issuecomment-597965464.

  2. Foi feito a comparação dos dados (diretório) com o shapefile das rotas rodoviárias no site do DNIT (disponível em http://servicos.dnit.gov.br/dnitcloud/index.php/s/oTpPRmYs5AAdiNr?path=%2FSNV%20Rotas%20(2015-Atual)%20(SHP), arquivo rota_201811A.zip) com o fim de notar se houve outras falhas de importação. Não foram encontradas outras falhas.

IgorEliezer commented 4 years ago

Com relação aos nomes (ver em sumário), acredito que rodovia.br são as rodovias sem nome definido no OpenStreetMap, não é?