@@ -39,11 +39,13 @@ class Dialog(QDialog, Ui_Dialog):
3939 def __init__ (self , iface ):
4040 QDialog .__init__ (self , iface .mainWindow ())
4141 self .iface = iface
42- # Set up the user interface from Designer.
4342 self .setupUi (self )
44- QObject . connect ( self . toolOut , SIGNAL ( "clicked()" ), self . outFile )
43+
4544 self .setWindowTitle (self .tr ("Count Points in Polygon" ))
46- self .buttonOk = self .buttonBox_2 .button ( QDialogButtonBox .Ok )
45+ self .btnOk = self .buttonBox .button ( QDialogButtonBox .Ok )
46+ self .btnClose = self .buttonBox .button ( QDialogButtonBox .Close )
47+
48+ QObject .connect (self .toolOut , SIGNAL ("clicked()" ), self .outFile )
4749 self .progressBar .setValue (0 )
4850 self .populateLayers ()
4951
@@ -56,93 +58,193 @@ def populateLayers( self ):
5658 layers = ftools_utils .getLayerNames ([QGis .Point ])
5759 self .inPoint .addItems (layers )
5860
61+ def outFile (self ):
62+ self .outShape .clear ()
63+ (self .shapefileName , self .encoding ) = ftools_utils .saveDialog (self )
64+ if self .shapefileName is None or self .encoding is None :
65+ return
66+ self .outShape .setText (QString (self .shapefileName ))
67+
5968 def accept (self ):
60- self .buttonOk .setEnabled ( False )
6169 if self .inPolygon .currentText () == "" :
62- QMessageBox .information (self , self .tr ("Count Points In Polygon" ), self .tr ("Please specify input polygon vector layer" ))
63- elif self .outShape .text () == "" :
64- QMessageBox .information (self , self .tr ("Count Points In Polygon" ), self .tr ("Please specify output shapefile" ))
70+ QMessageBox .information (self , self .tr ("Count Points In Polygon" ),
71+ self .tr ("Please specify input polygon vector layer" ))
6572 elif self .inPoint .currentText () == "" :
66- QMessageBox .information (self , self .tr ("Count Points In Polygon" ), self .tr ("Please specify input point vector layer" ))
73+ QMessageBox .information (self , self .tr ("Count Points In Polygon" ),
74+ self .tr ("Please specify input point vector layer" ))
6775 elif self .lnField .text () == "" :
68- QMessageBox .information (self , self .tr ("Count Points In Polygon" ), self .tr ("Please specify output count field" ))
76+ QMessageBox .information (self , self .tr ("Count Points In Polygon" ),
77+ self .tr ("Please specify output count field" ))
78+ elif self .outShape .text () == "" :
79+ QMessageBox .information (self , self .tr ("Count Points In Polygon" ),
80+ self .tr ("Please specify output shapefile" ))
6981 else :
70- inPoly = self .inPolygon .currentText ()
71- inPts = self .inPoint .currentText ()
72- inField = self .lnField .text ()
73- outPath = self .outShape .text ()
74- if outPath .contains ("\\ " ):
75- outName = outPath .right ((outPath .length () - outPath .lastIndexOf ("\\ " )) - 1 )
76- else :
77- outName = outPath .right ((outPath .length () - outPath .lastIndexOf ("/" )) - 1 )
78- if outName .endsWith (".shp" ):
79- outName = outName .left (outName .length () - 4 )
80- self .compute (inPoly , inPts , inField , outPath , self .progressBar )
81- self .outShape .clear ()
82- addToTOC = QMessageBox .question (self , self .tr ("Count Points in Polygon" ), self .tr ("Created output shapefile:\n %1\n \n Would you like to add the new layer to the TOC?" ).arg (unicode (outPath )), QMessageBox .Yes , QMessageBox .No , QMessageBox .NoButton )
83- if addToTOC == QMessageBox .Yes :
84- self .vlayer = QgsVectorLayer (outPath , unicode (outName ), "ogr" )
85- QgsMapLayerRegistry .instance ().addMapLayer (self .vlayer )
86- self .populateLayers ()
82+ inPoly = ftools_utils .getVectorLayerByName (self .inPolygon .currentText ())
83+ inPnts = ftools_utils .getVectorLayerByName (self .inPoint .currentText ())
84+
85+ polyProvider = inPoly .dataProvider ()
86+ pointProvider = inPnts .dataProvider ()
87+ if polyProvider .crs () <> pointProvider .crs ():
88+ QMessageBox .warning (self , self .tr ("CRS warning!" ),
89+ self .tr ("Warning: Input layers have non-matching CRS.\n This may cause unexpected results." ))
90+
91+ self .btnOk .setEnabled (False )
92+
93+ self .workThread = PointsInPolygonThread (inPoly , inPnts , self .lnField .text (), self .outShape .text (), self .encoding )
94+
95+ QObject .connect (self .workThread , SIGNAL ("rangeChanged(int)" ), self .setProgressRange )
96+ QObject .connect (self .workThread , SIGNAL ("updateProgress()" ), self .updateProgress )
97+ QObject .connect (self .workThread , SIGNAL ("processingFinished()" ), self .processFinished )
98+ QObject .connect (self .workThread , SIGNAL ("processingInterrupted()" ), self .processInterrupted )
99+
100+ self .btnClose .setText (self .tr ("Cancel" ))
101+ QObject .disconnect (self .buttonBox , SIGNAL ("rejected()" ), self .reject )
102+ QObject .connect (self .btnClose , SIGNAL ("clicked()" ), self .stopProcessing )
103+
104+ self .workThread .start ()
105+
106+ def setProgressRange (self , maxValue ):
107+ self .progressBar .setRange (0 , maxValue )
87108 self .progressBar .setValue (0 )
88- self .buttonOk .setEnabled ( True )
89109
90- def outFile (self ):
110+ def updateProgress (self ):
111+ self .progressBar .setValue (self .progressBar .value () + 1 )
112+
113+ def processFinished (self ):
114+ self .stopProcessing ()
115+
116+ addToTOC = QMessageBox .question (self , self .tr ("Count Points in Polygon" ),
117+ self .tr ("Created output shapefile:\n %1\n \n Would you like to add the new layer to the TOC?" ).arg (self .outShape .text ()),
118+ QMessageBox .Yes , QMessageBox .No , QMessageBox .NoButton )
119+ if addToTOC == QMessageBox .Yes :
120+ fileInfo = QFileInfo ( self .outShape .text () )
121+ layerName = fileInfo .completeBaseName ()
122+ layer = QgsVectorLayer (self .outShape .text (), layerName , "ogr" )
123+ QgsMapLayerRegistry .instance ().addMapLayer (layer )
124+ self .populateLayers ()
125+
126+ self .restoreGui ()
127+
128+ def processInterrupted (self ):
129+ self .restoreGui ()
130+
131+ def stopProcessing (self ):
132+ if self .workThread != None :
133+ self .workThread .stop ()
134+ self .workThread = None
135+
136+ def restoreGui (self ):
137+ self .progressBar .setRange (0 , 1 )
138+ self .progressBar .setValue (0 )
91139 self .outShape .clear ()
92- ( self .shapefileName , self .encoding ) = ftools_utils .saveDialog ( self )
93- if self .shapefileName is None or self .encoding is None :
94- return
95- self .outShape .setText ( QString ( self .shapefileName ) )
96-
97- def compute (self , inPoly , inPts , inField , outPath , progressBar ):
98- polyLayer = ftools_utils .getVectorLayerByName (inPoly )
99- pointLayer = ftools_utils .getVectorLayerByName (inPts )
100- polyProvider = polyLayer .dataProvider ()
101- pointProvider = pointLayer .dataProvider ()
102- if polyProvider .crs () <> pointProvider .crs ():
103- QMessageBox .warning (self , self .tr ("CRS warning!" ), self .tr ("Warning: Input layers have non-matching CRS.\n This may cause unexpected results." ))
140+
141+ QObject .disconnect (self .btnClose , SIGNAL ("clicked()" ), self .stopProcessing )
142+ QObject .connect (self .buttonBox , SIGNAL ("rejected()" ), self .reject )
143+ self .btnClose .setText (self .tr ("Close" ))
144+ self .btnOk .setEnabled (True )
145+
146+ class PointsInPolygonThread (QThread ):
147+ def __init__ ( self , inPoly , inPoints , fieldName , outPath , encoding ):
148+ QThread .__init__ ( self , QThread .currentThread () )
149+ self .mutex = QMutex ()
150+ self .stopMe = 0
151+ self .interrupted = False
152+
153+ self .layerPoly = inPoly
154+ self .layerPoints = inPoints
155+ self .fieldName = fieldName
156+ self .outPath = outPath
157+ self .encoding = encoding
158+
159+ def run (self ):
160+ self .mutex .lock ()
161+ self .stopMe = 0
162+ self .mutex .unlock ()
163+
164+ interrupted = False
165+
166+ polyProvider = self .layerPoly .dataProvider ()
167+ pointProvider = self .layerPoints .dataProvider ()
168+
104169 allAttrs = polyProvider .attributeIndexes ()
105170 polyProvider .select (allAttrs )
106- allAttrs = pointProvider .attributeIndexes ()
107- pointProvider .select (allAttrs )
108- fieldList = ftools_utils .getFieldList (polyLayer )
109- index = polyProvider .fieldNameIndex (unicode (inField ))
171+
172+ fieldList = ftools_utils .getFieldList (self .layerPoly )
173+ index = polyProvider .fieldNameIndex (unicode (self .fieldName ))
110174 if index == - 1 :
111175 index = polyProvider .fieldCount ()
112- field = QgsField (unicode (inField ), QVariant .Double , "real" , 24 , 15 , self .tr ("point count field" ))
176+ field = QgsField (unicode (self . fieldName ), QVariant .Double , "real" , 24 , 15 , self .tr ("point count field" ))
113177 fieldList [index ] = field
178+
114179 sRs = polyProvider .crs ()
115- check = QFile (self .shapefileName )
116- if check .exists ():
117- if not QgsVectorFileWriter .deleteShapeFile (self .shapefileName ):
180+ if QFile (self .outPath ).exists ():
181+ if not QgsVectorFileWriter .deleteShapeFile (self .outPath ):
118182 return
119- writer = QgsVectorFileWriter (self .shapefileName , self .encoding , fieldList , polyProvider .geometryType (), sRs )
120- inFeat = QgsFeature ()
121- inFeatB = QgsFeature ()
183+
184+ writer = QgsVectorFileWriter (self .outPath , self .encoding , fieldList ,
185+ polyProvider .geometryType (), sRs )
186+
187+ spatialIndex = ftools_utils .createIndex ( pointProvider )
188+ pointProvider .rewind ()
189+ pointProvider .select ()
190+
191+ self .emit (SIGNAL ("rangeChanged(int)" ), polyProvider .featureCount () )
192+
193+ polyFeat = QgsFeature ()
194+ pntFeat = QgsFeature ()
122195 outFeat = QgsFeature ()
123196 inGeom = QgsGeometry ()
124- start = 15.00
125- add = 85.00 / polyProvider .featureCount ()
126- spatialIndex = ftools_utils .createIndex ( pointProvider )
127- while polyProvider .nextFeature (inFeat ):
128- inGeom = inFeat .geometry ()
129- atMap = inFeat .attributeMap ()
197+ while polyProvider .nextFeature (polyFeat ):
198+ inGeom = polyFeat .geometry ()
199+ atMap = polyFeat .attributeMap ()
130200 outFeat .setAttributeMap (atMap )
131201 outFeat .setGeometry (inGeom )
132- pointList = []
202+
133203 count = 0
204+ pointList = []
205+ hasIntersection = True
134206 pointList = spatialIndex .intersects (inGeom .boundingBox ())
135- if len (pointList ) > 0 : check = 0
136- else : check = 1
137- if check == 0 :
138- for i in pointList :
139- pointProvider .featureAtId ( int ( i ), inFeatB , True , allAttrs )
140- tmpGeom = QgsGeometry ( inFeatB .geometry () )
141- if inGeom .intersects ( tmpGeom ):
142- count = count + 1
143- outFeat .setAttributeMap (atMap )
207+ if len (pointList ) > 0 :
208+ hasIntersection = True
209+ else :
210+ hasIntersection = False
211+
212+ if hasIntersection :
213+ for p in pointList :
214+ pointProvider .featureAtId (p , pntFeat , True )
215+ tmpGeom = QgsGeometry (pntFeat .geometry ())
216+ if inGeom .intersects (tmpGeom ):
217+ count += 1
218+
219+ self .mutex .lock ()
220+ s = self .stopMe
221+ self .mutex .unlock ()
222+ if s == 1 :
223+ interrupted = True
224+ break
225+
144226 outFeat .addAttribute (index , QVariant (count ))
145227 writer .addFeature (outFeat )
146- start = start + 1
147- progressBar .setValue (start )
228+
229+ self .emit ( SIGNAL ( "updateProgress()" ) )
230+
231+ self .mutex .lock ()
232+ s = self .stopMe
233+ self .mutex .unlock ()
234+ if s == 1 :
235+ interrupted = True
236+ break
237+
148238 del writer
239+
240+ if not interrupted :
241+ self .emit ( SIGNAL ( "processingFinished()" ) )
242+ else :
243+ self .emit ( SIGNAL ( "processingInterrupted()" ) )
244+
245+ def stop (self ):
246+ self .mutex .lock ()
247+ self .stopMe = 1
248+ self .mutex .unlock ()
249+
250+ QThread .wait ( self )
0 commit comments