ftools_utils.py

correction for the bug - Weigang Wei, 2014-01-06 06:40 AM

Download (14.3 KB)

 
1
# -*- coding: utf-8 -*-
2

    
3
#-----------------------------------------------------------
4
#
5
# fTools
6
# Copyright (C) 2008-2011  Carson Farmer
7
# EMAIL: carson.farmer (at) gmail.com
8
# WEB  : http://www.ftools.ca/fTools.html
9
#
10
# A collection of data management and analysis tools for vector data
11
#
12
#-----------------------------------------------------------
13
#
14
# licensed under the terms of GNU GPL 2
15
#
16
# This program is free software; you can redistribute it and/or modify
17
# it under the terms of the GNU General Public License as published by
18
# the Free Software Foundation; either version 2 of the License, or
19
# (at your option) any later version.
20
#
21
# This program is distributed in the hope that it will be useful,
22
# but WITHOUT ANY WARRANTY; without even the implied warranty of
23
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
# GNU General Public License for more details.
25
#
26
# You should have received a copy of the GNU General Public License along
27
# with this program; if not, write to the Free Software Foundation, Inc.,
28
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29
#
30
#---------------------------------------------------------------------
31

    
32
# Utility functions
33
# -------------------------------------------------
34
#
35
# convertFieldNameType( QgsField.name() )
36
# combineVectorFields( QgsVectorLayer, QgsVectorLayer )
37
# checkCRSCompatibility( QgsCoordinateReferenceSystem, QgsCoordinateReferenceSystem )
38
# writeVectorLayerToShape(QgsVectorLayer, QString *file path, QString *encoding style )
39
# getVectorTypeAsString( QgsVectorLayer )
40
# measurePerimeter( QgsGeometry )
41
# extractPoints( QgsGeometry )
42
# testForUniqueness( QList *QgsField, QList *QgsField )
43
# createUniqueFieldName( QgsField.name() )
44
# checkFieldNameLength( QgsFieldMap )
45
# getLayerNames( QGis.vectorType() )
46
# getFieldNames( QgsVectorLayer )
47
# getVectorLayerByName( QgsVectorLayer.name() )
48
# getFieldList( QgsVectorLayer )
49
# createIndex( QgsVectorDataProvider )
50
# addShapeToCanvas( QString *file path )
51
# getUniqueValues( QgsVectorDataProvider, int *field id )
52
# saveDialog( QWidget *parent )
53
# getFieldType( QgsVectorLayer, QgsField.name() )
54
# getUniqueValuesCount( QgsVectorLayer, int fieldIndex, bool useSelection ):
55
#
56
# -------------------------------------------------
57

    
58
from PyQt4.QtCore import *
59
from PyQt4.QtGui import *
60
from qgis.core import *
61
from qgis.gui import *
62

    
63
import locale
64

    
65
# For use with memory provider/layer, converts full field type to simple string
66
def convertFieldNameType( inName ):
67
    if inName == "Integer":
68
        return "int"
69
    elif inName == "Real":
70
        return "double"
71
    else:
72
        return "string"
73

    
74
# From two input field maps, create single field map
75
def combineVectorFields( layerA, layerB ):
76
    fieldsA = layerA.dataProvider().fields()
77
    fieldsB = layerB.dataProvider().fields()
78
    fieldsB = testForUniqueness( fieldsA, fieldsB )
79
    for f in fieldsB:
80
      fieldsA.append( f )
81
    return fieldsA
82

    
83
# Check if two input CRSs are identical
84
def checkCRSCompatibility( crsA, crsB ):
85
    if crsA == crsB:
86
        return True
87
    else:
88
        return False
89

    
90
# Convenience function to write vector layer to shapefile
91
def writeVectorLayerToShape( vlayer, outputPath, encoding ):
92
    mCodec = QTextCodec.codecForName( encoding )
93
    if not mCodec:
94
        return False
95
    #Here we should check that the output path is valid
96
    QgsVectorFileWriter.writeAsVectorFormat( vlayer, outputPath, encoding, vlayer.dataProvider().crs(), "ESRI Shapefile", False )
97
    return True
98

    
99
# For use with memory provider/layer, converts QGis vector type definition to simple string
100
def getVectorTypeAsString( vlayer ):
101
    if vlayer.geometryType() == QGis.Polygon:
