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:'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:"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:'service=osm 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!