2009-01-20 22:54:27 +00:00
|
|
|
from PyQt4.QtCore import *
|
|
|
|
from PyQt4.QtGui import *
|
|
|
|
from qgis.core import *
|
2009-08-16 22:40:48 +00:00
|
|
|
from ui_frmVisual import Ui_Dialog
|
2009-01-20 22:54:27 +00:00
|
|
|
import ftools_utils
|
|
|
|
import math
|
|
|
|
|
|
|
|
class VisualDialog( QDialog, Ui_Dialog ):
|
2009-04-21 14:29:25 +00:00
|
|
|
def __init__( self, iface, function ):
|
|
|
|
QDialog.__init__( self )
|
|
|
|
self.iface = iface
|
|
|
|
self.setupUi( self )
|
|
|
|
self.myFunction = function
|
|
|
|
if self.myFunction == 2 or self.myFunction == 3:
|
|
|
|
QObject.connect( self.inShape, SIGNAL( "currentIndexChanged(QString)" ), self.update )
|
|
|
|
self.manageGui()
|
|
|
|
self.cancel_close = self.buttonBox_2.button( QDialogButtonBox.Close )
|
|
|
|
self.progressBar.setValue( 0 )
|
2009-12-11 15:46:21 +00:00
|
|
|
self.partProgressBar.setValue( 0 )
|
|
|
|
self.partProgressBar.setEnabled( False )
|
2009-04-21 14:29:25 +00:00
|
|
|
|
|
|
|
def keyPressEvent( self, e ):
|
|
|
|
'''
|
|
|
|
Reimplemented key press event:
|
|
|
|
'''
|
|
|
|
if ( e.modifiers() == Qt.ControlModifier or e.modifiers() == Qt.MetaModifier ) and e.key() == Qt.Key_C:
|
|
|
|
selection = self.lstUnique.selectedItems()
|
|
|
|
items = QString()
|
2009-11-09 10:49:36 +00:00
|
|
|
if self.myFunction in ( 1, 2 ):
|
|
|
|
for rec in range( self.tblUnique.rowCount() ):
|
|
|
|
items.append( self.tblUnique.item( rec, 0 ).text() + "\n" )
|
|
|
|
else:
|
|
|
|
for rec in range( self.tblUnique.rowCount() ):
|
|
|
|
items.append( self.tblUnique.item( rec, 0 ).text() + ":" + self.tblUnique.item( rec, 1 ).text() + "\n" )
|
2009-04-21 14:29:25 +00:00
|
|
|
if not items.isEmpty():
|
|
|
|
clip_board = QApplication.clipboard()
|
|
|
|
clip_board.setText( items )
|
|
|
|
else:
|
|
|
|
QDialog.keyPressEvent( self, e )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def update( self ):
|
|
|
|
self.cmbField.clear()
|
|
|
|
inputLayer = unicode( self.inShape.currentText() )
|
|
|
|
if inputLayer != "":
|
|
|
|
changedLayer = ftools_utils.getVectorLayerByName( inputLayer )
|
|
|
|
changedField = changedLayer.dataProvider().fields()
|
2009-05-26 18:07:37 +00:00
|
|
|
# for Basic statistics (with or without selection)
|
|
|
|
if self.myFunction == 3:
|
|
|
|
if changedLayer.selectedFeatureCount() != 0:
|
|
|
|
self.useSelected.setCheckState( Qt.Checked )
|
|
|
|
else:
|
|
|
|
self.useSelected.setCheckState( Qt.Unchecked )
|
|
|
|
# add all fields in combobox because now we can work with text fields too
|
2009-04-21 14:29:25 +00:00
|
|
|
for i in changedField:
|
2009-11-09 10:49:36 +00:00
|
|
|
self.cmbField.addItem( unicode( changedField[i].name() ) )
|
2009-05-26 18:07:37 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def accept( self ):
|
|
|
|
if self.inShape.currentText() == "":
|
|
|
|
QMessageBox.information( self, "Error!", self.tr( "Please specify input vector layer" ) )
|
|
|
|
elif self.cmbField.isVisible() and self.cmbField.currentText() == "":
|
|
|
|
QMessageBox.information( self, "Error!", self.tr( "Please specify input field" ) )
|
|
|
|
else:
|
2009-05-26 18:07:37 +00:00
|
|
|
self.visual( self.inShape.currentText(), self.cmbField.currentText(), self.useSelected.checkState() )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def manageGui( self ):
|
|
|
|
if self.myFunction == 1: # Check geometry validity
|
|
|
|
self.setWindowTitle( self.tr( "Check geometry validity" ) )
|
|
|
|
self.cmbField.setVisible( False )
|
|
|
|
self.label.setVisible( False )
|
2009-05-26 18:07:37 +00:00
|
|
|
self.useSelected.setVisible( False )
|
2009-04-21 14:29:25 +00:00
|
|
|
self.label_2.setText( self.tr( "Geometry errors" ) )
|
|
|
|
self.label_4.setText( self.tr( "Total encountered errors" ) )
|
|
|
|
elif self.myFunction == 2: # List unique values
|
|
|
|
self.setWindowTitle( self.tr( "List unique values" ) )
|
|
|
|
self.label_2.setText( self.tr( "Unique values" ) )
|
|
|
|
self.label_4.setText(self.tr( "Total unique values" ) )
|
2009-05-26 18:07:37 +00:00
|
|
|
self.useSelected.setVisible( False )
|
2009-04-21 14:29:25 +00:00
|
|
|
elif self.myFunction == 3: # Basic statistics
|
|
|
|
self.setWindowTitle( self.tr( "Basics statistics" ) )
|
|
|
|
self.label_2.setText( self.tr( "Statistics output" ) )
|
|
|
|
self.label_4.setVisible( False )
|
|
|
|
self.lstCount.setVisible( False )
|
|
|
|
self.resize( 381, 400 )
|
|
|
|
elif self.myFunction == 4: # Nearest neighbour analysis
|
|
|
|
self.setWindowTitle( self.tr( "Nearest neighbour analysis" ) )
|
|
|
|
self.cmbField.setVisible( False )
|
|
|
|
self.label.setVisible( False )
|
2009-05-26 18:07:37 +00:00
|
|
|
self.useSelected.setVisible( False )
|
2009-04-21 14:29:25 +00:00
|
|
|
self.label_2.setText( self.tr( "Nearest neighbour statistics" ) )
|
|
|
|
self.label_4.setVisible( False )
|
|
|
|
self.lstCount.setVisible( False )
|
|
|
|
self.resize( 381, 200 )
|
|
|
|
self.inShape.clear()
|
|
|
|
if self.myFunction == 1:
|
|
|
|
myList = ftools_utils.getLayerNames( [ QGis.Polygon ] )
|
|
|
|
elif self.myFunction == 4:
|
|
|
|
myList = ftools_utils.getLayerNames( [ QGis.Point ] )
|
|
|
|
else:
|
|
|
|
myList = ftools_utils.getLayerNames( [ QGis.Point, QGis.Line, QGis.Polygon ] )
|
|
|
|
self.inShape.addItems( myList )
|
|
|
|
return
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
#1: Check geometry
|
|
|
|
#2: List unique values
|
|
|
|
#3: Basic statistics
|
|
|
|
#4: Nearest neighbour analysis
|
2009-05-26 18:07:37 +00:00
|
|
|
def visual( self, myLayer, myField, mySelection ):
|
2009-04-21 14:29:25 +00:00
|
|
|
vlayer = ftools_utils.getVectorLayerByName( myLayer )
|
2009-11-09 10:49:36 +00:00
|
|
|
self.tblUnique.clearContents()
|
|
|
|
self.tblUnique.setRowCount( 0 )
|
2009-04-21 14:29:25 +00:00
|
|
|
self.lstCount.clear()
|
2009-05-26 18:07:37 +00:00
|
|
|
self.testThread = visualThread( self.iface.mainWindow(), self, self.myFunction, vlayer, myField, mySelection )
|
2009-04-21 14:29:25 +00:00
|
|
|
QObject.connect( self.testThread, SIGNAL( "runFinished(PyQt_PyObject)" ), self.runFinishedFromThread )
|
|
|
|
QObject.connect( self.testThread, SIGNAL( "runStatus(PyQt_PyObject)" ), self.runStatusFromThread )
|
|
|
|
QObject.connect( self.testThread, SIGNAL( "runRange(PyQt_PyObject)" ), self.runRangeFromThread )
|
2009-12-11 15:46:21 +00:00
|
|
|
QObject.connect( self.testThread, SIGNAL( "runPartRange(PyQt_PyObject)" ), self.runPartRangeFromThread )
|
|
|
|
QObject.connect( self.testThread, SIGNAL( "runPartStatus(PyQt_PyObject)" ), self.runPartStatusFromThread )
|
2009-04-21 14:29:25 +00:00
|
|
|
self.cancel_close.setText( "Cancel" )
|
|
|
|
QObject.connect( self.cancel_close, SIGNAL( "clicked()" ), self.cancelThread )
|
|
|
|
self.testThread.start()
|
|
|
|
return True
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def cancelThread( self ):
|
|
|
|
self.testThread.stop()
|
|
|
|
|
|
|
|
def runFinishedFromThread( self, output ):
|
|
|
|
self.testThread.stop()
|
2009-11-09 10:49:36 +00:00
|
|
|
|
|
|
|
result = output[ 0 ]
|
|
|
|
numRows = len( result )
|
|
|
|
self.tblUnique.setRowCount( numRows )
|
|
|
|
if self.myFunction in ( 1, 2 ):
|
|
|
|
self.tblUnique.setColumnCount( 1 )
|
|
|
|
for rec in range( numRows ):
|
|
|
|
item = QTableWidgetItem( result[ rec ] )
|
|
|
|
self.tblUnique.setItem( rec, 0, item )
|
|
|
|
else:
|
|
|
|
self.tblUnique.setColumnCount( 2 )
|
|
|
|
for rec in range( numRows ):
|
|
|
|
tmp = result[ rec ].split( ":" )
|
|
|
|
item = QTableWidgetItem( tmp[ 0 ] )
|
|
|
|
self.tblUnique.setItem( rec, 0, item )
|
|
|
|
item = QTableWidgetItem( tmp[ 1 ] )
|
|
|
|
self.tblUnique.setItem( rec, 1, item )
|
|
|
|
self.tblUnique.setHorizontalHeaderLabels( [ "Parameter", "Value" ] )
|
|
|
|
self.tblUnique.horizontalHeader().setResizeMode( 1, QHeaderView.ResizeToContents )
|
|
|
|
self.tblUnique.horizontalHeader().show()
|
|
|
|
self.tblUnique.horizontalHeader().setResizeMode( 0, QHeaderView.Stretch )
|
|
|
|
self.tblUnique.resizeRowsToContents()
|
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
self.lstCount.insert( unicode( output[ 1 ] ) )
|
|
|
|
self.cancel_close.setText( "Close" )
|
|
|
|
QObject.disconnect( self.cancel_close, SIGNAL( "clicked()" ), self.cancelThread )
|
|
|
|
return True
|
|
|
|
|
|
|
|
def runStatusFromThread( self, status ):
|
|
|
|
self.progressBar.setValue( status )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def runRangeFromThread( self, range_vals ):
|
|
|
|
self.progressBar.setRange( range_vals[ 0 ], range_vals[ 1 ] )
|
2009-12-11 15:46:21 +00:00
|
|
|
|
|
|
|
def runPartStatusFromThread( self, status ):
|
|
|
|
self.partProgressBar.setValue( status )
|
|
|
|
if status >= self.part_max:
|
|
|
|
self.partProgressBar.setEnabled( False )
|
|
|
|
|
|
|
|
def runPartRangeFromThread( self, range_vals ):
|
|
|
|
self.part_max = range_vals[ 1 ]
|
|
|
|
self.partProgressBar.setEnabled( True )
|
|
|
|
self.partProgressBar.setRange( range_vals[ 0 ], range_vals[ 1 ] )
|
2009-04-21 14:29:25 +00:00
|
|
|
|
2009-01-20 22:54:27 +00:00
|
|
|
class visualThread( QThread ):
|
2009-05-26 18:07:37 +00:00
|
|
|
def __init__( self, parentThread, parentObject, function, vlayer, myField, mySelection ):
|
2009-04-21 14:29:25 +00:00
|
|
|
QThread.__init__( self, parentThread )
|
|
|
|
self.parent = parentObject
|
|
|
|
self.running = False
|
|
|
|
self.myFunction = function
|
|
|
|
self.vlayer = vlayer
|
|
|
|
self.myField = myField
|
2009-05-26 18:07:37 +00:00
|
|
|
self.mySelection = mySelection
|
2009-01-20 22:54:27 +00:00
|
|
|
# self.total = 0
|
|
|
|
# self.currentCount = 0
|
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def run( self ):
|
|
|
|
self.running = True
|
|
|
|
if self.myFunction == 1: # Check geometry
|
|
|
|
( lst, cnt ) = self.check_geometry( self.vlayer )
|
|
|
|
elif self.myFunction == 2: # List unique values
|
|
|
|
( lst, cnt ) = self.list_unique_values( self.vlayer, self.myField )
|
|
|
|
elif self.myFunction == 3: # Basic statistics
|
|
|
|
( lst, cnt ) = self.basic_statistics( self.vlayer, self.myField )
|
|
|
|
elif self.myFunction == 4: # Nearest neighbour analysis
|
|
|
|
( lst, cnt ) = self.nearest_neighbour_analysis( self.vlayer )
|
|
|
|
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), ( lst, cnt ) )
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def stop(self):
|
|
|
|
self.running = False
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def list_unique_values( self, vlayer, myField ):
|
|
|
|
vprovider = vlayer.dataProvider()
|
|
|
|
allAttrs = vprovider.attributeIndexes()
|
|
|
|
vprovider.select( allAttrs )
|
|
|
|
fields = vprovider.fields()
|
|
|
|
index = vprovider.fieldNameIndex( myField )
|
|
|
|
unique = ftools_utils.getUniqueValues( vprovider, int( index ) )
|
|
|
|
lstUnique = []
|
|
|
|
nFeat = len( unique )
|
|
|
|
nElement = 0
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
for item in unique:
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
lstUnique.append(item.toString().trimmed())
|
|
|
|
lstCount = len( unique )
|
|
|
|
return ( lstUnique, lstCount )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def basic_statistics( self, vlayer, myField ):
|
|
|
|
vprovider = vlayer.dataProvider()
|
|
|
|
allAttrs = vprovider.attributeIndexes()
|
|
|
|
vprovider.select( allAttrs )
|
|
|
|
fields = vprovider.fields()
|
|
|
|
index = vprovider.fieldNameIndex( myField )
|
|
|
|
feat = QgsFeature()
|
2009-05-25 21:05:34 +00:00
|
|
|
sumVal = 0.0
|
|
|
|
meanVal = 0.0
|
|
|
|
nVal = 0.0
|
2009-04-21 14:29:25 +00:00
|
|
|
values = []
|
|
|
|
first = True
|
|
|
|
nElement = 0
|
2009-05-26 18:07:37 +00:00
|
|
|
# determine selected field type
|
|
|
|
if ftools_utils.getFieldType( vlayer, myField ) == 'String':
|
|
|
|
fillVal = 0
|
|
|
|
emptyVal = 0
|
|
|
|
if self.mySelection: # only selected features
|
|
|
|
selection = vlayer.selectedFeatures()
|
|
|
|
nFeat = vlayer.selectedFeatureCount()
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
for f in selection:
|
|
|
|
atMap = f.attributeMap()
|
|
|
|
lenVal = float( len( atMap[ index ].toString() ) )
|
|
|
|
if first:
|
|
|
|
minVal = lenVal
|
|
|
|
maxVal = lenVal
|
|
|
|
first = False
|
|
|
|
else:
|
|
|
|
if lenVal < minVal: minVal = lenVal
|
|
|
|
if lenVal > maxVal: maxVal = lenVal
|
|
|
|
if lenVal != 0.00:
|
|
|
|
fillVal += 1
|
|
|
|
else:
|
|
|
|
emptyVal += 1
|
|
|
|
values.append( lenVal )
|
|
|
|
sumVal = sumVal + lenVal
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
else: # there is no selection, process the whole layer
|
|
|
|
nFeat = vprovider.featureCount()
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
while vprovider.nextFeature( feat ):
|
|
|
|
atMap = feat.attributeMap()
|
|
|
|
lenVal = float( len( atMap[ index ].toString() ) )
|
|
|
|
if first:
|
|
|
|
minVal = lenVal
|
|
|
|
maxVal = lenVal
|
|
|
|
first = False
|
|
|
|
else:
|
|
|
|
if lenVal < minVal: minVal = lenVal
|
|
|
|
if lenVal > maxVal: maxVal = lenVal
|
|
|
|
if lenVal != 0.00:
|
|
|
|
fillVal += 1
|
|
|
|
else:
|
|
|
|
emptyVal += 1
|
|
|
|
values.append( lenVal )
|
|
|
|
sumVal = sumVal + lenVal
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
nVal= float( len( values ) )
|
|
|
|
if nVal > 0.00:
|
|
|
|
meanVal = sumVal / nVal
|
|
|
|
lstStats = []
|
2009-11-09 10:49:36 +00:00
|
|
|
lstStats.append( self.tr( "Max. len:" ) + unicode( maxVal ) )
|
|
|
|
lstStats.append( self.tr( "Min. len:" ) + unicode( minVal ) )
|
|
|
|
lstStats.append( self.tr( "Mean. len:" ) + unicode( meanVal ) )
|
|
|
|
lstStats.append( self.tr( "Filled:" ) + unicode( fillVal ) )
|
|
|
|
lstStats.append( self.tr( "Empty:" ) + unicode( emptyVal ) )
|
|
|
|
lstStats.append( self.tr( "N:" ) + unicode( nVal ) )
|
2009-05-26 18:07:37 +00:00
|
|
|
return ( lstStats, [] )
|
|
|
|
else: # numeric field
|
|
|
|
stdVal = 0
|
|
|
|
cvVal = 0
|
2009-11-08 23:06:42 +00:00
|
|
|
rangeVal = 0
|
|
|
|
medianVal = 0
|
2009-05-26 18:07:37 +00:00
|
|
|
if self.mySelection: # only selected features
|
|
|
|
selection = vlayer.selectedFeatures()
|
|
|
|
nFeat = vlayer.selectedFeatureCount()
|
2009-11-09 10:49:36 +00:00
|
|
|
uniqueVal = ftools_utils.getUniqueValuesCount( vlayer, index, True )
|
2009-05-26 18:07:37 +00:00
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
for f in selection:
|
|
|
|
atMap = f.attributeMap()
|
|
|
|
value = float( atMap[ index ].toDouble()[ 0 ] )
|
|
|
|
if first:
|
|
|
|
minVal = value
|
|
|
|
maxVal = value
|
|
|
|
first = False
|
|
|
|
else:
|
|
|
|
if value < minVal: minVal = value
|
|
|
|
if value > maxVal: maxVal = value
|
|
|
|
values.append( value )
|
|
|
|
sumVal = sumVal + value
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
else: # there is no selection, process the whole layer
|
|
|
|
nFeat = vprovider.featureCount()
|
2009-11-08 23:06:42 +00:00
|
|
|
uniqueVal = ftools_utils.getUniqueValuesCount( vlayer, index, False )
|
2009-05-26 18:07:37 +00:00
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
while vprovider.nextFeature( feat ):
|
|
|
|
atMap = feat.attributeMap()
|
|
|
|
value = float( atMap[ index ].toDouble()[ 0 ] )
|
|
|
|
if first:
|
|
|
|
minVal = value
|
|
|
|
maxVal = value
|
|
|
|
first = False
|
|
|
|
else:
|
|
|
|
if value < minVal: minVal = value
|
|
|
|
if value > maxVal: maxVal = value
|
|
|
|
values.append( value )
|
|
|
|
sumVal = sumVal + value
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
nVal= float( len( values ) )
|
2009-11-08 23:06:42 +00:00
|
|
|
rangeVal = maxVal - minVal
|
2009-05-26 18:07:37 +00:00
|
|
|
if nVal > 0.00:
|
|
|
|
meanVal = sumVal / nVal
|
|
|
|
if meanVal != 0.00:
|
|
|
|
for val in values:
|
|
|
|
stdVal += ( ( val - meanVal ) * ( val - meanVal ) )
|
|
|
|
stdVal = math.sqrt( stdVal / nVal )
|
|
|
|
cvVal = stdVal / meanVal
|
2009-11-08 23:06:42 +00:00
|
|
|
if nVal > 1:
|
|
|
|
lstVal = values
|
|
|
|
lstVal.sort()
|
|
|
|
if ( nVal % 2 ) == 0:
|
|
|
|
medianVal = 0.5 * ( lstVal[ int( ( nVal - 1 ) / 2 ) ] + lstVal[ int( ( nVal ) / 2 ) ] )
|
|
|
|
else:
|
2009-11-28 20:03:12 +00:00
|
|
|
medianVal = lstVal[ int( ( nVal + 1 ) / 2 ) ]
|
2009-05-26 18:07:37 +00:00
|
|
|
lstStats = []
|
2009-11-09 10:49:36 +00:00
|
|
|
lstStats.append( self.tr( "Mean:" ) + unicode( meanVal ) )
|
|
|
|
lstStats.append( self.tr( "StdDev:" ) + unicode( stdVal ) )
|
|
|
|
lstStats.append( self.tr( "Sum:" ) + unicode( sumVal) )
|
|
|
|
lstStats.append( self.tr( "Min:" ) + unicode( minVal ) )
|
|
|
|
lstStats.append( self.tr( "Max:" ) + unicode( maxVal ) )
|
|
|
|
lstStats.append( self.tr( "N:" ) + unicode( nVal ) )
|
|
|
|
lstStats.append( self.tr( "CV:" ) + unicode( cvVal ) )
|
|
|
|
lstStats.append( self.tr( "Number of unique values:" ) + unicode( uniqueVal ) )
|
|
|
|
lstStats.append( self.tr( "Range:" ) + unicode( rangeVal ) )
|
|
|
|
lstStats.append( self.tr( "Median:" ) + unicode( medianVal ) )
|
2009-05-26 18:07:37 +00:00
|
|
|
return ( lstStats, [] )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def nearest_neighbour_analysis( self, vlayer ):
|
|
|
|
vprovider = vlayer.dataProvider()
|
|
|
|
allAttrs = vprovider.attributeIndexes()
|
|
|
|
vprovider.select( allAttrs )
|
|
|
|
feat = QgsFeature()
|
|
|
|
neighbour = QgsFeature()
|
|
|
|
sumDist = 0.00
|
|
|
|
distance = QgsDistanceArea()
|
|
|
|
A = vlayer.extent()
|
|
|
|
A = float( A.width() * A.height() )
|
|
|
|
index = ftools_utils.createIndex( vprovider )
|
|
|
|
vprovider.rewind()
|
|
|
|
nFeat = vprovider.featureCount()
|
|
|
|
nElement = 0
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
while vprovider.nextFeature( feat ):
|
|
|
|
neighbourID = index.nearestNeighbor( feat.geometry().asPoint(), 2 )[ 1 ]
|
|
|
|
vprovider.featureAtId( neighbourID, neighbour, True, [] )
|
|
|
|
nearDist = distance.measureLine( neighbour.geometry().asPoint(), feat.geometry().asPoint() )
|
|
|
|
sumDist += nearDist
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
nVal = vprovider.featureCount()
|
|
|
|
do = float( sumDist) / nVal
|
|
|
|
de = float( 0.5 / math.sqrt( nVal / A ) )
|
|
|
|
d = float( do / de )
|
|
|
|
SE = float( 0.26136 / math.sqrt( ( nVal * nVal ) / A ) )
|
|
|
|
zscore = float( ( do - de ) / SE )
|
|
|
|
lstStats = []
|
2009-11-09 10:49:36 +00:00
|
|
|
lstStats.append( self.tr( "Observed mean distance:" ) + unicode( do ) )
|
|
|
|
lstStats.append( self.tr( "Expected mean distance:" ) + unicode( de ) )
|
|
|
|
lstStats.append( self.tr( "Nearest neighbour index:" ) + unicode( d ) )
|
|
|
|
lstStats.append( self.tr( "N:" ) + unicode( nVal ) )
|
|
|
|
lstStats.append( self.tr( "Z-Score:" ) + unicode( zscore ) )
|
2009-04-21 14:29:25 +00:00
|
|
|
return ( lstStats, [] )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def check_geometry( self, vlayer ):
|
|
|
|
vprovider = vlayer.dataProvider()
|
|
|
|
allAttrs = vprovider.attributeIndexes()
|
|
|
|
vprovider.select( allAttrs )
|
|
|
|
feat = QgsFeature()
|
|
|
|
geom = QgsGeometry()
|
|
|
|
count = 0
|
|
|
|
lstErrors = []
|
|
|
|
nFeat = vprovider.featureCount()
|
|
|
|
nElement = 0
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
|
|
|
|
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
|
|
|
|
while vprovider.nextFeature( feat ):
|
|
|
|
geom = QgsGeometry( feat.geometry() )
|
|
|
|
nElement += 1
|
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
|
|
|
|
if geom.isMultipart():
|
|
|
|
polygons = geom.asMultiPolygon()
|
|
|
|
for polygon in polygons:
|
|
|
|
if not self.isHoleNested( polygon ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 contains an unnested hole" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if not self.isPolygonClosed( polygon ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 is not closed" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if self.isSelfIntersecting( polygon ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 is self intersecting" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if not self.isCorrectOrientation( polygon ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 has incorrect node ordering" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
|
|
|
|
else:
|
|
|
|
geom = geom.asPolygon()
|
|
|
|
if not self.isHoleNested( geom ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 contains an unnested hole" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if not self.isPolygonClosed( geom ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 is not closed" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if self.isSelfIntersecting( geom ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 is self intersecting" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
|
|
|
if not self.isCorrectOrientation( geom ):
|
|
|
|
lstErrors.append( self.tr( "Feature %1 has incorrect node ordering" ).arg( unicode( feat.id() ) ) )
|
|
|
|
count += 1
|
2009-12-11 15:46:21 +00:00
|
|
|
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nFeat )
|
2009-04-21 14:29:25 +00:00
|
|
|
return ( lstErrors, count )
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def isHoleNested( self, polygon ):
|
|
|
|
if len( polygon ) <= 1:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
outer = polygon[ 0 ]
|
|
|
|
for i in polygon[ 1: len( polygon ) ]:
|
|
|
|
if not self.arePointsInside( i, outer ):
|
|
|
|
return False
|
|
|
|
return True
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def arePointsInside( self, inner, outer ):
|
|
|
|
outer = QgsGeometry().fromPolygon( [ outer ] )
|
|
|
|
for j in inner:
|
|
|
|
if not outer.contains(j):
|
|
|
|
return False
|
|
|
|
return True
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def isPolygonClosed( self, polygon ):
|
|
|
|
for i in polygon:
|
|
|
|
first = i[ 0 ]
|
|
|
|
last = i[ len( i )-1 ]
|
|
|
|
if not first == last:
|
|
|
|
return False
|
|
|
|
return True
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def isSelfIntersecting( self, polygon ):
|
2009-12-11 15:46:21 +00:00
|
|
|
cPart = 0
|
|
|
|
for h in polygon:
|
|
|
|
cPart += len(h)
|
|
|
|
|
|
|
|
self.emit( SIGNAL( "runPartRange(PyQt_PyObject)" ), ( 0, cPart ) )
|
|
|
|
|
|
|
|
nPart = 0
|
2009-04-21 14:29:25 +00:00
|
|
|
for h in polygon:
|
2009-12-11 15:46:21 +00:00
|
|
|
for i in range( 0, len(h)-1 ):
|
|
|
|
self.emit( SIGNAL( "runPartStatus(PyQt_PyObject)" ), nPart )
|
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
count = 0
|
2009-12-11 15:46:21 +00:00
|
|
|
for j in range( i+1, len(h)-1 ):
|
2009-04-21 14:29:25 +00:00
|
|
|
if QgsGeometry().fromPolyline( [ h[ i ], h[ i + 1 ] ] ).intersects( QgsGeometry().fromPolyline( [ h[ j ], h[ j + 1 ] ] ) ):
|
|
|
|
count += 1
|
2009-12-11 15:46:21 +00:00
|
|
|
if count > 2:
|
|
|
|
self.emit( SIGNAL( "runPartStatus(PyQt_PyObject)" ), cPart )
|
2009-04-21 14:29:25 +00:00
|
|
|
return True
|
2009-12-11 15:46:21 +00:00
|
|
|
|
|
|
|
nPart += 1
|
|
|
|
|
|
|
|
self.emit( SIGNAL( "runPartStatus(PyQt_PyObject)" ), cPart )
|
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
return False
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def isCorrectOrientation( self, polygon ):
|
|
|
|
outer = True
|
|
|
|
for h in polygon:
|
|
|
|
if outer:
|
|
|
|
outer = False
|
|
|
|
if not self.isClockwise( h ):
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
if self.isClockwise(h):
|
|
|
|
return False
|
|
|
|
return True
|
2009-01-20 22:54:27 +00:00
|
|
|
|
2009-04-21 14:29:25 +00:00
|
|
|
def isClockwise( self, temp ):
|
|
|
|
area = 0
|
|
|
|
for pt in range( 0, len( temp ) -1 ):
|
|
|
|
area += ( temp[ pt ].x() * temp[ pt + 1 ].y() - temp[ pt + 1 ].x() * temp[ pt ].y() )
|
|
|
|
area = area / 2
|
|
|
|
if area <= 0:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|