UAT, România (poligon, geometrie unificată București)
Cod set de date
ro_admin_lau_bucharest_merged_polygon
Abordare practică
Geometria setului de date Limite administrative - UAT, România (poligon) a fost procesată pentru a comasa sectoarele Municipiului București într-o singură entitate. Pentru pașii de procesare, scriptul utilizează mai multe biblioteci open source și utilitare de sistem: GDAL, mapshaper, csvkit, mdb-tools, sed, awk. Scriptul rezultat este prezentat în secțiunea Script ETL și accesibil pentru descărcare pe pagina GitHub a geo-spatial.org.
Prelucrarea datelor
Comasarea geometriei Municipiului București
Geometria originală pentru cele șase sectoare ale Municipiului București au fost unificată într-o singură geometrie ce a primit numele București și codul siruta 403 (codul aferent nivelului administrativ de tip județ pentru București)
Conversia în formate de fișier populare
Datele au foct convertite în formatele de fișier utilizate de geo-spatial.org pentru distribuirea de date vectoriale: GeoPackage
, Shapefile
, Geoparquet
, FlatGeobuf
, GeoJSON
, TopoJSON
, KML
. Detalii despre motivația alegerii acestor formate și beneficiile fiecăruia sunt prezentate în ghidul cu privire la date. De asemenea, pentru nevoi interne, datele au fost încărcate în baza de date PostgreSQL/PostGIS.
Publicare datelor
Datele au fost documentate în Catalogul geo-spatial.org și puse la dispoziție pentru download/access prin protocolul HTTP și prin intermediul serviciilor standardizate OGC. Pentru mai multe detalii accesați Catalogul și/sau secțiunea Descărcare. Definițiile folosite pentru simbolizarea WMS a datelor au fost documentate în secțiunea Simbolizare SLD.
Script ETL
#!/usr/bin/zsh
##############################################################################################################
#🛠 Publicare/actualizare UAT(poligon, geometrie unificată București)
##############################################################################################################
#🎛 configurații
#🕹 activare mediu Anaconda cu bibliotecile necesare pentru procesare
source /home/ubuntu/anaconda3/etc/profile.d/conda.sh
conda activate geo
#🚏 definire căi date
lau_data_path="/storage/volumes/geoserver-1-storage/administrative_boundaries/lau"
#⚙️ PostGIS
pg_host="localhost"
pg_port=5432
pg_user="user"
pg_db="geospatial"
pg_pass="pass"
pg_schema="romania"
#⚙️ GeoServer
gs_url="http://localhost:8080/geoserver"
gs_user="user"
gs_pass="pass"
gs_workspace="administrative-boundaries"
gs_store="administrative-boundaries"
gs_layer_title="Limite administrative - UAT, România (poligon, geometrie unificată București)"
gs_layer_abstract="Set de date este derivat din Limite administrative - UAT, România (poligon). Geometria originală pentru cele șase sectoare ale Municipiului București au fost unificată într-o singură geometrie ce a primit numele București și codul siruta 403 (codul aferent nivelului administrativ de tip județ pentru București). Setul de date este util pentru reprezentări în care se dorește ca Municipiul București să apară ca o singură entitate."
gs_layer_keywords=("România" "UAT" "limite administrative" "vector" "poligon" "sectoare București comasate")
gs_layer_metadata_link="https://services.geo-spatial.org/geonetwork/srv/eng/catalog.search#/metadata/276ce5c1-2b60-43ee-b19c-25fb0c830b08"
gs_layer_style="administrative-boundaries:ro_admin_lau_bucharest_merged_polygon_labels"
gs_layer_secondary_style="administrative-boundaries:ro_admin_lau_bucharest_merged_polygon"
#⚙️ Date
layer_name="ro_admin_lau_bucharest_merged_polygon"
echo "
🛠 Procesare UAT poligon București comasat
"
#💾 creare versiune GeoPackage
echo "💾 creare versiune GeoPackage"
if [ -f ${lau_data_path}/${layer_name}.gpkg ]; then
rm ${lau_data_path}/${layer_name}.gpkg
fi
ogr2ogr -of GPKG -lco FID=id -nlt MULTIPOLYGON -nln ${layer_name} -dialect sqlite \
-sql "
SELECT
CASE
WHEN natCode IN (179141,179150,179169,179178,179187,179196) THEN 403
ELSE natCode
END AS natCode,
CASE
WHEN natCode IN (179141,179150,179169,179178,179187,179196) THEN 'București'
ELSE name
END AS name,
MIN(natLevName) AS natLevName,
MIN(countyId) AS countyId,
MIN(countyCode) AS countyCode,
MIN(county) AS county,
MIN(countyMn) AS countyMn,
MIN(regionId) AS regionId,
MIN(regionCode) AS regionCode,
MIN(region) AS region,
MIN(version) AS version,
ST_Union(geometry) AS geometry
FROM ro_admin_lau_polygon
GROUP BY
CASE
WHEN natCode IN (179141,179150,179169,179178,179187,179196) THEN 403
ELSE natCode
END,
CASE
WHEN natCode IN (179141,179150,179169,179178,179187,179196) THEN 'București'
ELSE name
END
" \
${lau_data_path}/${layer_name}.gpkg ${lau_data_path}/ro_admin_lau_polygon.gpkg
#💾 creare fișiere Esri Shapefile
echo "💾 creare fișiere Esri Shapefile"
if [ -f ${lau_data_path}/${layer_name}.zip ]; then
rm ${lau_data_path}/${layer_name}.zip
fi
ogr2ogr -lco ENCODING=UTF-8 -nln ${layer_name} -dialect sqlite -sql "SELECT a.id AS id, * FROM ${layer_name} AS a" ${lau_data_path}/${layer_name}.shp ${lau_data_path}/${layer_name}.gpkg
#📦 arhivare fișiere shp
echo "📦 arhivare fișiere shp"
zip -j ${lau_data_path}/${layer_name}.zip ${lau_data_path}/${layer_name}.dbf ${lau_data_path}/${layer_name}.shp ${lau_data_path}/${layer_name}.prj ${lau_data_path}/${layer_name}.shx ${lau_data_path}/${layer_name}.cpg
#💾 creare versiune FlatGeobuf
echo "💾 creare versiune FlatGeobuf"
if [ -f ${lau_data_path}/${layer_name}.fgb ]; then
rm ${lau_data_path}/${layer_name}.fgb
fi
ogr2ogr -of FlatGeobuf -nlt MULTIPOLYGON -nln ${layer_name} -dialect sqlite -sql "SELECT a.id AS id, * FROM ${layer_name} AS a" ${lau_data_path}/${layer_name}.fgb ${lau_data_path}/${layer_name}.gpkg
#💾 creare versiune GeoParquet
echo "💾 creare versiune GeoParquet"
if [ -f ${lau_data_path}/${layer_name}.parquet ]; then
rm ${lau_data_path}/${layer_name}.parquet
fi
ogr2ogr -of Parquet -nlt MULTIPOLYGON -nln ${layer_name} -dialect sqlite -sql "SELECT a.id AS id, * FROM ${layer_name} AS a" ${lau_data_path}/${layer_name}.parquet ${lau_data_path}/${layer_name}.gpkg
#💾 creare versiune GeoJSON
echo "💾 creare versiune GeoJSON"
if [ -f ${lau_data_path}/${layer_name}.geojson ]; then
rm ${lau_data_path}/${layer_name}.geojson
fi
ogr2ogr -of GeoJSON -t_srs EPSG:4326 -nln ${layer_name} -dialect sqlite -sql "SELECT a.id AS id, * FROM ${layer_name} AS a" ${lau_data_path}/${layer_name}.geojson ${lau_data_path}/${layer_name}.gpkg
#💾 creare versiune KML
echo "💾 creare versiune KML"
if [ -f ${lau_data_path}/${layer_name}.kml ]; then
rm ${lau_data_path}/${layer_name}.kml
fi
ogr2ogr -of KML -t_srs EPSG:4326 -dsco NameField=name ${lau_data_path}/${layer_name}.kml ${lau_data_path}/${layer_name}.gpkg
#💾 creare versiune TopoJSON
echo "💾 creare versiune TopoJSON"
if [ -f ${lau_data_path}/${layer_name}.topojson ]; then
rm ${lau_data_path}/${layer_name}.topojson
fi
mapshaper -i ${lau_data_path}/${layer_name}.geojson -o format=topojson ${lau_data_path}/${layer_name}.topojson
#💾 actualizarea setului de date în baza de date PostGIS
echo "💾 actualizarea setului de date în baza de date PostGIS"
ogr2ogr -of PostgreSQL PG:"host=${pg_host} port=${pg_port} user=${pg_user} dbname=${pg_db} password=${pg_pass}" -lco schema=${pg_schema} -lco GEOMETRY_NAME=geom -lco overwrite=yes ${lau_data_path}/${layer_name}.gpkg ${layer_name} -skipfailures -overwrite
#🖇 indexare date PostGIS
psql -h ${pg_host} -p ${pg_port} -U ${pg_user} -d ${pg_db} -c "
CREATE INDEX ${layer_name}_geom_idx ON romania.${layer_name} USING GIST (geom);
CLUSTER romania.${layer_name} USING ${layer_name}_geom_idx;"
#💾 publicarea/actualizarea serviciilor de date
echo "💾 publicarea/actualizarea serviciilor de date"
#❌ ștergere strat existent (dacă există)
echo "🔍 Verificare dacă există stratul."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -u $gs_user:$gs_pass \
"${gs_url}/rest/layers/${gs_workspace}:${layer_name}.xml")
if [ "$HTTP_STATUS" == "200" ]; then
echo "⚠️ Stratul există. Se șterge."
curl -s -u $gs_user:$gs_pass -XDELETE \
"${gs_url}/rest/layers/${gs_workspace}:${layer_name}?recurse=true"
echo "🗑️ Stratul a fost șters."
else
echo "✅ Nu există strat cu acest nume."
fi
#💾 creare strat
echo "➕ Creare strat ${layer_name}"
curl -s -u $gs_user:$gs_pass -XPOST -H "Content-type: text/xml" \
-d "<featureType>
<name>${layer_name}</name>
<nativeName>${layer_name}</nativeName>
<title>${gs_layer_title}</title>
<abstract>${gs_layer_abstract}</abstract>
</featureType>" \
"${gs_url}/rest/workspaces/${gs_workspace}/datastores/${gs_store}/featuretypes"
#💾 adăugare detalii suplimentare (keywords și metadata link)
echo "📝 Actualizare metadate"
keywords_xml=""
for keyword in "${gs_layer_keywords[@]}"; do
keywords_xml+="<string>${keyword}</string>"
done
curl -s -u $gs_user:$gs_pass -XPUT -H "Content-type: text/xml" \
-d "<featureType>
<keywords>
${keywords_xml}
</keywords>
<metadataLinks>
<metadataLink>
<type>text/xml</type>
<metadataType>ISO19115:2003</metadataType>
<content>${gs_layer_metadata_link}</content>
</metadataLink>
</metadataLinks>
</featureType>" \
"${gs_url}/rest/workspaces/${gs_workspace}/datastores/${gs_store}/featuretypes/${layer_name}"
#💾 Setare stil implicit + atașare stil suplimentar
echo "🎨 Setare stil implicit + atașare stil suplimentar..."
curl -s -u $gs_user:$gs_pass -XPUT -H "Content-type: text/xml" \
-d "<layer>
<defaultStyle>
<name>${gs_layer_style##*:}</name>
</defaultStyle>
<styles>
<style>
<name>${gs_layer_secondary_style##*:}</name>
</style>
</styles>
</layer>" \
"${gs_url}/rest/layers/${gs_workspace}:${layer_name}"
echo "✅ Stratul ${layer_name} a fost adăugat și configurat cu succes în GeoServer."
#🗑️ Ștergere fișiere intermediare
echo "🗑️ Ștergere fișiere Shapefile"
rm ${lau_data_path}/${layer_name}.dbf ${lau_data_path}/${layer_name}.shp ${lau_data_path}/${layer_name}.prj ${lau_data_path}/${layer_name}.shx ${lau_data_path}/${layer_name}.cpg
Simbolizare SLD
Simbolizare SLD implicită
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:se="http://www.opengis.net/se" version="1.1.0">
<NamedLayer>
<se:Name>UAT-uri</se:Name>
<UserStyle>
<se:Name>Limită UAT</se:Name>
<se:FeatureTypeStyle>
<!-- Regula afișată doar la scări < 1:300.000, fără etichete -->
<se:Rule>
<se:Name>Limită UAT</se:Name>
<se:MinScaleDenominator>300000</se:MinScaleDenominator>
<se:PolygonSymbolizer>
<se:Stroke>
<se:SvgParameter name="stroke">#be2edd</se:SvgParameter>
<se:SvgParameter name="stroke-width">1</se:SvgParameter>
<se:SvgParameter name="stroke-linejoin">bevel</se:SvgParameter>
</se:Stroke>
</se:PolygonSymbolizer>
</se:Rule>
<!-- Regula afișată doar la scări > 1:300.000, cu etichete -->
<se:Rule>
<se:Name>Limită UAT</se:Name>
<se:MaxScaleDenominator>300000</se:MaxScaleDenominator>
<se:PolygonSymbolizer>
<se:Stroke>
<se:SvgParameter name="stroke">#be2edd</se:SvgParameter>
<se:SvgParameter name="stroke-width">1</se:SvgParameter>
<se:SvgParameter name="stroke-linejoin">bevel</se:SvgParameter>
</se:Stroke>
</se:PolygonSymbolizer>
<se:TextSymbolizer>
<se:Label>
<ogc:PropertyName>name</ogc:PropertyName>
</se:Label>
<se:Font>
<se:SvgParameter name="font-family">Helvetica</se:SvgParameter>
<se:SvgParameter name="font-size">14</se:SvgParameter>
</se:Font>
<se:LabelPlacement>
<se:PointPlacement>
<se:AnchorPoint>
<se:AnchorPointX>0</se:AnchorPointX>
<se:AnchorPointY>0.5</se:AnchorPointY>
</se:AnchorPoint>
</se:PointPlacement>
</se:LabelPlacement>
<se:Halo>
<se:Radius>2</se:Radius>
<se:Fill>
<se:SvgParameter name="fill">#ffffff</se:SvgParameter>
</se:Fill>
</se:Halo>
<se:Fill>
<se:SvgParameter name="fill">#be2edd</se:SvgParameter>
</se:Fill>
<se:VendorOption name="maxDisplacement">1</se:VendorOption>
</se:TextSymbolizer>
</se:Rule>
</se:FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
Fișier accesibil și pe GitHub.
Simbolizare SLD alternativă
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:se="http://www.opengis.net/se" version="1.1.0">
<NamedLayer>
<se:Name>UAT-uri</se:Name>
<UserStyle>
<se:Name>Limită UAT</se:Name>
<se:FeatureTypeStyle>
<se:Rule>
<se:Name>Limită UAT</se:Name>
<se:PolygonSymbolizer>
<se:Stroke>
<se:SvgParameter name="stroke">#be2edd</se:SvgParameter>
<se:SvgParameter name="stroke-width">1</se:SvgParameter>
<se:SvgParameter name="stroke-linejoin">bevel</se:SvgParameter>
</se:Stroke>
</se:PolygonSymbolizer>
</se:Rule>
</se:FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
Fișier accesibil și pe GitHub.