Skip to content

Commit

Permalink
[FEATURE] Build spatial index tool for fTools (see #2779). Currently
Browse files Browse the repository at this point in the history
without icon
  • Loading branch information
alexbruy committed Nov 12, 2011
1 parent 55337b3 commit 48112cc
Show file tree
Hide file tree
Showing 3 changed files with 360 additions and 3 deletions.
13 changes: 10 additions & 3 deletions python/plugins/fTools/fTools.py
Expand Up @@ -43,7 +43,7 @@
import doIntersectLines, doSelectByLocation, doVectorSplit, doMeanCoords
import doPointDistance, doPointsInPolygon, doRandom, doRandPoints, doRegPoints
import doSpatialJoin, doSubsetSelect, doSumLines, doVectorGrid, doMergeShapes
import doValidate, doSimplify, doDefineProj
import doValidate, doSimplify, doDefineProj, doSpatialIndex

class fToolsPlugin:
def __init__(self,iface):
Expand Down Expand Up @@ -113,6 +113,7 @@ def updateThemeIcons(self, theme):
self.spatJoin.setIcon(QIcon(self.getThemeIcon("join_location.png")))
self.splitVect.setIcon(QIcon(self.getThemeIcon("split_layer.png")))
self.mergeShapes.setIcon(QIcon(self.getThemeIcon("merge_shapes.png")))
self.spatialIndex.setIcon(QIcon(self.getThemeIcon("spatial_index.png")))

def initGui(self):
if int(self.QgisVersion) < 1:
Expand Down Expand Up @@ -179,7 +180,8 @@ def initGui(self):
self.spatJoin = QAction(QCoreApplication.translate("fTools", "Join attributes by location"), self.iface.mainWindow())
self.splitVect = QAction(QCoreApplication.translate("fTools", "Split vector layer"), self.iface.mainWindow())
self.mergeShapes = QAction(QCoreApplication.translate("fTools", "Merge shapefiles to one"), self.iface.mainWindow())
self.dataManageMenu.addActions([self.define, self.spatJoin, self.splitVect, self.mergeShapes])
self.spatialIndex = QAction(QCoreApplication.translate("fTools", "Create spatial index"), self.iface.mainWindow())
self.dataManageMenu.addActions([self.define, self.spatJoin, self.splitVect, self.mergeShapes, self.spatialIndex])
self.updateThemeIcons("theme")

self.menu.addMenu(self.analysisMenu)
Expand Down Expand Up @@ -235,6 +237,7 @@ def initGui(self):
QObject.connect(self.spatJoin, SIGNAL("triggered()"), self.dospatJoin)
QObject.connect(self.splitVect, SIGNAL("triggered()"), self.dosplitVect)
QObject.connect(self.mergeShapes, SIGNAL("triggered()"), self.doMergeShapes)
QObject.connect(self.spatialIndex, SIGNAL("triggered()"), self.doSpatIndex)

def unload(self):
pass
Expand Down Expand Up @@ -319,7 +322,7 @@ def docentroids(self):
def dodelaunay(self):
d = doGeometry.GeometryDialog(self.iface, 8)
d.exec_()

def dovoronoi(self):
d = doGeometry.GeometryDialog(self.iface, 10)
d.exec_()
Expand Down Expand Up @@ -392,3 +395,7 @@ def doMergeShapes(self):
d = doMergeShapes.Dialog(self.iface)
d.exec_()

def doSpatIndex(self):
d = doSpatialIndex.Dialog(self.iface)
d.show()
d.exec_()
223 changes: 223 additions & 0 deletions python/plugins/fTools/tools/doSpatialIndex.py
@@ -0,0 +1,223 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
doSpatialIndex.py - build spatial index for vector layers or files
--------------------------------------
Date : 11-Nov-2011
Copyright : (C) 2011 by Alexander Bruy
Email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from qgis.core import *
from qgis.gui import *

import ftools_utils

from ui_frmSpatialIndex import Ui_Dialog

class Dialog( QDialog, Ui_Dialog ):
def __init__( self, iface ):
QDialog.__init__( self )
self.setupUi( self )
self.iface = iface

self.workThread = None

self.btnOk = self.buttonBox.button( QDialogButtonBox.Ok )
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )

QObject.connect( self.chkExternalFiles, SIGNAL( "stateChanged( int )" ), self.toggleExternalFiles )
QObject.connect( self.btnSelectFiles, SIGNAL( "clicked()" ), self.selectFiles )
QObject.connect( self.lstLayers, SIGNAL( "itemSelectionChanged()" ), self.updateLayerList )
QObject.connect( self.btnSelectAll, SIGNAL( "clicked()" ), self.selectAll )
QObject.connect( self.btnSelectNone, SIGNAL( "clicked()" ), self.selectNone )
QObject.connect( self.btnClearList, SIGNAL( "clicked()" ), self.clearList )

self.manageGui()

def manageGui( self ):
self.btnSelectFiles.setEnabled( False )
self.btnClearList.setEnabled( False )

self.fillLayersList()