102
        return "Polygon"
103
    elif vlayer.geometryType() == QGis.Line:
104
        return "LineString"
105
    elif vlayer.geometryType() == QGis.Point:
106
        return "Point"
107
    else:
108
        return False
109

    
110
# Compute area and perimeter of input polygon geometry
111
def getAreaAndPerimeter( geom ):
112
    measure = QgsDistanceArea()
113
    area = measure.measure( geom )
114
    perim = measurePerimeter( geom, measure )
115
    return ( area, perim )
116

    
117
# Compute perimeter of input polygon geometry
118
def measurePerimeter( geom ):
119
    measure = QgsDistanceArea()
120
    value = 0.00
121
    polygon = geom.asPolygon()
122
    for line in polygon:
123
        value += measure.measureLine( line )
124
    return value
125

    
126
# Generate list of QgsPoints from input geometry ( can be point, line, or polygon )
127
def extractPoints( geom ):
128
    multi_geom = QgsGeometry()
129
    temp_geom = []
130
    if geom.type() == 0: # it's a point
131
        if geom.isMultipart():
132
            temp_geom = geom.asMultiPoint()
133
        else:
134
            temp_geom.append(geom.asPoint())
135
    if geom.type() == 1: # it's a line
136
        if geom.isMultipart():
137
            multi_geom = geom.asMultiPolyline() #multi_geog is a multiline
138
            for i in multi_geom: #i is a line
139
                temp_geom.extend( i )
140
        else:
141
            temp_geom = geom.asPolyline()
142
    elif geom.type() == 2: # it's a polygon
143
        if geom.isMultipart():
144
            multi_geom = geom.asMultiPolygon() #multi_geom is a multipolygon
145
            for i in multi_geom: #i is a polygon
146
                for j in i: #j is a line
147
                    temp_geom.extend( j )
148
        else:
149
            multi_geom = geom.asPolygon() #multi_geom is a polygon
150
            for i in multi_geom: #i is a line
151
                temp_geom.extend( i )
152
    return temp_geom
153

    
154
# Check if two input field maps are unique, and resolve name issues if they aren't
155
def testForUniqueness( fieldList1, fieldList2 ):
156
    changed = True
157
    while changed:
158
        changed = False
159
        for i in range(0,len(fieldList1)):
160
            for j in range(0,len(fieldList2)):
161
                if fieldList1[i].name() == fieldList2[j].name():
162
                    fieldList2[j] = createUniqueFieldName( fieldList2[j] )
163
                    changed = True
164
    return fieldList2
165

    
166
# Create a unique field name based on input field name
167
def createUniqueFieldName( field ):
168
    check = field.name()[-2:]
169
    shortName = field.name()[:8]
170
    if check[0] == "_":
171
        try:
172
            val = int( check[-1:] )
173
            if val < 2:
174
                val = 2
175
            else:
176
                val = val + 1
177
            field.setName( shortName[len( shortName )-1:] + unicode( val ) )
178
#        except exceptions.ValueError: # the original file where exceptions are not defined
179
        except:
180
            field.setName( shortName + "_2" )
181
    else:
182
        field.setName( shortName + "_2" )
183
    return field
184

    
185
# Return list of field names with more than 10 characters length
186
def checkFieldNameLength( fieldList ):
187
    longNames = []
188
    for field in fieldList:
189
        if len ( field.name() ) > 10:
190
            longNames.append( field.name() )
191
    return longNames
192

    
193
# Return list of names of all layers in QgsMapLayerRegistry
194
def getLayerNames( vTypes ):
195
    layermap = QgsMapLayerRegistry.instance().mapLayers()
196
    layerlist = []
197
    if vTypes == "all":
198
        for name, layer in layermap.iteritems():
199
            layerlist.append( layer.name() )
200
    else:
201
        for name, layer in layermap.iteritems():
202
            if layer.type() == QgsMapLayer.VectorLayer:
203
                if layer.geometryType() in vTypes:
204
                    layerlist.append( layer.name() )
205
            elif layer.type() == QgsMapLayer.RasterLayer:
206
                if "Raster" in vTypes:
207
                    layerlist.append( layer.name() )
208
    return sorted( layerlist, cmp=locale.strcoll )
