def feat_to_pnt(inShp, outPnt, epsg=None): """ Get Centroid from each line in a PolyLine Feature Class """ import os from osgeo import ogr from glass.g.prop import drv_name from glass.g.lyr.fld import copy_flds from glass.g.prop.feat import lst_fld # TODO: check if geometry is correct # Open data polyData = ogr.GetDriverByName(drv_name(outPnt)).Open(inShp) polyLyr = polyData.GetLayer() # Get SRS for the output if not epsg: from glass.g.prop.prj import get_shp_sref srs = get_shp_sref(polyLyr) else: from glass.g.prop.prj import get_sref_from_epsg srs = get_sref_from_epsg(epsg) # Create output pntData = ogr.GetDriverByName(drv_name(outPnt)).CreateDataSource(outPnt) pntLyr = pntData.CreateLayer(os.path.splitext(os.path.basename(outPnt))[0], srs, geom_type=ogr.wkbPoint) # Copy fields from input to output fields = lst_fld(polyLyr) copy_flds(polyLyr, pntLyr) pntLyrDefn = pntLyr.GetLayerDefn() for feat in polyLyr: geom = feat.GetGeometryRef() pnt = geom.Centroid() new_feat = ogr.Feature(pntLyrDefn) new_feat.SetGeometry(pnt) for fld in fields: new_feat.SetField(fld, feat.GetField(fld)) pntLyr.CreateFeature(new_feat) new_feat.Destroy() del pntLyr del polyLyr pntData.Destroy() polyData.Destroy() return outPnt
def pnts_to_boundary(pntShp, outBound, distMeters): """ Create a boundary from Point using a tolerance in meters """ from osgeo import ogr from glass.pys.oss import fprop from glass.g.prop import drv_name from glass.g.gobj import new_pnt from glass.g.prop.prj import get_shp_sref SRS = get_shp_sref(pntShp) shp = ogr.GetDriverByName(drv_name(pntShp)).Open(pntShp) lyr = shp.GetLayer() outShp = ogr.GetDriverByName(drv_name(outBound)).CreateDataSource(outBound) outLyr = outShp.CreateLayer(fprop(outBound, 'fn', forceLower=True), SRS, geom_type=ogr.wkbPolygon) outDefn = outLyr.GetLayerDefn() for feat in lyr: __feat = ogr.Feature(outDefn) ring = ogr.Geometry(ogr.wkbLinearRing) geom = feat.GetGeometryRef() X, Y = geom.GetX(), geom.GetY() boundary_points = [ new_pnt(X - distMeters, Y + distMeters), # Topleft new_pnt(X + distMeters, Y + distMeters), # TopRight new_pnt(X + distMeters, Y - distMeters), # Lower Right new_pnt(X - distMeters, Y - distMeters), # Lower Left new_pnt(X - distMeters, Y + distMeters) ] for pnt in boundary_points: ring.AddPoint(pnt.GetX(), pnt.GetY()) polygon = ogr.Geometry(ogr.wkbPolygon) polygon.AddGeometry(ring) __feat.SetGeometry(polygon) outLyr.CreateFeature(__feat) feat.Destroy() __feat = None ring = None polygon = None shp.Destroy() outShp.Destroy() return outBound
def sel_by_loc(shp, boundary_filter, filtered_output): """ Filter a shp using the location of a boundary_filter shp For now the boundary must have only one feature Writes the filter on a new shp """ from osgeo import ogr from glass.g.prop import drv_name from glass.g.prop.feat import get_gtype from glass.g.lyr.fld import copy_flds from glass.g.cp import copy_feat from glass.pys.oss import fprop # Open main data dtSrc = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) lyr = dtSrc.GetLayer() # Get filter geom filter_shp = ogr.GetDriverByName( drv_name(boundary_filter)).Open(boundary_filter, 0) filter_lyr = filter_shp.GetLayer() c = 0 for f in filter_lyr: if c: break geom = f.GetGeometryRef() c += 1 filter_shp.Destroy() # Apply filter lyr.SetSpatialFilter(geom) # Copy filter objects to a new shape out = ogr.GetDriverByName( drv_name(filtered_output)).CreateDataSource(filtered_output) outLyr = out.CreateLayer( fprop(filtered_output, 'fn'), geom_type=get_gtype(shp, gisApi='ogr', name=None, py_cls=True) ) # Copy fields copy_flds(lyr, outLyr) copy_feat( lyr, outLyr, outDefn=outLyr.GetLayerDefn(), only_geom=False, gisApi='ogrlyr' )
def get_cntr_bnd(shp, isFile=None): """ Return centroid (OGR Point object) of a Boundary (layer with a single feature). """ from osgeo import ogr from glass.g.prop import drv_name if isFile: shp = ogr.GetDriverByName( drv_name(shp)).Open(shp, 0) lyr = shp.GetLayer() feat = lyr[0]; geom = feat.GetGeometryRef() else: geom = shp centroid = geom.Centroid() cnt = ogr.CreateGeometryFromWkt(centroid.ExportToWkt()) shp.Destroy() return cnt
def lst_fld(shp): """ Return a list with every field name in a vectorial layer """ from osgeo import ogr from glass.g.prop import drv_name if type(shp) == ogr.Layer: lyr = shp c=0 else: data = ogr.GetDriverByName( drv_name(shp)).Open(shp, 0) lyr = data.GetLayer() c= 1 defn = lyr.GetLayerDefn() fields = [] for i in range(0, defn.GetFieldCount()): fdefn = defn.GetFieldDefn(i) fields.append(fdefn.name) if c: del lyr data.Destroy() return fields
def geom_by_idx(inShp, idx): """ Get Geometry by index in file """ from osgeo import ogr from glass.g.prop import drv_name src = ogr.GetDriverByName(drv_name(inShp)).Open(inShp) lyr = src.GetLayer() c = 0 geom = None for f in lyr: if idx == c: geom = f.GetGeometryRef() else: c += 1 if not geom: raise ValueError("inShp has not idx") _geom = geom.ExportToWkt() del lyr src.Destroy() return _geom
def ogr_list_fields_defn(shp): """ Return a dict with the field name as key and the field definition as value Field defn is the same of saying name + type """ if type(shp) == ogr.Layer: lyr = shp c = 0 else: data = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) lyr = data.GetLayer() c = 1 defn = lyr.GetLayerDefn() fields = {} for i in range(0, defn.GetFieldCount()): fdefn = defn.GetFieldDefn(i) fieldType = fdefn.GetFieldTypeName(fdefn.GetType()) fields[fdefn.name] = {fdefn.GetType(): fieldType} if c: del lyr data.Destroy() return fields
def get_shp_sref(shp): """ Get Spatial Reference Object from Feature Class/Lyr """ from osgeo import ogr from glass.g.prop import drv_name if type(shp) == ogr.Layer: lyr = shp c = 0 else: data = ogr.GetDriverByName( drv_name(shp)).Open(shp) lyr = data.GetLayer() c = 1 spref = lyr.GetSpatialRef() if c: del lyr data.Destroy() return spref
def rst_val_to_points(pnt, rst): """ Extract, for a given point dataset, the value of a cell with the same location Returns a dict: d = { fid: value, ... } """ from osgeo import ogr, gdal from glass.g.prop import drv_name values_by_point = {} shp = ogr.GetDriverByName(drv_name(pnt)).Open(pnt, 0) lyr = shp.GetLayer() img = gdal.Open(rst) geo_transform = img.GetGeoTransform() band = img.GetRasterBand(1) for feat in lyr: geom = feat.GetGeometryRef() mx, my = geom.GetX(), geom.GetY() px = int((mx - geo_transform[0]) / geo_transform[1]) py = int((my - geo_transform[3]) / geo_transform[5]) val_pix = band.ReadAsArray(px, py, 1, 1) values_by_point[int(feat.GetFID())] = float(val_pix[0][0]) return values_by_point
def area_to_dic(shp): """ Return the following output: dic = { id_feat: area, ..., id_feat: area } """ from osgeo import ogr from glass.g.prop import drv_name o = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) l = o.GetLayer() d = {} c = 0 for feat in l: g = feat.GetGeometryRef() area = g.GetArea() d[c] = area c += 1 del l o.Destroy() return d
def shp_to_shp(inshp, outshp, gisApi='ogr', supportForSpatialLite=None): """ Convert a vectorial file to another with other file format API's Available: * ogr; * grass; When using gisApi='ogr' - Set supportForSpatialLite to True if outShp is a sqlite db and if you want SpatialLite support for that database. """ if gisApi == 'ogr': from glass.pys import execmd from glass.g.prop import drv_name out_driver = drv_name(outshp) if out_driver == 'SQLite' and supportForSpatialLite: splite = ' -dsco "SPATIALITE=YES"' else: splite = '' cmd = 'ogr2ogr -f "{drv}" {out} {_in}{lite}'.format(drv=out_driver, out=outshp, _in=inshp, lite=splite) # Run command cmdout = execmd(cmd) elif gisApi == 'grass': # TODO identify input geometry type import os from glass.pys.oss import fprop from glass.g.wenv.grs import run_grass from glass.g.prop.prj import get_epsg # Start GRASS GIS Session ws = os.path.dirname(outshp) loc = f'loc_{fprop(outshp, "fn")}' epsg = get_epsg(inshp) gbase = run_grass(ws, location=loc, srs=epsg) import grass.script.setup as gsetup gsetup.init(gbase, ws, loc, 'PERMANENT') from glass.g.it.shp import grs_to_shp, shp_to_grs gshp = shp_to_grs(inshp, fprop(inshp, 'fn')) grs_to_shp(gshp, outshp, 'area') else: raise ValueError('Sorry, API {} is not available'.format(gisApi)) return outshp
def clip(inFeat, clipFeat, outFeat, api_gis="grass", clip_by_region=None): """ Clip Analysis api_gis Options: * grass * pygrass * ogr2ogr """ from glass.pys.oss import fprop if api_gis == "pygrass" or api_gis == "grass": import os from glass.g.wenv.grs import run_grass from glass.g.prop.prj import get_epsg epsg = get_epsg(inFeat) work = os.path.dirname(outFeat) refname = fprop(outFeat, 'fn') loc = f"loc_{refname}" grsbase = run_grass(work, location=loc, srs=epsg) import grass.script.setup as gsetup gsetup.init(grsbase, work, loc, 'PERMANENT') from glass.g.it.shp import shp_to_grs, grs_to_shp from glass.g.prop.feat import feat_count shp = shp_to_grs(inFeat, fprop(inFeat, 'fn')) clp = shp_to_grs(clipFeat, fprop(clipFeat, 'fn')) # Clip rslt = grsclip(shp, clp, refname, cmd=True if api_gis == "grass" else None, clip_by_region=clip_by_region) # Export grs_to_shp(rslt, outFeat, 'area') elif api_gis == 'ogr2ogr': from glass.pys import execmd from glass.g.prop import drv_name rcmd = execmd( ("ogr2ogr -f \"{}\" {} {} -clipsrc {} -clipsrclayer {}").format( drv_name(outFeat), outFeat, inFeat, clipFeat, fprop(clipFeat, 'fn'))) else: raise ValueError("{} is not available!".format(api_gis)) return outFeat
def get_attr_values_in_location(inShp, attr, geomFilter=None, shpFilter=None): """ Get attributes of the features of inShp that intersects with geomFilter or shpFilter """ from osgeo import ogr from glass.g.prop import drv_name if not geomFilter and not shpFilter: raise ValueError( 'A geom object or a path to a sho file should be given' ) if shpFilter: # For now the shpFilter must have only one feature filter_shp = ogr.GetDriverByName( drv_name(shpFilter)).Open(shpFilter, 0) filter_lyr = filter_shp.GetLayer() c= 0 for f in filter_lyr: if c: break geom = f.GetGeometryRef() c += 1 filter_shp.Destroy() else: geom = geomFilter # Open Main data dtSrc = ogr.GetDriverByName(drv_name(inShp)).Open(inShp, 0) lyr = dtSrc.GetLayer() lyr.SetSpatialFilter(geom) # Get attribute values ATTRIBUTE_VAL = [feat.GetField(attr) for feat in lyr] dtSrc.Destroy() return ATTRIBUTE_VAL
def statistics_by_line_feat(lines, raster, statistic, new_field): """ Estimates raster statistic per line on a linear feature class statistic = statistic type (e.g. max, min, mean, sum) This method has an important problem - depends on the number of vertex of each features TODO: convert lines to raster and use the raster to get the statistics of each line """ from osgeo import ogr, gdal from glass.g.prop import drv_name from glass.g.smp import pnt_val_on_rst # Open feature class shp = ogr.GetDriverByName(drv_name(lines)).Open(lines, 1) lyr = shp.GetLayer() # Create new field lyr.CreateField(ogr.FieldDefn(new_field, ogr.OFTReal)) # Open Raster img = gdal.Open(raster) geo_transform = img.GetGeoTransform() band = img.GetRasterBand(1) # For feature in layer for feat in lyr: rst_values = [] # For point in line lnh = feat.GetGeometryRef() num_pnt = lnh.GetPointCount() for pnt in range(num_pnt): x, y, z = lnh.GetPoint(pnt) cell = pnt_val_on_rst(x, y, band, geo_transform) if not cell: continue else: rst_values.append(cell) if len(rst_values): if statistic == 'minimum': value = min(rst_values) elif statistic == 'maximum': value = max(rst_values) elif statistic == 'mean': value = sum(rst_values) / len(rst_values) elif statistic == 'sum': value = sum(rst_values) else: continue feat.SetField(new_field, value) lyr.SetFeature(feat)
def gpkgrst_to_rst(gpkg, tbl, outrst): """ Convert Raster in GeoPackage to single file """ from glass.pys import execmd from glass.g.prop import drv_name rcmd = execmd("gdal_translate -of {} {} {} -b 1 -oo TABLE={}".format( drv_name(outrst), gpkg, outrst, tbl)) return outrst
def obj_to_rst(inArray, outRst, template, noData=None, geotrans=None): """ Send Array to Raster """ from osgeo import gdal, osr, gdal_array from glass.g.prop import drv_name from glass.g.prop.rst import compress_option if type(template).__name__ == 'Dataset': img_template = template else: img_template = gdal.Open(template) geo_transform = img_template.GetGeoTransform() if not geotrans else \ geotrans rows, cols = inArray.shape drv_n = drv_name(outRst) driver = gdal.GetDriverByName(drv_n) c_opt = compress_option(drv_n) if c_opt: out = driver.Create(outRst, cols, rows, 1, gdal_array.NumericTypeCodeToGDALTypeCode( inArray.dtype), options=[c_opt]) else: out = driver.Create( outRst, cols, rows, 1, gdal_array.NumericTypeCodeToGDALTypeCode(inArray.dtype)) out.SetGeoTransform(geo_transform) outBand = out.GetRasterBand(1) if noData or noData == 0: outBand.SetNoDataValue(noData) outBand.WriteArray(inArray) proj = osr.SpatialReference(wkt=img_template.GetProjection()) if proj: out.SetProjection(img_template.GetProjection()) outBand.FlushCache() return outRst
def feat_count(shp, gisApi='pandas', work=None, loc=None): """ Count the number of features in a feature class API'S Available: * gdal; * arcpy; * pygrass; * pandas; """ if gisApi == 'ogr': from osgeo import ogr from glass.g.prop import drv_name data = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) lyr = data.GetLayer() fcnt = int(lyr.GetFeatureCount()) data.Destroy() elif gisApi == 'grass': if not work or not loc: raise ValueError(( "If gisApi=='grass', work and loc must be defined!" )) import os from glass.ng.prop.sql import row_num db = os.path.join( work, loc, 'PERMANENT', 'sqlite', 'sqlite.db' ) fcnt = row_num(db, shp, api='sqlite') elif gisApi == 'pandas': from glass.g.rd.shp import shp_to_obj gdf = shp_to_obj(shp) fcnt = int(gdf.shape[0]) del gdf else: raise ValueError('The api {} is not available'.format(gisApi)) return fcnt
def rst_to_rst(inRst, outRst): """ Convert a raster file to another raster format """ from glass.pys import execmd from glass.g.prop import drv_name outDrv = drv_name(outRst) cmd = 'gdal_translate -of {drv} {_in} {_out}'.format(drv=outDrv, _in=inRst, _out=outRst) cmdout = execmd(cmd) return outRst
def dic_buffer_array_to_shp(arrayBf, outShp, epsg, fields=None): """ Array with dict with buffer proprieties to Feature Class """ import os from osgeo import ogr from glass.g.prop import drv_name from glass.g.prop.prj import get_sref_from_epsg from glass.g.gp.prox.bfing.obj import xy_to_buffer # Get SRS for output srs = get_sref_from_epsg(epsg) # Create output DataSource and Layer outData = ogr.GetDriverByName(drv_name(outShp)).CreateDataSource(outShp) lyr = outData.CreateLayer(os.path.splitext(os.path.basename(outShp))[0], srs, geom_type=ogr.wkbPolygon) # Create fields if fields: from glass.g.lyr.fld import fields_to_lyr fields_to_lyr(lyr, fields) lyrDefn = lyr.GetLayerDefn() for _buffer in arrayBf: newFeat = ogr.Feature(lyrDefn) geom = xy_to_buffer(_buffer["X"], _buffer["Y"], _buffer["RADIUS"]) newFeat.SetGeometry(geom) for field in fields: if field in _buffer.keys(): newFeat.SetField(field, _buffer[field]) lyr.CreateFeature(newFeat) newFeat.Destroy() del lyrDefn outData.Destroy() return outShp
def shpext_to_boundshp(inShp, outShp, epsg=None): """ Read one feature class extent and create a boundary with that extent The outFile could be a Feature Class or one Raster Dataset """ from osgeo import ogr from glass.g.prop import drv_name from glass.pys.oss import fprop # Get SRS for the output if not epsg: from glass.g.prop.prj import get_shp_sref srs = get_shp_sref(inShp) else: from glass.g.prop.prj import get_sref_from_epsg srs= get_sref_from_epsg(epsg) # Write new file shp = ogr.GetDriverByName( drv_name(outShp)).CreateDataSource(outShp) lyr = shp.CreateLayer( fprop(outShp, 'fn', forceLower=True), srs, geom_type=ogr.wkbPolygon ) outDefn = lyr.GetLayerDefn() feat = ogr.Feature(outDefn) polygon = shpext_to_boundary(inShp) feat.SetGeometry(polygon) lyr.CreateFeature(feat) feat.Destroy() shp.Destroy() return outShp
def rst_val_to_points2(pntShp, listRasters): """ Pick raster value for each point in pntShp """ from osgeo import ogr from glass.pys import obj_to_lst from glass.g.prop import drv_name listRasters = obj_to_lst(listRasters) shp = ogr.GetDriverByName(drv_name(pntShp)).Open(pnt, 0) lyr = shp.GetLayer() pntDict = {} for feat in lyr: geom = feat.GetGeometryRef() x, y = geom.GetX(), geom.GetY() l = [] for rst in listRasters: img = gdal.Open(rst) geo_transform = img.GetGeoTransform() band = img.GetRasterBand(1) px = int((x - geo_transform[0]) / geo_transform[1]) py = int((y - geo_transform[3]) / geo_transform[5]) value = band.ReadAsArray(px, py, 1, 1) l.append(list(value)[0]) del img, geo_transform, band, px, py pntDict[feat.GetFID()] = l shp.Destroy() return pntDict
def comp_bnds(rsts, outRst): """ Composite Bands """ from osgeo import gdal, gdal_array from glass.g.rd.rst import rst_to_array from glass.g.prop import drv_name from glass.g.prop.rst import get_nodata from glass.g.prop.prj import get_rst_epsg, epsg_to_wkt # Get Arrays _as = [rst_to_array(r) for r in rsts] # Get nodata values nds = [get_nodata(r) for r in rsts] # Assume that first raster is the template img_temp = gdal.Open(rsts[0]) geo_tran = img_temp.GetGeoTransform() band = img_temp.GetRasterBand(1) dataType = gdal_array.NumericTypeCodeToGDALTypeCode(_as[0].dtype) rows, cols = _as[0].shape epsg = get_rst_epsg(rsts[0]) # Create Output drv = gdal.GetDriverByName(drv_name(outRst)) out = drv.Create(outRst, cols, rows, len(_as), dataType) out.SetGeoTransform(geo_tran) out.SetProjection(epsg_to_wkt(epsg)) # Write all bands for i in range(len(_as)): outBand = out.GetRasterBand(i + 1) outBand.SetNoDataValue(nds[i]) outBand.WriteArray(_as[i]) outBand.FlushCache() return outRst
def clip_rst(raster, clipShp, outRst, nodataValue=None, api='gdal'): """ Clip Raster using GDAL WARP """ if api == 'gdal': from glass.pys import execmd from glass.g.prop import drv_name outcmd = execmd(("gdalwarp {ndata}-cutline {clipshp} -crop_to_cutline " "-of {ext} {inraster} -overwrite {outrst}").format( clipshp=clipShp, inraster=raster, outrst=outRst, ext=drv_name(outRst), ndata="-dstnodata {} ".format(str(nodataValue)) if nodataValue else "")) elif api == 'pygrass': from grass.pygrass.modules import Module m = Module('r.clip', input=raster, output=outRst, overwrite=True, run_=False, quiet=True) m() elif api == 'grass': from glass.pys import execmd rcmd = execmd('r.clip input={} output={} --overwrite --quiet'.format( raster, outRst)) else: raise ValueError('API {} is not available'.format(api)) return outRst
def get_ext(shp): """ Return extent of a Vectorial file Return a tuple object with the follow order: (left, right, bottom, top) API'S Available: * ogr; """ gisApi = 'ogr' if gisApi == 'ogr': from osgeo import ogr from glass.g.prop import drv_name dt = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) lyr = dt.GetLayer() extent = lyr.GetExtent() dt.Destroy() return list(extent)
def proj(inShp, outShp, outEPSG, inEPSG=None, gisApi='ogr', sql=None, db_name=None): """ Project Geodata using GIS API's Available: * ogr; * ogr2ogr; * pandas; * ogr2ogr_SQLITE; * psql; """ import os if gisApi == 'ogr': """ Using ogr Python API """ if not inEPSG: raise ValueError( 'To use ogr API, you should specify the EPSG Code of the' ' input data using inEPSG parameter') from osgeo import ogr from glass.g.lyr.fld import copy_flds from glass.g.prop.feat import get_gtype from glass.g.prop import drv_name from glass.g.prop.prj import get_sref_from_epsg, get_trans_param from glass.pys.oss import fprop def copyShp(out, outDefn, lyr_in, trans): for f in lyr_in: g = f.GetGeometryRef() g.Transform(trans) new = ogr.Feature(outDefn) new.SetGeometry(g) for i in range(0, outDefn.GetFieldCount()): new.SetField( outDefn.GetFieldDefn(i).GetNameRef(), f.GetField(i)) out.CreateFeature(new) new.Destroy() f.Destroy() # ####### # # Project # # ####### # transP = get_trans_param(inEPSG, outEPSG) inData = ogr.GetDriverByName(drv_name(inShp)).Open(inShp, 0) inLyr = inData.GetLayer() out = ogr.GetDriverByName(drv_name(outShp)).CreateDataSource(outShp) outlyr = out.CreateLayer(fprop(outShp, 'fn'), get_sref_from_epsg(outEPSG), geom_type=get_gtype(inShp, name=None, py_cls=True, gisApi='ogr')) # Copy fields to the output copy_flds(inLyr, outlyr) # Copy/transform features from the input to the output outlyrDefn = outlyr.GetLayerDefn() copyShp(outlyr, outlyrDefn, inLyr, transP) inData.Destroy() out.Destroy() elif gisApi == 'ogr2ogr': """ Transform SRS of any OGR Compilant Data. Save the transformed data in a new file """ if not inEPSG: from glass.g.prop.prj import get_shp_epsg inEPSG = get_shp_epsg(inShp) if not inEPSG: raise ValueError('To use ogr2ogr, you must specify inEPSG') from glass.pys import execmd from glass.g.prop import drv_name cmd = ('ogr2ogr -f "{}" {} {}{} -s_srs EPSG:{} -t_srs EPSG:{}').format( drv_name(outShp), outShp, inShp, '' if not sql else ' -dialect sqlite -sql "{}"'.format(sql), str(inEPSG), str(outEPSG)) outcmd = execmd(cmd) elif gisApi == 'ogr2ogr_SQLITE': """ Transform SRS of a SQLITE DB table. Save the transformed data in a new table """ from glass.pys import execmd if not inEPSG: raise ValueError( ('With ogr2ogr_SQLITE, the definition of inEPSG is ' 'demandatory.')) # TODO: Verify if database is sqlite db, tbl = inShp['DB'], inShp['TABLE'] sql = 'SELECT * FROM {}'.format(tbl) if not sql else sql outcmd = execmd( ('ogr2ogr -update -append -f "SQLite" {db} -nln "{nt}" ' '-dialect sqlite -sql "{_sql}" -s_srs EPSG:{inepsg} ' '-t_srs EPSG:{outepsg} {db}').format(db=db, nt=outShp, _sql=sql, inepsg=str(inEPSG), outepsg=str(outEPSG))) elif gisApi == 'pandas': # Test if input Shp is GeoDataframe from glass.g.rd.shp import shp_to_obj from glass.g.wt.shp import df_to_shp df = shp_to_obj(inShp) # Project df newDf = df.to_crs('EPSG:{}'.format(str(outEPSG))) # Save as file return df_to_shp(df, outShp) elif gisApi == 'psql': from glass.ng.sql.db import create_db from glass.pys.oss import fprop from glass.g.it.db import shp_to_psql from glass.g.it.shp import dbtbl_to_shp from glass.g.prj.sql import sql_proj # Create Database if not db_name: db_name = create_db(fprop(outShp, 'fn', forceLower=True), api='psql') else: from glass.ng.prop.sql import db_exists isDb = db_exists(db_name) if not isDb: create_db(db_name, api='psql') # Import Data inTbl = shp_to_psql(db_name, inShp, api='shp2pgsql', encoding="LATIN1") # Transform oTbl = sql_proj(db_name, inTbl, fprop(outShp, 'fn', forceLower=True), outEPSG, geomCol='geom', newGeom='geom') # Export outShp = dbtbl_to_shp(db_name, oTbl, 'geom', outShp, api='psql', epsg=outEPSG) else: raise ValueError('Sorry, API {} is not available'.format(gisApi)) return outShp
def connect_lines_to_near_lines(inLines, nearLines, outLines, tollerance=1000): """ Connect all vertex in a line to the nearest vertex of the nearest line """ from osgeo import ogr from glass.pys.oss import fprop from glass.g.prop import drv_name from glass.g.prop.feat import get_gtype from glass.g.gp.prox.bfing.obj import draw_buffer # Check Geometries inLinesGeom = get_gtype(inLines, gisApi='ogr') nearLinesGeom = get_gtype(nearLines, gisApi='ogr') if inLinesGeom != 'LINESTRING' or \ nearLinesGeom != 'LINESTRING': raise ValueError('This method supports only LINESTRINGS') # Open inLines shpLines = ogr.GetDriverByName(drv_name(inLines)).Open(inLines) # Get Layer lyrLines = shpLines.GetLayer() # Open near shpNear = ogr.GetDriverByName(drv_name(nearLines)).Open(nearLines) # Create Output outSrc = ogr.GetDriverByName(drv_name(outLines)).CreateDataSource(outLines) outLyr = outSrc.CreateLayer(fprop(outLines, 'fn'), geom_type=ogr.wkbLineString) lineDefn = outLyr.GetLayerDefn() # For each point in 'inLines', find the near point on the # the 'nearLines' layer nearPoints = {} for feat in lyrLines: FID = feat.GetFID() # Get Geometry geom = feat.GetGeometryRef() # Get points nrPnt = geom.GetPointCount() for p in range(nrPnt): x, y, z = geom.GetPoint(p) pnt = ogr.Geometry(ogr.wkbPoint) pnt.AddPoint(x, y) # Get point buffer bufPnt = draw_buffer(pnt, tollerance) # Apply a spatial filter based on the buffer # to restrict the nearLines Layer lyrNear = shpNear.GetLayer() lyrNear.SetSpatialFilter(bufPnt) # For line in the filtered 'nearLyr' # Find the closest point dist = 0 for __feat in lyrNear: __FID = __feat.GetFID() __geom = __feat.GetGeometryRef() points = __geom.GetPointCount() for _p in range(points): _x, _y, _z = __geom.GetPoint(_p) distance = ((x - _x)**2 + (y - _y)**2)**0.5 if not dist: dist = [distance, _x, _y] else: if distance < dist[0]: dist = [distance, _x, _y] # Write a new line line = ogr.Geometry(ogr.wkbLineString) line.AddPoint(x, y) line.AddPoint(dist[1], dist[2]) new_feature = ogr.Feature(lineDefn) new_feature.SetGeometry(line) outLyr.CreateFeature(new_feature) new_feature.Destroy() del lyrNear outSrc.Destroy() shpPnt.Destroy() shpNear.Destroy() return outLines
def connect_points_to_near_line(inPnt, nearLines, outLines, tollerance=1000, nearLinesWpnt=None): """ Connect all points to the nearest line in the perpendicular """ import os import numpy as np from osgeo import ogr from shapely.geometry import LineString, Point from glass.g.prop import drv_name from glass.g.prop.feat import get_gtype from glass.pys.oss import fprop # Check Geometries inPntGeom = get_gtype(inPnt, gisApi='ogr') nearLinesGeom = get_gtype(nearLines, gisApi='ogr') if inPntGeom != 'POINT' or \ nearLinesGeom != 'LINESTRING': raise ValueError('This method supports only LINESTRINGS') # Open inLines shpPnt = ogr.GetDriverByName(drv_name(inPnt)).Open(inPnt) # Get Layer lyrPnt = shpPnt.GetLayer() # Open near shpNear = ogr.GetDriverByName(drv_name(nearLines)).Open(nearLines) # Create Output outSrc = ogr.GetDriverByName(drv_name(outLines)).CreateDataSource(outLines) outLyr = outSrc.CreateLayer(os.path.splitext( os.path.basename(outLines))[0], geom_type=ogr.wkbLineString) if nearLinesWpnt: newPointsInLines = {} lineDefn = outLyr.GetLayerDefn() # For each point in 'inLines', find the near point on the # the 'nearLines' layer for feat in lyrPnt: FID = feat.GetFID() # Get Geometry pnt = feat.GetGeometryRef() x, y = pnt.GetX(), pnt.GetY() # Get point buffer bufPnt = draw_buffer(pnt, tollerance) # Apply a spatial filter based on the buffer # to restrict the nearLines Layer lyrNear = shpNear.GetLayer() lyrNear.SetSpatialFilter(bufPnt) # For line in the filtered 'nearLyr' # Find point in the perpendicular dist = 0 for __feat in lyrNear: __FID = __feat.GetFID() __geom = __feat.GetGeometryRef() points = __geom.GetPointCount() for _p in range(points - 1): # Get line segment x1, y1, z1 = __geom.GetPoint(_p) x2, y2, z2 = __geom.GetPoint(_p + 1) # Create Shapely Geometries lnh = LineString([(x1, y1), (x2, y2)]) pnt = Point(x, y) # Get distance between point and line # Get near point of the line d = pnt.distance(lnh) npnt = lnh.interpolate(lnh.project(pnt)) if not dist: dist = [d, npnt.x, npnt.y] LINE_FID = __FID else: if d < dist[0]: dist = [d, npnt.x, npnt.y] LINE_FID = __FID # Write a new line line = ogr.Geometry(ogr.wkbLineString) line.AddPoint(x, y) line.AddPoint(dist[1], dist[2]) new_feature = ogr.Feature(lineDefn) new_feature.SetGeometry(line) outLyr.CreateFeature(new_feature) new_feature.Destroy() if nearLinesWpnt: if LINE_FID not in newPointsInLines: newPointsInLines[LINE_FID] = [Point(dist[1], dist[2])] else: newPointsInLines[LINE_FID].append(Point(dist[1], dist[2])) del lyrNear outSrc.Destroy() shpPnt.Destroy() shpNear.Destroy() if nearLinesWpnt: from glass.g.lyr.fld import copy_flds from shapely.ops import split as lnhSplit shpNear = ogr.GetDriverByName(drv_name(nearLines)).Open(nearLines) updateLines = ogr.GetDriverByName( drv_name(nearLinesWpnt)).CreateDataSource(nearLinesWpnt) upLnhLyr = updateLines.CreateLayer(fprop(nearLinesWpnt, 'fn'), geom_type=ogr.wkbLineString) # Create shpNear Layer Again lyrNear = shpNear.GetLayer() # Copy fields copy_flds(lyrNear, upLnhLyr) # Out lyr definition upDefn = upLnhLyr.GetLayerDefn() for feat in lyrNear: LINE_FID = feat.GetFID() geom = feat.GetGeometryRef() new_feature = ogr.Feature(upDefn) if LINE_FID not in newPointsInLines: # Copy line to updateLines layer new_feature.SetGeometry(geom) else: # Copy to Shapely Line String points = geom.GetPointCount() lstPnt = [] for _p in range(points): x1, y1, z1 = geom.GetPoint(_p) lstPnt.append((x1, y1)) shplyLnh = LineString(lstPnt) # For new point: # Line split and reconstruction for pnt in newPointsInLines[LINE_FID]: try: splitted = lnhSplit(shplyLnh, pnt) except: shpTstL = ogr.GetDriverByName( "ESRI Shapefile").CreateDataSource( r'D:\gis\xyz\lnht.shp') shpL = shpTstL.CreateLayer('lnht', geom_type=ogr.wkbLineString) shpTstP = ogr.GetDriverByName( "ESRI Shapefile").CreateDataSource( r'D:\gis\xyz\pntt.shp') shpP = shpTstL.CreateLayer('pntt', geom_type=ogr.wkbPoint) defnL = shpL.GetLayerDefn() defnP = shpP.GetLayerDefn() featL = ogr.Feature(defnL) featP = ogr.Feature(defnP) geomL = ogr.Geometry(ogr.wkbLineString) for i in list(shplyLnh.coords): geomL.AddPoint(i[0], i[1]) geomP = ogr.Geometry(ogr.wkbPoint) geomP.AddPoint( list(pnt.coords)[0][0], list(pnt.coords)[0][1]) featL.SetGeometry(geomL) featP.SetGeometry(geomP) shpL.CreateFeature(featL) shpP.CreateFeature(featP) shpTstL.Destroy() shpTstP.Destroy() return pnt, shplyLnh c = 0 for l in splitted: if not c: newLnh = list(l.coords) else: newlnh += list(l.coords)[1:] c += 1 shplyLnh = LineString(newLnh) # Finally copy line to updateLines Layer gLine = ogr.Geometry(ogr.wkbLineString) for __pnt in list(shplyLnh.coords): gLine.AddPoint(__pnt[0], __pnt[1]) for i in range(0, upDefn.GetFieldCount()): new_feature.SetField( upDefn.GetFieldDefn(i).GetNameRef(), feat.GetField(i)) upLnhLyr.CreateFeature(new_feature) new_feature.Destroy() shpNear.Destroy() return outLines
def shp_to_rst(shp, inSource, cellsize, nodata, outRaster, epsg=None, rst_template=None, snapRst=None, api='gdal'): """ Feature Class to Raster cellsize will be ignored if rst_template is defined * API's Available: - gdal; - pygrass; - grass; """ if api == 'gdal': from osgeo import gdal, ogr from glass.g.prop import drv_name if not epsg: from glass.g.prop.prj import get_shp_sref srs = get_shp_sref(shp).ExportToWkt() else: from glass.g.prop.prj import epsg_to_wkt srs = epsg_to_wkt(epsg) # Get Extent dtShp = ogr.GetDriverByName(drv_name(shp)).Open(shp, 0) lyr = dtShp.GetLayer() if not rst_template: if not snapRst: x_min, x_max, y_min, y_max = lyr.GetExtent() x_res = int((x_max - x_min) / cellsize) y_res = int((y_max - y_min) / cellsize) else: from glass.g.prop.rst import adjust_ext_to_snap x_min, y_max, y_res, x_res, cellsize = adjust_ext_to_snap( shp, snapRst) else: from glass.g.rd.rst import rst_to_array img_temp = gdal.Open(rst_template) geo_transform = img_temp.GetGeoTransform() y_res, x_res = rst_to_array(rst_template).shape # Create output dtRst = gdal.GetDriverByName(drv_name(outRaster)).Create( outRaster, x_res, y_res, gdal.GDT_Byte) if not rst_template: dtRst.SetGeoTransform((x_min, cellsize, 0, y_max, 0, -cellsize)) else: dtRst.SetGeoTransform(geo_transform) dtRst.SetProjection(str(srs)) bnd = dtRst.GetRasterBand(1) bnd.SetNoDataValue(nodata) gdal.RasterizeLayer(dtRst, [1], lyr, burn_values=[1]) del lyr dtShp.Destroy() elif api == 'grass' or api == 'pygrass': """ Use GRASS GIS - Start Session - Import data - Convert - Export """ import os from glass.pys.oss import fprop from glass.g.wenv.grs import run_grass from glass.g.prop.prj import get_epsg # Create GRASS GIS Session ws = os.path.dirname(outRaster) loc = fprop(outRaster, 'fn') epsg = get_epsg(shp) gbase = run_grass(ws, location=loc, srs=epsg) import grass.script.setup as gsetup gsetup.init(gbase, ws, loc, 'PERMANENT') # Import Packages from glass.g.it.shp import shp_to_grs from glass.g.it.rst import grs_to_rst from glass.g.wenv.grs import shp_to_region # Shape to GRASS GIS gshp = shp_to_grs(shp, fprop(shp, 'fn'), asCMD=True) # Set Region shp_to_region(gshp, cellsize) # Convert grst = grsshp_to_grsrst(gshp, inSource, gshp + '__rst', api="grass") # Export grs_to_rst(grst, outRaster, as_cmd=True) else: raise ValueError('API {} is not available'.format(api)) return outRaster
def eachfeat_to_newshp(inShp, outFolder, epsg=None, idCol=None): """ Export each feature in inShp to a new/single File """ import os from osgeo import ogr from glass.g.prop import drv_name from glass.g.prop.feat import get_gtype, lst_fld from glass.g.lyr.fld import copy_flds from glass.pys.oss import fprop inDt = ogr.GetDriverByName(drv_name(inShp)).Open(inShp) lyr = inDt.GetLayer() # Get SRS for the output if not epsg: from glass.g.prop.prj import get_shp_sref srs = get_shp_sref(lyr) else: from glass.g.prop.prj import get_sref_from_epsg srs = get_sref_from_epsg(epsg) # Get fields name fields = lst_fld(lyr) # Get Geometry type geomCls = get_gtype(inShp, gisApi='ogr', name=None, py_cls=True) # Read features and create a new file for each feature RESULT_SHP = [] for feat in lyr: # Create output ff = fprop(inShp, ['fn', 'ff']) newShp = os.path.join( outFolder, "{}_{}{}".format( ff['filename'], str(feat.GetFID()) if not idCol else str(feat.GetField(idCol)), ff['fileformat'])) newData = ogr.GetDriverByName( drv_name(newShp)).CreateDataSource(newShp) newLyr = newData.CreateLayer(fprop(newShp, 'fn'), srs, geom_type=geomCls) # Copy fields from input to output copy_flds(lyr, newLyr) newLyrDefn = newLyr.GetLayerDefn() # Create new feature newFeat = ogr.Feature(newLyrDefn) # Copy geometry geom = feat.GetGeometryRef() newFeat.SetGeometry(geom) # Set fields attributes for fld in fields: newFeat.SetField(fld, feat.GetField(fld)) # Save feature newLyr.CreateFeature(newFeat) newFeat.Destroy() del newLyr newData.Destroy() RESULT_SHP.append(newShp) return RESULT_SHP
def ogr_buffer(geom, radius, out_file, srs=None): """ For each geometry in the input, this method create a buffer and store it in a vetorial file Accepts files or lists with geom objects as inputs """ import os from osgeo import ogr from glass.g.prj import def_prj from glass.g.prop import drv_name from glass.g.prop.prj import get_sref_from_epsg from glass.g.gp.prox.bfing.obj import draw_buffer # Create output buffer_shp = ogr.GetDriverByName( drv_name(out_file)).CreateDataSource(out_file) buffer_lyr = buffer_shp.CreateLayer( os.path.splitext(os.path.basename(out_file))[0], get_sref_from_epsg(srs) if srs else None, geom_type=ogr.wkbPolygon) featDefn = buffer_lyr.GetLayerDefn() if type(geom) == list: for g in geom: feat = ogr.Feature(featDefn) feat.SetGeometry(draw_buffer(g, radius)) buffer_lyr.CreateFeature(feat) feat = None buffer_shp.Destroy() elif type(geom) == dict: if 'x' in geom and 'y' in geom: X = 'x' Y = 'y' elif 'X' in geom and 'Y' in geom: X = 'X' Y = 'Y' else: raise ValueError(('Your geom dict has invalid keys. ' 'Please use one of the following combinations: ' 'x, y; ' 'X, Y')) from glass.g.gobj import new_pnt feat = ogr.Feature(featDefn) g = new_pnt(geom[X], geom[Y]) feat.SetGeometry(draw_buffer(g, radius)) buffer_lyr.CreateFeature(feat) feat = None buffer_shp.Destroy() if srs: def_prj(out_file, epsg=srs) elif type(geom) == str: # Check if the input is a file if os.path.exists(geom): inShp = ogr.GetDriverByName(drv_name(geom)).Open(geom, 0) lyr = inShp.GetLayer() for f in lyr: g = f.GetGeometryRef() feat = ogr.Feature(featDefn) feat.SetGeometry(draw_buffer(g, radius)) buffer_lyr.CreateFeature(feat) feat = None buffer_shp.Destroy() inShp.Destroy() if srs: def_prj(out_file, epsg=srs) else: def_prj(out_file, template=geom) else: raise ValueError('The given path does not exist') else: raise ValueError('Your geom input is not valid') return out_file