Importar as moradas do continente
Posted by Jorge Gustavo Rocha on 28 March 2021 in Portuguese (Português).Para sistematizar a importação do continente, podem-se usar as seguintes scripts:
Sacar índices, gerar uma script para sacar os zips e sacar os zips:
#!/bin/bash
wget https://inspire.ine.pt/AD/atom/CDG_AD_BNM_pc_Norte_Atom.xml
wget https://inspire.ine.pt/AD/atom/CDG_AD_BNM_pc_Centro_Atom.xml
wget https://inspire.ine.pt/AD/atom/CDG_AD_BNM_pc_AML_Atom.xml
wget https://inspire.ine.pt/AD/atom/CDG_AD_BNM_pc_Alentejo_Atom.xml
wget https://inspire.ine.pt/AD/atom/CDG_AD_BNM_pc_Algarve_Atom.xml
awk '/Addresses_[0-9]+_EPSG3763.zip/ {print $3}' *.xml | sed 's/href=/wget /' > saca.sh
mkdir zips; cd zips; bash ../saca.sh
A script cria uma pasta zips com 278 zips (um para cada concelho do continente).
Para o restante processamento, usa-se o GDAL e uma base de dados PostgreSQL, onde é criada uma tabela moradas.
Nessa pasta, corre-se a seguinte script que processa concelho a concelho. Para cada concelho, são acrescentados os respetivos endereços à tabela moradas.
Script processa.sh:
#!/bin/bash
for filename in *.zip
do
base="${filename%.*}"
unzip $filename
echo "${filename%.*}"
GML_ATTRIBUTES_TO_OGR_FIELDS=YES GML_SKIP_RESOLVE_ELEMS=NONE ogr2ogr -f PostgreSQL PG:https://wiki.openstreetmap.org/wiki/Tag:'service=osm' GMLAS:$base.gml -nlt CONVERT_TO_LINEAR
psql service=osm -f insere.sql
rm $base.gml
done
A script processa.sh recorre a uma script SQL insere.sql, que é a seguinte:
insert into moradas (ogr_pkid, geom, numero , piso , fracao , toponimo , tipo , edificio , postcode)
with designator as (
select al.parent_ogr_pkid, json_object_agg(regexp_replace(ld.locatordesignator_type_href, 'http://inspire.ec.europa.eu/codelist/LocatorDesignatorTypeValue/(.*)Identifier', '\1'),
ld.locatordesignator_designator) as designator
from address_locator al, address_locator_addresslocator_designator ld
where al.ogr_pkid = ld.parent_ogr_pkid
group by al.parent_ogr_pkid, ld.parent_ogr_pkid),
buidname as (
select al.parent_ogr_pkid, gns.spellingofname_text
from address_locator al, address_locator_addresslocator_name alan, address_locator_addresslocator_name_locatorname_name alanln, geographicalname gn, geographicalname_spelling gns
where al.ogr_pkid = alan.parent_ogr_pkid and
alan.ogr_pkid =alanln.parent_ogr_pkid and
alanln.geographicalname_pkid = gn.ogr_pkid and
gn.ogr_pkid = gns.parent_ogr_pkid),
position as (
select ap.parent_ogr_pkid, ap.geographicposition_geometry
from address_position ap),
postcode as (
select parent_ogr_pkid, pd.postcode
from address_component ac left join postaldescriptor pd on ac.href_postaldescriptor_pkid = pd.ogr_pkid
where href_postaldescriptor_pkid is not null),
toponimo as (
with tfnp as (
select parent_ogr_pkid, json_object_agg( regexp_replace(partofname_type_href , 'http://inspire.ec.europa.eu/codelist/PartTypeValue/(.*)', '\1'), partofname_part) as partofname
from thoroughfarename_ad_name_thoroughfarenamevalue_nameparts
group by parent_ogr_pkid)
select ac.parent_ogr_pkid, tfnp.partofname
from address_component ac left join thoroughfarename tf on ac.href_thoroughfarename_pkid = tf.ogr_pkid
left join thoroughfarename_ad_name tfn on tf.ogr_pkid = tfn.parent_ogr_pkid
left join tfnp on tfnp.parent_ogr_pkid = tfn.ogr_pkid where href_thoroughfarename_pkid is not null)
select a.ogr_pkid, p.geographicposition_geometry as geom, d.designator->>'building' as numero, d.designator->>'floor' as piso, d.designator->>'unit' as fracao,
t.partofname->>'name' as toponimo, t.partofname->>'type' as tipo, buidname.spellingofname_text as edificio, pc.postcode
from address a, position p, designator d, toponimo t, postcode pc, buidname
where a.ogr_pkid = p.parent_ogr_pkid and a.ogr_pkid = d.parent_ogr_pkid and a.ogr_pkid = pc.parent_ogr_pkid and a.ogr_pkid = t.parent_ogr_pkid and a.ogr_pkid = buidname.parent_ogr_pkid;
drop table address;
drop table address_building;
drop table address_component;
drop table address_locator;
drop table address_locator_addresslocator_designator;
drop table address_locator_addresslocator_name;
drop table address_locator_addresslocator_name_locatorname_name;
drop table address_metadataproperty;
drop table address_name;
drop table address_parcel;
drop table address_position;
drop table addressareaname;
drop table addressareaname_ad_name;
drop table addressareaname_gml_name;
drop table addressareaname_metadataproperty;
drop table addressareaname_situatedwithin;
drop table administrativeboundary;
drop table administrativeboundary_admunit;
drop table administrativeboundary_metadataproperty;
drop table administrativeboundary_name;
drop table administrativeboundary_nationallevel;
drop table administrativeunit;
drop table administrativeunit_administeredby;
drop table administrativeunit_au_name;
drop table administrativeunit_boundary;
drop table administrativeunit_coadminister;
drop table administrativeunit_condominium;
drop table administrativeunit_gml_name;
drop table administrativeunit_lowerlevelunit;
drop table administrativeunit_metadataproperty;
drop table administrativeunit_nationallevelname;
drop table administrativeunit_residenceofauthority;
drop table adminunitname;
drop table adminunitname_ad_name;
drop table adminunitname_gml_name;
drop table adminunitname_metadataproperty;
drop table adminunitname_situatedwithin;
drop table basicpropertyunit;
drop table basicpropertyunit_metadataproperty;
drop table basicpropertyunit_name;
drop table cadastralparcel;
drop table cadastralparcel_basicpropertyunit;
drop table cadastralparcel_metadataproperty;
drop table cadastralparcel_name;
drop table cadastralzoning;
drop table cadastralzoning_cp_name;
drop table cadastralzoning_gml_name;
drop table cadastralzoning_levelname;
drop table cadastralzoning_metadataproperty;
drop table condominium;
drop table condominium_admunit;
drop table condominium_au_name;
drop table condominium_gml_name;
drop table condominium_metadataproperty;
drop table geographicalname;
drop table geographicalname_spelling;
drop table inspireid;
drop table location;
drop table md_resolution;
drop table namedplace;
drop table namedplace_gml_name;
drop table namedplace_gn_name;
drop table namedplace_localtype;
drop table namedplace_metadataproperty;
drop table namedplace_relatedspatialobject;
drop table namedplace_type;
drop table postaldescriptor;
drop table postaldescriptor_metadataproperty;
drop table postaldescriptor_name;
drop table postaldescriptor_postname;
drop table postaldescriptor_situatedwithin;
drop table thoroughfarename;
drop table thoroughfarename_ad_name;
drop table thoroughfarename_ad_name_thoroughfarenamevalue_nameparts;
drop table thoroughfarename_gml_name;
drop table thoroughfarename_metadataproperty;
drop table thoroughfarename_situatedwithin;
drop table thoroughfarename_transportlink;
Depois deste processamento, na tabela moradas têm-se os endereços do INE para o continente, no sistema de coordenadas ETRS89/Portugal TM06.
Para exportar os endereços por concelhos, carrega-se a tabela dos concelhos do continente (gerada a partir da CAOP) na base dados. Com base nessa tabela, gera-se uma script com a exportação concelho a concelho.
Cada linha da script de exportação é gerada com (continente.sql):
select 'mkdir "' || concelho || '"; ogr2ogr -f "ESRI Shapefile" "' || concelho || '/' || dicofre || '.shp" PG:"https://wiki.openstreetmap.org/wiki/Tag:service=osm" -sql "select m.* from moradas m, concelhos c where st_contains(c.geom, m.geom) and c.concelho = ' || '''' || concelho || '''"' from concelhos;
psql service=osm -t -f continente.sql > continente.sh
mkdir continente; cd continente
bash ../continente.sh
Finalmente, para se poder usar a tabela moradas no QGIS ou para a publicar através de serviços WMS ou WFS/QFS3, dá jeito ter uma chave primária e um índice espacial.
ALTER TABLE moradas ADD CONSTRAINT moradas_pk PRIMARY KEY (ogr_pkid);
CREATE INDEX moradas_geom_idx ON moradas USING gist (geom);
O resultado são 278 pastas, uma por concelho, e em cada pasta está a shapefile com os endereços desse concelho.
As pastas podem ser acedidas a partir uma nextcloud experimental para a comunidade OpenStreetMap PT, em importação dos endereços do continente. As shapefiles por concelhos estão nas pasta continente. Partilhei outras pastas, para incluir as scripts.
O backup no formato PostgrSQL das tabelas usadas (moradas e concelhos, derivada da CAOP 2020) está também nessa pasta, em enderecos-202103282354.backup.
Essas mesmas duas tabelas estão em continente.gpkg, que pode ser aberto no QGIS. Foi exportado com:
ogr2ogr -f GPKG continente.gpkg PG:https://wiki.openstreetmap.org/wiki/Tag:'service=osm https://wiki.openstreetmap.org/wiki/Tag:tables=moradas,concelhos'
Querem uma shapefile com as moradas todas? Eu criei uma, mas tem mais de 2Gb. Está em continente.shp.zip. Não tem índice espacial, para não ocupar mais espaço. Vai dar cabo de alguns softwares foleiros a correr em sistemas operativos duvidosos.
Para o continente, ficam assim disponíveis 5 669 971 endereços. Vou dizer por extenso: cinco milhões, seiscentos e sessenta e nove mil, novecentos e setenta e um endereços.
Bom trabalho!
Discussion
Comment from Jorge Gustavo Rocha on 29 March 2021 at 00:15
Acrescentei os formatos
*.osme*.jsonpara cada concelho do continente, com a script2osm.shque está na pastacontinente.Comment from lels07 on 23 March 2023 at 09:33
Bom dia Jorge . Visto que as coordenadas que o OSM(descarregadas através do Geofabrik) usam o sistema EPSG4324-WGS84, seria necessário transformar os endereços do INE para este sistema. Por acaso, tem uma solução para esta questão? Já trabalhou nesta situação aqui descrita?
Obrigado pela ajuda .
Comment from Jorge Gustavo Rocha on 23 March 2023 at 15:29
A transformação de coordenadas por de ser feita na linha de comandos com o ogr2ogr, no Postgresql ou num cliente SIG, como o QGIS. Todas estas soluções indicadas usam a mesma biblioteca Proj, que é a responsável pela transformação das coordenadas. Recomenda-se vivamente a configuração do Proj com as grelhas fornecidas pela DGT.