209

    
210
# Return list of names of all fields from input QgsVectorLayer
211
def getFieldNames( vlayer ):
212
    fieldmap = getFieldList( vlayer )
213
    fieldlist = []
214
    for field in fieldmap:
215
        if not field.name() in fieldlist:
216
            fieldlist.append( field.name() )
217
    return sorted( fieldlist, cmp=locale.strcoll )
218

    
219
# Return QgsVectorLayer from a layer name ( as string )
220
def getVectorLayerByName( myName ):
221
    layermap = QgsMapLayerRegistry.instance().mapLayers()
222
    for name, layer in layermap.iteritems():
223
        if layer.type() == QgsMapLayer.VectorLayer and layer.name() == myName:
224
            if layer.isValid():
225
                return layer
226
            else:
227
                return None
228

    
229
# Return QgsRasterLayer from a layer name ( as string )
230
def getRasterLayerByName( myName ):
231
    layermap = QgsMapLayerRegistry.instance().mapLayers()
232
    for name, layer in layermap.iteritems():
233
        if layer.type() == QgsMapLayer.RasterLayer and layer.name() == myName:
234
            if layer.isValid():
235
                return layer
236
            else:
237
                return None
238

    
239
# Return QgsMapLayer from a layer name ( as string )
240
def getMapLayerByName( myName ):
241
    layermap = QgsMapLayerRegistry.instance().mapLayers()
242
    for name, layer in layermap.iteritems():
243
        if layer.name() == myName:
244
            if layer.isValid():
245
                return layer
246
            else:
247
                return None
248

    
249
# Return the field list of a vector layer
250
def getFieldList( vlayer ):
251
    return vlayer.dataProvider().fields()
252

    
253
# Convinience function to create a spatial index for input QgsVectorDataProvider
254
def createIndex( provider ):
255
    feat = QgsFeature()
256
    index = QgsSpatialIndex()
257
    fit = provider.getFeatures()
258
    while fit.nextFeature( feat ):
259
        index.insertFeature( feat )
260
    return index
261

    
262
# Convinience function to add a vector layer to canvas based on input shapefile path ( as string )
263
def addShapeToCanvas( shapefile_path ):
264
    file_info = QFileInfo( shapefile_path )
265
    if file_info.exists():
266
        layer_name = file_info.completeBaseName()
267
    else:
268
        return False
269
    vlayer_new = QgsVectorLayer( shapefile_path, layer_name, "ogr" )
270
    if vlayer_new.isValid():
271
        QgsMapLayerRegistry.instance().addMapLayers( [vlayer_new] )
272
        return True
273
    else:
274
        return False
275

    
276
# Return all unique values in field based on field index
277
def getUniqueValues( provider, index ):
278
    return provider.uniqueValues( index )
279

    
280
# Generate a save file dialog with a dropdown box for choosing encoding style
281
def saveDialog( parent, filtering="Shapefiles (*.shp *.SHP)"):
282
    settings = QSettings()
283
    dirName = settings.value( "/UI/lastShapefileDir" )
284
    encode = settings.value( "/UI/encoding" )
285
    fileDialog = QgsEncodingFileDialog( parent, "Save output shapefile", dirName, filtering, encode )
286
    fileDialog.setDefaultSuffix( "shp" )
287
    fileDialog.setFileMode( QFileDialog.AnyFile )
288
    fileDialog.setAcceptMode( QFileDialog.AcceptSave )
289
    fileDialog.setConfirmOverwrite( True )
290
    if not fileDialog.exec_() == QDialog.Accepted:
291
            return None, None
292
    files = fileDialog.selectedFiles()
293
    settings.setValue("/UI/lastShapefileDir", QFileInfo( unicode( files[0] ) ).absolutePath() )
294
    return ( unicode( files[0] ), unicode( fileDialog.encoding() ) )
295

    
296
# Generate a save file dialog with a dropdown box for choosing encoding style
297
# with mode="SingleFile" will allow to select only one file, in other cases - several files
298
def openDialog( parent, filtering="Shapefiles (*.shp *.SHP)", dialogMode="SingleFile"):
299
    settings = QSettings()
300
    dirName = settings.value( "/UI/lastShapefileDir" )
301
    encode = settings.value( "/UI/encoding" )
