~ubuntu-branches/ubuntu/wily/qgis/wily

« back to all changes in this revision

Viewing changes to python/plugins/fTools/tools/doRandPoints.py

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#-----------------------------------------------------------
 
2
 
3
# Generate Random Points
 
4
#
 
5
# A QGIS plugin for generating a simple random points
 
6
# shapefile. 
 
7
#
 
8
# Copyright (C) 2008  Carson Farmer
 
9
#
 
10
# EMAIL: carson.farmer (at) gmail.com
 
11
# WEB  : www.geog.uvic.ca/spar/carson
 
12
#
 
13
#-----------------------------------------------------------
 
14
 
15
# licensed under the terms of GNU GPL 2
 
16
 
17
# This program is free software; you can redistribute it and/or modify
 
18
# it under the terms of the GNU General Public License as published by
 
19
# the Free Software Foundation; either version 2 of the License, or
 
20
# (at your option) any later version.
 
21
 
22
# This program is distributed in the hope that it will be useful,
 
23
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
24
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
25
# GNU General Public License for more details.
 
26
 
27
# You should have received a copy of the GNU General Public License along
 
28
# with this program; if not, write to the Free Software Foundation, Inc.,
 
29
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
30
 
31
#---------------------------------------------------------------------
 
32
 
 
33
from PyQt4.QtCore import *
 
34
from PyQt4.QtGui import *
 
35
 
 
36
from qgis.core import *
 
37
from random import *
 
38
import math, ftools_utils
 
39
from ui_frmRandPoints import Ui_Dialog
 
40
 
 
41
class Dialog(QDialog, Ui_Dialog):
 
42
    def __init__(self, iface):
 
43
        QDialog.__init__(self)
 
44
        self.iface = iface
 
45
        self.setupUi(self)
 
46
        QObject.connect(self.toolOut, SIGNAL("clicked()"), self.outFile)
 
47
        QObject.connect(self.inShape, SIGNAL("currentIndexChanged(QString)"), self.update)
 
48
        self.progressBar.setValue(0)
 
49
        self.setWindowTitle("Random points")
 
50
        mapCanvas = self.iface.mapCanvas()
 
51
        for i in range(mapCanvas.layerCount()):
 
52
            layer = mapCanvas.layer(i)
 
53
            if (layer.type() == layer.VectorLayer and layer.geometryType() == QGis.Polygon) or layer.type() == layer.RasterLayer:
 
54
                self.inShape.addItem(layer.name())
 
55
 
 
56
# If input layer is changed, update field list                          
 
57
    def update(self, inputLayer):
 
58
        self.cmbField.clear()
 
59
        changedLayer = self.getMapLayerByName(inputLayer)
 
60
        if changedLayer.type() == changedLayer.VectorLayer:
 
61
                self.rdoStratified.setEnabled(True)
 
62
                self.rdoDensity.setEnabled(True)
 
63
                self.rdoField.setEnabled(True)
 
64
                self.label_4.setEnabled(True)
 
65
                changedLayer = self.getVectorLayerByName(inputLayer)
 
66
                changedFields = self.getFieldList(changedLayer)
 
67
                for i in changedFields:
 
68
                        self.cmbField.addItem(unicode(changedFields[i].name()))
 
69
        else:
 
70
                self.rdoUnstratified.setChecked(True)
 
71
                self.rdoStratified.setEnabled(False)
 
72
                self.rdoDensity.setEnabled(False)
 
73
                self.rdoField.setEnabled(False)
 
74
                self.spnStratified.setEnabled(False)
 
75
                self.spnDensity.setEnabled(False)
 
76
                self.cmbField.setEnabled(False)
 
77
                self.label_4.setEnabled(False)
 
78
 
 
79
# when 'OK' button is pressed, gather required inputs, and initiate random points generation            
 
80
    def accept(self):
 
81
        if self.inShape.currentText() == "":
 
82
            QMessageBox.information(self, "Random Points", "No input layer specified")
 
83
        elif self.outShape.text() == "":
 
84
            QMessageBox.information(self, "Random Points", "Please specify output shapefile")
 
85
        else:
 
86
                inName = self.inShape.currentText()
 
87
                self.progressBar.setValue(1)
 
88
                outPath = self.outShape.text()
 
89
                self.progressBar.setValue(2.5)
 
90
                if outPath.contains("\\"):
 
91
                        outName = outPath.right((outPath.length() - outPath.lastIndexOf("\\")) - 1)
 
