-
- Controle sintático
- Sistemas de coordenadas padronizados
-
- Uso geral
- Interação PostgREST
-
- Instalando somente o zip
- Reproduzindo o processo completo
- Compatibilidade
- Homologação
Como a decisão de projeto foi reusar os nomes das células como pontos de referência, precisamos primeiramente entender a relação entre os pontos e os nomes. A consulta SQL abaixo nos auxilia nessa empreitada didática e de reengencharia:
-- Depois de rodar step2 apenas.
DROP TABLE IF EXISTS grade_id04_teste1;
CREATE TABLE grade_id04_teste1 AS
SELECT gid, nome_1km,
p[2]||'-'||p[3] AS nome_xy,
c[1]||'-'||c[2] AS centro_xy,
ST_SetSRID( ST_MakePoint(p[2],p[3]),952019) pt_ref,
ST_SetSRID( ST_MakePoint(c[1],c[2]),952019) pt_center,
grid_ibge.draw_cell( c[1], c[2], CASE WHEN p[1]=6 THEN 100 ELSE 500 END) AS geom
FROM (
SELECT nome_1km, grid_ibge.name_to_gid(id_unico) as gid,
grid_ibge.name_to_parts_normalized(id_unico) p,
grid_ibge.name_to_center(id_unico) c,
geom2 as geom
FROM (SELECT *, st_transform(geom,952019) as geom2 FROM grade_id04 ) t1
) t2
LIMIT 29000
; -- pode reduzir LIMIT, é só para visualizar algo no Sul do Brasil com QGIS
Nas colunas originais de nome_*
(ex. nome_1km
) adotam-se as coordenadas XY Albers, destacadas pela coluna nome_xy
.
Para entender melhor a direção dos eixos X e Y podemos visualizar apenas um pequeno trecho com os pontos de grade_id04
no QGIS:
Os pontos de referência de nome id_unico
do IBGE (pt_ref), nas grades 1KM e 200M, tem sua localização indicada abaixo, quando visualizamos a tabela original grade_id04
sobreposta a esta grade_id04_pts
no QGIS:
A seta azul indica o deslocamento necessário para ir de pt_ref para pt_center específicos de cada célula. Como células de 200M e 1KM coexistem no mesmo conjunto de dados, o IBGE parece ter optado pelo deslocamento no ponto de referência das células de 200M, para evitar confusão com os pontos das de 1KM.
Por fim, podemos confirmar no QGIS que da grade de 5KM em diante (10KM, 50KM, etc.), todas as grades de sumarização (ST_Union do script abaixo) seguem a referência no canto inferior esquerdo, como na de 1KM.
-- Query de sumarização em células 5KM:
DROP TABLE IF EXISTS grade_id04_5km;
CREATE TABLE grade_id04_5km AS
SELECT gid, p[2]||'-'||p[3] AS pt, n,
ST_SetSRID( ST_MakePoint(p[2],p[3]),952019) pt_geom,
geom -- bordas da união dos componentes (células 5KM parciais)
FROM (
SELECT grid_ibge.name_to_gid(nome_5km) as gid, n,
grid_ibge.name_to_parts_normalized(nome_5km) p,
geom
FROM (
SELECT nome_5km, COUNT(*) n,
ST_UNion( ST_simplify(geom,0.00001) ) as geom
FROM grade_id04
GROUP BY nome_5km
) t1
) t2;
Desta evidência final do comportamento dos pontos de referência chegamos à função que coloca pontos de referência (oriundos de id_unico
, nome_1km
, nome_5km
, etc.) no centro da célula:
CREATE FUNCTION grid_ibge.name_to_center(name text) RETURNS int[] AS $f$
SELECT CASE
WHEN L=6 THEN array[ x_ref+halfside, y_ref-halfside ]
ELSE array[ x_ref+halfside, y_ref+halfside ]
END
FROM (
SELECT p[1] as L, p[2] as x_ref, p[3] as y_ref,
grid_ibge.level_to_size(p[1])/2::int as halfside
FROM ( SELECT grid_ibge.name_to_parts_normalized(name) p ) t1
) t2
$f$ LANGUAGE SQL IMMUTABLE;
Os processos de encode/decode do geocódigo oficial da grade IBGE, ou seja, aquilo que o IBGE chama de nome da célula, requerem um certo controle para satisfazer as convenções adotadas pelo IBGE. Essas convenções — infelizmente não foram documentadas, foram obtidas intuitivamente e testadas sistematicamente — foram traduzidas em funções.
As seguintes funções da biblioteca grid_ibge
garantem a decodificação de nomes em parâmetros da célula:
-
name_to_parts(name text)
explode o nome nas suas partes (text[]
), a partir da sua expressão regular(\d+(?:M|KM))E(\d+)N(\d+)
, nesta ordem: largura da célula, prefixo da coordenada X (leste) e prefixo da coordenada Y (norte). A largura é dada com respectiva unidade (M ou KM), enquanto os prefixos de coordenada são apenas os primeiros dígitos significativos (os demais são zeros). -
prefix_to_level(prefix text)
transforma o prefixo de nome de célula, que representa a largura da célula ("200M", "1KM", "..."), em nível hierárquico. Por exemplo nível 0 para "500KM", nível 5 para "1KM". -
name_to_gid(name text)
transforma as partes do nome (largura e prefixos de coordenada) emgid
(bigint
). Obtém as partes com a função name_to_parts e o nível com prefix_to_level. Como a grade Albers adotada adota o metro como unidade, e o Brasil se encaixa em coordenadas X de 7 dígitos e coordenadas Y de 8 dígitos, o conversão apenas preenche com os zeros faltantes; tomando o cuidado de incluir zero a esquerda quando forem 7 dígitos em Y.
A transformação de volta, codificando o nome de célula a partir do gid
, é obtida com as funções:
-
level_to_prefix(level int)
devolve a largura da célula textualmente (valor e unidade), a partir do nível hierárquico. Por exemplo a largura do nível L1 é "100KM". -
gid_to_name(gid bigint)
reconstroe o nome oficial da célula a partir do indexadorgid
. O IBGE estabeleceu 3 regras sintáticas para compor os prefixos de coordenada: nas células L6 são expressos com 5 dígitos, nas "células padrão" com 4 dígitos e nas "células do norte" também com 5 dígitos. Esta última regra pode ser evidenciada pelas coordenadas Y mais ao norte a partir do 10 mil.
Algumas funções de biblioteca trabalham em sistemas de coordenadas diferentes, mas todos são internamente padronizados, seguindo as seguintes convenções:
-
LatLon GeoURI, (lat,lon,uncert) onde lat é latitude, lon é longitude e uncert é incerteza (raio do disco de incerteza em metros). O SRID do GeoURI é o 4326.
-
XY Albers, (x,y,Level) onde x e y são as coordenadas Albers e Level o nível hierárquico da grade.
-
IJ Unitário, (i,j,s) onde i e j são índices da "grade quadrada unitária" e s, size, é o tamanho do lado da célula desta grade (portanto determina a resolução da grade unitária e seu nível).
Transformações padronizadas:
-
(lat,lon,uncert)→(x,y,L) Implementada por
ST_Transform(geom,952019)
euncertain_to_size(uncert)
. -
(x,y,L)→(i,j,s) A rigor não transforma, mas "colapsa" todos os pontos XY da célula em seu IJ. Implementada por
xyL_collapseTo_ijS(x,y,L)
. -
(i,j,s)→(x,y,L) As coordenadas XY quantizadas podem ser obtidas de volta tomando-se um ponto interior de referência na célula. Implementada por
ijS_to_xySref(i,j,s)
, onde s (size) é a largura da célula-alvo. Por ter S livre, fundamentaxySany_to_gid()
. Larguras arbitrárias podem ser convertidas poruncertain_to_size(uncert)
.
Os arquivos contendo código-fonte da implementação passo-a-passo (steps) são utilizados pelo makefile, a seguir um breve resumo de cada.
step1_download_IBGE.sh
. Baixa os arquivos originais do IBGE por wget
, gerado pela consulta:
SELECT p||'.zip'
FROM unnest(grid_ibge.quadrantes_text(
'wget -c http://geoftp.ibge.gov.br/recortes_para_fins_estatisticos/grade_estatistica/censo_2010/grade_id'
)) t(p);
Conjunto step2*_pubLib-*.sql
. Arquivos de instalação da biblioteca do schema public
, (public library - PubLib). São comuns a outros projetos e podem receber atualizações para manter a compatibilidade global do ecossistema. O sufixo do nome de arquivo (aggregated
, json
, string
, etc.) são as categorias definidas pelo guia PostgreSQL, exceto pela categoria overload
que reunem funções de conversão de tipo ou de sobrecarga build-in, que podem gerar problemas maiores de compatibilidade.
step3_build_IBGE.sh
. Monta em /tmp/sandbox/ibge_grade
os shapefiles originais do IBGE, baixados pelo step1, e rodando shp2pgsql
, comando que vem junto com o pacote PostGIS
.
step4_prepareGridLibs.sql
. Arquivo de instalação da biblioteca principal, com funções para a manipulação da grade compacta e conversão entre as representações original e compacta.
step5opt1_fromOriginal.sql
. Processo de ingestão de dados a partir da grade original.
step5opt2_fromCsv.sql
. Processo de ingestão de dados a partir do arquivo compactado.
step6_asserts.sql
. O PostgreSQL oferece o comando PL/pgSQL ASSERT
que ajuda a documentar testes, com base na tradição das asserções lógicas. Por exemplo:
do $$
begin -- Testando o operador "="
ASSERT 1 = 2, 'Oops, o valor 1 não é 2...';
ASSERT 1 = 1, 'Erro mesmo, o valor 1 era para ser 1!';
end;
$$ LANGUAGE plpgsql; -- A execução resulta só no "Oops".
Foram criados conjuntos de 1 ou mais Testes de Regressão para cada função relevante, que serão então utilizados sempre que alguma modificação no git for feita, garantindo que bugs não sejam "injetados" pelas modificações.
step7_homolog.sql
. A homologação das funções implementadas pelo step4 se dá pelo assert com os dados originais dos shapefiles do IBGE, montantados pelo step3. Demora um pouco para rodar, e tem como finalidade única deixar registrados os critérios de homologação empregados, para quem desejar auditar.
O assert_csv_samples.sh
é um guia didático, através de exemplos, para a manipulação dos dados brutos de grid_ibge_censo2010_info.csv
em terminal Linux.
Principais funções em step4_prepareGridLibs.sql
, para a manipulação da grade compacta e conversão entre as representações original e compacta, todas do SQL SCHEMA grid_ibge
:
Inferência de nível hierárquico:
gid_to_level(gid bigint) → int
:level_to_prefix(level int) → text
: converte o número do nível (nível hierárquico da grade do IBGE) para o prefixo original usado em id_unico.level_to_size(level int) → int
: converte a convenção de número de nível (nível hierárquico da grade do IBGE) em tamanho do lado da célula, em metros.prefix_to_level(prefix text) → int
: converte o prefixo original (usado em id_unico) em número de nível (nível hierárquico da grade do IBGE).size_to_level(size int) → int
:uncertain_to_size(u int) → int
:
Inferência de quadrante:
quadrantes() → int[]
: lista dos quadrantes oficiais.quadrantes_text(prefix text DEFAULT 'ID_') → text[]
: wrap para quadrantes().xy_to_quadrante(x int, y int) → int
:xy_to_quadrante(xyd int[]) → int
: wrap paraxy_to_quadrante_text(x int, y int, prefix text DEFAULT 'ID_') → text
: wrap paraxy_to_quadrante_text(xyd int[], prefix text DEFAULT 'ID_') → text
: wrap paraxy_to_quadrante_valid(x int, y int) → int
:gid_to_quadrante(gid bigint) → int
:
Transformações padronizadas:
gid_to_gid(gid bigint, L int) → bigint
: se L menor, retorna a célula-mãe; se L maior, retorna a célula contida mais próxima do centro.gid_to_xyLcenter(gid bigint) → int[]
: converte Bigint gid em centro-XY Albers e nível da célula.gid_to_xyLref(gid bigint) → int[]
:ijS_to_xySref(i int, j int, s int) → int[]
:ijS_to_xySref(xys int[]) → int[]
: wrap para ijS_to_xySref().ptgeomAny_to_gid( geom geometry(Point,4326), L int ) → bigint
:xyLcenter_to_gid(x int, y int, nivel int) → bigint
:xyLcenter_to_xyLref(x int, y int, nivel int) → int[]
:xyL_to_xyLcenter(x int, y int, L int DEFAULT 0) → int[]
:xyL_to_xySref(x int, y int, L int DEFAULT 0) → int[]
: wrap para xyL_to_xySref().xyL_to_xySref(xyL int[]) → int[]
:
Conversão de nome:
gid_to_name(gid bigint) → text
: converte Bigint gid no nome de célula original do IBGE.name_to_gid(name text) → bigint
: converte a string de nome de célula original do IBGE em Bigint gid.name_to_parts(name text) → text[]
: divide a string do nome da célula do IBGE em três partes.name_to_parts_normalized(name text) → int[]
:name_to_xyLcenter(name text) → int[]
:
"Snap to grid":
xyL_collapseTo_ijS(x int, y int, L int) → int[]
:xyL_collapseTo_ijS(xyL int[]) → int[]
: wrap paraxyL_collapseTo_ijS(int,int,int)
.xyS_collapseTo_ijS(x int, y int, s int) → int[]
:xyS_collapseTo_ijS(xyS int[]) → int[]
: wrap paraxyS_collapseTo_ijS(int,int,int)
Transformações compostas com "Snap to grid":
xyLany_to_gid(x int, y int, L int) → bigint
:xyLany_to_name(x int, y int, L int) → text
:xyLany_to_name(xyL int[], L int default NULL) → text
: wrap paraxyLref_to_gid(x int, y int, nivel int) → bigint
:xyLref_to_gid(xyL int[]) → bigint
: wrap paraxySany_to_gid(x int, y int, S int) → bigint
:
Apoio à manipulação LatLong e GeoURI:
latlonAny_to_gid(lat real, lon real, L int) → bigint
: wrap para xyLany_to_gid().latlonAny_to_gid(latlon real[], L int DEFAULT NULL) → bigint
: wrap para latlonAny_to_gid().geoURI_to_gid(geoURI text, L int DEFAULT 5) → bigint
:
Geometria da célula em Albers:
draw_cell(gid)
: desenha a célula identificada por seu gid.draw_cell(x_ref,y_ref,L)
: desenho arbitrário de uma célula de nível L a partir do suposto ponto de referência.draw_cell(name)
: desenha a célula identificada por seu nome IBGE.draw_cell_center(gid)
: desenha ponto do centro?draw_cell_center(name)
: ? ... vername_to_xyLcenter()
API:
api.resolver_geo_uri(geouri text) → JSONb
: devolve diversas informações sobre o ponto e a célula onde está contido.api.resolver_gecode(code text, type text, subtype text) → JSONb
: mesmo queresolver_geo_uri()
, porém usando um geocódigo como argumento.
A API de microservice foi implementada conforme nossa proposta de aprimoramento do protocolo GeoURI na INDE de 2020, através do PostgREST. Endpoints previstos:
Endpoint | Descrição |
---|---|
osm.org/geo:{lat},{lon} |
efetua resolver_geo_uri() com nível default, L5, ou seja, retorna célula de 1km. Por exemplo -3.807267,-38.522481 retorna a célula 1KM, mãe de 200ME67098N108696 . |
osm.org/geo:{lat},{long};u={uncertainty} |
efetua resolver_geo_uri() com nível aferido por uncertain_to_size() . Por exemplo -3.807267,-38.522481;u=4000 retorna a célula 5KM, mãe de 200ME67098N108696 . |
osm.org/geo:br_ibge:{nome} |
retorna célula solicitada na sintaxe original, por exemplo 5KME5300N9630 retorna seus dados. |
osm.org/geo:ghs:{geohash} |
retorna célula IBGE com diâmetro de mesma ordem de grandeza, e contendo o centro do Geohash requisitado. |
Use no terminal, a parir desta pasta, o comando make
para listar as alternativas de instalação integral (all1 ou all2 descritas abaixo), que rodam todos os targets necessários, exceto clean
. O comando make
sem target informa também o que fazem os demais targets, que podem ser executados em separado.
Na pasta anterior, em /src/README.md, as versões e configurações necessárias são detalhadas.
Recomenda-se o mais simples, que é obter a Grade Estatística IBGE Compacta diretamente a partir do CSV zipado desta distribuição git. Basta executar, em terminal Linux:
make all2
Se o objetivo for reproduzir, auditorar ou atualizar a partir da Grade Estatística IBGE Original, demora um pouco mais e requer um pouco mais de espaço em disco, mas é igualmente simples. Basta executar no terminal Linux, nesta pasta, o comando:
make all1
Ou executar, na sequência, cada um dos targets definidos nas dependências de all1.
No final de make grid_orig_get
(ou meio do make all1
) todas as tabelas de quadrantes, grade_id*
, terão sido criadas:
grade_id04: 66031 itens inseridos
grade_id13: 31126 itens inseridos
grade_id14: 537732 itens inseridos
grade_id15: 306162 itens inseridos
...
grade_id92: 5091 itens inseridos
grade_id93: 1901 itens inseridos
(56 rows)
Executando em seguida o make grid_alt1_fromOrig
(final do make all1
), as tabelas são lidas e as geometrias de célula são convertidas em coordenadas de centro (na função grid_ibge.censo2010_info_load()
), para formar o identificador de célula com representação binária compacta (representado em bigint) na tabela grid_ibge.censo2010_info
. O resultado será resumido pela comparação:
resource | tables | tot_bytes | tot_size | tot_lines | bytes_per_line |
---|---|---|---|---|---|
Grade IBGE original | 56 | 4311826432 | 4112 MB | 13286489 | 325 |
Grade compacta | 1 | 726556672 | 693 MB | 13924454 | 52 |
nível | núm. células |
---|---|
0 | 56 |
1 | 1000 |
2 | 3802 |
3 | 90624 |
4 | 358069 |
5 | 8860553 |
6 | 4610350 |
A tabela da nova grade pode ainda ser gravada como CSV,
COPY grid_ibge.censo2010_info TO '/tmp/grid_ibge_censo2010_info.csv' CSV HEADER;
Se por acaso o IBGE gerar uma nova versão da grade original, o arquivo CSV deve então ser zipado com o comando zip
Linux e gravado no presente repositório git, na pasta /data/BR_IBGE.
Use make
na pasta /src
para ver instruções e rodar targets desejados.
O software foi testado com as seguintes versões e configurações:
-
PostgreSQL v12 ou v13, e PostGIS v3. Disponível em localhost como service. Rodar make com outra
pg_uri
se o usuário não for postgres -
psql
v13. Configurado nomakefile
para rodar já autenticado pelo usuário do terminal . -
pastas default: rodar o
make
a partir da própria pasta git,/src/BR_new
. Geração de arquivos pelo servidor local PostgreSQL em/tmp/pg_io
.
Para testes pode-se usar git clone https://git.osm.codes/BR_IBGE.git
ou uma versão específica zipada, por exemplo wget -c https://git.osm.codes/BR_IBGE/archive/refs/tags/
. Em seguida, estes seriam os procedimentos básicos para rodar o make em terminal bash, por exemplo:
cd grid-tests/src/BR_new
make
O make
sem target vai apenas listar as opções. Para rodar um target específico usar make nomeTarget
.
Para rodar com outra base ou outra URI de conexão com PostreSQL server, usar por exemplo make db=outraBase pg_uri=outraConexao nomeTarget
.
Homologar significa assegurar que todos os aspectos críticos ou relevantes do sistema implementado estejam 100% em conformidade com o especificado.
Podemos assegurar através de comparações com o original, em alguns casos o teste comparativo pode ser sistemático, ou seja, varrendo-se todos os itens existentes; em outros, por limitação de tempo ou CPU, se restringe a uma amostragem representativa.
Foram criadas duas VIEWS para essa finaldiade:
- ....
Aspectos selecionados e respectivos testes, baseados em comparação com os shapefiles originais do IBGE:
-
Geometria das células: certificadas pela sobreposição exata
-
Nomenclatura das células