def fillLayersList( self ):
self.lstLayers.clear()
layers = ftools_utils.getLayerNames( [ QGis.Line, QGis.Point, QGis.Polygon ] )
for lay in layers:
source = ftools_utils.getVectorLayerByName( lay ).source()
item = QListWidgetItem( lay, self.lstLayers )
item.setData( Qt.UserRole, source )
item.setData( Qt.ToolTipRole, source )

def toggleExternalFiles( self ):
if self.chkExternalFiles.isChecked():
self.btnSelectFiles.setEnabled( True )
self.btnClearList.setEnabled( True )
self.btnSelectAll.setEnabled( False )
self.btnSelectNone.setEnabled( False )

self.lstLayers.clear()
self.lstLayers.setSelectionMode( QAbstractItemView.NoSelection )
self.layers = []
else:
self.btnSelectFiles.setEnabled( False )
self.btnClearList.setEnabled( False )
self.btnSelectAll.setEnabled( True )
self.btnSelectNone.setEnabled( True )

self.fillLayersList()
self.lstLayers.setSelectionMode( QAbstractItemView.ExtendedSelection )
self.updateLayerList()

def updateLayerList( self ):
self.layers = []
selection = self.lstLayers.selectedItems()
for item in selection:
self.layers.append( item.text() )

def selectFiles( self ):
filters = QgsProviderRegistry.instance().fileVectorFilters()
( files, self.encoding ) = ftools_utils.openDialog( self, filtering = filters, dialogMode = "MultipleFiles" )
if files is None:
return

self.layers.extend( [ unicode( f ) for f in files ] )
self.lstLayers.addItems( files )

def selectAll( self ):
self.lstLayers.selectAll()

def selectNone( self ):
self.lstLayers.clearSelection()

def clearList( self ):
self.layers = []
self.lstLayers.clear()

def accept( self ):
QApplication.setOverrideCursor( Qt.WaitCursor )
self.btnOk.setEnabled( False )

self.workThread = SpatialIdxThread( self.layers, self.chkExternalFiles.isChecked() )
self.progressBar.setRange( 0, len( self.layers ) )

QObject.connect( self.workThread, SIGNAL( "layerProcessed()" ), self.layerProcessed )
QObject.connect( self.workThread, SIGNAL( "processFinished( PyQt_PyObject )" ), self.processFinished )
QObject.connect( self.workThread, SIGNAL( "processInterrupted()" ), self.processInterrupted )

self.btnClose.setText( self.tr( "Cancel" ) )
QObject.disconnect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
QObject.connect( self.btnClose, SIGNAL( "clicked()" ), self.stopProcessing )

self.workThread.start()

def layerProcessed( self ):
self.progressBar.setValue( self.progressBar.value() + 1 )

def processInterrupted( self ):
self.restoreGui()

def processFinished( self, errors ):
self.stopProcessing()
self.restoreGui()

if not errors.isEmpty():
msg = QString( "Processing of the following layers/files ended with error:<br><br>" ).append( errors.join( "<br>" ) )
QErrorMessage( self ).showMessage( msg )

QMessageBox.information( self, self.tr( "Finished" ), self.tr( "Processing completed." ) )

def stopProcessing( self ):
if self.workThread != None:
self.workThread.stop()
self.workThread = None

def restoreGui( self ):
self.progressBar.setValue( 0 )
QApplication.restoreOverrideCursor()
QObject.connect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
self.btnClose.setText( self.tr( "Close" ) )
self.btnOk.setEnabled( True )

if self.chkExternalFiles.isChecked():
self.clearList()

class SpatialIdxThread( QThread ):
def __init__( self, layers, isFiles ):
QThread.__init__( self, QThread.currentThread() )
self.layers = layers
self.isFiles = isFiles

self.mutex = QMutex()
self.stopMe = 0

self.errors = QStringList()

def run( self ):
self.mutex.lock()
self.stopMe = 0
self.mutex.unlock()

interrupted = False

if self.isFiles:
for layer in self.layers:
vl = QgsVectorLayer( layer, "tmp", "ogr" )
provider = vl.dataProvider()
if provider.capabilities() & QgsVectorDataProvider.CreateSpatialIndex:
if not provider.createSpatialIndex():
self.errors.append( layer )
else:
self.errors.append( layer )

self.emit( SIGNAL( "layerProcessed()" ) )

self.mutex.lock()
s = self.stopMe
self.mutex.unlock()
if s == 1:
interrupted = True
break
else:
for layer in self.layers:
vl = ftools_utils.getVectorLayerByName( layer )
provider = vl.dataProvider()
if provider.capabilities() & QgsVectorDataProvider.CreateSpatialIndex:
if not provider.createSpatialIndex():
self.errors.append( layer )
else:
self.errors.append( layer )

self.emit( SIGNAL( "layerProcessed()" ) )

self.mutex.lock()
s = self.stopMe
self.mutex.unlock()
if s == 1:
interrupted = True
break

if not interrupted:
self.emit( SIGNAL( "processFinished( PyQt_PyObject )" ), self.errors )
else:
self.emit( SIGNAL( "processInterrupted()" ) )

def stop( self ):
self.mutex.lock()
self.stopMe = 1
self.mutex.unlock()

QThread.wait( self )

0 comments on commit 48112cc

Please sign in to comment.