92
                else:
 
93
                        outName = outPath.right((outPath.length() - outPath.lastIndexOf("/")) - 1)
 
94
                if outName.endsWith(".shp"):
 
95
                        outName = outName.left(outName.length() - 4)
 
96
                self.progressBar.setValue(5)
 
97
                mLayer = self.getMapLayerByName(unicode(inName))
 
98
                if mLayer.type() == mLayer.VectorLayer:
 
99
                        inLayer = QgsVectorLayer(unicode(mLayer.source(),'latin1'),  unicode(mLayer.name(),'latin1'),  unicode(mLayer.dataProvider().name()))
 
100
                        if self.rdoUnstratified.isChecked():
 
101
                                design = "unstratified"
 
102
                                value = self.spnUnstratified.value()
 
103
                        elif self.rdoStratified.isChecked():
 
104
                                design = "stratified"
 
105
                                value = self.spnStratified.value()
 
106
                        elif self.rdoDensity.isChecked():
 
107
                                design = "density"
 
108
                                value = self.spnDensity.value()
 
109
                        else:
 
110
                                design = "field"
 
111
                                value = unicode(self.cmbField.currentText())
 
112
                elif mLayer.type() == mLayer.RasterLayer:
 
113
                        inLayer = QgsRasterLayer(unicode(mLayer.source(),'latin1'), unicode(mLayer.name(),'latin1'))
 
114
                        design = "unstratified"
 
115
                        value = self.spnUnstratified.value()
 
116
                else:
 
117
                        QMessageBox.information(self, "Random Points", "Unknown layer type...")
 
118
                if self.chkMinimum.isChecked():
 
119
                        minimum = self.spnMinimum.value()
 
120
                else:
 
121
                        minimum = 0.00
 
122
                self.progressBar.setValue(10)
 
123
                self.randomize(inLayer, outPath, minimum, design, value, self.progressBar)
 
124
                self.progressBar.setValue(100)
 
125
                self.outShape.clear()
 
126
                addToTOC = QMessageBox.question(self, "Random Points", "Created output point Shapefile:\n" + outPath 
 
127
                        + "\n\nWould you like to add the new layer to the TOC?", QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton)
 
128
                if addToTOC == QMessageBox.Yes:
 
129
                        self.vlayer = QgsVectorLayer(outPath, unicode(outName), "ogr")
 
130
                        QgsMapLayerRegistry.instance().addMapLayer(self.vlayer)
 
131
                self.progressBar.setValue(0)            
 
132
 
 
133
    def outFile(self):
 
134
                self.outShape.clear()
 
135
                ( self.shapefileName, self.encoding ) = ftools_utils.saveDialog( self )
 
136
                if self.shapefileName is None or self.encoding is None:
 
137
                        return
 
138
                self.outShape.setText( QString( self.shapefileName ) )
 
139
                        
 
140
# combine all polygons in layer to create single polygon (slow for complex polygons)     
 
141
    def createSinglePolygon(self, vlayer, progressBar):
 
142
                provider = vlayer.dataProvider()
 
143
                allAttrs = provider.attributeIndexes()
 
144
                provider.select(allAttrs)
 
145
                feat = QgsFeature()
 
146
                geom = QgsGeometry()
 
147
                geom2 = QgsGeometry()
 
148
                provider.nextFeature(feat)
 
149
                geom = feat.geometry()
 
150
                count = 10.00
 
151
                add = 40.00 / provider.featureCount()
 
152
                provider.rewind()
 
153
                provider.nextFeature(feat)
 
154
                geom = QgsGeometry(feat.geometry())
 
155
                while provider.nextFeature(feat):
 
156
                        geom = geom.combine(QgsGeometry( feat.geometry() ))
 
157
                        count = count + add
 
158
                        progressBar.setValue(count)
 
159
                return geom
 
160
        
 
161
# Generate list of random points     
 
162
    def simpleRandom(self, n, bound, xmin, xmax, ymin, ymax):
 
163
                seed()
 
164
                points = []
 
165
                i = 1
 
166
                while i <= n:
 
167
                        pGeom = QgsGeometry().fromPoint(QgsPoint(xmin + (xmax-xmin) * random(), ymin + (ymax-ymin) * random()))
 
168
                        if pGeom.intersects(bound):
 
169
                                points.append(pGeom)
 
170
                                i = i + 1
 
171
                return points
 
