2010-03-08 02:20:27 +00:00
# -*- coding: utf-8 -*-
2009-01-20 22:54:27 +00:00
#-----------------------------------------------------------
#
2011-03-07 23:29:15 +00:00
# fTools
# Copyright (C) 2008-2011 Carson Farmer
2009-01-20 22:54:27 +00:00
# EMAIL: carson.farmer (at) gmail.com
2011-03-07 23:29:15 +00:00
# WEB : http://www.ftools.ca/fTools.html
#
# A collection of data management and analysis tools for vector data
2009-01-20 22:54:27 +00:00
#
#-----------------------------------------------------------
2011-03-07 23:29:15 +00:00
#
2009-01-20 22:54:27 +00:00
# licensed under the terms of GNU GPL 2
2011-03-07 23:29:15 +00:00
#
2009-01-20 22:54:27 +00:00
# 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.
2011-03-07 23:29:15 +00:00
#
2009-01-20 22:54:27 +00:00
# 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.
2011-03-07 23:29:15 +00:00
#
2009-01-20 22:54:27 +00:00
# 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.
2011-03-07 23:29:15 +00:00
#
2009-01-20 22:54:27 +00:00
#---------------------------------------------------------------------
2009-02-01 15:44:02 +00:00
from PyQt4 . QtCore import *
from PyQt4 . QtGui import *
from qgis . core import *
from random import *
import math , ftools_utils
2009-08-16 22:40:48 +00:00
from ui_frmRandPoints import Ui_Dialog
2009-02-01 15:44:02 +00:00
class Dialog ( QDialog , Ui_Dialog ) :
def __init__ ( self , iface ) :
QDialog . __init__ ( self )
self . iface = iface
self . setupUi ( self )
QObject . connect ( self . toolOut , SIGNAL ( " clicked() " ) , self . outFile )
QObject . connect ( self . inShape , SIGNAL ( " currentIndexChanged(QString) " ) , self . update )
2009-01-20 22:54:27 +00:00
self . progressBar . setValue ( 0 )
2009-12-31 09:57:28 +00:00
self . setWindowTitle ( self . tr ( " Random Points " ) )
2010-05-13 22:55:59 +00:00
self . buttonOk = self . buttonBox_2 . button ( QDialogButtonBox . Ok )
2011-11-12 13:05:27 +02:00
self . populateLayers ( )
def populateLayers ( self ) :
2010-03-10 01:11:11 +00:00
layers = ftools_utils . getLayerNames ( [ QGis . Polygon , " Raster " ] )
2011-11-12 13:05:27 +02:00
QObject . disconnect ( self . inShape , SIGNAL ( " currentIndexChanged(QString) " ) , self . update )
self . inShape . clear ( )
2010-03-10 01:11:11 +00:00
self . inShape . addItems ( layers )
2011-11-12 13:05:27 +02:00
QObject . connect ( self . inShape , SIGNAL ( " currentIndexChanged(QString) " ) , self . update )
2009-01-20 22:54:27 +00:00
2010-05-13 22:55:59 +00:00
# If input layer is changed, update field list
2009-02-01 15:44:02 +00:00
def update ( self , inputLayer ) :
2009-01-20 22:54:27 +00:00
self . cmbField . clear ( )
2010-03-10 01:11:11 +00:00
changedLayer = ftools_utils . getMapLayerByName ( unicode ( inputLayer ) )
2009-01-20 22:54:27 +00:00
if changedLayer . type ( ) == changedLayer . VectorLayer :
2010-03-08 02:20:27 +00:00
self . rdoStratified . setEnabled ( True )
self . rdoDensity . setEnabled ( True )
self . rdoField . setEnabled ( True )
self . label_4 . setEnabled ( True )
2010-03-10 01:11:11 +00:00
changedLayer = ftools_utils . getVectorLayerByName ( inputLayer )
changedFields = ftools_utils . getFieldList ( changedLayer )
2010-03-08 02:20:27 +00:00
for i in changedFields :
self . cmbField . addItem ( unicode ( changedFields [ i ] . name ( ) ) )
2009-01-20 22:54:27 +00:00
else :
2010-03-08 02:20:27 +00:00
self . rdoUnstratified . setChecked ( True )
self . rdoStratified . setEnabled ( False )
self . rdoDensity . setEnabled ( False )
self . rdoField . setEnabled ( False )
self . spnStratified . setEnabled ( False )
self . spnDensity . setEnabled ( False )
self . cmbField . setEnabled ( False )
self . label_4 . setEnabled ( False )
2009-01-20 22:54:27 +00:00
2010-05-13 22:55:59 +00:00
# when 'OK' button is pressed, gather required inputs, and initiate random points generation
2009-02-01 15:44:02 +00:00
def accept ( self ) :
2010-05-13 22:55:59 +00:00
self . buttonOk . setEnabled ( False )
2010-03-08 02:20:27 +00:00
if self . inShape . currentText ( ) == " " :
QMessageBox . information ( self , self . tr ( " Random Points " ) , self . tr ( " No input layer specified " ) )
elif self . outShape . text ( ) == " " :
QMessageBox . information ( self , self . tr ( " Random Points " ) , self . tr ( " Please specify output shapefile " ) )
else :
inName = self . inShape . currentText ( )
self . progressBar . setValue ( 1 )
outPath = self . outShape . text ( )
self . progressBar . setValue ( 2.5 )
if outPath . contains ( " \\ " ) :
outName = outPath . right ( ( outPath . length ( ) - outPath . lastIndexOf ( " \\ " ) ) - 1 )
else :
outName = outPath . right ( ( outPath . length ( ) - outPath . lastIndexOf ( " / " ) ) - 1 )
if outName . endsWith ( " .shp " ) :
outName = outName . left ( outName . length ( ) - 4 )
self . progressBar . setValue ( 5 )
2010-03-10 01:11:11 +00:00
mLayer = ftools_utils . getMapLayerByName ( unicode ( inName ) )
2010-03-08 02:20:27 +00:00
if mLayer . type ( ) == mLayer . VectorLayer :
inLayer = QgsVectorLayer ( unicode ( mLayer . source ( ) ) , unicode ( mLayer . name ( ) ) , unicode ( mLayer . dataProvider ( ) . name ( ) ) )
if self . rdoUnstratified . isChecked ( ) :
design = self . tr ( " unstratified " )
value = self . spnUnstratified . value ( )
elif self . rdoStratified . isChecked ( ) :
design = self . tr ( " stratified " )
value = self . spnStratified . value ( )
elif self . rdoDensity . isChecked ( ) :
design = self . tr ( " density " )
value = self . spnDensity . value ( )
else :
design = self . tr ( " field " )
value = unicode ( self . cmbField . currentText ( ) )
elif mLayer . type ( ) == mLayer . RasterLayer :
inLayer = QgsRasterLayer ( unicode ( mLayer . source ( ) ) , unicode ( mLayer . name ( ) ) )
design = self . tr ( " unstratified " )
value = self . spnUnstratified . value ( )
else :
QMessageBox . information ( self , self . tr ( " Random Points " ) , self . tr ( " Unknown layer type... " ) )
2010-11-21 22:33:42 +00:00
minimum = 0.00
2010-03-08 02:20:27 +00:00
self . progressBar . setValue ( 10 )
self . randomize ( inLayer , outPath , minimum , design , value )
self . progressBar . setValue ( 100 )
self . outShape . clear ( )
addToTOC = QMessageBox . question ( self , self . tr ( " Random Points " ) ,
self . tr ( " Created output point shapefile: \n % 1 \n \n Would you like to add the new layer to the TOC? " ) . arg ( outPath ) , QMessageBox . Yes , QMessageBox . No , QMessageBox . NoButton )
if addToTOC == QMessageBox . Yes :
self . vlayer = QgsVectorLayer ( outPath , unicode ( outName ) , " ogr " )
QgsMapLayerRegistry . instance ( ) . addMapLayer ( self . vlayer )
2011-11-12 13:05:27 +02:00
self . populateLayers ( )
2010-05-13 22:55:59 +00:00
self . progressBar . setValue ( 0 )
self . buttonOk . setEnabled ( True )
2009-02-01 15:44:02 +00:00
2009-01-20 22:54:27 +00:00
def outFile ( self ) :
2010-03-08 02:20:27 +00:00
self . outShape . clear ( )
( self . shapefileName , self . encoding ) = ftools_utils . saveDialog ( self )
if self . shapefileName is None or self . encoding is None :
return
self . outShape . setText ( QString ( self . shapefileName ) )
2011-07-29 19:57:22 +03:00
2010-05-13 22:55:59 +00:00
# combine all polygons in layer to create single polygon (slow for complex polygons)
2010-03-08 02:20:27 +00:00
def createSinglePolygon ( self , vlayer ) :
provider = vlayer . dataProvider ( )
allAttrs = provider . attributeIndexes ( )
provider . select ( allAttrs )
feat = QgsFeature ( )
geom = QgsGeometry ( )
2010-06-30 22:50:17 +00:00
#geom2 = QgsGeometry()
2010-03-08 02:20:27 +00:00
provider . nextFeature ( feat )
2010-06-30 22:50:17 +00:00
geom = QgsGeometry ( feat . geometry ( ) )
2010-03-08 02:20:27 +00:00
count = 10.00
add = ( 40.00 - 10.00 ) / provider . featureCount ( )
2010-06-30 22:50:17 +00:00
#provider.rewind()
#provider.nextFeature(feat)
#geom = QgsGeometry(feat.geometry())
2010-03-08 02:20:27 +00:00
while provider . nextFeature ( feat ) :
geom = geom . combine ( QgsGeometry ( feat . geometry ( ) ) )
count = count + add
self . progressBar . setValue ( count )
return geom
2011-07-29 19:57:22 +03:00
2010-05-13 22:55:59 +00:00
# Generate list of random points
2009-01-20 22:54:27 +00:00
def simpleRandom ( self , n , bound , xmin , xmax , ymin , ymax ) :
2010-03-08 02:20:27 +00:00
seed ( )
points = [ ]
i = 1
count = 40.00
2011-07-29 19:57:22 +03:00
if n == 0 :
return [ ]
2010-03-08 02:20:27 +00:00
add = ( 70.00 - 40.00 ) / n
while i < = n :
pGeom = QgsGeometry ( ) . fromPoint ( QgsPoint ( xmin + ( xmax - xmin ) * random ( ) , ymin + ( ymax - ymin ) * random ( ) ) )
if pGeom . intersects ( bound ) :
points . append ( pGeom )
i = i + 1
count = count + add
self . progressBar . setValue ( count )
return points
2009-01-20 22:54:27 +00:00
2010-06-30 22:50:17 +00:00
def vectorRandom ( self , n , layer , xmin , xmax , ymin , ymax ) :
provider = layer . dataProvider ( )
provider . select ( [ ] )
index = ftools_utils . createIndex ( provider )
seed ( )
points = [ ]
feat = QgsFeature ( )
i = 1
count = 40.00
add = ( 70.00 - 40.00 ) / n
while i < = n :
point = QgsPoint ( xmin + ( xmax - xmin ) * random ( ) , ymin + ( ymax - ymin ) * random ( ) )
pGeom = QgsGeometry ( ) . fromPoint ( point )
ids = index . intersects ( pGeom . buffer ( 5 , 5 ) . boundingBox ( ) )
for id in ids :
provider . featureAtId ( int ( id ) , feat , True )
tGeom = QgsGeometry ( feat . geometry ( ) )
if pGeom . intersects ( tGeom ) :
points . append ( pGeom )
i = i + 1
count = count + add
self . progressBar . setValue ( count )
break
return points
2010-03-08 02:20:27 +00:00
def randomize ( self , inLayer , outPath , minimum , design , value ) :
outFeat = QgsFeature ( )
if design == self . tr ( " unstratified " ) :
ext = inLayer . extent ( )
2010-06-30 22:50:17 +00:00
if inLayer . type ( ) == inLayer . RasterLayer :
points = self . simpleRandom ( int ( value ) , ext , ext . xMinimum ( ) ,
ext . xMaximum ( ) , ext . yMinimum ( ) , ext . yMaximum ( ) )
else :
points = self . vectorRandom ( int ( value ) , inLayer ,
ext . xMinimum ( ) , ext . xMaximum ( ) , ext . yMinimum ( ) , ext . yMaximum ( ) )
2010-03-08 02:20:27 +00:00
else : points = self . loopThruPolygons ( inLayer , value , design )
2011-11-12 13:05:27 +02:00
crs = self . iface . mapCanvas ( ) . mapRenderer ( ) . destinationSrs ( )
2010-03-08 02:20:27 +00:00
if not crs . isValid ( ) : crs = None
fields = { 0 : QgsField ( " ID " , QVariant . Int ) }
check = QFile ( self . shapefileName )
if check . exists ( ) :
if not QgsVectorFileWriter . deleteShapeFile ( self . shapefileName ) :
return
writer = QgsVectorFileWriter ( self . shapefileName , self . encoding , fields , QGis . WKBPoint , crs )
idVar = 0
count = 70.00
add = ( 100.00 - 70.00 ) / len ( points )
for i in points :
outFeat . setGeometry ( i )
outFeat . addAttribute ( 0 , QVariant ( idVar ) )
writer . addFeature ( outFeat )
idVar = idVar + 1
count = count + add
self . progressBar . setValue ( count )
del writer
2011-07-29 19:57:22 +03:00
#
2010-03-08 02:20:27 +00:00
def loopThruPolygons ( self , inLayer , numRand , design ) :
sProvider = inLayer . dataProvider ( )
sAllAttrs = sProvider . attributeIndexes ( )
sProvider . select ( sAllAttrs )
sFeat = QgsFeature ( )
sGeom = QgsGeometry ( )
sPoints = [ ]
2010-06-30 22:54:16 +00:00
if design == self . tr ( " field " ) :
2010-03-08 02:20:27 +00:00
for ( i , attr ) in sProvider . fields ( ) . iteritems ( ) :
2010-06-30 22:54:16 +00:00
if ( unicode ( numRand ) == attr . name ( ) ) :
index = i #get input field index
break
2010-03-08 02:20:27 +00:00
count = 10.00
add = 60.00 / sProvider . featureCount ( )
while sProvider . nextFeature ( sFeat ) :
sGeom = sFeat . geometry ( )
if design == self . tr ( " density " ) :
sDistArea = QgsDistanceArea ( )
value = int ( round ( numRand * sDistArea . measure ( sGeom ) ) )
elif design == self . tr ( " field " ) :
sAtMap = sFeat . attributeMap ( )
value = sAtMap [ index ] . toInt ( ) [ 0 ]
else :
value = numRand
sExt = sGeom . boundingBox ( )
sPoints . extend ( self . simpleRandom ( value , sGeom , sExt . xMinimum ( ) , sExt . xMaximum ( ) , sExt . yMinimum ( ) , sExt . yMaximum ( ) ) )
count = count + add
self . progressBar . setValue ( count )
return sPoints