mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
451 lines
15 KiB
Python
451 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
#-----------------------------------------------------------
|
|
#
|
|
# fTools
|
|
# Copyright (C) 2008-2011 Carson Farmer
|
|
# EMAIL: carson.farmer (at) gmail.com
|
|
# WEB : http://www.ftools.ca/fTools.html
|
|
#
|
|
# A collection of data management and analysis tools for vector data
|
|
#
|
|
#-----------------------------------------------------------
|
|
#
|
|
# licensed under the terms of GNU GPL 2
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
#---------------------------------------------------------------------
|
|
|
|
# Utility functions
|
|
# -------------------------------------------------
|
|
#
|
|
# convertFieldNameType( QgsField.name() )
|
|
# combineVectorFields( QgsVectorLayer, QgsVectorLayer )
|
|
# checkCRSCompatibility( QgsCoordinateReferenceSystem, QgsCoordinateReferenceSystem )
|
|
# writeVectorLayerToShape(QgsVectorLayer, QString *file path, QString *encoding style )
|
|
# getVectorTypeAsString( QgsVectorLayer )
|
|
# measurePerimeter( QgsGeometry )
|
|
# extractPoints( QgsGeometry )
|
|
# testForUniqueness( QList *QgsField, QList *QgsField )
|
|
# createUniqueFieldName( QgsField.name() )
|
|
# checkFieldNameLength( QgsFieldMap )
|
|
# getLayerNames( QGis.vectorType() )
|
|
# getFieldNames( QgsVectorLayer )
|
|
# getVectorLayerByName( QgsVectorLayer.name() )
|
|
# getFieldList( QgsVectorLayer )
|
|
# createIndex( QgsVectorDataProvider )
|
|
# addShapeToCanvas( QString *file path )
|
|
# getUniqueValues( QgsVectorDataProvider, int *field id )
|
|
# saveDialog( QWidget *parent )
|
|
# getFieldType( QgsVectorLayer, QgsField.name() )
|
|
# getUniqueValuesCount( QgsVectorLayer, int fieldIndex, bool useSelection ):
|
|
#
|
|
# -------------------------------------------------
|
|
|
|
from PyQt4.QtCore import QTextCodec, QFileInfo, QSettings, QCoreApplication
|
|
from PyQt4.QtGui import QDialog, QFileDialog
|
|
from qgis.core import QgsVectorFileWriter, QGis, QgsDistanceArea, QgsGeometry, QgsMapLayer, QgsVectorLayer, QgsMapLayerRegistry, QgsFeature, QgsSpatialIndex
|
|
from qgis.gui import QgsEncodingFileDialog
|
|
|
|
import locale
|
|
|
|
# For use with memory provider/layer, converts full field type to simple string
|
|
|
|
|
|
def convertFieldNameType(inName):
|
|
if inName == "Integer":
|
|
return "int"
|
|
elif inName == "Real":
|
|
return "double"
|
|
else:
|
|
return "string"
|
|
|
|
# From two input field maps, create single field map
|
|
|
|
|
|
def combineVectorFields(layerA, layerB):
|
|
fieldsA = layerA.dataProvider().fields()
|
|
fieldsB = layerB.dataProvider().fields()
|
|
fieldsB = testForUniqueness(fieldsA, fieldsB)
|
|
for f in fieldsB:
|
|
fieldsA.append(f)
|
|
return fieldsA
|
|
|
|
# Check if two input CRSs are identical
|
|
|
|
|
|
def checkCRSCompatibility(crsA, crsB):
|
|
if crsA == crsB:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
# Convenience function to write vector layer to shapefile
|
|
|
|
|
|
def writeVectorLayerToShape(vlayer, outputPath, encoding):
|
|
mCodec = QTextCodec.codecForName(encoding)
|
|
if not mCodec:
|
|
return False
|
|
#Here we should check that the output path is valid
|
|
QgsVectorFileWriter.writeAsVectorFormat(vlayer, outputPath, encoding, vlayer.dataProvider().crs(), "ESRI Shapefile", False)
|
|
return True
|
|
|
|
# For use with memory provider/layer, converts QGis vector type definition to simple string
|
|
|
|
|
|
def getVectorTypeAsString(vlayer):
|
|
if vlayer.geometryType() == QGis.Polygon:
|
|
return "Polygon"
|
|
elif vlayer.geometryType() == QGis.Line:
|
|
return "LineString"
|
|
elif vlayer.geometryType() == QGis.Point:
|
|
return "Point"
|
|
else:
|
|
return False
|
|
|
|
# Compute area and perimeter of input polygon geometry
|
|
|
|
|
|
def getAreaAndPerimeter(geom):
|
|
measure = QgsDistanceArea()
|
|
area = measure.measure(geom)
|
|
perim = measurePerimeter(geom, measure)
|
|
return (area, perim)
|
|
|
|
# Compute perimeter of input polygon geometry
|
|
|
|
|
|
def measurePerimeter(geom):
|
|
measure = QgsDistanceArea()
|
|
value = 0.00
|
|
polygon = geom.asPolygon()
|
|
for line in polygon:
|
|
value += measure.measureLine(line)
|
|
return value
|
|
|
|
# Generate list of QgsPoints from input geometry ( can be point, line, or polygon )
|
|
|
|
|
|
def extractPoints(geom):
|
|
multi_geom = QgsGeometry()
|
|
temp_geom = []
|
|
if geom.type() == 0: # it's a point
|
|
if geom.isMultipart():
|
|
temp_geom = geom.asMultiPoint()
|
|
else:
|
|
temp_geom.append(geom.asPoint())
|
|
elif geom.type() == 1: # it's a line
|
|
if geom.isMultipart():
|
|
multi_geom = geom.asMultiPolyline() # multi_geog is a multiline
|
|
for i in multi_geom: # i is a line
|
|
temp_geom.extend(i)
|
|
else:
|
|
temp_geom = geom.asPolyline()
|
|
elif geom.type() == 2: # it's a polygon
|
|
if geom.isMultipart():
|
|
multi_geom = geom.asMultiPolygon() # multi_geom is a multipolygon
|
|
for i in multi_geom: # i is a polygon
|
|
for j in i: # j is a line
|
|
temp_geom.extend(j)
|
|
else:
|
|
multi_geom = geom.asPolygon() # multi_geom is a polygon
|
|
for i in multi_geom: # i is a line
|
|
temp_geom.extend(i)
|
|
# FIXME - if there is none of know geoms (point, line, polygon) show an warning message
|
|
return temp_geom
|
|
|
|
# Check if two input field maps are unique, and resolve name issues if they aren't
|
|
|
|
|
|
def testForUniqueness(fieldList1, fieldList2):
|
|
changed = True
|
|
while changed:
|
|
changed = False
|
|
for i in range(0, len(fieldList1)):
|
|
for j in range(0, len(fieldList2)):
|
|
if fieldList1[i].name() == fieldList2[j].name():
|
|
fieldList2[j] = createUniqueFieldName(fieldList2[j])
|
|
changed = True
|
|
return fieldList2
|
|
|
|
# Create a unique field name based on input field name
|
|
|
|
|
|
def createUniqueFieldName(field):
|
|
check = field.name()[-2:]
|
|
shortName = field.name()[:8]
|
|
if check[0] == "_":
|
|
try:
|
|
val = int(check[-1:])
|
|
if val < 2:
|
|
val = 2
|
|
else:
|
|
val = val + 1
|
|
field.setName(shortName[:-1] + unicode(val))
|
|
except ValueError:
|
|
field.setName(shortName + "_2")
|
|
else:
|
|
field.setName(shortName + "_2")
|
|
return field
|
|
|
|
# Return list of field names with more than 10 characters length
|
|
|
|
|
|
def checkFieldNameLength(fieldList):
|
|
longNames = []
|
|
for field in fieldList:
|
|
if len(field.name()) > 10:
|
|
longNames.append(field.name())
|
|
return longNames
|
|
|
|
# Return list of names of all layers in QgsMapLayerRegistry
|
|
|
|
|
|
def getLayerNames(vTypes):
|
|
layermap = QgsMapLayerRegistry.instance().mapLayers()
|
|
layerlist = []
|
|
if vTypes == "all":
|
|
for name, layer in layermap.iteritems():
|
|
layerlist.append(layer.name())
|
|
else:
|
|
for name, layer in layermap.iteritems():
|
|
if layer.type() == QgsMapLayer.VectorLayer:
|
|
if layer.geometryType() in vTypes:
|
|
layerlist.append(layer.name())
|
|
elif layer.type() == QgsMapLayer.RasterLayer:
|
|
if "Raster" in vTypes:
|
|
layerlist.append(layer.name())
|
|
return sorted(layerlist, cmp=locale.strcoll)
|
|
|
|
# Return list of names of all fields from input QgsVectorLayer
|
|
|
|
|
|
def getFieldNames(vlayer):
|
|
fieldmap = getFieldList(vlayer)
|
|
fieldlist = []
|
|
for field in fieldmap:
|
|
if not field.name() in fieldlist:
|
|
fieldlist.append(field.name())
|
|
return sorted(fieldlist, cmp=locale.strcoll)
|
|
|
|
# Return QgsVectorLayer from a layer name ( as string )
|
|
|
|
|
|
def getVectorLayerByName(myName):
|
|
layermap = QgsMapLayerRegistry.instance().mapLayers()
|
|
for name, layer in layermap.iteritems():
|
|
if layer.type() == QgsMapLayer.VectorLayer and layer.name() == myName:
|
|
if layer.isValid():
|
|
return layer
|
|
else:
|
|
return None
|
|
|
|
# Return QgsRasterLayer from a layer name ( as string )
|
|
|
|
|
|
def getRasterLayerByName(myName):
|
|
layermap = QgsMapLayerRegistry.instance().mapLayers()
|
|
for name, layer in layermap.iteritems():
|
|
if layer.type() == QgsMapLayer.RasterLayer and layer.name() == myName:
|
|
if layer.isValid():
|
|
return layer
|
|
else:
|
|
return None
|
|
|
|
# Return QgsMapLayer from a layer name ( as string )
|
|
|
|
|
|
def getMapLayerByName(myName):
|
|
layermap = QgsMapLayerRegistry.instance().mapLayers()
|
|
for name, layer in layermap.iteritems():
|
|
if layer.name() == myName:
|
|
if layer.isValid():
|
|
return layer
|
|
else:
|
|
return None
|
|
|
|
# Return the field list of a vector layer
|
|
|
|
|
|
def getFieldList(vlayer):
|
|
return vlayer.dataProvider().fields()
|
|
|
|
# Convinience function to create a spatial index for input QgsVectorDataProvider
|
|
|
|
|
|
def createIndex(provider):
|
|
feat = QgsFeature()
|
|
index = QgsSpatialIndex()
|
|
fit = provider.getFeatures()
|
|
while fit.nextFeature(feat):
|
|
index.insertFeature(feat)
|
|
return index
|
|
|
|
# Convinience function to add a vector layer to canvas based on input shapefile path ( as string )
|
|
|
|
|
|
def addShapeToCanvas(shapefile_path):
|
|
file_info = QFileInfo(shapefile_path)
|
|
if file_info.exists():
|
|
layer_name = file_info.completeBaseName()
|
|
else:
|
|
return False
|
|
vlayer_new = QgsVectorLayer(shapefile_path, layer_name, "ogr")
|
|
if vlayer_new.isValid():
|
|
QgsMapLayerRegistry.instance().addMapLayers([vlayer_new])
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
# Return all unique values in field based on field index
|
|
|
|
|
|
def getUniqueValues(provider, index):
|
|
return provider.uniqueValues(index)
|
|
|
|
# Generate a save file dialog with a dropdown box for choosing encoding style
|
|
|
|
|
|
def saveDialog(parent, filtering="Shapefiles (*.shp *.SHP)"):
|
|
settings = QSettings()
|
|
dirName = settings.value("/UI/lastShapefileDir")
|
|
encode = settings.value("/UI/encoding")
|
|
fileDialog = QgsEncodingFileDialog(parent, QCoreApplication.translate("fTools", "Save output shapefile"), dirName, filtering, encode)
|
|
fileDialog.setDefaultSuffix("shp")
|
|
fileDialog.setFileMode(QFileDialog.AnyFile)
|
|
fileDialog.setAcceptMode(QFileDialog.AcceptSave)
|
|
fileDialog.setConfirmOverwrite(True)
|
|
if not fileDialog.exec_() == QDialog.Accepted:
|
|
return None, None
|
|
files = fileDialog.selectedFiles()
|
|
settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(files[0])).absolutePath())
|
|
return (unicode(files[0]), unicode(fileDialog.encoding()))
|
|
|
|
# Generate a save file dialog with a dropdown box for choosing encoding style
|
|
# with mode="SingleFile" will allow to select only one file, in other cases - several files
|
|
|
|
|
|
def openDialog(parent, filtering="Shapefiles (*.shp *.SHP)", dialogMode="SingleFile"):
|
|
settings = QSettings()
|
|
dirName = settings.value("/UI/lastShapefileDir")
|
|
encode = settings.value("/UI/encoding")
|
|
fileDialog = QgsEncodingFileDialog(
|
|
parent,
|
|
QCoreApplication.translate("fTools", "Select input file")
|
|
if dialogMode == "SingleFile" else
|
|
QCoreApplication.translate("fTools", "Select input files"),
|
|
dirName, filtering, encode)
|
|
fileDialog.setFileMode(QFileDialog.ExistingFiles)
|
|
fileDialog.setAcceptMode(QFileDialog.AcceptOpen)
|
|
if not fileDialog.exec_() == QDialog.Accepted:
|
|
return None, None
|
|
files = fileDialog.selectedFiles()
|
|
settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(files[0])).absolutePath())
|
|
if dialogMode == "SingleFile":
|
|
return (unicode(files[0]), unicode(fileDialog.encoding()))
|
|
else:
|
|
return (files, unicode(fileDialog.encoding()))
|
|
|
|
# Generate a select directory dialog with a dropdown box for choosing encoding style
|
|
|
|
|
|
def dirDialog(parent):
|
|
settings = QSettings()
|
|
dirName = settings.value("/UI/lastShapefileDir")
|
|
encode = settings.value("/UI/encoding")
|
|
fileDialog = QgsEncodingFileDialog(parent, QCoreApplication.translate("fTools", "Save output directory"), dirName, encode)
|
|
fileDialog.setFileMode(QFileDialog.DirectoryOnly)
|
|
fileDialog.setAcceptMode(QFileDialog.AcceptSave)
|
|
fileDialog.setConfirmOverwrite(False)
|
|
if not fileDialog.exec_() == QDialog.Accepted:
|
|
return None, None
|
|
folders = fileDialog.selectedFiles()
|
|
settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(folders[0])).absolutePath())
|
|
return (unicode(folders[0]), unicode(fileDialog.encoding()))
|
|
|
|
# Return field type from it's name
|
|
|
|
|
|
def getFieldType(vlayer, fieldName):
|
|
for field in vlayer.dataProvider().fields():
|
|
if field.name() == fieldName:
|
|
return field.typeName()
|
|
|
|
# return the number of unique values in field
|
|
|
|
|
|
def getUniqueValuesCount(vlayer, fieldIndex, useSelection):
|
|
count = 0
|
|
values = []
|
|
if useSelection:
|
|
selection = vlayer.selectedFeatures()
|
|
for f in selection:
|
|
v = f.attributes()[fieldIndex]
|
|
if v not in values:
|
|
values.append(v)
|
|
count += 1
|
|
else:
|
|
feat = QgsFeature()
|
|
fit = vlayer.dataProvider().getFeatures()
|
|
while fit.nextFeature(feat):
|
|
v = feat.attributes()[fieldIndex]
|
|
if v not in values:
|
|
values.append(v)
|
|
count += 1
|
|
return count
|
|
|
|
|
|
def getGeomType(gT):
|
|
if gT == 3 or gT == 6:
|
|
gTypeListPoly = [QGis.WKBPolygon, QGis.WKBMultiPolygon]
|
|
return gTypeListPoly
|
|
elif gT == 2 or gT == 5:
|
|
gTypeListLine = [QGis.WKBLineString, QGis.WKBMultiLineString]
|
|
return gTypeListLine
|
|
elif gT == 1 or gT == 4:
|
|
gTypeListPoint = [QGis.WKBPoint, QGis.WKBMultiPoint]
|
|
return gTypeListPoint
|
|
|
|
|
|
def getShapesByGeometryType(baseDir, inShapes, geomType):
|
|
outShapes = []
|
|
for fileName in inShapes:
|
|
layerPath = QFileInfo(baseDir + "/" + fileName).absoluteFilePath()
|
|
vLayer = QgsVectorLayer(layerPath, QFileInfo(layerPath).baseName(), "ogr")
|
|
if not vLayer.isValid():
|
|
continue
|
|
layerGeometry = vLayer.geometryType()
|
|
if layerGeometry == QGis.Polygon and geomType == 0:
|
|
outShapes.append(fileName)
|
|
elif layerGeometry == QGis.Line and geomType == 1:
|
|
outShapes.append(fileName)
|
|
elif layerGeometry == QGis.Point and geomType == 2:
|
|
outShapes.append(fileName)
|
|
|
|
if len(outShapes) == 0:
|
|
return None
|
|
|
|
return outShapes
|
|
|
|
|
|
def getShapefileName(outPath, extension='.shp'):
|
|
import os.path
|
|
outName = os.path.basename(outPath)
|
|
if outName.endswith(extension):
|
|
outName = outName[:-len(extension)]
|
|
return outName
|