def testGetFeatures(self): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in provider.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) it = self.provider.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # expect feature to be valid self.assertTrue(f.isValid()) # split off the first 5 attributes only - some provider test datasets will include # additional attributes which we ignore attrs = f.attributes()[0:5] # force the num_char attribute to be text - some providers (eg delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f['pk']] = attrs geometries[f['pk']] = f.constGeometry() and f.constGeometry( ).exportToWkt() expected_attributes = { 5: [5, -200, NULL, 'NuLl', '5'], 3: [3, 300, 'Pear', 'PEaR', '3'], 1: [1, 100, 'Orange', 'oranGe', '1'], 2: [2, 200, 'Apple', 'Apple', '2'], 4: [4, 400, 'Honey', 'Honey', '4'] } self.assertEqual( attributes, expected_attributes, 'Expected {}, got {}'.format(expected_attributes, attributes)) expected_geometries = { 1: 'Point (-70.332 66.33)', 2: 'Point (-68.2 70.8)', 3: None, 4: 'Point(-65.32 78.3)', 5: 'Point(-71.123 78.23)' } for pk, geom in expected_geometries.items(): if geom: assert compareWkt( geom, geometries[pk] ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( pk, geom, geometries[pk].exportToWkt()) else: self.assertFalse(geometries[pk], 'Expected null geometry for {}'.format(pk))
def poly2nb(self): lst = [] index = QgsSpatialIndex() featsA = self.lyr.getFeatures() featsB = self.lyr.getFeatures() for ft in featsA: index.insertFeature(ft) featB = QgsFeature() prv = self.lyr.dataProvider() while featsB.nextFeature(featB): geomB = featB.constGeometry() idb = featB.id() idxs = index.intersects(geomB.boundingBox()) sor = [] for idx in idxs: rqst = QgsFeatureRequest().setFilterFid(idx) featA = prv.getFeatures(rqst).next() ida = featA.id() geomA = QgsGeometry(featA.geometry()) if idb!=ida: if geomB.touches(geomA)==True: sor.append(ida) lst.append(sor) return lst
def nbCalc(self): lsta = [] lstb = [] index = QgsSpatialIndex() featsA = self.lyr.getFeatures() featsB = self.lyr.getFeatures() for ft in featsA: index.insertFeature(ft) featB = QgsFeature() prv = self.lyr.dataProvider() while featsB.nextFeature(featB): geomB = featB.constGeometry() idb = featB.id() idxs = index.intersects(geomB.boundingBox()) for idx in idxs: rqst = QgsFeatureRequest().setFilterFid(idx) featA = prv.getFeatures(rqst).next() ida = featA.id() geomA = QgsGeometry(featA.geometry()) if idb>ida: if geomB.touches(geomA)==True: lsta.append(idb) lstb.append(ida) # self.plainTextEdit.insertPlainText('%s - %s\n' % (idb, ida)) lstc = [lsta, lstb] return lstc
def testGetFeatures(self): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in provider.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) it = self.provider.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # expect feature to be valid self.assertTrue(f.isValid()) # split off the first 5 attributes only - some provider test datasets will include # additional attributes which we ignore attrs = f.attributes()[0:5] # force the num_char attribute to be text - some providers (eg delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f["pk"]] = attrs geometries[f["pk"]] = f.constGeometry() and f.constGeometry().exportToWkt() expected_attributes = { 5: [5, -200, NULL, "NuLl", "5"], 3: [3, 300, "Pear", "PEaR", "3"], 1: [1, 100, "Orange", "oranGe", "1"], 2: [2, 200, "Apple", "Apple", "2"], 4: [4, 400, "Honey", "Honey", "4"], } self.assertEqual(attributes, expected_attributes, "Expected {}, got {}".format(expected_attributes, attributes)) expected_geometries = { 1: "Point (-70.332 66.33)", 2: "Point (-68.2 70.8)", 3: None, 4: "Point(-65.32 78.3)", 5: "Point(-71.123 78.23)", } for pk, geom in expected_geometries.items(): if geom: assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( pk, geom, geometries[pk].exportToWkt() ) else: self.assertFalse(geometries[pk], "Expected null geometry for {}".format(pk))
def layerData(self, layer, request={}, offset=0): # Retrieve the data for a layer first = True data = {} fields = [] fieldTypes = [] fr = QgsFeatureRequest() if request: if 'exact' in request and request['exact']: fr.setFlags(QgsFeatureRequest.ExactIntersect) if 'nogeom' in request and request['nogeom']: fr.setFlags(QgsFeatureRequest.NoGeometry) if 'fid' in request: fr.setFilterFid(request['fid']) elif 'extents' in request: fr.setFilterRect(QgsRectangle(*request['extents'])) if 'attributes' in request: fr.setSubsetOfAttributes(request['attributes']) # IMPORTANT - we do not use `for f in layer.getFeatures(fr):` as we need # to verify that existing attributes and geometry are correctly cleared # from the feature when calling nextFeature() it = layer.getFeatures(fr) f = QgsFeature() while it.nextFeature(f): if first: first = False for field in f.fields(): fields.append(str(field.name())) fieldTypes.append(str(field.typeName())) if sys.version_info.major == 2: fielddata = dict((name, unicode(f[name])) for name in fields) else: fielddata = dict((name, str(f[name])) for name in fields) g = f.constGeometry() if g: fielddata[geomkey] = str(g.exportToWkt()) else: fielddata[geomkey] = "None" fielddata[fidkey] = f.id() id = fielddata[fields[0]] description = fielddata[fields[1]] fielddata['id'] = id fielddata['description'] = description data[f.id() + offset] = fielddata if 'id' not in fields: fields.insert(0, 'id') if 'description' not in fields: fields.insert(1, 'description') fields.append(fidkey) fields.append(geomkey) return fields, fieldTypes, data
def layerData(self, layer, request={}, offset=0): # Retrieve the data for a layer first = True data = {} fields = [] fieldTypes = [] fr = QgsFeatureRequest() if request: if "exact" in request and request["exact"]: fr.setFlags(QgsFeatureRequest.ExactIntersect) if "nogeom" in request and request["nogeom"]: fr.setFlags(QgsFeatureRequest.NoGeometry) if "fid" in request: fr.setFilterFid(request["fid"]) elif "extents" in request: fr.setFilterRect(QgsRectangle(*request["extents"])) if "attributes" in request: fr.setSubsetOfAttributes(request["attributes"]) # IMPORTANT - we do not use `for f in layer.getFeatures(fr):` as we need # to verify that existing attributes and geometry are correctly cleared # from the feature when calling nextFeature() it = layer.getFeatures(fr) f = QgsFeature() while it.nextFeature(f): if first: first = False for field in f.fields(): fields.append(str(field.name())) fieldTypes.append(str(field.typeName())) if sys.version_info.major == 2: fielddata = dict((name, unicode(f[name])) for name in fields) else: fielddata = dict((name, str(f[name])) for name in fields) g = f.constGeometry() if g: fielddata[geomkey] = str(g.exportToWkt()) else: fielddata[geomkey] = "None" fielddata[fidkey] = f.id() id = fielddata[fields[0]] description = fielddata[fields[1]] fielddata["id"] = id fielddata["description"] = description data[f.id() + offset] = fielddata if "id" not in fields: fields.insert(0, "id") if "description" not in fields: fields.insert(1, "description") fields.append(fidkey) fields.append(geomkey) return fields, fieldTypes, data
class FeatureHighlightItem(QgsMapCanvasItem): # Code ported from QGIS QgsHighlight def __init__(self, mapCanvas, feature, layer): super(FeatureHighlightItem, self).__init__(mapCanvas) self._mapCanvas = None # QgsMapCanvas self._brush = QBrush() self._pen = QPen() self._feature = None # QgsFeature() self._layer = None # QgsMapLayer() self._buffer = 0.0 self._minWidth = 0.0 self._mapCanvas = mapCanvas if (not layer or not feature or not isinstance(feature, QgsFeature) or not feature.geometry() or feature.geometry().isEmpty() or not feature.geometry().isGeosValid()): return self._feature = QgsFeature(feature) # Force deep copy self._layer = layer self.setLineColor(Application.highlightLineColor()) self.setFillColor(Application.highlightFillColor()) self._minWidth = Application.highlightMinimumWidth() self._buffer = Application.highlightBuffer() if self._mapCanvas.mapSettings().hasCrsTransformEnabled(): ct = self._mapCanvas.mapSettings().layerTransform(self._layer) if ct: self._feature.geometry().transform(ct) self.updateRect() self.update() def remove(self): self._mapCanvas.scene().removeItem(self) def setLineWidth(self, width): self._pen.setWidth(width) def setLineColor(self, color): self._pen.setColor(color) def setFillColor(self, fillColor): self._brush.setColor(fillColor) self._brush.setStyle(Qt.SolidPattern) def setBuffer(self, buff): self._buffer = buff def setMinWidth(self, width): self._minWidth = width def layer(self): return self._layer def updatePosition(self): pass # protected: def paint(self, painter, option=None, widget=None): # Override if not self._feature: return mapSettings = self._mapCanvas.mapSettings() context = QgsRenderContext.fromMapSettings(mapSettings) renderer = self._getRenderer(context, self._pen.color(), self._brush.color()) if renderer: context.setPainter(painter) renderer.startRender(context, self._layer.fields()) renderer.renderFeature(self._feature, context) renderer.stopRender(context) def updateRect(self): if self._feature and self._feature.constGeometry(): m2p = self._mapCanvas.mapSettings().mapToPixel() topLeft = m2p.toMapPoint(0, 0) res = m2p.mapUnitsPerPixel() imageSize = self._mapCanvas.mapSettings().outputSize() rect = QgsRectangle(topLeft.x(), topLeft.y(), topLeft.x() + imageSize.width() * res, topLeft.y() - imageSize.height() * res) self.setRect(rect) self.setVisible(True) else: self.setRect(QgsRectangle()) # private: def _setSymbol(self, symbol, context, color, fillColor): if not symbol: return for symbolLayer in reversed(symbol.symbolLayers()): if symbolLayer: if symbolLayer.subSymbol(): self._setSymbol(symbolLayer.subSymbol(), context, color, fillColor) else: symbolLayer.setColor(color) symbolLayer.setOutlineColor(color) symbolLayer.setFillColor(fillColor) if isinstance(symbolLayer, QgsSimpleMarkerSymbolLayerV2): symbolLayer.setOutlineWidth( self._getSymbolWidth( context, symbolLayer.outlineWidth(), symbolLayer.outlineWidthUnit())) if symbolLayer.type() == QgsSymbolV2.Line: symbolLayer.setWidth( self._getSymbolWidth(context, symbolLayer.width(), symbolLayer.widthUnit())) if symbolLayer.type() == QgsSymbolV2.Fill: symbolLayer.setBorderWidth( self._getSymbolWidth(context, symbolLayer.borderWidth(), symbolLayer.outputUnit())) symbolLayer.removeDataDefinedProperty('color') symbolLayer.removeDataDefinedProperty('color_border') def _getSymbolWidth(self, context, width, unit): scale = 1.0 if unit == QgsSymbolV2.MapUnit: scale = QgsSymbolLayerV2Utils.lineWidthScaleFactor( context, QgsSymbolV2.MM) / QgsSymbolLayerV2Utils.lineWidthScaleFactor( context, QgsSymbolV2.MapUnit) width = max(width + 2 * self._buffer * scale, self._minWidth * scale) return width def _getRenderer(self, context, color, fillColor): renderer = None if self._layer and self._layer.rendererV2(): renderer = self._layer.rendererV2().clone() if renderer: for symbol in renderer.symbols2(context): self._setSymbol(symbol, context, color, fillColor) return renderer
class FeatureHighlight(QgsMapCanvasItem): _mapCanvas = None # QgsMapCanvas _brush = QBrush() _pen = QPen() _feature = None # QgsFeature() _layer = None # QgsMapLayer() _buffer = 0.0 _minWidth = 0.0 def __init__(self, mapCanvas, feature, layer): super(FeatureHighlight, self).__init__(mapCanvas) self._mapCanvas = mapCanvas if not layer or not feature or not isinstance(feature, QgsFeature) or not feature.geometry() or feature.geometry().isEmpty() or not feature.geometry().isGeosValid(): return self._feature = QgsFeature(feature) # Force deep copy self._layer = layer self.setLineColor(Project.highlightLineColor()) self.setFillColor(Project.highlightFillColor()) self._minWidth = Project.highlightMinimumWidth() self._buffer = Project.highlightBuffer() if self._mapCanvas.mapSettings().hasCrsTransformEnabled(): ct = self._mapCanvas.mapSettings().layerTransform(self._layer) if ct: self._feature.geometry().transform(ct) self.updateRect() self.update() def remove(self): self._mapCanvas.scene().removeItem(self) def setLineWidth(self, width): self._pen.setWidth(width) def setLineColor(self, color): self._pen.setColor(color) def setFillColor(self, fillColor): self._brush.setColor(fillColor) self._brush.setStyle(Qt.SolidPattern) def setBuffer(self, buff): self._buffer = buff def setMinWidth(self, width): self._minWidth = width def layer(self): return self._layer def updatePosition(self): pass # protected: def paint(self, painter, option=None, widget=None): # Override if not self._feature: return mapSettings = self._mapCanvas.mapSettings() context = QgsRenderContext.fromMapSettings(mapSettings) renderer = self._getRenderer(context, self._pen.color(), self._brush.color()) if renderer: context.setPainter(painter) renderer.startRender(context, self._layer.fields()) renderer.renderFeature(self._feature, context) renderer.stopRender(context) def updateRect(self): if self._feature and self._feature.constGeometry(): m2p = self._mapCanvas.mapSettings().mapToPixel() topLeft = m2p.toMapPoint(0, 0) res = m2p.mapUnitsPerPixel() imageSize = self._mapCanvas.mapSettings().outputSize() rect = QgsRectangle(topLeft.x(), topLeft.y(),topLeft.x() + imageSize.width()*res, topLeft.y() - imageSize.height()*res) self.setRect(rect) self.setVisible(True) else: self.setRect(QgsRectangle()) # private: def _setSymbol(self, symbol, context, color, fillColor): if not symbol: return for symbolLayer in reversed(symbol.symbolLayers()): if symbolLayer: if symbolLayer.subSymbol(): self._setSymbol(symbolLayer.subSymbol(), context, color, fillColor) else: symbolLayer.setColor(color) symbolLayer.setOutlineColor(color) symbolLayer.setFillColor(fillColor) if isinstance(symbolLayer, QgsSimpleMarkerSymbolLayerV2): symbolLayer.setOutlineWidth(self._getSymbolWidth(context, symbolLayer.outlineWidth(), symbolLayer.outlineWidthUnit())) if symbolLayer.type() == QgsSymbolV2.Line: symbolLayer.setWidth(self._getSymbolWidth(context, symbolLayer.width(), symbolLayer.widthUnit())) if symbolLayer.type() == QgsSymbolV2.Fill: symbolLayer.setBorderWidth(self._getSymbolWidth(context, symbolLayer.borderWidth(), symbolLayer.outputUnit())) symbolLayer.removeDataDefinedProperty('color') symbolLayer.removeDataDefinedProperty('color_border') def _getSymbolWidth(self, context, width, unit): scale = 1.0 if unit == QgsSymbolV2.MapUnit: scale = QgsSymbolLayerV2Utils.lineWidthScaleFactor(context, QgsSymbolV2.MM) / QgsSymbolLayerV2Utils.lineWidthScaleFactor(context, QgsSymbolV2.MapUnit) width = max(width + 2 * self._buffer * scale, self._minWidth * scale) return width def _getRenderer(self, context, color, fillColor): renderer = None if self._layer and self._layer.rendererV2(): renderer = self._layer.rendererV2().clone() if renderer: for symbol in renderer.symbols2(context): self._setSymbol(symbol, context, color, fillColor) return renderer