def run(self): # set dialog widgets self.dlg.ls_layers.clear() self.dlg.buttonBox.button(QDialogButtonBox.Ok).setDisabled(True) has_selected_features = False # check if an active layer exists active_layer_name = '' if self.iface.activeLayer() is not None: active_layer_name = self.iface.activeLayer().name() # all vector layers get added to the list for index, layer in enumerate(self.iface.legendInterface().layers()): if layer.type() == QgsMapLayer.VectorLayer: # if there are selected features toggle has_selected_features if layer.selectedFeatureCount(): has_selected_features = True self.dlg.ls_layers.addItem(layer.name()) # select the active layer by default if layer.name() == active_layer_name: self.dlg.ls_layers.setCurrentRow(index) # if at least one vector layer has selected features enable checkbutton cb_selected_only if has_selected_features: self.dlg.cb_selected_only.setEnabled(True) self.dlg.cb_selected_only.setChecked(True) else: self.dlg.cb_selected_only.setChecked(False) self.dlg.cb_selected_only.setEnabled(False) # initialize cb_output # remember the layer being selected the last time last_index = self.dlg.cb_output.currentText() # populate the combo box with the polygon layers listed in the current legend self.set_output_layer_combobox(2, last_index) # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result == 1: geom = [] # read selected list entries and get the map layer for layer_name in self.dlg.ls_layers.selectedItems(): active_layer = QgsMapLayerRegistry.instance().mapLayersByName( layer_name.text())[0] # get all or the currently selected features according to state of cb_selected_only # convert each feature to points if active_layer.selectedFeatureCount( ) and self.dlg.cb_selected_only.checkState(): for feat in active_layer.selectedFeatures(): geom.extend(extract_points(feat.geometry())) else: for feat in active_layer.getFeatures(): geom.extend(extract_points(feat.geometry())) num_points = len(geom) if num_points == 0: return None # Send WARNING to the message bar to inform about a probably long running time if num_points > 1000: msg = self.msg_bar.createMessage( u'Please be patient, processing of more then {} points may take a while' .format(int(num_points))) self.msg_bar.pushWidget(msg, QgsMessageBar.WARNING, 2) # if more then 5000 points ask user to confirm if num_points > 5000: proceed = QMessageBox.question( None, 'Please confirm', 'Do you really want to proceed?', QMessageBox.Yes | QMessageBox.No) if proceed == QMessageBox.No: QApplication.instance().setOverrideCursor(Qt.ArrowCursor) return None # change cursor to inform user about ongoing processing QApplication.instance().setOverrideCursor(Qt.BusyCursor) # generate the hull geometry # process points with prior clustering hull_list = [] if self.dlg.gb_clustering.isChecked(): clusters = SSNClusters( geom, self.dlg.sb_neighborhood_list_size.value()).get_clusters() for cluster in clusters.keys(): the_hull = concave_hull(clusters[cluster], self.dlg.sb_neighbors.value()) if the_hull: hull_list.append( [as_polygon(the_hull), len(clusters[cluster])]) else: # process points without clustering the_hull = concave_hull(geom, self.dlg.sb_neighbors.value()) hull_list.append([as_polygon(the_hull), len(geom)]) # write hull geometries to output device success = self.create_output_feature(hull_list) # report result in QGIS message bar if success: msg = self.msg_bar.createMessage( _translate( 'ConcaveHull', '{} Concave hulls created successfully'.format( int(len(hull_list))), None)) self.msg_bar.pushWidget(msg, QgsMessageBar.INFO, 5) # reset cursor QApplication.instance().setOverrideCursor(Qt.ArrowCursor) return None
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue( self.INPUT)) SELECTED_ONLY = self.getParameterValue(self.SELECTED_ONLY) kneighbors = int(self.getParameterValue(self.KNEIGHBORS)) use_field = self.getParameterValue(self.METHOD) == 1 field_name = self.getParameterValue(self.FIELD) # temporarily alter the processing environment old_setting = ProcessingConfig.getSetting( ProcessingConfig.USE_SELECTED) ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, SELECTED_ONLY) # get properties of the field the grouping is based on if use_field: field = QgsField(field_name) field.setType(QVariant.String) field.setLength(255) index = layer.fieldNameIndex(field_name) field_type = layer.pendingFields()[index].type() if field_type == QVariant.Int: field.setType(QVariant.Int) field.setLength(20) elif field_type == QVariant.Double: field.setType(QVariant.Double) field.setLength(20) field.setPrecision(6) else: field.setType(QVariant.String) field.setLength(255) fields = [QgsField('clusterId', QVariant.Int, '', 20), field] else: # setup the fields of the output layer fields = [QgsField('clusterId', QVariant.Int, '', 20)] #fields.extend(layer.pendingFields().toList()) # initialize writer writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPoint, layer.crs()) current = 0 fid = 1 if use_field: # get unique values of field denoted by index as filter conditions unique_values = layer.uniqueValues(index) total = 100.0 / float(layer.featureCount() * len(unique_values)) for unique in unique_values: points = [] first = True features = vector.features(layer) for in_feature in features: value = in_feature[field_name] if value == unique: if first: val = unique first = False points.extend( vector.extractPoints( QgsGeometry(in_feature.geometry()))) current += 1 progress.setPercentage(int(current * total)) # A minimum of 3 points is necessary to proceed if len(points) >= 3: out_feature = QgsFeature() try: clusters = SSNClusters(points, kneighbors).get_clusters() for cluster in clusters.keys(): #mpoint = QgsGeometry.fromMultiPoint([QgsPoint(point[0], point[1]) for point in clusters[cluster]]) for member in clusters[cluster]: point = QgsGeometry.fromPoint( QgsPoint(member[0], member[1])) out_feature.setGeometry(point) out_feature.setAttributes([fid, val]) writer.addFeature(out_feature) fid += 1 except: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, 'Exception while computing clusters.') raise GeoAlgorithmExecutionException( 'Exception while computing clusters.') finally: ProcessingConfig.setSettingValue( ProcessingConfig.USE_SELECTED, old_setting) else: points = [] features = vector.features(layer) total = 100.0 / float(len(features)) for in_feature in features: ##points.append(in_feature.geometry().asPoint()) points.extend( vector.extractPoints(QgsGeometry(in_feature.geometry()))) current += 1 progress.setPercentage(int(current * total)) out_feature = QgsFeature() try: clusters = SSNClusters(points, kneighbors).get_clusters() for cluster in clusters.keys(): #mpoint = QgsGeometry.fromMultiPoint([QgsPoint(point[0], point[1]) for point in clusters[cluster]]) for member in clusters[cluster]: point = QgsGeometry.fromPoint( QgsPoint(member[0], member[1])) out_feature.setGeometry(point) out_feature.setAttributes([cluster]) writer.addFeature(out_feature) except: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, 'Exception while computing clusters.') raise GeoAlgorithmExecutionException( 'Exception while computing clusters') finally: ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, old_setting) del writer