def get_connected_segments_by_selection(self, segment, direction, index, dict_features, items=list(), count_d=0, vertex=None): geom = segment.geometry() if vertex is None: if direction == 1: vertex = QgsGeometry(geom.vertexAt(0)) elif direction == -1: vertex = QgsGeometry(geom.vertexAt(len(geom.asPolyline()) - 1)) bbox = vertex.boundingBox() candidates_ids = index.intersects(bbox) candidate_features = [ dict_features[candidate_id] for candidate_id in candidates_ids ] touches = list() for candidate_feature in candidate_features: if candidate_feature.id() != segment.id(): if candidate_feature.geometry().touches(vertex): touches.append(candidate_feature) if len(touches) == 1: # select next vertex next_geom = touches[0].geometry() start_vertex = QgsGeometry(next_geom.vertexAt(0)) end_vertex = QgsGeometry( next_geom.vertexAt(len(next_geom.asPolyline()) - 1)) next_vertex = None if vertex.asWkt() == start_vertex.asWkt(): next_vertex = end_vertex else: next_vertex = start_vertex if touches[0].id() not in items: items.append(touches[0].id()) return self.get_connected_segments_by_selection( touches[0], direction, index, dict_features, items, count_d, next_vertex) else: if count_d < 1: # in circular geometries it can happen that the condition of exit is not satisfied, # reason for which the number of consecutive iterations is counted not to stay in an infinite cycle. count_d += 1 return self.get_connected_segments_by_selection( touches[0], direction, index, dict_features, items, count_d, next_vertex) else: return items else: return items
def findPlots(self): vl = self.layerComboBox.currentLayer() trans = QgsCoordinateTransform(vl.crs(), QgsCoordinateReferenceSystem(2180), QgsProject.instance()) if not self.selectCheckBox.isChecked(): geom = QgsGeometry().unaryUnion( [QgsGeometry(f.geometry()) for f in vl.getFeatures()]) geom.transform(trans) if geom.isEmpty(): self.iface.messageBar().pushMessage( 'Przeciecia LPIS', u'Brak obiektów na warstwie', level=Qgis.Warning) return False else: geom = QgsGeometry().unaryUnion( [QgsGeometry(f.geometry()) for f in vl.selectedFeatures()]) geom.transform(trans) if geom.isEmpty(): self.iface.messageBar().pushMessage( 'Przeciecia LPIS', u'Brak zaznaczonych obiektów', level=Qgis.Warning) return False params = {'wkt': geom.asWkt(), 'key': self.keyLineEdit.text().strip()} data = '' try: r = urllib.request.urlopen( 'http://api.gis-support.pl/intersect?key=' + params['key'], json.dumps(params).encode('utf-8')) if r.getcode() == 403: self.iface.messageBar().pushMessage( u'Przecięcia LPIS', u'Nieprawidłowy klucz GIS Support', level=Qgis.Critical) return False resp = json.loads(r.read().decode()) data = resp['data'] except: data = 'app connection problem' if not data: self.iface.messageBar().pushMessage( u'Przecięcia LPIS', u'Warstwa nie przecina żadnej działki', level=Qgis.Warning) elif data == 'db connection problem': self.iface.messageBar().pushMessage(u'Przecięcia LPIS', u'Problem połączenia z bazą', level=Qgis.Critical) elif data == 'app connection problem': self.iface.messageBar().pushMessage( u'Przecięcia LPIS', u'Problem połączenia z aplikacją', level=Qgis.Critical) else: self.createOutputLayer(resp) return True return False
def set_snap_geometry(self, geom: QgsGeometry): ''' snap lines to outline of given geometry Parameters ---------- snap_geometry : QgsGeometry geometry to snap lines to ''' if not geom: return if SHAPELY_LOADED: self.snap_geometry = wkt.loads(geom.asWkt()).boundary # alternative for MacOS else: self.snap_geometry = QgsCurvePolygon() self.snap_geometry.fromWkt(geom.asWkt())
def getRings(self, geometry): rings = [] # TODO: remove when the error is resolved # Error: The expected object type is a QgsCurvePolygon but it receives a QgsPoint, however the WKT of the # QgsPoint corresponds to either a QgsPolygon or QgsMultiPolygon (yeap, it must be a bug in QGIS) if type(geometry) == QgsPoint or type(geometry) == QgsLineString: geom = QgsGeometry().fromWkt(geometry.asWkt()) curve = None if geom.isMultipart(): curve = QgsMultiPolygon() curve.fromWkt(geom.asWkt()) else: curve = QgsPolygon() curve.fromWkt(geom.asWkt()) geometry = curve.toCurveType() if isinstance(geometry, QgsGeometryCollection): # collection for i in range(geometry.numGeometries()): if QgsWkbTypes.geometryType(geometry.geometryN( i).wkbType()) == QgsWkbTypes.PolygonGeometry: rings.extend(self.getRings(geometry.geometryN(i))) else: # Converts geometry to curve, because exteriorRing is a method from curve polygons if isinstance(geometry, QgsPolygon): geom = geometry.toCurveType() geometry = geom # not collection rings.append(geometry.exteriorRing().clone()) for i in range(geometry.numInteriorRings()): rings.append(geometry.interiorRing(i).clone()) return rings
def set_user_extent(self, extent, crs): """Setter for the user requested extent. This function will redraw the rubberband if needed. :param extent: The user extent. :type extent: QgsGeometry :param crs: The CRS of the extent. :type crs: QgsCoordinateReferenceSystem """ extent = QgsGeometry(extent) transform = QgsCoordinateTransform(crs, self.crs, QgsProject.instance()) extent.transform(transform) self._user_extent = extent set_setting('user_extent', extent.asWkt()) set_setting('user_extent_crs', crs.authid()) if self._show_rubber_bands: self.display_user_extent()
def set_user_extent(self, extent, crs): """Setter for the user requested extent. This function will redraw the rubberband if needed. :param extent: The user extent. :type extent: QgsGeometry :param crs: The CRS of the extent. :type crs: QgsCoordinateReferenceSystem """ extent = QgsGeometry(extent) transform = QgsCoordinateTransform( crs, self.crs, QgsProject.instance()) extent.transform(transform) self._user_extent = extent set_setting('user_extent', extent.asWkt()) set_setting('user_extent_crs', crs.authid()) if self._show_rubber_bands: self.display_user_extent()
def onGeometryChanged(self, currRestriction): # Added by TH to deal with RestrictionsInProposals # When a geometry is changed; we need to check whether or not the feature is part of the current proposal QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. fid: " + str(currRestriction.id()) + " GeometryID: " + str(currRestriction.attribute("GeometryID")), tag="TOMs panel") # disconnect signal for geometryChanged #self.origLayer.geometryChanged.disconnect(self.on_cached_geometry_changed) #self.proposalsManager.TOMsToolChanged.disconnect() #self.currLayer = self.iface.activeLayer() QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. Layer: " + str(self.origLayer.name()), tag="TOMs panel") #currLayer.geometryChanged.disconnect(self.onGeometryChanged) #QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. geometryChange signal disconnected.", tag="TOMs panel") idxRestrictionID = self.origLayer.fields().indexFromName("RestrictionID") QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. currProposal: " + str(self.proposalsManager.currentProposal()), tag="TOMs panel") # Now obtain the changed feature (not sure which geometry) #currFeature = self.THgetFeature(fid, currLayer) #self.origFeature.printFeature() #currFeature = currRestriction newGeometry = QgsGeometry(self.feature_band.asGeometry()) QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - newGeom incoming: " + newGeometry.asWkt(), tag="TOMs panel") QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. currRestrictionID: " + str(currRestriction[idxRestrictionID]), tag="TOMs panel") if not self.restrictionInProposal(currRestriction[idxRestrictionID], self.getRestrictionLayerTableID(self.origLayer), self.proposalsManager.currentProposal()): QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - adding details to RestrictionsInProposal", tag="TOMs panel") # This one is not in the current Proposal, so now we need to: # - generate a new ID and assign it to the feature for which the geometry has changed # - switch the geometries arround so that the original feature has the original geometry and the new feature has the new geometry # - add the details to RestrictionsInProposal originalfeature = self.origFeature.getFeature() newFeature = QgsFeature(self.origLayer.fields()) newFeature.setAttributes(currRestriction.attributes()) newFeature.setGeometry(newGeometry) newRestrictionID = str(uuid.uuid4()) newFeature[idxRestrictionID] = newRestrictionID idxOpenDate = self.origLayer.fields().indexFromName("OpenDate") idxGeometryID = self.origLayer.fields().indexFromName("GeometryID") newFeature[idxOpenDate] = None newFeature[idxGeometryID] = None #currLayer.addFeature(newFeature) self.origLayer.addFeatures([newFeature]) QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - attributes: " + str(newFeature.attributes()), tag="TOMs panel") QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - newGeom: " + newFeature.geometry().asWkt(), tag="TOMs panel") originalGeomBuffer = QgsGeometry(originalfeature.geometry()) QgsMessageLog.logMessage( "In TOMsNodeTool:onGeometryChanged - originalGeom: " + originalGeomBuffer.asWkt(), tag="TOMs panel") self.origLayer.changeGeometry(currRestriction.id(), originalGeomBuffer) QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - geometries switched.", tag="TOMs panel") self.addRestrictionToProposal(currRestriction[idxRestrictionID], self.getRestrictionLayerTableID(self.origLayer), self.proposalsManager.currentProposal(), RestrictionAction.OPEN) # close the original feature QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - feature closed.", tag="TOMs panel") self.addRestrictionToProposal(newRestrictionID, self.getRestrictionLayerTableID(self.origLayer), self.proposalsManager.currentProposal(), RestrictionAction.OPEN) # open the new one QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - feature opened.", tag="TOMs panel") #self.proposalsManager.updateMapCanvas() else: # assign the changed geometry to the current feature #currRestriction.setGeometry(newGeometry) pass QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - newGeom (2): " + currRestriction.geometry().asWkt(), tag="TOMs panel") # Trying to unset map tool to force updates ... #self.iface.mapCanvas().unsetMapTool(self.iface.mapCanvas().mapTool()) #currMapTool = self.iface.mapCanvas().mapTool() #currAction = currMapTool.action() #currMapToolAction = self.iface.mapCanvas().mapTool().action().setChecked(False) # uncheck current tool self.restrictionTransaction.commitTransactionGroup(self.origLayer) #self.restrictionTransaction.deleteTransactionGroup() self.origLayer.deselect(self.origFeature.getFeature().id()) self.shutDownNodeTool() # **** New """"#currRestrictionRestrictionID = currFeature[idxRestrictionID] QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged. currRestrictionID: " + str(self.currFeature[idxRestrictionID]), tag="TOMs panel") self.currFeature.setGeometry(newGeometry) QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - attributes: " + str(self.currFeature.attributes()), tag="TOMs panel") QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - newGeom: " + self.currFeature.geometry().asWkt(), tag="TOMs panel") # Trying to unset map tool to force updates ... #self.iface.mapCanvas().unsetMapTool(self.iface.mapCanvas().mapTool()) # change active layer status = self.iface.setActiveLayer(None) self.restrictionTransaction.commitTransactionGroup(self.currLayer) #self.restrictionTransaction.deleteTransactionGroup() #QTimer.singleShot(0, functools.partial(RestrictionTypeUtils.commitRestrictionChanges, origLayer)) #QgsMessageLog.logMessage("In TOMsNodeTool:onGeometryChanged - geometry saved.", tag="TOMs panel")""" return
def calcIntersects(self, task): try: QgsMessageLog.logMessage( 'Started task {}'.format(task.description()), self.MESSAGE_CATEGORY, Qgis.Info) self.setFilterLayer(self.inters_layer) filters_dict = {} if self.settings_layer is not None: for fieldname in self.settings_layer.get("filters_fields"): filters_dict[fieldname] = CommonTools.getFilterValues( fieldname, self.filter_layout) current_feature_idx = self.map_clicked_dlg.tableClickedWays.currentRow( ) current_feature_id = int( self.map_clicked_dlg.tableClickedWays.item( current_feature_idx, 0).text()) current_feature = self.current_layer.getFeature(current_feature_id) current_feature_geom = current_feature.geometry() current_feature_length = round(current_feature_geom.length(), 2) percent_inters = int(filters_dict.get("_percent", "0")) buffer_size = float(filters_dict.get("_buffer_size", "0.01")) layer_by_percent = ( filters_dict.get("_by_addition_layer") ) # слой, по пересечению объектов которых будет высчитываться процент пересечения current_feature_buf = current_feature_geom.buffer(buffer_size, 5) il_objects_result_dict = { } # конечный результат отобранных пересекаемых объектов il_fields_aliases_dict = self.inters_layer.attributeAliases( ) # алиасы полей слоя additional_layers = self.getAdditionalLayerData( ) # дополнительные пересекаемые слои (для вычисления количества общих пересечений) if layer_by_percent: # если сравнение по общим объектам дополнительного слоя self.dockWidget.labelResult.setText( f"Слой <{self.inters_layer.name()}>.\n" f"Результат отбора по общим объектам в слое <{layer_by_percent.name()}>.\n" f"(Id объекта: {current_feature_id}. Длина объекта: {current_feature_length}) м." ) else: # если сравнение по длине self.dockWidget.labelResult.setText( f"Слой <{self.inters_layer.name()}>.\n" f"Результат отбора по длине пересечений.\n" f"(Id объекта: {current_feature_id}. Длина объекта: {current_feature_length} м.)" ) # генерация фильтра для получения всех объектов слоя filter_expression = self.generateFilterExpression(filters_dict) if filter_expression: expr = QgsExpression(filter_expression) request = QgsFeatureRequest(expr) inters_layer_features = list( self.inters_layer.getFeatures(request)) else: inters_layer_features = list(self.inters_layer.getFeatures()) fcnt = (len((inters_layer_features)) ) # общее число (отфильтрованных) объектов в слое for idx, intfeat in enumerate(inters_layer_features): if intfeat.id( ) == current_feature_id and self.current_layer == self.inters_layer: #отсекаем сравниваемую линию continue if intfeat.geometry().intersects(current_feature_buf): task.setProgress(idx / float(fcnt) * 100) if task.isCanceled(): self.stopped(task) return intfeat_buffer = intfeat.geometry().buffer( buffer_size, 5 ) # буфер пересекающихся линий, для отображения пересечений intersection_buffer = QgsGeometry( intfeat_buffer).intersection( current_feature_buf) # для отображения пересечений intersection_line = QgsGeometry(intfeat.geometry( )).intersection( current_feature_buf ) # части текущей линии, которые попали в буфер сравниваемого объекта intfeat_length = intfeat.geometry().length() intersection_line_length = intersection_line.length() attrs_add_layers_for_intfeat = None # Количество пересекаемых объектов из дополнительных слоев attrs_add_layers_for_intersection = None # Количество общих пересекаемых объектов из дополнительных слоев if layer_by_percent: # если сравнивать по общим пересекаемыым объектам, а не по длине attrs_add_layers_for_intfeat = self.getAdditionalLayersAttrs( additional_layers, intfeat.geometry(), 'Объекты в ') attrs_add_layers_for_intersection = self.getAdditionalLayersAttrs( additional_layers, intersection_line, 'Общее в ') cnt_intfeat_by_layer = attrs_add_layers_for_intfeat[ 'Объекты в ' + layer_by_percent.name()] cnt_intersection_by_layer = attrs_add_layers_for_intersection[ 'Общее в ' + layer_by_percent.name()] if cnt_intfeat_by_layer == 0: result_percent_inters = 0 else: result_percent_inters = ( cnt_intersection_by_layer / cnt_intfeat_by_layer) * 100 else: # если сравнивать по длине # процент - отношение длины пересечения к длине пересекаемого пути result_percent_inters = (intersection_line_length / intfeat_length) * 100 if result_percent_inters >= percent_inters: attrs_sys = { "feature_id": intfeat.id(), "WKT_inters_feature": intfeat.geometry().asWkt(), "WKT_intersection_line": intersection_line.asWkt() } attrs_calculated = { "Длина объекта": round(intfeat_length, 2), "Длина пересечения": round(intersection_line_length, 2), "Процент пересечения": round(result_percent_inters, 2) } attrs_feature_layer = self.getDictFeaturesAttributes( intfeat, il_fields_aliases_dict) if not attrs_add_layers_for_intfeat: attrs_add_layers_for_intfeat = self.getAdditionalLayersAttrs( additional_layers, intfeat.geometry(), 'Объекты в ') if not attrs_add_layers_for_intersection: attrs_add_layers_for_intersection = self.getAdditionalLayersAttrs( additional_layers, intersection_line, 'Общее в ') feat_attrs = {} feat_attrs = { **attrs_sys, **attrs_feature_layer, **attrs_calculated, **attrs_add_layers_for_intfeat, **attrs_add_layers_for_intersection } # объединение высчитываемых атрибутов и атрибутов слоя (объекта) il_objects_result_dict[intfeat.id()] = feat_attrs il_objects_result_dict = OrderedDict( sorted(il_objects_result_dict.items(), key=lambda kv: kv[1]["Процент пересечения"], reverse=True)) self.setFilterLayer(self.inters_layer, list(il_objects_result_dict.keys())) return il_objects_result_dict except Exception as e: exc_type, exc_obj, exc_tb = os.system.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] print(exc_type, fname, exc_tb.tb_lineno) message = f"{exc_tb.tb_lineno}, {str(e)}, {exc_type}, {fname}" QgsMessageLog.logMessage(message, self.MESSAGE_CATEGORY, Qgis.Info)