172
        
 
173
# Get vector layer by name from TOC     
 
174
    def getVectorLayerByName(self, myName):
 
175
                mc = self.iface.mapCanvas()
 
176
                nLayers = mc.layerCount()
 
177
                for l in range(nLayers):
 
178
                        layer = mc.layer(l)
 
179
                        if layer.name() == unicode(myName):
 
180
                                vlayer = QgsVectorLayer(unicode(layer.source()),  unicode(myName),  unicode(layer.dataProvider().name()))
 
181
                                if vlayer.isValid():
 
182
                                        return vlayer
 
183
                                else:
 
184
                                        QMessageBox.information(self, "Generate Centroids", "Vector layer is not valid")
 
185
        
 
186
# Get map layer by name from TOC     
 
187
    def getMapLayerByName(self, myName):
 
188
        mc = self.iface.mapCanvas()
 
189
        nLayers = mc.layerCount()
 
190
        for l in range(nLayers):
 
191
                layer = mc.layer(l)
 
192
                if layer.name() == unicode(myName):
 
193
                        if layer.isValid():
 
194
                                return layer
 
195
# Retrieve the field map of a vector Layer
 
196
    def getFieldList(self, vlayer):
 
197
        fProvider = vlayer.dataProvider()
 
198
        feat = QgsFeature()
 
199
        allAttrs = fProvider.attributeIndexes()
 
200
        fProvider.select(allAttrs)
 
201
        myFields = fProvider.fields()
 
202
        return myFields
 
203
        
 
204
 
 
205
    def randomize(self, inLayer, outPath, minimum, design, value, progressBar):
 
206
                outFeat = QgsFeature()
 
207
                if design == "unstratified":
 
208
                        ext = inLayer.extent()
 
209
                        if inLayer.type() == inLayer.RasterLayer: bound = ext
 
210
                        else: bound = self.createSinglePolygon(inLayer, progressBar)
 
211
                        points = self.simpleRandom(int(value), bound, ext.xMinimum(), ext.xMaximum(), ext.yMinimum(), ext.yMaximum())
 
212
                        progressBar.setValue(70)
 
213
                else: points = self.loopThruPolygons(inLayer, value, design, progressBar)
 
214
 
 
215
                fields = { 0 : QgsField("ID", QVariant.Int) }
 
216
                check = QFile(self.shapefileName)
 
217
                if check.exists():
 
218
                        if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName):
 
219
                                return
 
220
                writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fields, QGis.WKBPoint, None)
 
221
                idVar = 0
 
222
                count = 70.00
 
223
                add = 30.00 / len(points)
 
224
                for i in points:
 
225
                        outFeat.setGeometry(i)
 
226
                        outFeat.addAttribute(0, QVariant(idVar))
 
227
                        writer.addFeature(outFeat)
 
228
                        idVar = idVar + 1
 
229
                        count = count + add
 
230
                        progressBar.setValue(count)
 
231
                del writer
 
232
        
 
233
#   
 
234
    def loopThruPolygons(self, inLayer, numRand, design, progressBar):
 
235
                sProvider = inLayer.dataProvider()
 
236
                sAllAttrs = sProvider.attributeIndexes()
 
237
                sProvider.select(sAllAttrs)
 
238
                sFeat = QgsFeature()
 
239
                sGeom = QgsGeometry()
 
240
                sPoints = []
 
241
                if design == "field":
 
242
                        for (i, attr) in sProvider.fields().iteritems():
 
243
                                if (unicode(numRand) == attr.name()): index = i #get input field index
 
244
                count = 10.00
 
245
                add = 60.00 / sProvider.featureCount()
 
246
                while sProvider.nextFeature(sFeat):
 
247
                        sGeom = sFeat.geometry()
 
248
                        if design == "density":
 
249
                                sDistArea = QgsDistanceArea()
 
250
                                value = int(round(numRand * sDistArea.measure(sGeom)))
 
251
                        elif design == "field":
 
252
                                sAtMap = sFeat.attributeMap()
 
253
                                value = sAtMap[index].toInt()[0]
 
254
                        else:
 
255
                                value = numRand
 
256
                        sExt = sGeom.boundingBox()
 
257
                        sPoints.extend(self.simpleRandom(value, sGeom, sExt.xMinimum(), sExt.xMaximum(), sExt.yMinimum(), sExt.yMaximum()))
 
258
                        count = count + add
 
259
                        progressBar.setValue(count)
 
260
                return sPoints