302
    fileDialog = QgsEncodingFileDialog( parent, "Save output shapefile", dirName, filtering, encode )
303
    fileDialog.setFileMode( QFileDialog.ExistingFiles )
304
    fileDialog.setAcceptMode( QFileDialog.AcceptOpen )
305
    if not fileDialog.exec_() == QDialog.Accepted:
306
            return None, None
307
    files = fileDialog.selectedFiles()
308
    settings.setValue("/UI/lastShapefileDir", QFileInfo( unicode( files[0] ) ).absolutePath() )
309
    if dialogMode == "SingleFile":
310
      return ( unicode( files[0] ), unicode( fileDialog.encoding() ) )
311
    else:
312
      return ( files, unicode( fileDialog.encoding() ) )
313

    
314
# Generate a select directory dialog with a dropdown box for choosing encoding style
315
def dirDialog( parent ):
316
    settings = QSettings()
317
    dirName = settings.value( "/UI/lastShapefileDir" )
318
    encode = settings.value( "/UI/encoding" )
319
    fileDialog = QgsEncodingFileDialog( parent, "Save output shapefile", dirName, encode )
320
    fileDialog.setFileMode( QFileDialog.DirectoryOnly )
321
    fileDialog.setAcceptMode( QFileDialog.AcceptSave )
322
    fileDialog.setConfirmOverwrite( False )
323
    if not fileDialog.exec_() == QDialog.Accepted:
324
            return None, None
325
    folders = fileDialog.selectedFiles()
326
    settings.setValue("/UI/lastShapefileDir", QFileInfo( unicode( folders[0] ) ).absolutePath() )
327
    return ( unicode( folders[0] ), unicode( fileDialog.encoding() ) )
328

    
329
# Return field type from it's name
330
def getFieldType(vlayer, fieldName):
331
    for field in vlayer.dataProvider().fields():
332
        if field.name() == fieldName:
333
            return field.typeName()
334

    
335
# return the number of unique values in field
336
def getUniqueValuesCount( vlayer, fieldIndex, useSelection ):
337
    count = 0
338
    values = []
339
    if useSelection:
340
        selection = vlayer.selectedFeatures()
341
        for f in selection:
342
            v = f.attributes()[ fieldIndex ]
343
            if v not in values:
344
                values.append( v )
345
                count += 1
346
    else:
347
        feat = QgsFeature()
348
        fit = vlayer.dataProvider().getFeatures()
349
        while fit.nextFeature( feat ):
350
            v = feat.attributes()[ fieldIndex ]
351
            if v not in values:
352
                values.append( v )
353
                count += 1
354
    return count
355

    
356
def getGeomType(gT):
357
  if gT == 3 or gT == 6:
358
    gTypeListPoly = [ QGis.WKBPolygon, QGis.WKBMultiPolygon ]
359
    return gTypeListPoly
360
  elif gT == 2 or gT == 5:
361
    gTypeListLine = [ QGis.WKBLineString, QGis.WKBMultiLineString ]
362
    return gTypeListLine
363
  elif gT == 1 or gT == 4:
364
    gTypeListPoint = [ QGis.WKBPoint, QGis.WKBMultiPoint ]
365
    return gTypeListPoint
366

    
367
def getShapesByGeometryType( baseDir, inShapes, geomType ):
368
  outShapes = []
369
  for fileName in inShapes:
370
    layerPath = QFileInfo( baseDir + "/" + fileName ).absoluteFilePath()
371
    vLayer = QgsVectorLayer( layerPath, QFileInfo( layerPath ).baseName(), "ogr" )
372
    if not vLayer.isValid():
373
      continue
374
    layerGeometry = vLayer.geometryType()
375
    if layerGeometry == QGis.Polygon and geomType == 0:
376
      outShapes.append(fileName)
377
    elif layerGeometry == QGis.Line and geomType == 1:
378
      outShapes.append(fileName)
379
    elif layerGeometry == QGis.Point and geomType == 2:
380
      outShapes.append(fileName)
381

    
382
  if len(outShapes) == 0:
383
    return None
384

    
385
  return outShapes
386

    
387
def getShapefileName( outPath, extension='.shp' ):
388
    import os.path
389
    outName=os.path.basename(outPath)
390
    if outName.endswith(extension):
391
        outName=outName[:-len(extension)]
392
    return outName
393