apb_extra_osgeo_utils
Package apb_extra_osgeo_utils
Modules to add common functionality to OSGEO GDAL
. Requires GDAL
library C previously installed
(see how here https://gdal.org/download.html#binaries).
Requires GDAL
library version 3.6<=3.9 installed.
To install:
pip install apb_extra_osgeo_utils
Documentation here apb_extra_osgeo_utils
1# coding=utf-8 2# 3# Author: Ernesto Arredondo Martinez (ernestone@gmail.com) 4# Created: 7/6/19 18:23 5# Last modified: 7/6/19 14:27 6# Copyright (c) 2019 7""" 8.. include:: ../README.md 9""" 10 11import logging 12import os 13import re 14from collections import OrderedDict, namedtuple 15 16import math 17from osgeo import ogr, osr 18from osgeo.ogr import ODsCCreateLayer, OLCAlterFieldDefn, OLCCreateField, ODsCTransactions, \ 19 ODsCDeleteLayer, OLCTransactions, Geometry, ODrCCreateDataSource, GeomFieldDefn 20 21from apb_extra_utils import misc as utils 22 23SIMPLIFY_TOLERANCE = 1e-6 24DRIVERS_GDAL_NOT_DELETE_LAYERS = ('POSTGRESQL',) 25DRIVERS_OLD_SRS_AXIS_MAPPING_4326 = ('GEOJSON', 'GPKG', 'POSTGRESQL') 26PREFFIX_GEOMS_LAYERS_GDAL = 'geom_' 27PREFFIX_GEOMS_LAYERS_GDAL_CSV = '_WKT' 28 29print_debug = logging.debug 30print_warning = logging.warning 31 32 33def srs_ref_from_epsg_code(code_epsg: int, old_axis_mapping=False) -> osr.SpatialReference: 34 """ 35 36 Args: 37 code_epsg (int): 38 old_axis_mapping (bool=False): Por cambio entre GDAL2.0 y GDAL3.0 se (vease 39 https://github.com/OSGeo/gdal/blob/master/gdal/MIGRATION_GUIDE.TXT) por defecto se utiliza el mapeo de ejes 40 clasico LONG,LAT 41 42 Returns: 43 srs (osr.SpatialReference) 44 """ 45 srs = osr.SpatialReference() 46 if old_axis_mapping: 47 try: 48 from osgeo.osr import OAMS_TRADITIONAL_GIS_ORDER 49 print_debug("OAMS_TRADITIONAL_GIS_ORDER") 50 srs.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER) 51 except ImportError: 52 print_warning("OAMS_TRADITIONAL_GIS_ORDER not available") 53 54 ret = srs.ImportFromEPSG(code_epsg) 55 if ret != 0: 56 raise Warning("No se puede retornar un osgeo.osr.SpatialReference EPSG para el codigo '{}'!!".format(code_epsg)) 57 58 return srs 59 60 61def layer_gdal_from_file(path_file: str, 62 nom_driver: str = 'GeoJSON', 63 nom_geom: str = None, 64 default_srs_epsg_code: int = 4326, 65 default_order_long_lat: bool = True): 66 """ 67 68 Args: 69 path_file (str): 70 nom_driver (str='GeoJSON'): 71 nom_geom (str=None): si se informa devolverá la layer solo con la geometria especificada 72 default_srs_epsg_code (int=4326): codigo del sistema de coordenadas que asignará por defecto si la layer 73 NO tiene sistema definido 74 default_order_long_lat (bool=True): si no viene informado el SRS y se usa el default EPSG4326 entonces se supone 75 por defecto que las geometria vienen en orden antiguo LONGITUD, LATITUD 76 77 Returns: 78 layer_gdal (osgeo.ogr.Layer), nom_layer (str), datasource_gdal (osgeo.ogr.DataSource) 79 """ 80 drvr = ogr.GetDriverByName(nom_driver) 81 82 nom_layer, ext = utils.split_ext_file(os.path.basename(path_file)) 83 if ext.lower().endswith("zip"): 84 path_file = "/vsizip/{}".format(path_file) 85 86 ds_vector_file = drvr.Open(path_file, 0) 87 88 a_layer = None 89 if ds_vector_file: 90 a_layer = ds_vector_file.GetLayer(0) 91 92 if nom_geom: 93 lay_def = a_layer.GetLayerDefn() 94 nom_geom = nom_geom.strip().upper() 95 96 if lay_def.GetGeomFieldCount() > 1: 97 idx_geom = lay_def.GetGeomFieldIndex(nom_geom) 98 if idx_geom < 0: 99 raise Exception("El fichero vectorial '{}' no contiene una geometria con el nombre '{}'".format( 100 ds_vector_file.GetName(), nom_geom)) 101 elif idx_geom > 0: 102 # Convertimos a layer en MEMORY para poder cambiar estructura 103 ds_mem = ds_gdal_memory() 104 a_layer = create_layer_from_layer_gdal_on_ds_gdal(ds_mem, a_layer, nom_layer, nom_geom, 105 exclude_cols_geoms=False, null_geoms=True) 106 if a_layer: 107 ds_vector_file = ds_mem 108 109 elif not a_layer.GetGeometryColumn() and lay_def.GetGeomFieldDefn(0): 110 lay_def.GetGeomFieldDefn(0).SetName(nom_geom) 111 112 if a_layer: 113 # Por si no carga el SRS se asigna el :default_srs_epsg_code (defecto epsg:4326) 114 for gf in geom_fields_layer_gdal(a_layer): 115 if not gf.GetSpatialRef(): 116 gf.SetSpatialRef(srs_ref_from_epsg_code(default_srs_epsg_code, default_order_long_lat)) 117 118 return a_layer, nom_layer, ds_vector_file 119 120 121def datasource_gdal_vector_file(nom_driver_gdal, nom_ds, a_dir, create=None, from_zip=False, **create_options): 122 """ 123 Crea datasource gdal para driver de tipo fichero 124 Args: 125 nom_driver_gdal (str): 126 nom_ds (str): 127 a_dir (str): 128 create (bool=None): Por defecto crea el datasource si este no existe y se abre sin problemas previamente. 129 Si False entonces NO lo crea en ningún caso, y si True lo creará sin intentar abrirlo 130 from_zip (bool=False): 131 **create_options: lista claves valores con opciones de creacion para el datasource de GDAL 132 p.e.: NameField="SEQENTITAT", DescriptionField="SW_URN" 133 134 Returns: 135 datasource_gdal (osgeo.ogr.DataSource), overwrited (bool) 136 """ 137 driver, exts_driver = driver_gdal(nom_driver_gdal) 138 if not exts_driver: 139 raise Exception("ERROR! - El driver GDAL {} no es de tipo fichero vectorial".format(driver)) 140 141 base_path_file = os.path.normpath(os.path.join(a_dir, nom_ds.strip().lower())) 142 _, ext_base = os.path.splitext(base_path_file) 143 144 vsi_prefix = "" 145 if from_zip: 146 ext_file = "zip" 147 vsi_prefix = "/vsizip/" 148 else: 149 if "topojson" in (ext.lower() for ext in exts_driver): 150 ext_file = "topojson" 151 else: 152 ext_file = exts_driver[0] 153 154 if (os.path.exists(base_path_file) and os.path.isfile( 155 base_path_file)) or ext_base.lower() == f'.{ext_file.lower()}': 156 path_file = base_path_file 157 else: 158 path_file = "{}.{}".format(base_path_file, ext_file) 159 160 overwrited = False 161 datasource_gdal = None 162 if not create and os.path.exists(path_file): 163 open_path_file = "{}{}".format(vsi_prefix, path_file) 164 datasource_gdal = driver.Open(open_path_file, 1) 165 if datasource_gdal is None: 166 datasource_gdal = driver.Open(open_path_file) 167 168 if datasource_gdal: 169 overwrited = True 170 171 if create or (create is not False and datasource_gdal is None and driver.TestCapability(ODrCCreateDataSource)): 172 datasource_gdal = driver.CreateDataSource(path_file, 173 list("{}={}".format(opt, val) for opt, val in create_options.items())) 174 175 return datasource_gdal, overwrited 176 177 178def driver_gdal(nom_driver): 179 """ 180 Devuelve el driver GDAL solicitado y si es de tipo fichero vectorial tambien devuelve la extension 181 Si no coincide exactamente devuelve el que tiene nombre más parecido. 182 Verificar con drivers_ogr_gdal_disponibles() los disponibles 183 184 Args: 185 nom_driver: 186 Returns: 187 driver_gdal (osgeo.ogr.Driver), exts_driver (list) 188 """ 189 driver_gdal = ogr.GetDriverByName(nom_driver) 190 exts_drvr = driver_gdal.GetMetadata().get('DMD_EXTENSIONS', "").split(" ") 191 192 return driver_gdal, exts_drvr 193 194 195def ds_gdal_memory(): 196 """ 197 Devuelve un osgeo.ogr.DataSource de tipo "memory" 198 199 Returns: 200 datasource_gdal (osgeo.ogr.DataSource) 201 """ 202 return ogr.GetDriverByName("memory").CreateDataSource("") 203 204 205def set_create_option_list_for_layer_gdal(layer_gdal, drvr_name="GPKG", **extra_opt_list): 206 """ 207 Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options 208 pasadas por defecto 209 210 Args: 211 layer_gdal (ogr.Layer): 212 drvr_name (str="GPKG"): nombre de driver GDAL 213 extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL 214 215 Returns: 216 opt_list (dict) 217 """ 218 opt_list = set_create_option_list_for_driver_gdal(drvr_name, **extra_opt_list) 219 220 opt_geom_name = "GEOMETRY_NAME" 221 if opt_geom_name not in opt_list: 222 nom_geom_src = layer_gdal.GetGeometryColumn() 223 if nom_geom_src: 224 opt_list[opt_geom_name] = "{}={}".format(opt_geom_name, nom_geom_src) 225 226 return opt_list 227 228 229def set_create_option_list_for_driver_gdal(drvr_name="GPKG", **extra_opt_list): 230 """ 231 Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options 232 pasadas por defecto 233 234 Args: 235 drvr_name (str="GPKG"): nombre de driver GDAL 236 extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL 237 238 Returns: 239 opt_list (dict) 240 """ 241 # Se quitan las options que no son de creacion para el driver especificado 242 drvr, exts_drvr = driver_gdal(drvr_name) 243 if not drvr: 244 Exception("!ERROR! - El nombre de driver '{}' no es un driver GDAL disponible".format(drvr_name)) 245 246 opt_list = {k.upper(): v.upper() for k, v in extra_opt_list.items()} 247 248 if not "FID" in opt_list and drvr.name == 'GPKG': 249 opt_list["FID"] = 'FID=FID_GPKG' 250 251 if drvr.name == "GeoJSON": 252 if "WRITE_BBOX" not in opt_list: 253 opt_list["WRITE_BBOX"] = 'WRITE_BBOX=YES' 254 255 if drvr.name == "CSV": 256 if "CREATE_CSVT" not in opt_list: 257 opt_list["CREATE_CSVT"] = 'CREATE_CSVT=YES' 258 if "GEOMETRY" not in opt_list: 259 opt_list["GEOMETRY"] = 'GEOMETRY=AS_WKT' 260 261 if drvr.GetMetadataItem('DS_LAYER_CREATIONOPTIONLIST'): 262 list_opts_drvr = drvr.GetMetadataItem('DS_LAYER_CREATIONOPTIONLIST') 263 keys_opt_list = list(opt_list.keys()) 264 for n_opt in keys_opt_list: 265 if list_opts_drvr.find(n_opt) < 0: 266 opt_list.pop(n_opt) 267 268 if "SPATIAL_INDEX" not in opt_list and \ 269 list_opts_drvr.find("SPATIAL_INDEX") >= 0 and drvr.name != 'PostgreSQL': 270 opt_list["SPATIAL_INDEX"] = 'SPATIAL_INDEX=YES' 271 272 return opt_list 273 274 275def copy_layer_gdal_to_ds_gdal(layer_src, ds_gdal_dest, nom_layer=None, nom_geom=None, 276 overwrite=True, **extra_opt_list): 277 """ 278 Copia una layer_gdal a otro datasource gdal 279 280 Args: 281 layer_src: 282 ds_gdal_dest: 283 nom_layer (str=None): OPC - Si no viene informado cogerá el nombre de la layer 284 nom_geom (str=None): OPC - Si se informa se cogerá como el nombre de la geometria de la nueva layer 285 overwrite (bool=True): 286 **extra_opt_list (str): Lista claves-valores de opciones para copylayer o createLayer 287 del driver de ds_gdal indicado 288 289 Returns: 290 layer_dest (ogr.layer) 291 """ 292 if not nom_layer: 293 nom_layer = layer_src.GetName() 294 nom_layer = nom_layer.strip().lower() 295 296 layer_dest = ds_gdal_dest.GetLayerByName(nom_layer) 297 if layer_dest: 298 if not overwrite: 299 return layer_dest 300 else: 301 ds_gdal_dest.DeleteLayer(nom_layer) 302 303 drvr_name = ds_gdal_dest.GetDriver().GetName() 304 305 extra_opt_list["IDENTIFIER"] = "IDENTIFIER={}".format(nom_layer) 306 307 opt_list = set_create_option_list_for_layer_gdal(layer_src, drvr_name=drvr_name, 308 **{k.upper(): v.upper() for k, v in extra_opt_list.items()}) 309 310 layer_dest = ds_gdal_dest.CopyLayer(layer_src, nom_layer, list(opt_list.values())) 311 312 if layer_dest: 313 if not layer_dest.GetGeometryColumn() and layer_dest.GetLayerDefn().GetGeomFieldDefn(0) and \ 314 (layer_src.GetGeometryColumn() or nom_geom): 315 if not nom_geom: 316 nom_geom = layer_src.GetGeometryColumn() 317 else: 318 nom_geom = nom_geom.upper() 319 320 layer_dest.GetLayerDefn().GetGeomFieldDefn(0).SetName(nom_geom) 321 322 if drvr_name == "GPKG": 323 create_spatial_index_layer_gpkg(ds_gdal_dest, nom_layer) 324 325 return layer_dest 326 327 328def layer_gtype_from_geoms(layer_gdal, nom_geom=None): 329 """ 330 A partir de la 1º geometria informada de una layer_gdal devuelve el tipo de geometria que es. Si no encuentra 331 devuelve el geom_type de la layer (layer_gdal.GetGeomType()) 332 333 Args: 334 layer_gdal (osgeo.ogr.Layer): 335 nom_geom (str=None): Nombre geometria 336 337 Returns: 338 geom_type (int=layer_gdal.GetGeomType()): Si no encuentra devuelve 0 por defecto (GEOMETRY) 339 """ 340 idx_geom = 0 341 if nom_geom: 342 idx_geom = layer_gdal.GetLayerDefn().GetGeomFieldIndex(nom_geom) 343 344 if idx_geom >= 0: 345 layer_gdal.ResetReading() 346 return next((f.GetGeomFieldRef(idx_geom).GetGeometryType() 347 for f in layer_gdal if f.GetGeomFieldRef(idx_geom)), 348 layer_gdal.GetGeomType()) 349 350 351def srs_for_layer(layer_src, nom_geom_src=None): 352 """ 353 Devuelve el SpatialReference de la layer_gdal 354 Args: 355 layer_src (ogr.Layer) 356 nom_geom_src (str=None): Nombre geometria 357 358 Returns: 359 srs_lyr_src (osgeo.osr.SpatialReference) 360 """ 361 srs_lyr_src = layer_src.GetSpatialRef() 362 layer_src_def = layer_src.GetLayerDefn() 363 364 if act_geom_field := layer_src_def.GetGeomFieldDefn(0): 365 if nom_geom_src: 366 idx_act_geom_field = layer_src_def.GetGeomFieldIndex(nom_geom_src) 367 if idx_act_geom_field >= 0: 368 act_geom_field = layer_src_def.GetGeomFieldDefn(idx_act_geom_field) 369 370 if act_geom_field.GetSpatialRef(): 371 srs_lyr_src = act_geom_field.GetSpatialRef() 372 373 return srs_lyr_src 374 375 376def create_layer_from_layer_gdal_on_ds_gdal(ds_gdal_dest, layer_src, nom_layer=None, nom_geom_src=None, sel_camps=None, 377 exclude_cols_geoms=True, tolerance_simplify=None, null_geoms=False, 378 gtype_layer_from_geoms=True, epsg_code_dest=None, 379 epsg_code_src_default=4326, old_axis_mapping_srs=None, **extra_opt_list): 380 """ 381 Crea nuevo layer a partir de layer_gdal. 382 383 Args: 384 ds_gdal_dest (ogr.DataSource): 385 layer_src (ogr.Layer): 386 nom_layer (str=None): 387 nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará 388 como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante 389 sel_camps (list=None): OPC - Lista de campos a escoger de la layer original 390 exclude_cols_geoms (bool=True): Por defecto de la lista de columnas alfanuméricas (no geometrias) excluirá las 391 columnas que hagan referencia a alguna de las geometrias 392 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer 393 Mirar método Simplify() sobre osgeo.ogr.Geometry 394 null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula 395 gtype_layer_from_geoms (bool=True): Por defecto, si gtype de layer origen == 0 (GEOMETRY) deducirá el tipo de 396 geometria (POINT, LINE o POLYGON) a partir de la primera informada 397 encontrada en la layer_origen 398 epsg_code_dest (int=None): Codigo EPSG para le que se transformarán las geometrias desde el SRS original 399 epsg_code_src_default (int=4326): Codigo EPSG que se usará para las layer_src que NO tengan SRS asignado 400 old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2) 401 **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado 402 403 Returns: 404 layer_out (ogr.Layer) 405 """ 406 desc_ds_gdal = ds_gdal_dest.GetDescription() 407 drvr_name = ds_gdal_dest.GetDriver().GetName().upper() 408 print_debug("Inici crear layer '{}' en ds_gdal '{}'".format( 409 (nom_layer if nom_layer else layer_src.GetName()).upper(), 410 desc_ds_gdal if desc_ds_gdal else drvr_name)) 411 412 geoms_src = geoms_layer_gdal(layer_src) 413 camps_src = cols_layer_gdal(layer_src) 414 415 if nom_geom_src: 416 nom_geom_src = nom_geom_src.upper() 417 if len(geoms_src) > 1: 418 if nom_geom_src not in map(lambda ng: ng.upper(), geoms_src): 419 raise Exception("Argumento :NOM_GEOM = '{}' erróneo ya que " 420 "LAYER_GDAL original no contiene dicha geometria".format(nom_geom_src)) 421 elif len(geoms_src) == 0: 422 raise Exception("Argumento :NOM_GEOM = '{}' erróneo ya que " 423 "LAYER_GDAL original no contiene geometrias".format(nom_geom_src)) 424 425 if sel_camps: 426 sel_camps = {ng.upper() for ng in sel_camps} 427 if not sel_camps.issubset(camps_src): 428 raise Exception("Argumento :SEL_CAMPS = '[{}]' erróneo ya que " 429 "LAYER_GDAL no contiene alguno de los campos indicados".format(",".join(sel_camps))) 430 else: 431 sel_camps = set() 432 433 if not nom_layer: 434 nom_layer = layer_src.GetName() 435 else: 436 nom_layer = nom_layer.strip() 437 438 nom_layer = nom_layer.lower() 439 440 gtype = layer_src.GetGeomType() 441 srs_lyr_src = layer_src.GetSpatialRef() 442 443 layer_src_def = layer_src.GetLayerDefn() 444 act_geom_field = layer_src_def.GetGeomFieldDefn(0) 445 nom_geom_out = None 446 447 if act_geom_field: 448 if nom_geom_src: 449 idx_act_geom_field = layer_src_def.GetGeomFieldIndex(nom_geom_src) 450 if idx_act_geom_field >= 0: 451 act_geom_field = layer_src_def.GetGeomFieldDefn(idx_act_geom_field) 452 nom_geom_out = fix_affix_geom_name_layer_gdal(nom_geom_src, layer_src) 453 454 gtype = act_geom_field.GetType() 455 if gtype_layer_from_geoms and not gtype: 456 gtype = layer_gtype_from_geoms(layer_src, nom_geom_src) 457 458 if act_geom_field.GetSpatialRef(): 459 srs_lyr_src = act_geom_field.GetSpatialRef() 460 461 if sel_camps: 462 sel_camps = {c.strip().upper() for c in sel_camps} 463 464 geoms_src_minus_affix = geoms_layer_gdal(layer_src, PREFFIX_GEOMS_LAYERS_GDAL) 465 if exclude_cols_geoms: 466 if sel_camps: 467 sel_camps.difference_update(geoms_src_minus_affix) 468 else: 469 sel_camps = cols_layer_gdal(layer_src).difference(geoms_src_minus_affix) 470 471 srs_lyr_dest = None 472 if not srs_lyr_src and epsg_code_src_default: 473 srs_lyr_src = srs_ref_from_epsg_code(epsg_code_src_default, old_axis_mapping=old_axis_mapping_srs) 474 if srs_lyr_src: 475 if old_axis_mapping_srs is None and epsg_code_dest == 4326: 476 old_axis_mapping_srs = drvr_name in DRIVERS_OLD_SRS_AXIS_MAPPING_4326 477 478 if epsg_code_dest: 479 srs_lyr_dest = srs_ref_from_epsg_code(epsg_code_dest, old_axis_mapping=old_axis_mapping_srs) 480 else: 481 srs_lyr_dest = srs_lyr_src 482 483 if ds_gdal_dest.TestCapability(ODsCCreateLayer): 484 # To avoid message "Warning" 485 if ds_gdal_dest.TestCapability(ODsCDeleteLayer) and ds_gdal_dest.GetLayerByName(nom_layer): 486 ds_gdal_dest.DeleteLayer(nom_layer) 487 488 layer_out, nom_layer = create_layer_on_ds_gdal(ds_gdal_dest, nom_layer, nom_geom_out, gtype, srs_lyr_dest, 489 **extra_opt_list) 490 else: 491 layer_out = ds_gdal_dest.GetLayer(0) 492 493 geom_field_out = None 494 if layer_out.TestCapability(OLCAlterFieldDefn): 495 layer_out_def = layer_out.GetLayerDefn() 496 geom_field_out = layer_out_def.GetGeomFieldDefn(0) 497 if geom_field_out: 498 if not nom_geom_out: 499 nom_geom_out = act_geom_field.GetNameRef() 500 if not nom_geom_out: 501 nom_geom_out = "GEOMETRY" 502 geom_field_out.SetName(nom_geom_out) 503 504 if layer_out.TestCapability(OLCCreateField): 505 for fd in fields_layer_gdal(layer_src): 506 nom_fd = fd.GetNameRef().upper() 507 if layer_out.FindFieldIndex(nom_fd, True) < 0 and (not sel_camps or nom_fd in sel_camps) and \ 508 nom_fd not in (gn.upper() for gn in geoms_src_minus_affix): 509 layer_out.CreateField(fd) 510 511 for gfd in geom_fields_layer_gdal(layer_src): 512 nom_gfd = fix_affix_geom_name_layer_gdal(gfd.GetNameRef(), layer_src).upper() 513 if (not sel_camps or nom_gfd in sel_camps) and \ 514 (nom_gfd not in geoms_src or not exclude_cols_geoms) and \ 515 nom_gfd != nom_geom_out: 516 gfd_def_src = layer_src_def.GetGeomFieldDefn(layer_src_def.GetGeomFieldIndex(gfd.GetNameRef())) 517 gfd_def_dest = GeomFieldDefn(nom_gfd, gfd_def_src.GetType()) 518 if srs_lyr_dest: 519 gfd_def_dest.SetSpatialRef(srs_lyr_dest) 520 layer_out.CreateGeomField(gfd_def_dest) 521 522 if not geom_field_out: 523 null_geoms = True # Si no hay geom siempre se añaden 524 525 add_layer_features_to_layer(layer_src, ds_gdal_dest, layer_out, nom_geom_src, nom_geom_out, 526 srs_lyr_dest=srs_lyr_dest, 527 null_geoms=null_geoms, 528 tolerance_simplify=tolerance_simplify, 529 epsg_code_src_default=epsg_code_src_default, 530 old_axis_mapping_srs=old_axis_mapping_srs) 531 532 if drvr_name == "GPKG": 533 create_spatial_index_layer_gpkg(ds_gdal_dest, nom_layer) 534 535 if drvr_name == 'CSV': 536 path_csv = ds_gdal_dest.GetName() 537 if os.path.exists(path_csv): 538 rename_wkt_geoms_csv(path_csv) 539 540 return ds_gdal_dest.GetLayerByName(nom_layer) 541 542 543def rename_wkt_geoms_csv(path_csv): 544 """ 545 Remove "_WKT" affix from WKT geometry fields in CSV file 546 547 Args: 548 path_csv (str): Path to CSV file 549 550 Returns: 551 552 """ 553 with open(path_csv, 'r', encoding='utf-8') as r_file: 554 content_csv = r_file.readlines() 555 first_line = next(iter(content_csv), None) 556 if first_line: 557 new_first_line = first_line.replace(PREFFIX_GEOMS_LAYERS_GDAL_CSV, '') 558 if new_first_line != first_line: 559 content_csv[0] = new_first_line 560 with open(path_csv, 'w', encoding='utf-8') as w_file: 561 w_file.writelines(content_csv) 562 563 564def add_layer_features_to_layer(layer_src, ds_gdal_dest, layer_dest, nom_geom_src=None, nom_geom_dest=None, 565 srs_lyr_dest=None, null_geoms=False, tolerance_simplify=None, 566 remove_prev_features=False, epsg_code_src_default=4326, old_axis_mapping_srs=None): 567 """ 568 From a layer of a dataset, add the features to another layer of another dataset. 569 570 Args: 571 layer_src (ogr.Layer): Layer origen 572 ds_gdal_dest (gdal.Dataset): Dataset destino 573 layer_dest (ogr.Layer): Layer destino 574 nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará 575 como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante 576 nom_geom_dest (str): 577 srs_lyr_dest (ogr.SpatialReference=None): Spatial Reference System de la layer_dest 578 null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula 579 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer 580 Mirar método Simplify() sobre osgeo.ogr.Geometry 581 remove_prev_features (bool=False): Si es True, se eliminarán las features previas de la layer_dest 582 epsg_code_src_default (int=4326): EPSG code del srs de la layer_src si no se encuentra 583 old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2) 584 585 Returns: 586 587 """ 588 geoms_out = geoms_layer_gdal(layer_dest) 589 cols_out = cols_layer_gdal(layer_dest) 590 591 geom_transform = None 592 srs_lyr_src = srs_for_layer(layer_src, nom_geom_src) 593 if not srs_lyr_src: 594 srs_lyr_src = srs_ref_from_epsg_code(epsg_code_src_default, old_axis_mapping_srs) 595 596 if srs_lyr_dest is None: 597 srs_lyr_dest = srs_for_layer(layer_dest, nom_geom_dest) 598 599 if srs_lyr_dest and not srs_lyr_src.IsSame(srs_lyr_dest): 600 geom_transform = osr.CoordinateTransformation(srs_lyr_src, srs_lyr_dest) 601 602 ds_trans = ds_gdal_dest.TestCapability(ODsCTransactions) 603 604 if remove_prev_features: 605 if ds_trans: 606 layer_dest.StartTransaction() 607 for feat in layer_dest: 608 layer_dest.DeleteFeature(feat.GetFID()) 609 if ds_trans: 610 layer_dest.CommitTransaction() 611 612 if ds_trans: 613 layer_dest.StartTransaction() 614 615 i = 0 616 for feat_src, geom_src, nt_src in feats_layer_gdal(layer_src, nom_geom_src): 617 cols_out_chk = [col.upper() for col in cols_out.union(geoms_out)] 618 vals_camps = {nc: val for nc, val in nt_src._asdict().items() 619 if nc.upper() in cols_out_chk} 620 if null_geoms or geom_src: 621 if nom_geom_dest: 622 vals_camps[nom_geom_dest.upper()] = geom_src 623 624 add_feature_to_layer_gdal(layer_dest, 625 tolerance_simplify=tolerance_simplify, 626 geom_trans=geom_transform, 627 **vals_camps) 628 629 if i > 0 and (i % 1000) == 0: 630 print_debug("{} registres tractats...".format(str(i))) 631 i += 1 632 if ds_trans: 633 layer_dest.CommitTransaction() 634 635 636def create_layer_on_ds_gdal(ds_gdal_dest, nom_layer, nom_geom=None, gtype=None, srs_lyr_out=None, **extra_opt_list): 637 """ 638 639 Args: 640 ds_gdal_dest (ogr.DataSource): 641 nom_layer (str): 642 nom_geom (str=None): 643 gtype (OGRwkbGeometryType=None): Indicar integer representativo del tipo de geometria de la layer (ogr.wkbPoint, ogr.wkbPolygon, ogr.LineString, ...) 644 srs_lyr_out (osr.SpatialReference=None): codigo epsg del sistema de coordenadas de la geometria 645 **extra_opt_list: Calves valores option list creacion layer gdal 646 647 Returns: 648 layer_gdal (ogr.Layer), nom_layer (str) 649 """ 650 drvr_name = ds_gdal_dest.GetDriver().GetName().upper() 651 652 opt_list = {k.upper(): v.upper() for k, v in extra_opt_list.items()} 653 654 opt_geom_name = "GEOMETRY_NAME" 655 if nom_geom: 656 opt_list[opt_geom_name] = "{}={}".format(opt_geom_name, nom_geom.upper()) 657 else: 658 if opt_geom_name in opt_list: 659 opt_list.pop(opt_geom_name) 660 gtype = ogr.wkbNone 661 662 opt_list["IDENTIFIER"] = opt_list.get("IDENTIFIER", "IDENTIFIER={}".format(nom_layer)) 663 664 opt_list = set_create_option_list_for_driver_gdal(drvr_name, **{k.upper(): v.upper() for k, v in opt_list.items()}) 665 666 if ds_gdal_dest.TestCapability(ODsCDeleteLayer) and ds_gdal_dest.GetLayerByName(nom_layer): 667 print_warning("!ATENCION! - Se sobreescribirá la layer '{}' sobre el datasource GDAL '{}'".format( 668 nom_layer, ds_gdal_dest.GetDescription())) 669 ds_gdal_dest.DeleteLayer(nom_layer) 670 671 if drvr_name.upper() == "KML": 672 nom_layer = nom_layer.replace("-", "__") 673 674 layer_out = ds_gdal_dest.CreateLayer(nom_layer, srs_lyr_out, geom_type=gtype, options=list(opt_list.values())) 675 676 return layer_out, layer_out.GetName() if layer_out else None 677 678 679def create_spatial_index_layer_gpkg(ds_gpkg, nom_layer): 680 """ 681 Crea spatial index sobre una layer (layer_gpkg) de un datosource gpkg (ds_gpkg) 682 683 Args: 684 ds_gpkg (osgeo.ogr.DataSource): 685 layer_gpkg (ogr.Layer): 686 687 Returns: 688 bool 689 """ 690 layer_gpkg = ds_gpkg.GetLayerByName(nom_layer) 691 if layer_gpkg and layer_gpkg.GetGeometryColumn(): 692 # Se crea spatial_index ya que GDAL NO lo hace 693 ds_gpkg.StartTransaction() 694 ds_gpkg.ExecuteSQL("SELECT CreateSpatialIndex('{tab_name}', '{geom_name}') ".format( 695 tab_name=layer_gpkg.GetName(), 696 geom_name=layer_gpkg.GetGeometryColumn())) 697 ds_gpkg.CommitTransaction() 698 699 return True 700 else: 701 return False 702 703 704def add_feature_to_layer_gdal(layer_gdal, tolerance_simplify=None, geom_trans=None, commit=False, **valors_camps): 705 """ 706 707 Args: 708 layer_gdal (ogr.Layer): 709 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer. 710 Mirar método Simplify() sobre osgeo.ogr.Geometry 711 geom_trans (osr.CoordinateTransformation=None): transformacion para convertir las geometrias a otro SRS 712 commit (bool=False): Per defecte no farà commit de la transaccio 713 **valors_camps: pares nombre_campo=valor de la feature a crear 714 715 Returns: 716 feat (ogr.Feature) 717 """ 718 dd_feat = ogr.Feature(layer_gdal.GetLayerDefn()) 719 720 for camp, val in valors_camps.items(): 721 idx_geom = dd_feat.GetGeomFieldIndex(camp) 722 es_geom = idx_geom >= 0 723 if es_geom: 724 if val: 725 if tolerance_simplify: 726 val = val.Simplify(tolerance_simplify) 727 if val and geom_trans: 728 val.Transform(geom_trans) 729 730 dd_feat.SetGeomField(idx_geom, val) 731 732 idx_fld = dd_feat.GetFieldIndex(camp) 733 if idx_fld >= 0: 734 if val: 735 if es_geom or hasattr(val, "ExportToIsoWkt"): 736 val = val.ExportToIsoWkt() 737 dd_feat.SetField(camp, val) 738 else: 739 dd_feat.SetFieldNull(camp) 740 741 if idx_fld < 0 and idx_geom < 0: 742 if isinstance(val, Geometry): 743 if geom_trans: 744 val.Transform(geom_trans) 745 dd_feat.SetGeometry(val) 746 elif val: 747 print_warning("!ATENCION! - La :layer_gdal no contiene el campo '{}'".format(camp)) 748 749 commit_trans = commit and layer_gdal.TestCapability(OLCTransactions) 750 if commit_trans: 751 layer_gdal.StartTransaction() 752 753 new_feat = layer_gdal.CreateFeature(dd_feat) 754 755 if commit_trans: 756 layer_gdal.CommitTransaction() 757 758 return new_feat 759 760 761def drivers_ogr_gdal_disponibles(): 762 """ 763 Retorna lista de drivers disponibles a través de la librería osgeo-gdal-ogr 764 765 Returns: 766 dict 767 """ 768 cnt = ogr.GetDriverCount() 769 driver_list = [] 770 drivers = OrderedDict() 771 772 for i in range(cnt): 773 driver = ogr.GetDriver(i) 774 driver_name = driver.GetName() 775 driver_list.append(driver_name) 776 777 for driver_name in driver_list: 778 # Is File GeoDatabase available? 779 drv = ogr.GetDriverByName(driver_name) 780 if drv is None: 781 print_warning("{} !!ATENTION - driver NOT available!!".format(driver_name)) 782 else: 783 drivers[driver_name] = drv 784 print_debug(driver_name) 785 786 return drivers 787 788 789def drivers_ogr_gdal_vector_file(): 790 """ 791 Devuelve diccionario con los driver gdal para fichero vectorial 792 793 Returns: 794 dict 795 """ 796 return {nd: d for nd, d in drivers_ogr_gdal_disponibles().items() 797 if hasattr(d, "GetMetadata_Dict") and d.GetMetadata_Dict().get('DMD_EXTENSIONS')} 798 799 800def format_nom_column(nom_col): 801 """ 802 803 Args: 804 nom_col: 805 806 Returns: 807 str 808 """ 809 return nom_col.replace(" ", "_") 810 811 812def namedtuple_layer_gdal(layer_gdal, extract_affix_geom_fld=None): 813 """ 814 Devuelve namedTuple con los campos del layer pasado por parametro 815 816 Args: 817 layer_gdal: 818 extract_affix_geom_fld (str=None): 819 820 Returns: 821 namedtuple: con nombre "gdalFeatDef_{NOM_LAYER}" y con los campos de la layer 822 """ 823 camps_layer = set() 824 for fld in fields_layer_gdal(layer_gdal): 825 camps_layer.add(format_nom_column(fld.GetNameRef())) 826 827 for nom_geom in geoms_layer_gdal(layer_gdal, extract_affix=extract_affix_geom_fld): 828 camps_layer.add(format_nom_column(nom_geom)) 829 830 nom_layer = layer_gdal.GetName().upper().split(".")[0].replace("-", "_") 831 return namedtuple(f"gdalFeatDef_{nom_layer}", camps_layer) 832 833 834def feats_layer_ds_gdal(ds_gdal, nom_layer=None, filter_sql=None): 835 """ 836 Itera las features (registros de una layer de gdal) y los devuelve como un namdetuple 837 838 Args: 839 ds_gdal: datasource gdal 840 nom_layer (str=None): Si no viene informado cogerá la primera layer que encuentre en el datasource 841 filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. 842 Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html) 843 844 Returns: 845 ogr.Feature, ogr.Geometry, namedtuple_layer_gdal 846 """ 847 if not nom_layer: 848 layer_gdal = ds_gdal.GetLayer() 849 else: 850 layer_gdal = ds_gdal.GetLayerByName(nom_layer) 851 852 if layer_gdal: 853 for feat, geom, vals in feats_layer_gdal(layer_gdal, filter_sql=filter_sql): 854 yield feat, geom, vals 855 856 857def feats_layer_gdal(layer_gdal, nom_geom=None, filter_sql=None, extract_affix_geom_fld=PREFFIX_GEOMS_LAYERS_GDAL): 858 """ 859 Itera las features (registros de una layer de gdal) y los devuelve como un namdtuple 860 861 Args: 862 layer_gdal (ogr.Layer): 863 nom_geom (str=None): Por defecto la geometria activa o principal 864 filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. 865 Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html) 866 extract_affix_geom_fld (str=SUFFIX_GEOMS_LAYERS_GDAL): Por defecto quita el sufijo 'geom_' a los campos geom 867 868 Returns: 869 ogr.Feature, ogr.Geometry, namedtuple_layer_gdal 870 """ 871 layer_gdal.ResetReading() 872 ntup_layer = namedtuple_layer_gdal(layer_gdal, extract_affix_geom_fld) 873 n_geoms_layer = {nom_geom_feat: fix_affix_geom_name_layer_gdal(nom_geom_feat, layer_gdal, extract_affix_geom_fld) 874 for nom_geom_feat in geoms_layer_gdal(layer_gdal)} 875 876 if filter_sql: 877 layer_gdal.SetAttributeFilter(filter_sql) 878 879 def vals_feature_gdal(feat_gdal): 880 vals = {} 881 for camp, val in feat_gdal.items().items(): 882 vals[format_nom_column(camp)] = val 883 884 for camp_geom, camp_geom_val in n_geoms_layer.items(): 885 idx_geom = feat_gdal.GetGeomFieldIndex(camp_geom) 886 if idx_geom >= 0: 887 vals[camp_geom_val] = feat_gdal.GetGeomFieldRef(idx_geom) 888 889 return vals 890 891 if layer_gdal: 892 for f_tab in layer_gdal: 893 idx_geom = f_tab.GetGeomFieldIndex(nom_geom) if nom_geom else -1 894 yield f_tab, \ 895 f_tab.GetGeomFieldRef(idx_geom) if idx_geom >= 0 else f_tab.geometry(), \ 896 ntup_layer(**vals_feature_gdal(f_tab)) 897 898 layer_gdal.ResetReading() 899 900 901def distinct_vals_camp_layer_gdal(layer_gdal, nom_camp, filter_sql=None): 902 """ 903 Devuelve set con distintos valores para el campo indicado del layer GDAL indicada 904 905 Args: 906 layer_gdal (ogr.Layer): 907 nom_camp (str): 908 filter_sql (str=None): 909 910 Returns: 911 set 912 """ 913 if nom_camp.upper() not in cols_layer_gdal(layer_gdal): 914 raise Exception("Argumento :NOM_CAMP = '{}' erróneo ya que " 915 "LAYER_GDAL no contiene el campo indicado".format(nom_camp)) 916 917 return {getattr(nt_feat, nom_camp.upper()) 918 for feat, geom, nt_feat in feats_layer_gdal(layer_gdal, filter_sql=filter_sql)} 919 920 921def fields_layer_gdal(layer_gdal): 922 """ 923 Itera sobre los FieldDefn de una layer gdal 924 925 Args: 926 layer_gdal: 927 928 Yields: 929 osgeo.ogr.FieldDefn 930 """ 931 layer_def = layer_gdal.GetLayerDefn() 932 for i in range(0, layer_def.GetFieldCount()): 933 yield layer_def.GetFieldDefn(i) 934 935 layer_def = None 936 937 938def geom_fields_layer_gdal(layer_gdal): 939 """ 940 Itera sobre los GeomFieldDefn de una layer gdal 941 942 Args: 943 layer_gdal: 944 945 Yields: 946 osgeo.ogr.GeomFieldDefn 947 """ 948 layer_def = layer_gdal.GetLayerDefn() 949 for i in range(0, layer_def.GetGeomFieldCount()): 950 yield layer_def.GetGeomFieldDefn(i) 951 952 layer_def = None 953 954 955def nom_layers_datasource_gdal(ds_gdal): 956 """ 957 958 Args: 959 ds_gdal (ogr.Datasource: 960 961 Returns: 962 set 963 """ 964 return {l.GetName() for l in ds_gdal} 965 966 967def cols_layer_gdal(layer_gdal): 968 """ 969 Retorna lista con las columnas de una layer gdal 970 971 Args: 972 layer_gdal: 973 974 Returns: 975 set 976 """ 977 camps = set() 978 for fd in fields_layer_gdal(layer_gdal): 979 # camps.add(fd.GetName().upper()) 980 camps.add(fd.GetNameRef()) 981 982 return camps 983 984 985def geoms_layer_gdal(layer_gdal, extract_affix=None): 986 """ 987 Retorna lista con las columnas geométricas de una layer gdal 988 989 Args: 990 layer_gdal: 991 extract_affix (str=None=): if informed extract the affix passed 992 993 Returns: 994 set 995 """ 996 camps_geom = set() 997 for gdf in geom_fields_layer_gdal(layer_gdal): 998 # camps_geom.add(gdf.GetName().upper()) 999 name_ref = gdf.GetNameRef() 1000 if extract_affix: 1001 name_ref = fix_affix_geom_name_layer_gdal(name_ref, layer_gdal, extract_affix) 1002 camps_geom.add(name_ref) 1003 1004 return camps_geom 1005 1006 1007def fix_affix_geom_name_layer_gdal(geom_name, layer_gdal, affix=PREFFIX_GEOMS_LAYERS_GDAL): 1008 """ 1009 Extract affix (default=PREFFIX_GEOMS_LAYERS_GDAL) from name geoms if correspond with other column 1010 Fix GDAL > 3.4 where geoms on GeoCSV arrive with preffix 'geom_' 1011 1012 Args: 1013 geom_name (str): 1014 layer_gdal: 1015 affix (str=PREFFIX_GEOMS_LAYERS_GDAL): 1016 1017 Returns: 1018 str 1019 """ 1020 cols_layer = cols_layer_gdal(layer_gdal) 1021 geom_name_layer = geom_name 1022 if geom_name.lower().startswith(affix): 1023 geom_name_aux = re.sub(affix, '', geom_name, flags=re.IGNORECASE) 1024 if geom_name_aux.lower() in (col.lower() for col in cols_layer): 1025 geom_name_layer = geom_name_aux 1026 1027 return geom_name_layer 1028 1029 1030def add_layer_gdal_to_ds_gdal(ds_gdal, layer_gdal, nom_layer=None, lite=False, srs_epsg_code=None, multi_geom=False, 1031 nom_geom=None, null_geoms=False, **extra_opt_list): 1032 """ 1033 Añade una layer_gdal a un datasource_gdal. Si es una layer con multigeometrias las separa en una layer por geometria 1034 1035 Args: 1036 ds_gdal (osgeo.ogr.Datasource): 1037 layer_gdal (osgeo.ogr.Layer): 1038 nom_layer (str=None): 1039 lite (bool=False): 1040 srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir 1041 las geometrias 1042 nom_geom (str=None): nombre de geometria de layer origen (layer_gdal) que se copiará, si no todas 1043 multi_geom (bool=False): Si el DS_GDAL destino permite multigeometria 1044 null_geoms (bool=False): Indica si se admitirán registros con NULL geoms. Por defecto NO 1045 **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado 1046 1047 Returns: 1048 new_layers_ds_gdal (list) 1049 """ 1050 new_layers_ds_gdal = [] 1051 1052 if not nom_layer: 1053 nom_layer = layer_gdal.GetName() 1054 1055 geoms_layer = geoms_layer_gdal(layer_gdal) 1056 if nom_geom: 1057 if nom_geom.upper() not in (g.upper() for g in geoms_layer): 1058 Exception("!ERROR! - Nombre de geometria '{}' no existe en la layer GDAL origen") 1059 else: 1060 geoms_layer = (nom_geom,) 1061 1062 if geoms_layer: 1063 tol = None 1064 if lite: 1065 tol = SIMPLIFY_TOLERANCE 1066 1067 nom_layer_base = nom_layer.split("-")[0] 1068 if not multi_geom: 1069 for geom_name in geoms_layer: 1070 # Fix GDAL > 3.4 where geoms on GeoCSV arrive with preffix 'geom_' 1071 geom_name_layer = fix_affix_geom_name_layer_gdal(geom_name, layer_gdal) 1072 1073 nom_layer = "{}-{}".format(nom_layer_base, geom_name_layer).lower() 1074 extra_opt_list["GEOMETRY_NAME"] = "GEOMETRY_NAME={}".format(geom_name_layer) 1075 lyr = create_layer_from_layer_gdal_on_ds_gdal(ds_gdal, layer_gdal, nom_layer, geom_name, 1076 tolerance_simplify=tol, null_geoms=null_geoms, 1077 epsg_code_dest=srs_epsg_code, **extra_opt_list) 1078 new_layers_ds_gdal.append(lyr) 1079 else: 1080 lyr = create_layer_from_layer_gdal_on_ds_gdal(ds_gdal, layer_gdal, nom_layer, exclude_cols_geoms=False, 1081 tolerance_simplify=tol, null_geoms=True, 1082 epsg_code_dest=srs_epsg_code, **extra_opt_list) 1083 new_layers_ds_gdal.append(lyr) 1084 else: 1085 if ds_gdal.GetDriver().GetName() == 'PostgreSQL': 1086 extra_opt_list.update(dict( 1087 precision=extra_opt_list.get('precision', 'PRECISION=NO') 1088 )) 1089 1090 lyr = copy_layer_gdal_to_ds_gdal(layer_gdal, ds_gdal, nom_layer.lower(), **extra_opt_list) 1091 new_layers_ds_gdal.append(lyr) 1092 1093 return new_layers_ds_gdal 1094 1095 1096def copy_layers_gpkg(ds_gpkg, driver, dir_base, lite=False, srs_epsg_code=None, zipped=True): 1097 """ 1098 1099 Args: 1100 ds_gpkg (osgeo.ogr.Datasource): 1101 driver (str): 1102 dir_base (str=None): 1103 lite (bool=False): 1104 srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir 1105 las geometrias 1106 zipped (bool=False): 1107 1108 Returns: 1109 num_layers (int) 1110 """ 1111 num_layers = 0 1112 subdir_drvr = os.path.normpath(os.path.join(dir_base, driver.upper())) 1113 utils.create_dir(subdir_drvr) 1114 1115 for layer_gpkg in (ds_gpkg.GetLayer(id_lyr) for id_lyr in range(ds_gpkg.GetLayerCount() - 1)): 1116 if driver == "GPKG": 1117 nom_ds, ext = utils.split_ext_file(os.path.basename(ds_gpkg.name)) 1118 else: 1119 nom_ds = f"{layer_gpkg.GetName()}".lower() 1120 1121 ds_gdal, existia = datasource_gdal_vector_file(driver, nom_ds, subdir_drvr) 1122 1123 add_layer_gdal_to_ds_gdal(ds_gdal, layer_gpkg, lite=lite, srs_epsg_code=srs_epsg_code) 1124 1125 num_layers += 1 1126 1127 return num_layers 1128 1129 1130def set_csvt_for_layer_csv(path_csv, **tipus_camps): 1131 """ 1132 Crea/Modifica el CSVT asociado con los tipos indicados para cada columna 1133 1134 Args: 1135 path_csv (str): 1136 **tipus_camps: clave=valor con el nombre del campo y el tipo de campo asociado (p.e. String(25), WKT, Integer,...) 1137 1138 Returns: 1139 path_csvt (str) 1140 """ 1141 lyr_csv, nom_layer, ds_lyr = layer_gdal_from_file(path_csv, "CSV") 1142 if not lyr_csv: 1143 print_warning("!ATENCIO! - No s'ha pogut obrir la layer CSV '{}'".format(path_csv)) 1144 return 1145 1146 path_lyr_csvt = os.path.join(os.path.dirname(path_csv), "{}.csvt".format(nom_layer)) 1147 tips_lyr = {} 1148 for fld in fields_layer_gdal(lyr_csv): 1149 tip_fld = fld.GetFieldTypeName(fld.GetType()) 1150 sufix = "" 1151 w = fld.GetWidth() 1152 if w: 1153 sufix = "{}".format(w) 1154 p = fld.GetPrecision() 1155 if p: 1156 sufix += ".{}".format(p) 1157 if sufix: 1158 tip_fld += "({})".format(sufix) 1159 1160 tips_lyr[fld.name.upper()] = tip_fld 1161 1162 for nom_camp, tip_camp in tipus_camps.items(): 1163 nom_camp = nom_camp.upper() 1164 if nom_camp not in tips_lyr: 1165 print_warning("!ATENCIO! - Camp '{}' no existeix sobre la layer CSV '{}'".format(nom_camp, path_csv)) 1166 continue 1167 1168 tips_lyr[nom_camp] = tip_camp 1169 1170 with open(path_lyr_csvt, mode="w", encoding="utf8") as f_csvt: 1171 f_csvt.write(",".join(tips_lyr.values())) 1172 1173 1174def zip_and_clean_ds_csv(path_csv): 1175 """ 1176 # Zipea datasource osgeo CSV y como GDAL no crea los tipos WKT para las geometrias en el CSVT se fuerza 1177 1178 Args: 1179 path_csv (str): path Datasource osgeo CSV 1180 1181 Returns: 1182 zip_path (str) 1183 """ 1184 ds_gdal_csv, dummy = datasource_gdal_vector_file("CSV", os.path.basename(path_csv).split(".")[0], 1185 os.path.dirname(path_csv)) 1186 layer_csv = ds_gdal_csv.GetLayer(0) 1187 tips_geoms = {gn: "WKT" for gn in 1188 (*geoms_layer_gdal(layer_csv, extract_affix=PREFFIX_GEOMS_LAYERS_GDAL), 1189 *geoms_layer_gdal(layer_csv, extract_affix=PREFFIX_GEOMS_LAYERS_GDAL_CSV))} 1190 path_csv = ds_gdal_csv.GetDescription() 1191 ds_gdal_csv = None # Cerramos el datasource para que se guarden los cambios 1192 if path_csv and os.path.exists(path_csv): 1193 if tips_geoms: 1194 set_csvt_for_layer_csv(path_csv, **tips_geoms) 1195 rename_wkt_geoms_csv(path_csv) 1196 dir_base_csv = os.path.dirname(path_csv) 1197 nom_layer = os.path.basename(path_csv).split(".")[0] 1198 l_files_csv = [os.path.join(dir_base_csv, nf) for nf in os.listdir(dir_base_csv) 1199 if nf.lower().startswith(nom_layer.lower()) and 1200 any(nf.lower().endswith(ext) for ext in ('csv', 'csvt'))] 1201 zip_path = utils.zip_files(os.path.join(dir_base_csv, "{}.zip".format(nom_layer)), l_files_csv) 1202 if zip_path: 1203 for fl_csv in l_files_csv: 1204 os.remove(fl_csv) 1205 1206 return zip_path 1207 1208 1209def convert_angle(pt_xy, deg_ang, orig_srs, dest_srs): 1210 """ 1211 1212 Args: 1213 pt_xy (tuple): 1214 deg_ang (float): 1215 orig_srs (osr.SpatialReference): 1216 dest_srs (osr.SpatialReference): 1217 1218 Returns: 1219 1220 """ 1221 trans = osr.CoordinateTransformation(orig_srs, dest_srs) 1222 x, y = pt_xy 1223 dx = math.sin(math.radians(deg_ang)) * 0.00000001 1224 dy = math.cos(math.radians(deg_ang)) * 0.00000001 1225 pt1 = ogr.CreateGeometryFromWkt("POINT ({} {})".format(x, y)) 1226 pt2 = ogr.CreateGeometryFromWkt("POINT ({} {})".format(x + dx, y + dy)) 1227 pt1.Transform(trans) 1228 pt2.Transform(trans) 1229 x1, y1, z1 = pt1.GetPoint() 1230 x2, y2, z2 = pt2.GetPoint() 1231 1232 return math.degrees(math.atan2(y2 - y1, x2 - x1)) 1233 1234 1235def transform_ogr_geom(a_ogr_geom, from_espg_code, to_epsg_code): 1236 """ 1237 Transforma una geometria OGR según los EPSG indicados 1238 1239 Args: 1240 a_ogr_geom (ogr.geometry): una geometria del tipo OGR 1241 from_espg_code (int): codigo numérico del EPSG actual para la geometria 1242 to_epsg_code (int): codigo numérico del EPSG al que se quiere transformar 1243 1244 Returns: 1245 ogr.geometry 1246 """ 1247 source = osr.SpatialReference() 1248 source.ImportFromEPSG(from_espg_code) 1249 1250 target = osr.SpatialReference() 1251 target.ImportFromEPSG(to_epsg_code) 1252 1253 a_transform = osr.CoordinateTransformation(source, target) 1254 a_ogr_geom.Transform(a_transform) 1255 1256 return a_ogr_geom 1257 1258 1259def ds_postgis(dbname='POSTGRES', host='localhost', port='5432', user='postgres', password='postgres', schema='public'): 1260 """ 1261 Retorna datasource GDAL para ddbb postgis 1262 1263 Args: 1264 dbname: 1265 host: 1266 port: 1267 user: 1268 password: 1269 schema: 1270 1271 Returns: 1272 osgeo.ogr.DataSource 1273 """ 1274 pg_conn = f"PG:dbname='{dbname}' host='{host}' port='{port}' user='{user}' password='{password}' active_schema='{schema}'" 1275 drvr, exts = driver_gdal('PostgreSQL') 1276 return drvr.Open(pg_conn, 1) 1277 1278 1279def reset_sequence_layer_postgis(ds_postgis, nom_layer): 1280 """ 1281 Resetea la secuencia de la layer PostGIS indicada 1282 1283 Args: 1284 ds_postgis (osgeo.ogr.DataSource): datasource de la ddbb PostGIS: 1285 nom_layer (str): nombre de la layer PostGIS 1286 1287 Returns: 1288 bool: True si se ha reseteado correctamente 1289 """ 1290 ok = False 1291 layer_dest = ds_postgis.GetLayerByName(nom_layer) 1292 fid_column = layer_dest.GetFIDColumn() 1293 get_seq_sql = f"SELECT pg_get_serial_sequence('{nom_layer}', '{fid_column}') FROM information_schema.columns " \ 1294 f"WHERE table_name = '{nom_layer}' AND column_default LIKE 'nextval%'" 1295 1296 if res_get_seq := ds_postgis.ExecuteSQL(get_seq_sql): 1297 seq_name = res_get_seq.GetNextFeature().GetField(0) 1298 ds_postgis.StartTransaction() 1299 reset_seq = f"SELECT setval('{seq_name}', 1, false);" 1300 ds_postgis.ExecuteSQL(reset_seq) 1301 ds_postgis.CommitTransaction() 1302 ok = True 1303 1304 return ok 1305 1306 1307if __name__ == '__main__': 1308 import fire 1309 1310 fire.Fire()
2141def debug(msg, *args, **kwargs): 2142 """ 2143 Log a message with severity 'DEBUG' on the root logger. If the logger has 2144 no handlers, call basicConfig() to add a console handler with a pre-defined 2145 format. 2146 """ 2147 if len(root.handlers) == 0: 2148 basicConfig() 2149 root.debug(msg, *args, **kwargs)
Log a message with severity 'DEBUG' on the root logger. If the logger has no handlers, call basicConfig() to add a console handler with a pre-defined format.
2116def warning(msg, *args, **kwargs): 2117 """ 2118 Log a message with severity 'WARNING' on the root logger. If the logger has 2119 no handlers, call basicConfig() to add a console handler with a pre-defined 2120 format. 2121 """ 2122 if len(root.handlers) == 0: 2123 basicConfig() 2124 root.warning(msg, *args, **kwargs)
Log a message with severity 'WARNING' on the root logger. If the logger has no handlers, call basicConfig() to add a console handler with a pre-defined format.
34def srs_ref_from_epsg_code(code_epsg: int, old_axis_mapping=False) -> osr.SpatialReference: 35 """ 36 37 Args: 38 code_epsg (int): 39 old_axis_mapping (bool=False): Por cambio entre GDAL2.0 y GDAL3.0 se (vease 40 https://github.com/OSGeo/gdal/blob/master/gdal/MIGRATION_GUIDE.TXT) por defecto se utiliza el mapeo de ejes 41 clasico LONG,LAT 42 43 Returns: 44 srs (osr.SpatialReference) 45 """ 46 srs = osr.SpatialReference() 47 if old_axis_mapping: 48 try: 49 from osgeo.osr import OAMS_TRADITIONAL_GIS_ORDER 50 print_debug("OAMS_TRADITIONAL_GIS_ORDER") 51 srs.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER) 52 except ImportError: 53 print_warning("OAMS_TRADITIONAL_GIS_ORDER not available") 54 55 ret = srs.ImportFromEPSG(code_epsg) 56 if ret != 0: 57 raise Warning("No se puede retornar un osgeo.osr.SpatialReference EPSG para el codigo '{}'!!".format(code_epsg)) 58 59 return srs
Arguments:
- code_epsg (int):
- old_axis_mapping (bool=False): Por cambio entre GDAL2.0 y GDAL3.0 se (vease
https://github.com/OSGeo/gdal/blob/master/gdal/MIGRATION_GUIDE.TXT) por defecto se utiliza el mapeo de ejes clasico LONG,LAT
Returns:
srs (osr.SpatialReference)
62def layer_gdal_from_file(path_file: str, 63 nom_driver: str = 'GeoJSON', 64 nom_geom: str = None, 65 default_srs_epsg_code: int = 4326, 66 default_order_long_lat: bool = True): 67 """ 68 69 Args: 70 path_file (str): 71 nom_driver (str='GeoJSON'): 72 nom_geom (str=None): si se informa devolverá la layer solo con la geometria especificada 73 default_srs_epsg_code (int=4326): codigo del sistema de coordenadas que asignará por defecto si la layer 74 NO tiene sistema definido 75 default_order_long_lat (bool=True): si no viene informado el SRS y se usa el default EPSG4326 entonces se supone 76 por defecto que las geometria vienen en orden antiguo LONGITUD, LATITUD 77 78 Returns: 79 layer_gdal (osgeo.ogr.Layer), nom_layer (str), datasource_gdal (osgeo.ogr.DataSource) 80 """ 81 drvr = ogr.GetDriverByName(nom_driver) 82 83 nom_layer, ext = utils.split_ext_file(os.path.basename(path_file)) 84 if ext.lower().endswith("zip"): 85 path_file = "/vsizip/{}".format(path_file) 86 87 ds_vector_file = drvr.Open(path_file, 0) 88 89 a_layer = None 90 if ds_vector_file: 91 a_layer = ds_vector_file.GetLayer(0) 92 93 if nom_geom: 94 lay_def = a_layer.GetLayerDefn() 95 nom_geom = nom_geom.strip().upper() 96 97 if lay_def.GetGeomFieldCount() > 1: 98 idx_geom = lay_def.GetGeomFieldIndex(nom_geom) 99 if idx_geom < 0: 100 raise Exception("El fichero vectorial '{}' no contiene una geometria con el nombre '{}'".format( 101 ds_vector_file.GetName(), nom_geom)) 102 elif idx_geom > 0: 103 # Convertimos a layer en MEMORY para poder cambiar estructura 104 ds_mem = ds_gdal_memory() 105 a_layer = create_layer_from_layer_gdal_on_ds_gdal(ds_mem, a_layer, nom_layer, nom_geom, 106 exclude_cols_geoms=False, null_geoms=True) 107 if a_layer: 108 ds_vector_file = ds_mem 109 110 elif not a_layer.GetGeometryColumn() and lay_def.GetGeomFieldDefn(0): 111 lay_def.GetGeomFieldDefn(0).SetName(nom_geom) 112 113 if a_layer: 114 # Por si no carga el SRS se asigna el :default_srs_epsg_code (defecto epsg:4326) 115 for gf in geom_fields_layer_gdal(a_layer): 116 if not gf.GetSpatialRef(): 117 gf.SetSpatialRef(srs_ref_from_epsg_code(default_srs_epsg_code, default_order_long_lat)) 118 119 return a_layer, nom_layer, ds_vector_file
Arguments:
- path_file (str):
- nom_driver (str='GeoJSON'):
- nom_geom (str=None): si se informa devolverá la layer solo con la geometria especificada
- default_srs_epsg_code (int=4326): codigo del sistema de coordenadas que asignará por defecto si la layer NO tiene sistema definido
- default_order_long_lat (bool=True): si no viene informado el SRS y se usa el default EPSG4326 entonces se supone por defecto que las geometria vienen en orden antiguo LONGITUD, LATITUD
Returns:
layer_gdal (osgeo.ogr.Layer), nom_layer (str), datasource_gdal (osgeo.ogr.DataSource)
122def datasource_gdal_vector_file(nom_driver_gdal, nom_ds, a_dir, create=None, from_zip=False, **create_options): 123 """ 124 Crea datasource gdal para driver de tipo fichero 125 Args: 126 nom_driver_gdal (str): 127 nom_ds (str): 128 a_dir (str): 129 create (bool=None): Por defecto crea el datasource si este no existe y se abre sin problemas previamente. 130 Si False entonces NO lo crea en ningún caso, y si True lo creará sin intentar abrirlo 131 from_zip (bool=False): 132 **create_options: lista claves valores con opciones de creacion para el datasource de GDAL 133 p.e.: NameField="SEQENTITAT", DescriptionField="SW_URN" 134 135 Returns: 136 datasource_gdal (osgeo.ogr.DataSource), overwrited (bool) 137 """ 138 driver, exts_driver = driver_gdal(nom_driver_gdal) 139 if not exts_driver: 140 raise Exception("ERROR! - El driver GDAL {} no es de tipo fichero vectorial".format(driver)) 141 142 base_path_file = os.path.normpath(os.path.join(a_dir, nom_ds.strip().lower())) 143 _, ext_base = os.path.splitext(base_path_file) 144 145 vsi_prefix = "" 146 if from_zip: 147 ext_file = "zip" 148 vsi_prefix = "/vsizip/" 149 else: 150 if "topojson" in (ext.lower() for ext in exts_driver): 151 ext_file = "topojson" 152 else: 153 ext_file = exts_driver[0] 154 155 if (os.path.exists(base_path_file) and os.path.isfile( 156 base_path_file)) or ext_base.lower() == f'.{ext_file.lower()}': 157 path_file = base_path_file 158 else: 159 path_file = "{}.{}".format(base_path_file, ext_file) 160 161 overwrited = False 162 datasource_gdal = None 163 if not create and os.path.exists(path_file): 164 open_path_file = "{}{}".format(vsi_prefix, path_file) 165 datasource_gdal = driver.Open(open_path_file, 1) 166 if datasource_gdal is None: 167 datasource_gdal = driver.Open(open_path_file) 168 169 if datasource_gdal: 170 overwrited = True 171 172 if create or (create is not False and datasource_gdal is None and driver.TestCapability(ODrCCreateDataSource)): 173 datasource_gdal = driver.CreateDataSource(path_file, 174 list("{}={}".format(opt, val) for opt, val in create_options.items())) 175 176 return datasource_gdal, overwrited
Crea datasource gdal para driver de tipo fichero
Arguments:
- nom_driver_gdal (str):
- nom_ds (str):
- a_dir (str):
- create (bool=None): Por defecto crea el datasource si este no existe y se abre sin problemas previamente. Si False entonces NO lo crea en ningún caso, y si True lo creará sin intentar abrirlo
- from_zip (bool=False):
- **create_options: lista claves valores con opciones de creacion para el datasource de GDAL p.e.: NameField="SEQENTITAT", DescriptionField="SW_URN"
Returns:
datasource_gdal (osgeo.ogr.DataSource), overwrited (bool)
179def driver_gdal(nom_driver): 180 """ 181 Devuelve el driver GDAL solicitado y si es de tipo fichero vectorial tambien devuelve la extension 182 Si no coincide exactamente devuelve el que tiene nombre más parecido. 183 Verificar con drivers_ogr_gdal_disponibles() los disponibles 184 185 Args: 186 nom_driver: 187 Returns: 188 driver_gdal (osgeo.ogr.Driver), exts_driver (list) 189 """ 190 driver_gdal = ogr.GetDriverByName(nom_driver) 191 exts_drvr = driver_gdal.GetMetadata().get('DMD_EXTENSIONS', "").split(" ") 192 193 return driver_gdal, exts_drvr
Devuelve el driver GDAL solicitado y si es de tipo fichero vectorial tambien devuelve la extension Si no coincide exactamente devuelve el que tiene nombre más parecido. Verificar con drivers_ogr_gdal_disponibles() los disponibles
Arguments:
- nom_driver:
Returns:
driver_gdal (osgeo.ogr.Driver), exts_driver (list)
196def ds_gdal_memory(): 197 """ 198 Devuelve un osgeo.ogr.DataSource de tipo "memory" 199 200 Returns: 201 datasource_gdal (osgeo.ogr.DataSource) 202 """ 203 return ogr.GetDriverByName("memory").CreateDataSource("")
Devuelve un osgeo.ogr.DataSource de tipo "memory"
Returns:
datasource_gdal (osgeo.ogr.DataSource)
206def set_create_option_list_for_layer_gdal(layer_gdal, drvr_name="GPKG", **extra_opt_list): 207 """ 208 Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options 209 pasadas por defecto 210 211 Args: 212 layer_gdal (ogr.Layer): 213 drvr_name (str="GPKG"): nombre de driver GDAL 214 extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL 215 216 Returns: 217 opt_list (dict) 218 """ 219 opt_list = set_create_option_list_for_driver_gdal(drvr_name, **extra_opt_list) 220 221 opt_geom_name = "GEOMETRY_NAME" 222 if opt_geom_name not in opt_list: 223 nom_geom_src = layer_gdal.GetGeometryColumn() 224 if nom_geom_src: 225 opt_list[opt_geom_name] = "{}={}".format(opt_geom_name, nom_geom_src) 226 227 return opt_list
Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options pasadas por defecto
Arguments:
- layer_gdal (ogr.Layer):
- drvr_name (str="GPKG"): nombre de driver GDAL
- extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL
Returns:
opt_list (dict)
230def set_create_option_list_for_driver_gdal(drvr_name="GPKG", **extra_opt_list): 231 """ 232 Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options 233 pasadas por defecto 234 235 Args: 236 drvr_name (str="GPKG"): nombre de driver GDAL 237 extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL 238 239 Returns: 240 opt_list (dict) 241 """ 242 # Se quitan las options que no son de creacion para el driver especificado 243 drvr, exts_drvr = driver_gdal(drvr_name) 244 if not drvr: 245 Exception("!ERROR! - El nombre de driver '{}' no es un driver GDAL disponible".format(drvr_name)) 246 247 opt_list = {k.upper(): v.upper() for k, v in extra_opt_list.items()} 248 249 if not "FID" in opt_list and drvr.name == 'GPKG': 250 opt_list["FID"] = 'FID=FID_GPKG' 251 252 if drvr.name == "GeoJSON": 253 if "WRITE_BBOX" not in opt_list: 254 opt_list["WRITE_BBOX"] = 'WRITE_BBOX=YES' 255 256 if drvr.name == "CSV": 257 if "CREATE_CSVT" not in opt_list: 258 opt_list["CREATE_CSVT"] = 'CREATE_CSVT=YES' 259 if "GEOMETRY" not in opt_list: 260 opt_list["GEOMETRY"] = 'GEOMETRY=AS_WKT' 261 262 if drvr.GetMetadataItem('DS_LAYER_CREATIONOPTIONLIST'): 263 list_opts_drvr = drvr.GetMetadataItem('DS_LAYER_CREATIONOPTIONLIST') 264 keys_opt_list = list(opt_list.keys()) 265 for n_opt in keys_opt_list: 266 if list_opts_drvr.find(n_opt) < 0: 267 opt_list.pop(n_opt) 268 269 if "SPATIAL_INDEX" not in opt_list and \ 270 list_opts_drvr.find("SPATIAL_INDEX") >= 0 and drvr.name != 'PostgreSQL': 271 opt_list["SPATIAL_INDEX"] = 'SPATIAL_INDEX=YES' 272 273 return opt_list
Devuelve la lista de create options GDAL a partir de una layer, el driver para el que se quiere crear y options pasadas por defecto
Arguments:
- drvr_name (str="GPKG"): nombre de driver GDAL
- extra_opt_list: lista pares claves-valores que se corresponden con option create list del driver GDAL
Returns:
opt_list (dict)
276def copy_layer_gdal_to_ds_gdal(layer_src, ds_gdal_dest, nom_layer=None, nom_geom=None, 277 overwrite=True, **extra_opt_list): 278 """ 279 Copia una layer_gdal a otro datasource gdal 280 281 Args: 282 layer_src: 283 ds_gdal_dest: 284 nom_layer (str=None): OPC - Si no viene informado cogerá el nombre de la layer 285 nom_geom (str=None): OPC - Si se informa se cogerá como el nombre de la geometria de la nueva layer 286 overwrite (bool=True): 287 **extra_opt_list (str): Lista claves-valores de opciones para copylayer o createLayer 288 del driver de ds_gdal indicado 289 290 Returns: 291 layer_dest (ogr.layer) 292 """ 293 if not nom_layer: 294 nom_layer = layer_src.GetName() 295 nom_layer = nom_layer.strip().lower() 296 297 layer_dest = ds_gdal_dest.GetLayerByName(nom_layer) 298 if layer_dest: 299 if not overwrite: 300 return layer_dest 301 else: 302 ds_gdal_dest.DeleteLayer(nom_layer) 303 304 drvr_name = ds_gdal_dest.GetDriver().GetName() 305 306 extra_opt_list["IDENTIFIER"] = "IDENTIFIER={}".format(nom_layer) 307 308 opt_list = set_create_option_list_for_layer_gdal(layer_src, drvr_name=drvr_name, 309 **{k.upper(): v.upper() for k, v in extra_opt_list.items()}) 310 311 layer_dest = ds_gdal_dest.CopyLayer(layer_src, nom_layer, list(opt_list.values())) 312 313 if layer_dest: 314 if not layer_dest.GetGeometryColumn() and layer_dest.GetLayerDefn().GetGeomFieldDefn(0) and \ 315 (layer_src.GetGeometryColumn() or nom_geom): 316 if not nom_geom: 317 nom_geom = layer_src.GetGeometryColumn() 318 else: 319 nom_geom = nom_geom.upper() 320 321 layer_dest.GetLayerDefn().GetGeomFieldDefn(0).SetName(nom_geom) 322 323 if drvr_name == "GPKG": 324 create_spatial_index_layer_gpkg(ds_gdal_dest, nom_layer) 325 326 return layer_dest
Copia una layer_gdal a otro datasource gdal
Arguments:
- layer_src:
- ds_gdal_dest:
- nom_layer (str=None): OPC - Si no viene informado cogerá el nombre de la layer
- nom_geom (str=None): OPC - Si se informa se cogerá como el nombre de la geometria de la nueva layer
- overwrite (bool=True):
- **extra_opt_list (str): Lista claves-valores de opciones para copylayer o createLayer del driver de ds_gdal indicado
Returns:
layer_dest (ogr.layer)
329def layer_gtype_from_geoms(layer_gdal, nom_geom=None): 330 """ 331 A partir de la 1º geometria informada de una layer_gdal devuelve el tipo de geometria que es. Si no encuentra 332 devuelve el geom_type de la layer (layer_gdal.GetGeomType()) 333 334 Args: 335 layer_gdal (osgeo.ogr.Layer): 336 nom_geom (str=None): Nombre geometria 337 338 Returns: 339 geom_type (int=layer_gdal.GetGeomType()): Si no encuentra devuelve 0 por defecto (GEOMETRY) 340 """ 341 idx_geom = 0 342 if nom_geom: 343 idx_geom = layer_gdal.GetLayerDefn().GetGeomFieldIndex(nom_geom) 344 345 if idx_geom >= 0: 346 layer_gdal.ResetReading() 347 return next((f.GetGeomFieldRef(idx_geom).GetGeometryType() 348 for f in layer_gdal if f.GetGeomFieldRef(idx_geom)), 349 layer_gdal.GetGeomType())
A partir de la 1º geometria informada de una layer_gdal devuelve el tipo de geometria que es. Si no encuentra devuelve el geom_type de la layer (layer_gdal.GetGeomType())
Arguments:
- layer_gdal (osgeo.ogr.Layer):
- nom_geom (str=None): Nombre geometria
Returns:
geom_type (int=layer_gdal.GetGeomType()): Si no encuentra devuelve 0 por defecto (GEOMETRY)
352def srs_for_layer(layer_src, nom_geom_src=None): 353 """ 354 Devuelve el SpatialReference de la layer_gdal 355 Args: 356 layer_src (ogr.Layer) 357 nom_geom_src (str=None): Nombre geometria 358 359 Returns: 360 srs_lyr_src (osgeo.osr.SpatialReference) 361 """ 362 srs_lyr_src = layer_src.GetSpatialRef() 363 layer_src_def = layer_src.GetLayerDefn() 364 365 if act_geom_field := layer_src_def.GetGeomFieldDefn(0): 366 if nom_geom_src: 367 idx_act_geom_field = layer_src_def.GetGeomFieldIndex(nom_geom_src) 368 if idx_act_geom_field >= 0: 369 act_geom_field = layer_src_def.GetGeomFieldDefn(idx_act_geom_field) 370 371 if act_geom_field.GetSpatialRef(): 372 srs_lyr_src = act_geom_field.GetSpatialRef() 373 374 return srs_lyr_src
Devuelve el SpatialReference de la layer_gdal
Arguments:
- layer_src (ogr.Layer)
- nom_geom_src (str=None): Nombre geometria
Returns:
srs_lyr_src (osgeo.osr.SpatialReference)
377def create_layer_from_layer_gdal_on_ds_gdal(ds_gdal_dest, layer_src, nom_layer=None, nom_geom_src=None, sel_camps=None, 378 exclude_cols_geoms=True, tolerance_simplify=None, null_geoms=False, 379 gtype_layer_from_geoms=True, epsg_code_dest=None, 380 epsg_code_src_default=4326, old_axis_mapping_srs=None, **extra_opt_list): 381 """ 382 Crea nuevo layer a partir de layer_gdal. 383 384 Args: 385 ds_gdal_dest (ogr.DataSource): 386 layer_src (ogr.Layer): 387 nom_layer (str=None): 388 nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará 389 como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante 390 sel_camps (list=None): OPC - Lista de campos a escoger de la layer original 391 exclude_cols_geoms (bool=True): Por defecto de la lista de columnas alfanuméricas (no geometrias) excluirá las 392 columnas que hagan referencia a alguna de las geometrias 393 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer 394 Mirar método Simplify() sobre osgeo.ogr.Geometry 395 null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula 396 gtype_layer_from_geoms (bool=True): Por defecto, si gtype de layer origen == 0 (GEOMETRY) deducirá el tipo de 397 geometria (POINT, LINE o POLYGON) a partir de la primera informada 398 encontrada en la layer_origen 399 epsg_code_dest (int=None): Codigo EPSG para le que se transformarán las geometrias desde el SRS original 400 epsg_code_src_default (int=4326): Codigo EPSG que se usará para las layer_src que NO tengan SRS asignado 401 old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2) 402 **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado 403 404 Returns: 405 layer_out (ogr.Layer) 406 """ 407 desc_ds_gdal = ds_gdal_dest.GetDescription() 408 drvr_name = ds_gdal_dest.GetDriver().GetName().upper() 409 print_debug("Inici crear layer '{}' en ds_gdal '{}'".format( 410 (nom_layer if nom_layer else layer_src.GetName()).upper(), 411 desc_ds_gdal if desc_ds_gdal else drvr_name)) 412 413 geoms_src = geoms_layer_gdal(layer_src) 414 camps_src = cols_layer_gdal(layer_src) 415 416 if nom_geom_src: 417 nom_geom_src = nom_geom_src.upper() 418 if len(geoms_src) > 1: 419 if nom_geom_src not in map(lambda ng: ng.upper(), geoms_src): 420 raise Exception("Argumento :NOM_GEOM = '{}' erróneo ya que " 421 "LAYER_GDAL original no contiene dicha geometria".format(nom_geom_src)) 422 elif len(geoms_src) == 0: 423 raise Exception("Argumento :NOM_GEOM = '{}' erróneo ya que " 424 "LAYER_GDAL original no contiene geometrias".format(nom_geom_src)) 425 426 if sel_camps: 427 sel_camps = {ng.upper() for ng in sel_camps} 428 if not sel_camps.issubset(camps_src): 429 raise Exception("Argumento :SEL_CAMPS = '[{}]' erróneo ya que " 430 "LAYER_GDAL no contiene alguno de los campos indicados".format(",".join(sel_camps))) 431 else: 432 sel_camps = set() 433 434 if not nom_layer: 435 nom_layer = layer_src.GetName() 436 else: 437 nom_layer = nom_layer.strip() 438 439 nom_layer = nom_layer.lower() 440 441 gtype = layer_src.GetGeomType() 442 srs_lyr_src = layer_src.GetSpatialRef() 443 444 layer_src_def = layer_src.GetLayerDefn() 445 act_geom_field = layer_src_def.GetGeomFieldDefn(0) 446 nom_geom_out = None 447 448 if act_geom_field: 449 if nom_geom_src: 450 idx_act_geom_field = layer_src_def.GetGeomFieldIndex(nom_geom_src) 451 if idx_act_geom_field >= 0: 452 act_geom_field = layer_src_def.GetGeomFieldDefn(idx_act_geom_field) 453 nom_geom_out = fix_affix_geom_name_layer_gdal(nom_geom_src, layer_src) 454 455 gtype = act_geom_field.GetType() 456 if gtype_layer_from_geoms and not gtype: 457 gtype = layer_gtype_from_geoms(layer_src, nom_geom_src) 458 459 if act_geom_field.GetSpatialRef(): 460 srs_lyr_src = act_geom_field.GetSpatialRef() 461 462 if sel_camps: 463 sel_camps = {c.strip().upper() for c in sel_camps} 464 465 geoms_src_minus_affix = geoms_layer_gdal(layer_src, PREFFIX_GEOMS_LAYERS_GDAL) 466 if exclude_cols_geoms: 467 if sel_camps: 468 sel_camps.difference_update(geoms_src_minus_affix) 469 else: 470 sel_camps = cols_layer_gdal(layer_src).difference(geoms_src_minus_affix) 471 472 srs_lyr_dest = None 473 if not srs_lyr_src and epsg_code_src_default: 474 srs_lyr_src = srs_ref_from_epsg_code(epsg_code_src_default, old_axis_mapping=old_axis_mapping_srs) 475 if srs_lyr_src: 476 if old_axis_mapping_srs is None and epsg_code_dest == 4326: 477 old_axis_mapping_srs = drvr_name in DRIVERS_OLD_SRS_AXIS_MAPPING_4326 478 479 if epsg_code_dest: 480 srs_lyr_dest = srs_ref_from_epsg_code(epsg_code_dest, old_axis_mapping=old_axis_mapping_srs) 481 else: 482 srs_lyr_dest = srs_lyr_src 483 484 if ds_gdal_dest.TestCapability(ODsCCreateLayer): 485 # To avoid message "Warning" 486 if ds_gdal_dest.TestCapability(ODsCDeleteLayer) and ds_gdal_dest.GetLayerByName(nom_layer): 487 ds_gdal_dest.DeleteLayer(nom_layer) 488 489 layer_out, nom_layer = create_layer_on_ds_gdal(ds_gdal_dest, nom_layer, nom_geom_out, gtype, srs_lyr_dest, 490 **extra_opt_list) 491 else: 492 layer_out = ds_gdal_dest.GetLayer(0) 493 494 geom_field_out = None 495 if layer_out.TestCapability(OLCAlterFieldDefn): 496 layer_out_def = layer_out.GetLayerDefn() 497 geom_field_out = layer_out_def.GetGeomFieldDefn(0) 498 if geom_field_out: 499 if not nom_geom_out: 500 nom_geom_out = act_geom_field.GetNameRef() 501 if not nom_geom_out: 502 nom_geom_out = "GEOMETRY" 503 geom_field_out.SetName(nom_geom_out) 504 505 if layer_out.TestCapability(OLCCreateField): 506 for fd in fields_layer_gdal(layer_src): 507 nom_fd = fd.GetNameRef().upper() 508 if layer_out.FindFieldIndex(nom_fd, True) < 0 and (not sel_camps or nom_fd in sel_camps) and \ 509 nom_fd not in (gn.upper() for gn in geoms_src_minus_affix): 510 layer_out.CreateField(fd) 511 512 for gfd in geom_fields_layer_gdal(layer_src): 513 nom_gfd = fix_affix_geom_name_layer_gdal(gfd.GetNameRef(), layer_src).upper() 514 if (not sel_camps or nom_gfd in sel_camps) and \ 515 (nom_gfd not in geoms_src or not exclude_cols_geoms) and \ 516 nom_gfd != nom_geom_out: 517 gfd_def_src = layer_src_def.GetGeomFieldDefn(layer_src_def.GetGeomFieldIndex(gfd.GetNameRef())) 518 gfd_def_dest = GeomFieldDefn(nom_gfd, gfd_def_src.GetType()) 519 if srs_lyr_dest: 520 gfd_def_dest.SetSpatialRef(srs_lyr_dest) 521 layer_out.CreateGeomField(gfd_def_dest) 522 523 if not geom_field_out: 524 null_geoms = True # Si no hay geom siempre se añaden 525 526 add_layer_features_to_layer(layer_src, ds_gdal_dest, layer_out, nom_geom_src, nom_geom_out, 527 srs_lyr_dest=srs_lyr_dest, 528 null_geoms=null_geoms, 529 tolerance_simplify=tolerance_simplify, 530 epsg_code_src_default=epsg_code_src_default, 531 old_axis_mapping_srs=old_axis_mapping_srs) 532 533 if drvr_name == "GPKG": 534 create_spatial_index_layer_gpkg(ds_gdal_dest, nom_layer) 535 536 if drvr_name == 'CSV': 537 path_csv = ds_gdal_dest.GetName() 538 if os.path.exists(path_csv): 539 rename_wkt_geoms_csv(path_csv) 540 541 return ds_gdal_dest.GetLayerByName(nom_layer)
Crea nuevo layer a partir de layer_gdal.
Arguments:
- ds_gdal_dest (ogr.DataSource):
- layer_src (ogr.Layer):
- nom_layer (str=None):
- nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante
- sel_camps (list=None): OPC - Lista de campos a escoger de la layer original
- exclude_cols_geoms (bool=True): Por defecto de la lista de columnas alfanuméricas (no geometrias) excluirá las columnas que hagan referencia a alguna de las geometrias
- tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer Mirar método Simplify() sobre osgeo.ogr.Geometry
- null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula
- gtype_layer_from_geoms (bool=True): Por defecto, si gtype de layer origen == 0 (GEOMETRY) deducirá el tipo de geometria (POINT, LINE o POLYGON) a partir de la primera informada encontrada en la layer_origen
- epsg_code_dest (int=None): Codigo EPSG para le que se transformarán las geometrias desde el SRS original
- epsg_code_src_default (int=4326): Codigo EPSG que se usará para las layer_src que NO tengan SRS asignado
- old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2)
- **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado
Returns:
layer_out (ogr.Layer)
544def rename_wkt_geoms_csv(path_csv): 545 """ 546 Remove "_WKT" affix from WKT geometry fields in CSV file 547 548 Args: 549 path_csv (str): Path to CSV file 550 551 Returns: 552 553 """ 554 with open(path_csv, 'r', encoding='utf-8') as r_file: 555 content_csv = r_file.readlines() 556 first_line = next(iter(content_csv), None) 557 if first_line: 558 new_first_line = first_line.replace(PREFFIX_GEOMS_LAYERS_GDAL_CSV, '') 559 if new_first_line != first_line: 560 content_csv[0] = new_first_line 561 with open(path_csv, 'w', encoding='utf-8') as w_file: 562 w_file.writelines(content_csv)
Remove "_WKT" affix from WKT geometry fields in CSV file
Arguments:
- path_csv (str): Path to CSV file
Returns:
565def add_layer_features_to_layer(layer_src, ds_gdal_dest, layer_dest, nom_geom_src=None, nom_geom_dest=None, 566 srs_lyr_dest=None, null_geoms=False, tolerance_simplify=None, 567 remove_prev_features=False, epsg_code_src_default=4326, old_axis_mapping_srs=None): 568 """ 569 From a layer of a dataset, add the features to another layer of another dataset. 570 571 Args: 572 layer_src (ogr.Layer): Layer origen 573 ds_gdal_dest (gdal.Dataset): Dataset destino 574 layer_dest (ogr.Layer): Layer destino 575 nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará 576 como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante 577 nom_geom_dest (str): 578 srs_lyr_dest (ogr.SpatialReference=None): Spatial Reference System de la layer_dest 579 null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula 580 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer 581 Mirar método Simplify() sobre osgeo.ogr.Geometry 582 remove_prev_features (bool=False): Si es True, se eliminarán las features previas de la layer_dest 583 epsg_code_src_default (int=4326): EPSG code del srs de la layer_src si no se encuentra 584 old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2) 585 586 Returns: 587 588 """ 589 geoms_out = geoms_layer_gdal(layer_dest) 590 cols_out = cols_layer_gdal(layer_dest) 591 592 geom_transform = None 593 srs_lyr_src = srs_for_layer(layer_src, nom_geom_src) 594 if not srs_lyr_src: 595 srs_lyr_src = srs_ref_from_epsg_code(epsg_code_src_default, old_axis_mapping_srs) 596 597 if srs_lyr_dest is None: 598 srs_lyr_dest = srs_for_layer(layer_dest, nom_geom_dest) 599 600 if srs_lyr_dest and not srs_lyr_src.IsSame(srs_lyr_dest): 601 geom_transform = osr.CoordinateTransformation(srs_lyr_src, srs_lyr_dest) 602 603 ds_trans = ds_gdal_dest.TestCapability(ODsCTransactions) 604 605 if remove_prev_features: 606 if ds_trans: 607 layer_dest.StartTransaction() 608 for feat in layer_dest: 609 layer_dest.DeleteFeature(feat.GetFID()) 610 if ds_trans: 611 layer_dest.CommitTransaction() 612 613 if ds_trans: 614 layer_dest.StartTransaction() 615 616 i = 0 617 for feat_src, geom_src, nt_src in feats_layer_gdal(layer_src, nom_geom_src): 618 cols_out_chk = [col.upper() for col in cols_out.union(geoms_out)] 619 vals_camps = {nc: val for nc, val in nt_src._asdict().items() 620 if nc.upper() in cols_out_chk} 621 if null_geoms or geom_src: 622 if nom_geom_dest: 623 vals_camps[nom_geom_dest.upper()] = geom_src 624 625 add_feature_to_layer_gdal(layer_dest, 626 tolerance_simplify=tolerance_simplify, 627 geom_trans=geom_transform, 628 **vals_camps) 629 630 if i > 0 and (i % 1000) == 0: 631 print_debug("{} registres tractats...".format(str(i))) 632 i += 1 633 if ds_trans: 634 layer_dest.CommitTransaction()
From a layer of a dataset, add the features to another layer of another dataset.
Arguments:
- layer_src (ogr.Layer): Layer origen
- ds_gdal_dest (gdal.Dataset): Dataset destino
- layer_dest (ogr.Layer): Layer destino
- nom_geom_src (str=None): Si el nombre no se corresponde con ninguna de las geometrias de la layer_src se utilizará como ALIAS de la geometria 0 (la defecto) de la nueva layer resultante
- nom_geom_dest (str):
- srs_lyr_dest (ogr.SpatialReference=None): Spatial Reference System de la layer_dest
- null_geoms (bool=False): Por defecto no grabará las filas que la geometria principal (nom_geom) es nula
- tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer Mirar método Simplify() sobre osgeo.ogr.Geometry
- remove_prev_features (bool=False): Si es True, se eliminarán las features previas de la layer_dest
- epsg_code_src_default (int=4326): EPSG code del srs de la layer_src si no se encuentra
- old_axis_mapping_srs (bool=None): setea si quieres usar old mapping axes en (LONG, LAT) (GDAL >3.2)
Returns:
637def create_layer_on_ds_gdal(ds_gdal_dest, nom_layer, nom_geom=None, gtype=None, srs_lyr_out=None, **extra_opt_list): 638 """ 639 640 Args: 641 ds_gdal_dest (ogr.DataSource): 642 nom_layer (str): 643 nom_geom (str=None): 644 gtype (OGRwkbGeometryType=None): Indicar integer representativo del tipo de geometria de la layer (ogr.wkbPoint, ogr.wkbPolygon, ogr.LineString, ...) 645 srs_lyr_out (osr.SpatialReference=None): codigo epsg del sistema de coordenadas de la geometria 646 **extra_opt_list: Calves valores option list creacion layer gdal 647 648 Returns: 649 layer_gdal (ogr.Layer), nom_layer (str) 650 """ 651 drvr_name = ds_gdal_dest.GetDriver().GetName().upper() 652 653 opt_list = {k.upper(): v.upper() for k, v in extra_opt_list.items()} 654 655 opt_geom_name = "GEOMETRY_NAME" 656 if nom_geom: 657 opt_list[opt_geom_name] = "{}={}".format(opt_geom_name, nom_geom.upper()) 658 else: 659 if opt_geom_name in opt_list: 660 opt_list.pop(opt_geom_name) 661 gtype = ogr.wkbNone 662 663 opt_list["IDENTIFIER"] = opt_list.get("IDENTIFIER", "IDENTIFIER={}".format(nom_layer)) 664 665 opt_list = set_create_option_list_for_driver_gdal(drvr_name, **{k.upper(): v.upper() for k, v in opt_list.items()}) 666 667 if ds_gdal_dest.TestCapability(ODsCDeleteLayer) and ds_gdal_dest.GetLayerByName(nom_layer): 668 print_warning("!ATENCION! - Se sobreescribirá la layer '{}' sobre el datasource GDAL '{}'".format( 669 nom_layer, ds_gdal_dest.GetDescription())) 670 ds_gdal_dest.DeleteLayer(nom_layer) 671 672 if drvr_name.upper() == "KML": 673 nom_layer = nom_layer.replace("-", "__") 674 675 layer_out = ds_gdal_dest.CreateLayer(nom_layer, srs_lyr_out, geom_type=gtype, options=list(opt_list.values())) 676 677 return layer_out, layer_out.GetName() if layer_out else None
Arguments:
- ds_gdal_dest (ogr.DataSource):
- nom_layer (str):
- nom_geom (str=None):
- gtype (OGRwkbGeometryType=None): Indicar integer representativo del tipo de geometria de la layer (ogr.wkbPoint, ogr.wkbPolygon, ogr.LineString, ...)
- srs_lyr_out (osr.SpatialReference=None): codigo epsg del sistema de coordenadas de la geometria
- **extra_opt_list: Calves valores option list creacion layer gdal
Returns:
layer_gdal (ogr.Layer), nom_layer (str)
680def create_spatial_index_layer_gpkg(ds_gpkg, nom_layer): 681 """ 682 Crea spatial index sobre una layer (layer_gpkg) de un datosource gpkg (ds_gpkg) 683 684 Args: 685 ds_gpkg (osgeo.ogr.DataSource): 686 layer_gpkg (ogr.Layer): 687 688 Returns: 689 bool 690 """ 691 layer_gpkg = ds_gpkg.GetLayerByName(nom_layer) 692 if layer_gpkg and layer_gpkg.GetGeometryColumn(): 693 # Se crea spatial_index ya que GDAL NO lo hace 694 ds_gpkg.StartTransaction() 695 ds_gpkg.ExecuteSQL("SELECT CreateSpatialIndex('{tab_name}', '{geom_name}') ".format( 696 tab_name=layer_gpkg.GetName(), 697 geom_name=layer_gpkg.GetGeometryColumn())) 698 ds_gpkg.CommitTransaction() 699 700 return True 701 else: 702 return False
Crea spatial index sobre una layer (layer_gpkg) de un datosource gpkg (ds_gpkg)
Arguments:
- ds_gpkg (osgeo.ogr.DataSource):
- layer_gpkg (ogr.Layer):
Returns:
bool
705def add_feature_to_layer_gdal(layer_gdal, tolerance_simplify=None, geom_trans=None, commit=False, **valors_camps): 706 """ 707 708 Args: 709 layer_gdal (ogr.Layer): 710 tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer. 711 Mirar método Simplify() sobre osgeo.ogr.Geometry 712 geom_trans (osr.CoordinateTransformation=None): transformacion para convertir las geometrias a otro SRS 713 commit (bool=False): Per defecte no farà commit de la transaccio 714 **valors_camps: pares nombre_campo=valor de la feature a crear 715 716 Returns: 717 feat (ogr.Feature) 718 """ 719 dd_feat = ogr.Feature(layer_gdal.GetLayerDefn()) 720 721 for camp, val in valors_camps.items(): 722 idx_geom = dd_feat.GetGeomFieldIndex(camp) 723 es_geom = idx_geom >= 0 724 if es_geom: 725 if val: 726 if tolerance_simplify: 727 val = val.Simplify(tolerance_simplify) 728 if val and geom_trans: 729 val.Transform(geom_trans) 730 731 dd_feat.SetGeomField(idx_geom, val) 732 733 idx_fld = dd_feat.GetFieldIndex(camp) 734 if idx_fld >= 0: 735 if val: 736 if es_geom or hasattr(val, "ExportToIsoWkt"): 737 val = val.ExportToIsoWkt() 738 dd_feat.SetField(camp, val) 739 else: 740 dd_feat.SetFieldNull(camp) 741 742 if idx_fld < 0 and idx_geom < 0: 743 if isinstance(val, Geometry): 744 if geom_trans: 745 val.Transform(geom_trans) 746 dd_feat.SetGeometry(val) 747 elif val: 748 print_warning("!ATENCION! - La :layer_gdal no contiene el campo '{}'".format(camp)) 749 750 commit_trans = commit and layer_gdal.TestCapability(OLCTransactions) 751 if commit_trans: 752 layer_gdal.StartTransaction() 753 754 new_feat = layer_gdal.CreateFeature(dd_feat) 755 756 if commit_trans: 757 layer_gdal.CommitTransaction() 758 759 return new_feat
Arguments:
- layer_gdal (ogr.Layer):
- tolerance_simplify (float=None): Tolerancia (distancia minima) en unidades del srs de la layer. Mirar método Simplify() sobre osgeo.ogr.Geometry
- geom_trans (osr.CoordinateTransformation=None): transformacion para convertir las geometrias a otro SRS
- commit (bool=False): Per defecte no farà commit de la transaccio
- **valors_camps: pares nombre_campo=valor de la feature a crear
Returns:
feat (ogr.Feature)
762def drivers_ogr_gdal_disponibles(): 763 """ 764 Retorna lista de drivers disponibles a través de la librería osgeo-gdal-ogr 765 766 Returns: 767 dict 768 """ 769 cnt = ogr.GetDriverCount() 770 driver_list = [] 771 drivers = OrderedDict() 772 773 for i in range(cnt): 774 driver = ogr.GetDriver(i) 775 driver_name = driver.GetName() 776 driver_list.append(driver_name) 777 778 for driver_name in driver_list: 779 # Is File GeoDatabase available? 780 drv = ogr.GetDriverByName(driver_name) 781 if drv is None: 782 print_warning("{} !!ATENTION - driver NOT available!!".format(driver_name)) 783 else: 784 drivers[driver_name] = drv 785 print_debug(driver_name) 786 787 return drivers
Retorna lista de drivers disponibles a través de la librería osgeo-gdal-ogr
Returns:
dict
790def drivers_ogr_gdal_vector_file(): 791 """ 792 Devuelve diccionario con los driver gdal para fichero vectorial 793 794 Returns: 795 dict 796 """ 797 return {nd: d for nd, d in drivers_ogr_gdal_disponibles().items() 798 if hasattr(d, "GetMetadata_Dict") and d.GetMetadata_Dict().get('DMD_EXTENSIONS')}
Devuelve diccionario con los driver gdal para fichero vectorial
Returns:
dict
801def format_nom_column(nom_col): 802 """ 803 804 Args: 805 nom_col: 806 807 Returns: 808 str 809 """ 810 return nom_col.replace(" ", "_")
Arguments:
- nom_col:
Returns:
str
813def namedtuple_layer_gdal(layer_gdal, extract_affix_geom_fld=None): 814 """ 815 Devuelve namedTuple con los campos del layer pasado por parametro 816 817 Args: 818 layer_gdal: 819 extract_affix_geom_fld (str=None): 820 821 Returns: 822 namedtuple: con nombre "gdalFeatDef_{NOM_LAYER}" y con los campos de la layer 823 """ 824 camps_layer = set() 825 for fld in fields_layer_gdal(layer_gdal): 826 camps_layer.add(format_nom_column(fld.GetNameRef())) 827 828 for nom_geom in geoms_layer_gdal(layer_gdal, extract_affix=extract_affix_geom_fld): 829 camps_layer.add(format_nom_column(nom_geom)) 830 831 nom_layer = layer_gdal.GetName().upper().split(".")[0].replace("-", "_") 832 return namedtuple(f"gdalFeatDef_{nom_layer}", camps_layer)
Devuelve namedTuple con los campos del layer pasado por parametro
Arguments:
- layer_gdal:
- extract_affix_geom_fld (str=None):
Returns:
namedtuple: con nombre "gdalFeatDef_{NOM_LAYER}" y con los campos de la layer
835def feats_layer_ds_gdal(ds_gdal, nom_layer=None, filter_sql=None): 836 """ 837 Itera las features (registros de una layer de gdal) y los devuelve como un namdetuple 838 839 Args: 840 ds_gdal: datasource gdal 841 nom_layer (str=None): Si no viene informado cogerá la primera layer que encuentre en el datasource 842 filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. 843 Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html) 844 845 Returns: 846 ogr.Feature, ogr.Geometry, namedtuple_layer_gdal 847 """ 848 if not nom_layer: 849 layer_gdal = ds_gdal.GetLayer() 850 else: 851 layer_gdal = ds_gdal.GetLayerByName(nom_layer) 852 853 if layer_gdal: 854 for feat, geom, vals in feats_layer_gdal(layer_gdal, filter_sql=filter_sql): 855 yield feat, geom, vals
Itera las features (registros de una layer de gdal) y los devuelve como un namdetuple
Arguments:
- ds_gdal: datasource gdal
- nom_layer (str=None): Si no viene informado cogerá la primera layer que encuentre en el datasource
- filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html)
Returns:
ogr.Feature, ogr.Geometry, namedtuple_layer_gdal
858def feats_layer_gdal(layer_gdal, nom_geom=None, filter_sql=None, extract_affix_geom_fld=PREFFIX_GEOMS_LAYERS_GDAL): 859 """ 860 Itera las features (registros de una layer de gdal) y los devuelve como un namdtuple 861 862 Args: 863 layer_gdal (ogr.Layer): 864 nom_geom (str=None): Por defecto la geometria activa o principal 865 filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. 866 Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html) 867 extract_affix_geom_fld (str=SUFFIX_GEOMS_LAYERS_GDAL): Por defecto quita el sufijo 'geom_' a los campos geom 868 869 Returns: 870 ogr.Feature, ogr.Geometry, namedtuple_layer_gdal 871 """ 872 layer_gdal.ResetReading() 873 ntup_layer = namedtuple_layer_gdal(layer_gdal, extract_affix_geom_fld) 874 n_geoms_layer = {nom_geom_feat: fix_affix_geom_name_layer_gdal(nom_geom_feat, layer_gdal, extract_affix_geom_fld) 875 for nom_geom_feat in geoms_layer_gdal(layer_gdal)} 876 877 if filter_sql: 878 layer_gdal.SetAttributeFilter(filter_sql) 879 880 def vals_feature_gdal(feat_gdal): 881 vals = {} 882 for camp, val in feat_gdal.items().items(): 883 vals[format_nom_column(camp)] = val 884 885 for camp_geom, camp_geom_val in n_geoms_layer.items(): 886 idx_geom = feat_gdal.GetGeomFieldIndex(camp_geom) 887 if idx_geom >= 0: 888 vals[camp_geom_val] = feat_gdal.GetGeomFieldRef(idx_geom) 889 890 return vals 891 892 if layer_gdal: 893 for f_tab in layer_gdal: 894 idx_geom = f_tab.GetGeomFieldIndex(nom_geom) if nom_geom else -1 895 yield f_tab, \ 896 f_tab.GetGeomFieldRef(idx_geom) if idx_geom >= 0 else f_tab.geometry(), \ 897 ntup_layer(**vals_feature_gdal(f_tab)) 898 899 layer_gdal.ResetReading()
Itera las features (registros de una layer de gdal) y los devuelve como un namdtuple
Arguments:
- layer_gdal (ogr.Layer):
- nom_geom (str=None): Por defecto la geometria activa o principal
- filter_sql (str=None): Si viene informado se aplicará como filtro sql a la layer seleccionada. Utiliza OGR SQL (vease https://www.gdal.org/ogr_sql.html)
- extract_affix_geom_fld (str=SUFFIX_GEOMS_LAYERS_GDAL): Por defecto quita el sufijo 'geom_' a los campos geom
Returns:
ogr.Feature, ogr.Geometry, namedtuple_layer_gdal
902def distinct_vals_camp_layer_gdal(layer_gdal, nom_camp, filter_sql=None): 903 """ 904 Devuelve set con distintos valores para el campo indicado del layer GDAL indicada 905 906 Args: 907 layer_gdal (ogr.Layer): 908 nom_camp (str): 909 filter_sql (str=None): 910 911 Returns: 912 set 913 """ 914 if nom_camp.upper() not in cols_layer_gdal(layer_gdal): 915 raise Exception("Argumento :NOM_CAMP = '{}' erróneo ya que " 916 "LAYER_GDAL no contiene el campo indicado".format(nom_camp)) 917 918 return {getattr(nt_feat, nom_camp.upper()) 919 for feat, geom, nt_feat in feats_layer_gdal(layer_gdal, filter_sql=filter_sql)}
Devuelve set con distintos valores para el campo indicado del layer GDAL indicada
Arguments:
- layer_gdal (ogr.Layer):
- nom_camp (str):
- filter_sql (str=None):
Returns:
set
922def fields_layer_gdal(layer_gdal): 923 """ 924 Itera sobre los FieldDefn de una layer gdal 925 926 Args: 927 layer_gdal: 928 929 Yields: 930 osgeo.ogr.FieldDefn 931 """ 932 layer_def = layer_gdal.GetLayerDefn() 933 for i in range(0, layer_def.GetFieldCount()): 934 yield layer_def.GetFieldDefn(i) 935 936 layer_def = None
Itera sobre los FieldDefn de una layer gdal
Arguments:
- layer_gdal:
Yields:
osgeo.ogr.FieldDefn
939def geom_fields_layer_gdal(layer_gdal): 940 """ 941 Itera sobre los GeomFieldDefn de una layer gdal 942 943 Args: 944 layer_gdal: 945 946 Yields: 947 osgeo.ogr.GeomFieldDefn 948 """ 949 layer_def = layer_gdal.GetLayerDefn() 950 for i in range(0, layer_def.GetGeomFieldCount()): 951 yield layer_def.GetGeomFieldDefn(i) 952 953 layer_def = None
Itera sobre los GeomFieldDefn de una layer gdal
Arguments:
- layer_gdal:
Yields:
osgeo.ogr.GeomFieldDefn
956def nom_layers_datasource_gdal(ds_gdal): 957 """ 958 959 Args: 960 ds_gdal (ogr.Datasource: 961 962 Returns: 963 set 964 """ 965 return {l.GetName() for l in ds_gdal}
Arguments:
- ds_gdal (ogr.Datasource:
Returns:
set
968def cols_layer_gdal(layer_gdal): 969 """ 970 Retorna lista con las columnas de una layer gdal 971 972 Args: 973 layer_gdal: 974 975 Returns: 976 set 977 """ 978 camps = set() 979 for fd in fields_layer_gdal(layer_gdal): 980 # camps.add(fd.GetName().upper()) 981 camps.add(fd.GetNameRef()) 982 983 return camps
Retorna lista con las columnas de una layer gdal
Arguments:
- layer_gdal:
Returns:
set
986def geoms_layer_gdal(layer_gdal, extract_affix=None): 987 """ 988 Retorna lista con las columnas geométricas de una layer gdal 989 990 Args: 991 layer_gdal: 992 extract_affix (str=None=): if informed extract the affix passed 993 994 Returns: 995 set 996 """ 997 camps_geom = set() 998 for gdf in geom_fields_layer_gdal(layer_gdal): 999 # camps_geom.add(gdf.GetName().upper()) 1000 name_ref = gdf.GetNameRef() 1001 if extract_affix: 1002 name_ref = fix_affix_geom_name_layer_gdal(name_ref, layer_gdal, extract_affix) 1003 camps_geom.add(name_ref) 1004 1005 return camps_geom
Retorna lista con las columnas geométricas de una layer gdal
Arguments:
- layer_gdal:
- extract_affix (str=None=): if informed extract the affix passed
Returns:
set
1008def fix_affix_geom_name_layer_gdal(geom_name, layer_gdal, affix=PREFFIX_GEOMS_LAYERS_GDAL): 1009 """ 1010 Extract affix (default=PREFFIX_GEOMS_LAYERS_GDAL) from name geoms if correspond with other column 1011 Fix GDAL > 3.4 where geoms on GeoCSV arrive with preffix 'geom_' 1012 1013 Args: 1014 geom_name (str): 1015 layer_gdal: 1016 affix (str=PREFFIX_GEOMS_LAYERS_GDAL): 1017 1018 Returns: 1019 str 1020 """ 1021 cols_layer = cols_layer_gdal(layer_gdal) 1022 geom_name_layer = geom_name 1023 if geom_name.lower().startswith(affix): 1024 geom_name_aux = re.sub(affix, '', geom_name, flags=re.IGNORECASE) 1025 if geom_name_aux.lower() in (col.lower() for col in cols_layer): 1026 geom_name_layer = geom_name_aux 1027 1028 return geom_name_layer
Extract affix (default=PREFFIX_GEOMS_LAYERS_GDAL) from name geoms if correspond with other column Fix GDAL > 3.4 where geoms on GeoCSV arrive with preffix 'geom_'
Arguments:
- geom_name (str):
- layer_gdal:
- affix (str=PREFFIX_GEOMS_LAYERS_GDAL):
Returns:
str
1031def add_layer_gdal_to_ds_gdal(ds_gdal, layer_gdal, nom_layer=None, lite=False, srs_epsg_code=None, multi_geom=False, 1032 nom_geom=None, null_geoms=False, **extra_opt_list): 1033 """ 1034 Añade una layer_gdal a un datasource_gdal. Si es una layer con multigeometrias las separa en una layer por geometria 1035 1036 Args: 1037 ds_gdal (osgeo.ogr.Datasource): 1038 layer_gdal (osgeo.ogr.Layer): 1039 nom_layer (str=None): 1040 lite (bool=False): 1041 srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir 1042 las geometrias 1043 nom_geom (str=None): nombre de geometria de layer origen (layer_gdal) que se copiará, si no todas 1044 multi_geom (bool=False): Si el DS_GDAL destino permite multigeometria 1045 null_geoms (bool=False): Indica si se admitirán registros con NULL geoms. Por defecto NO 1046 **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado 1047 1048 Returns: 1049 new_layers_ds_gdal (list) 1050 """ 1051 new_layers_ds_gdal = [] 1052 1053 if not nom_layer: 1054 nom_layer = layer_gdal.GetName() 1055 1056 geoms_layer = geoms_layer_gdal(layer_gdal) 1057 if nom_geom: 1058 if nom_geom.upper() not in (g.upper() for g in geoms_layer): 1059 Exception("!ERROR! - Nombre de geometria '{}' no existe en la layer GDAL origen") 1060 else: 1061 geoms_layer = (nom_geom,) 1062 1063 if geoms_layer: 1064 tol = None 1065 if lite: 1066 tol = SIMPLIFY_TOLERANCE 1067 1068 nom_layer_base = nom_layer.split("-")[0] 1069 if not multi_geom: 1070 for geom_name in geoms_layer: 1071 # Fix GDAL > 3.4 where geoms on GeoCSV arrive with preffix 'geom_' 1072 geom_name_layer = fix_affix_geom_name_layer_gdal(geom_name, layer_gdal) 1073 1074 nom_layer = "{}-{}".format(nom_layer_base, geom_name_layer).lower() 1075 extra_opt_list["GEOMETRY_NAME"] = "GEOMETRY_NAME={}".format(geom_name_layer) 1076 lyr = create_layer_from_layer_gdal_on_ds_gdal(ds_gdal, layer_gdal, nom_layer, geom_name, 1077 tolerance_simplify=tol, null_geoms=null_geoms, 1078 epsg_code_dest=srs_epsg_code, **extra_opt_list) 1079 new_layers_ds_gdal.append(lyr) 1080 else: 1081 lyr = create_layer_from_layer_gdal_on_ds_gdal(ds_gdal, layer_gdal, nom_layer, exclude_cols_geoms=False, 1082 tolerance_simplify=tol, null_geoms=True, 1083 epsg_code_dest=srs_epsg_code, **extra_opt_list) 1084 new_layers_ds_gdal.append(lyr) 1085 else: 1086 if ds_gdal.GetDriver().GetName() == 'PostgreSQL': 1087 extra_opt_list.update(dict( 1088 precision=extra_opt_list.get('precision', 'PRECISION=NO') 1089 )) 1090 1091 lyr = copy_layer_gdal_to_ds_gdal(layer_gdal, ds_gdal, nom_layer.lower(), **extra_opt_list) 1092 new_layers_ds_gdal.append(lyr) 1093 1094 return new_layers_ds_gdal
Añade una layer_gdal a un datasource_gdal. Si es una layer con multigeometrias las separa en una layer por geometria
Arguments:
- ds_gdal (osgeo.ogr.Datasource):
- layer_gdal (osgeo.ogr.Layer):
- nom_layer (str=None):
- lite (bool=False):
- srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir las geometrias
- nom_geom (str=None): nombre de geometria de layer origen (layer_gdal) que se copiará, si no todas
- multi_geom (bool=False): Si el DS_GDAL destino permite multigeometria
- null_geoms (bool=False): Indica si se admitirán registros con NULL geoms. Por defecto NO
- **extra_opt_list (str): Lista claves-valores de opciones para createLayer del driver de ds_gdal indicado
Returns:
new_layers_ds_gdal (list)
1097def copy_layers_gpkg(ds_gpkg, driver, dir_base, lite=False, srs_epsg_code=None, zipped=True): 1098 """ 1099 1100 Args: 1101 ds_gpkg (osgeo.ogr.Datasource): 1102 driver (str): 1103 dir_base (str=None): 1104 lite (bool=False): 1105 srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir 1106 las geometrias 1107 zipped (bool=False): 1108 1109 Returns: 1110 num_layers (int) 1111 """ 1112 num_layers = 0 1113 subdir_drvr = os.path.normpath(os.path.join(dir_base, driver.upper())) 1114 utils.create_dir(subdir_drvr) 1115 1116 for layer_gpkg in (ds_gpkg.GetLayer(id_lyr) for id_lyr in range(ds_gpkg.GetLayerCount() - 1)): 1117 if driver == "GPKG": 1118 nom_ds, ext = utils.split_ext_file(os.path.basename(ds_gpkg.name)) 1119 else: 1120 nom_ds = f"{layer_gpkg.GetName()}".lower() 1121 1122 ds_gdal, existia = datasource_gdal_vector_file(driver, nom_ds, subdir_drvr) 1123 1124 add_layer_gdal_to_ds_gdal(ds_gdal, layer_gpkg, lite=lite, srs_epsg_code=srs_epsg_code) 1125 1126 num_layers += 1 1127 1128 return num_layers
Arguments:
- ds_gpkg (osgeo.ogr.Datasource):
- driver (str):
- dir_base (str=None):
- lite (bool=False):
- srs_epsg_code (int=None): codigo EPSG para el sistema de coordenadas con el que se quieren convertir las geometrias
- zipped (bool=False):
Returns:
num_layers (int)
1131def set_csvt_for_layer_csv(path_csv, **tipus_camps): 1132 """ 1133 Crea/Modifica el CSVT asociado con los tipos indicados para cada columna 1134 1135 Args: 1136 path_csv (str): 1137 **tipus_camps: clave=valor con el nombre del campo y el tipo de campo asociado (p.e. String(25), WKT, Integer,...) 1138 1139 Returns: 1140 path_csvt (str) 1141 """ 1142 lyr_csv, nom_layer, ds_lyr = layer_gdal_from_file(path_csv, "CSV") 1143 if not lyr_csv: 1144 print_warning("!ATENCIO! - No s'ha pogut obrir la layer CSV '{}'".format(path_csv)) 1145 return 1146 1147 path_lyr_csvt = os.path.join(os.path.dirname(path_csv), "{}.csvt".format(nom_layer)) 1148 tips_lyr = {} 1149 for fld in fields_layer_gdal(lyr_csv): 1150 tip_fld = fld.GetFieldTypeName(fld.GetType()) 1151 sufix = "" 1152 w = fld.GetWidth() 1153 if w: 1154 sufix = "{}".format(w) 1155 p = fld.GetPrecision() 1156 if p: 1157 sufix += ".{}".format(p) 1158 if sufix: 1159 tip_fld += "({})".format(sufix) 1160 1161 tips_lyr[fld.name.upper()] = tip_fld 1162 1163 for nom_camp, tip_camp in tipus_camps.items(): 1164 nom_camp = nom_camp.upper() 1165 if nom_camp not in tips_lyr: 1166 print_warning("!ATENCIO! - Camp '{}' no existeix sobre la layer CSV '{}'".format(nom_camp, path_csv)) 1167 continue 1168 1169 tips_lyr[nom_camp] = tip_camp 1170 1171 with open(path_lyr_csvt, mode="w", encoding="utf8") as f_csvt: 1172 f_csvt.write(",".join(tips_lyr.values()))
Crea/Modifica el CSVT asociado con los tipos indicados para cada columna
Arguments:
- path_csv (str):
- **tipus_camps: clave=valor con el nombre del campo y el tipo de campo asociado (p.e. String(25), WKT, Integer,...)
Returns:
path_csvt (str)
1175def zip_and_clean_ds_csv(path_csv): 1176 """ 1177 # Zipea datasource osgeo CSV y como GDAL no crea los tipos WKT para las geometrias en el CSVT se fuerza 1178 1179 Args: 1180 path_csv (str): path Datasource osgeo CSV 1181 1182 Returns: 1183 zip_path (str) 1184 """ 1185 ds_gdal_csv, dummy = datasource_gdal_vector_file("CSV", os.path.basename(path_csv).split(".")[0], 1186 os.path.dirname(path_csv)) 1187 layer_csv = ds_gdal_csv.GetLayer(0) 1188 tips_geoms = {gn: "WKT" for gn in 1189 (*geoms_layer_gdal(layer_csv, extract_affix=PREFFIX_GEOMS_LAYERS_GDAL), 1190 *geoms_layer_gdal(layer_csv, extract_affix=PREFFIX_GEOMS_LAYERS_GDAL_CSV))} 1191 path_csv = ds_gdal_csv.GetDescription() 1192 ds_gdal_csv = None # Cerramos el datasource para que se guarden los cambios 1193 if path_csv and os.path.exists(path_csv): 1194 if tips_geoms: 1195 set_csvt_for_layer_csv(path_csv, **tips_geoms) 1196 rename_wkt_geoms_csv(path_csv) 1197 dir_base_csv = os.path.dirname(path_csv) 1198 nom_layer = os.path.basename(path_csv).split(".")[0] 1199 l_files_csv = [os.path.join(dir_base_csv, nf) for nf in os.listdir(dir_base_csv) 1200 if nf.lower().startswith(nom_layer.lower()) and 1201 any(nf.lower().endswith(ext) for ext in ('csv', 'csvt'))] 1202 zip_path = utils.zip_files(os.path.join(dir_base_csv, "{}.zip".format(nom_layer)), l_files_csv) 1203 if zip_path: 1204 for fl_csv in l_files_csv: 1205 os.remove(fl_csv) 1206 1207 return zip_path
Zipea datasource osgeo CSV y como GDAL no crea los tipos WKT para las geometrias en el CSVT se fuerza
Arguments:
- path_csv (str): path Datasource osgeo CSV
Returns:
zip_path (str)
1210def convert_angle(pt_xy, deg_ang, orig_srs, dest_srs): 1211 """ 1212 1213 Args: 1214 pt_xy (tuple): 1215 deg_ang (float): 1216 orig_srs (osr.SpatialReference): 1217 dest_srs (osr.SpatialReference): 1218 1219 Returns: 1220 1221 """ 1222 trans = osr.CoordinateTransformation(orig_srs, dest_srs) 1223 x, y = pt_xy 1224 dx = math.sin(math.radians(deg_ang)) * 0.00000001 1225 dy = math.cos(math.radians(deg_ang)) * 0.00000001 1226 pt1 = ogr.CreateGeometryFromWkt("POINT ({} {})".format(x, y)) 1227 pt2 = ogr.CreateGeometryFromWkt("POINT ({} {})".format(x + dx, y + dy)) 1228 pt1.Transform(trans) 1229 pt2.Transform(trans) 1230 x1, y1, z1 = pt1.GetPoint() 1231 x2, y2, z2 = pt2.GetPoint() 1232 1233 return math.degrees(math.atan2(y2 - y1, x2 - x1))
Arguments:
- pt_xy (tuple):
- deg_ang (float):
- orig_srs (osr.SpatialReference):
- dest_srs (osr.SpatialReference):
Returns:
1236def transform_ogr_geom(a_ogr_geom, from_espg_code, to_epsg_code): 1237 """ 1238 Transforma una geometria OGR según los EPSG indicados 1239 1240 Args: 1241 a_ogr_geom (ogr.geometry): una geometria del tipo OGR 1242 from_espg_code (int): codigo numérico del EPSG actual para la geometria 1243 to_epsg_code (int): codigo numérico del EPSG al que se quiere transformar 1244 1245 Returns: 1246 ogr.geometry 1247 """ 1248 source = osr.SpatialReference() 1249 source.ImportFromEPSG(from_espg_code) 1250 1251 target = osr.SpatialReference() 1252 target.ImportFromEPSG(to_epsg_code) 1253 1254 a_transform = osr.CoordinateTransformation(source, target) 1255 a_ogr_geom.Transform(a_transform) 1256 1257 return a_ogr_geom
Transforma una geometria OGR según los EPSG indicados
Arguments:
- a_ogr_geom (ogr.geometry): una geometria del tipo OGR
- from_espg_code (int): codigo numérico del EPSG actual para la geometria
- to_epsg_code (int): codigo numérico del EPSG al que se quiere transformar
Returns:
ogr.geometry
1260def ds_postgis(dbname='POSTGRES', host='localhost', port='5432', user='postgres', password='postgres', schema='public'): 1261 """ 1262 Retorna datasource GDAL para ddbb postgis 1263 1264 Args: 1265 dbname: 1266 host: 1267 port: 1268 user: 1269 password: 1270 schema: 1271 1272 Returns: 1273 osgeo.ogr.DataSource 1274 """ 1275 pg_conn = f"PG:dbname='{dbname}' host='{host}' port='{port}' user='{user}' password='{password}' active_schema='{schema}'" 1276 drvr, exts = driver_gdal('PostgreSQL') 1277 return drvr.Open(pg_conn, 1)
Retorna datasource GDAL para ddbb postgis
Arguments:
- dbname:
- host:
- port:
- user:
- password:
- schema:
Returns:
osgeo.ogr.DataSource
1280def reset_sequence_layer_postgis(ds_postgis, nom_layer): 1281 """ 1282 Resetea la secuencia de la layer PostGIS indicada 1283 1284 Args: 1285 ds_postgis (osgeo.ogr.DataSource): datasource de la ddbb PostGIS: 1286 nom_layer (str): nombre de la layer PostGIS 1287 1288 Returns: 1289 bool: True si se ha reseteado correctamente 1290 """ 1291 ok = False 1292 layer_dest = ds_postgis.GetLayerByName(nom_layer) 1293 fid_column = layer_dest.GetFIDColumn() 1294 get_seq_sql = f"SELECT pg_get_serial_sequence('{nom_layer}', '{fid_column}') FROM information_schema.columns " \ 1295 f"WHERE table_name = '{nom_layer}' AND column_default LIKE 'nextval%'" 1296 1297 if res_get_seq := ds_postgis.ExecuteSQL(get_seq_sql): 1298 seq_name = res_get_seq.GetNextFeature().GetField(0) 1299 ds_postgis.StartTransaction() 1300 reset_seq = f"SELECT setval('{seq_name}', 1, false);" 1301 ds_postgis.ExecuteSQL(reset_seq) 1302 ds_postgis.CommitTransaction() 1303 ok = True 1304 1305 return ok
Resetea la secuencia de la layer PostGIS indicada
Arguments:
- ds_postgis (osgeo.ogr.DataSource): datasource de la ddbb PostGIS:
- nom_layer (str): nombre de la layer PostGIS
Returns:
bool: True si se ha reseteado correctamente