def onReturnPressed(self): try: txt = self.editSearch.text().strip() self.plugin.lastSearch = self.editSearch.text() self.plugin.limitSearchToExtent = (self.cbExtent.isChecked()) options = self.plugin.gnOptions options2 = {} if self.plugin.limitSearchToExtent: sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) geom = xform.transform(self.plugin.canvas.extent()) options2 = {'viewbox': str(geom.xMinimum()) + ',' + str(geom.yMaximum()) + ',' + str(geom.xMaximum()) + ',' + str(geom.yMinimum())} params = {'q': txt, 'addressdetails': '0'} self.searchJson(params, self.plugin.gnUsername, options, options2) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass
def extent_to_geo_array(extent, source_crs, dest_crs=None): """Convert the supplied extent to geographic and return as an array. :param extent: Rectangle defining a spatial extent in any CRS. :type extent: QgsRectangle :param source_crs: Coordinate system used for extent. :type source_crs: QgsCoordinateReferenceSystem :returns: a list in the form [xmin, ymin, xmax, ymax] where all coordinates provided are in Geographic / EPSG:4326. :rtype: list """ if dest_crs is None: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) else: geo_crs = dest_crs transform = QgsCoordinateTransform(source_crs, geo_crs) # Get the clip area in the layer's crs transformed_extent = transform.transformBoundingBox(extent) geo_extent = [ transformed_extent.xMinimum(), transformed_extent.yMinimum(), transformed_extent.xMaximum(), transformed_extent.yMaximum()] return geo_extent
def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom
def viewport_geo_array(map_canvas): """Obtain the map canvas current extent in EPSG:4326. :param map_canvas: A map canvas instance. :type map_canvas: QgsMapCanvas :returns: A list in the form [xmin, ymin, xmax, ymax] where all coordinates provided are in Geographic / EPSG:4326. :rtype: list .. note:: Delegates to extent_to_geo_array() """ # get the current viewport extent rectangle = map_canvas.extent() if map_canvas.hasCrsTransformEnabled(): crs = map_canvas.mapRenderer().destinationCrs() else: # some code duplication from extentToGeoArray here # in favour of clarity of logic... crs = QgsCoordinateReferenceSystem() crs.createFromSrid(4326) return extent_to_geo_array(rectangle, crs)
def setUp(self): """Fixture run before all tests""" register_impact_functions() self.maxDiff = None # show full diff for assert errors os.environ['LANG'] = 'en' self.DOCK.show_only_visible_layers_flag = True load_standard_layers(self.DOCK) self.DOCK.cboHazard.setCurrentIndex(0) self.DOCK.cboExposure.setCurrentIndex(0) self.DOCK.cboFunction.setCurrentIndex(0) self.DOCK.run_in_thread_flag = False self.DOCK.show_only_visible_layers_flag = False self.DOCK.set_layer_from_title_flag = False self.DOCK.zoom_to_impact_flag = False self.DOCK.hide_exposure_flag = False self.DOCK.show_intermediate_layers = False set_jakarta_extent() self._keywordIO = KeywordIO() self._defaults = get_defaults() # Set extent as Jakarta extent geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) self.extent = extent_to_geo_array(CANVAS.extent(), geo_crs)
def viewport_geo_array(map_canvas): """Obtain the map canvas current extent in EPSG:4326. :param map_canvas: A map canvas instance. :type map_canvas: QgsMapCanvas :returns: A list in the form [xmin, ymin, xmax, ymax] where all coordinates provided are in Geographic / EPSG:4326. :rtype: list .. note:: Delegates to extent_to_array() """ # get the current viewport extent rectangle = map_canvas.extent() destination_crs = QgsCoordinateReferenceSystem() destination_crs.createFromSrid(4326) if map_canvas.hasCrsTransformEnabled(): source_crs = map_canvas.mapRenderer().destinationCrs() else: source_crs = destination_crs return extent_to_array(rectangle, source_crs, destination_crs)
def setUpClass(cls): """Run before all tests""" # qgis instances cls._QgisApp, cls._Canvas, cls._Iface, cls._Parent = \ QGISAPP, CANVAS, IFACE, PARENT cls._PalReportDir = PALREPORTDIR # verify that spatialite provider is available msg = ('\nSpatialite provider not found, ' 'SKIPPING TEST SUITE') res = 'spatialite' in QgsProviderRegistry.instance().providerList() assert res, msg # load the FreeSansQGIS labeling test font fontdb = QFontDatabase() cls._TestFontID = fontdb.addApplicationFont( os.path.join(cls._TestDataDir, 'font', 'FreeSansQGIS.ttf')) msg = ('\nCould not store test font in font database, ' 'SKIPPING TEST SUITE') assert cls._TestFontID != -1, msg cls._TestFont = fontdb.font('FreeSansQGIS', 'Medium', 48) appfont = QApplication.font() msg = ('\nCould not load test font from font database, ' 'SKIPPING TEST SUITE') assert cls._TestFont.toString() != appfont.toString(), msg cls._TestFunction = '' cls._TestGroup = '' cls._TestGroupPrefix = '' cls._TestGroupAbbr = '' # initialize class MapRegistry, Canvas, MapRenderer, Map and PAL cls._MapRegistry = QgsMapLayerRegistry.instance() # set color to match render test comparisons background cls._Canvas.setCanvasColor(QColor(152, 219, 249)) cls._Map = cls._Canvas.map() cls._Map.resize(QSize(600, 400)) cls._MapRenderer = cls._Canvas.mapRenderer() crs = QgsCoordinateReferenceSystem() # default for labeling test data sources: WGS 84 / UTM zone 13N crs.createFromSrid(32613) cls._MapRenderer.setDestinationCrs(crs) # TODO: match and store platform's native logical output dpi cls._MapRenderer.setOutputSize(QSize(600, 400), 72) cls._Pal = QgsPalLabeling() cls._MapRenderer.setLabelingEngine(cls._Pal) cls._PalEngine = cls._MapRenderer.labelingEngine() msg = ('\nCould not initialize PAL labeling engine, ' 'SKIPPING TEST SUITE') assert cls._PalEngine, msg
def get_lon_lat_extent(self): map_canvas = self.iface.mapCanvas() extent = map_canvas.mapSettings().extent() if map_canvas.hasCrsTransformEnabled(): crs_map = map_canvas.mapSettings().destinationCrs() else: crs_map = map_canvas.currentLayer().crs() if crs_map.authid() != u'EPSG:4326': crs_4326 = QgsCoordinateReferenceSystem() crs_4326.createFromSrid(4326) return QgsCoordinateTransform(crs_map, crs_4326).transform(extent) return extent
def render_layers(layer_paths): """ :param layer_paths: A list of layer paths. :return: Buffer containing output. Note caller is responsible for closing the buffer with buffer.close() :rtype: QBuffer """ layers = [] extent = None crs = QgsCoordinateReferenceSystem() crs.createFromSrid(3857) for layer_path in layer_paths: map_layer = QgsVectorLayer(layer_path, None, 'ogr') QgsMapLayerRegistry.instance().addMapLayer(map_layer) transform = QgsCoordinateTransform(map_layer.crs(), crs) print map_layer.extent().toString() layer_extent = transform.transform(map_layer.extent()) if extent is None: extent = layer_extent else: extent.combineExtentWith(layer_extent) print extent.toString() # set layer set layers.append(map_layer.id()) # add ID of every layer map_settings = QgsMapSettings() map_settings.setDestinationCrs(crs) map_settings.setCrsTransformEnabled(True) map_settings.setExtent(extent) map_settings.setOutputSize(QSize(1000, 1000)) map_settings.setLayers(layers) # job = QgsMapRendererParallelJob(settings) job = QgsMapRendererSequentialJob(map_settings) job.start() job.waitForFinished() image = job.renderedImage() # Save teh image to a buffer map_buffer = QBuffer() map_buffer.open(QIODevice.ReadWrite) image.save(map_buffer, "PNG") image.save('/tmp/test.png', 'png') # clean up QgsMapLayerRegistry.instance().removeAllMapLayers() return map_buffer
def get_wgs84_resolution(layer): """Return resolution of raster layer in EPSG:4326. If input layer is already in EPSG:4326, simply return the resolution If not, work it out based on EPSG:4326 representations of its extent. :param layer: Raster layer :type layer: QgsRasterLayer or QgsMapLayer :returns: The resolution of the given layer in the form of (res_x, res_y) :rtype: tuple """ msg = tr( 'Input layer to get_wgs84_resolution must be a raster layer. ' 'I got: %s' % str(layer.type())[1:-1]) if not layer.type() == QgsMapLayer.RasterLayer: raise RuntimeError(msg) if layer.crs().authid() == 'EPSG:4326': cell_size = ( layer.rasterUnitsPerPixelX(), layer.rasterUnitsPerPixelY()) else: # Otherwise, work it out based on EPSG:4326 representations of # its extent # Reproject extent to EPSG:4326 geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) transform = QgsCoordinateTransform(layer.crs(), geo_crs) extent = layer.extent() projected_extent = transform.transformBoundingBox(extent) # Estimate resolution x columns = layer.width() width = abs( projected_extent.xMaximum() - projected_extent.xMinimum()) cell_size_x = width / columns # Estimate resolution y rows = layer.height() height = abs( projected_extent.yMaximum() - projected_extent.yMinimum()) cell_size_y = height / rows cell_size = (cell_size_x, cell_size_y) return cell_size
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" crs.createFromSrid(4326) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) return ms
def printToPdf(self, params): self.check_required_params(params) with change_directory(self.project_root): crs = QgsCoordinateReferenceSystem() crs.createFromSrid(params.get('srs')) mapRenderer = QgsMapRenderer() mapUnits = crs.mapUnits() mapRenderer.setMapUnits(mapUnits) mapExtent = QgsRectangle(*params.get('bbox')) mapRenderer.setExtent(mapExtent) le = QgsPalLabeling() mapRenderer.setLabelingEngine(le) layers = params.get('layers') self.setTransparencies(layers, params.get('transparencies')) mapRenderer.setLayerSet(layers) composer = ( self.getLayoutbyName(params['layout']) .firstChildElement('Composition') ) comp = QgsComposition(mapRenderer) comp.setPlotStyle(QgsComposition.Print) comp.readXML(composer, self.doc) # read composition elements comp.addItemsFromXML(composer, self.doc) comp.setPrintResolution(90) # set bbox for the first Map in the layout comp_map = comp.getComposerMapById(0) comp_map.setNewExtent(QgsRectangle(*params.get('bbox'))) # comp_map.setNewScale(10000) # comp_map.setLayerSet(layers) # comp_map.setKeepLayerSet(True) # save the file comp.exportAsPDF(params['tmpFile'] + '.pdf')
def _geo_extent_to_canvas_crs(self, extent): """Transform a bounding box into the CRS of the canvas. :param extent: An extent in geographic coordinates. :type extent: QgsRectangle :returns: The extent in CRS of the canvas. :rtype: QgsRectangle """ # make sure the extent is in the same crs as the canvas destination_crs = self.iface.mapCanvas().mapRenderer().destinationCrs() source_crs = QgsCoordinateReferenceSystem() source_crs.createFromSrid(4326) transform = QgsCoordinateTransform(source_crs, destination_crs) extent = transform.transformBoundingBox(extent) return extent
def doLocalize(self): try: # center bbox = self.plugin.canvas.extent() sourceCrs = self.plugin.canvas.mapSettings().destinationCrs() targetCrs = QgsCoordinateReferenceSystem() targetCrs.createFromSrid(4326) xform = QgsCoordinateTransform(sourceCrs, targetCrs, QgsProject.instance()) bbox = xform.transform(bbox) params = {"lon": str(bbox.center().x()), "lat": str(bbox.center().y()), "zoom": "10"} self.findNearbyJSON(params, self.plugin.gnUsername, self.plugin.gnOptions) except Exception as e: for m in e.args: QgsMessageLog.logMessage(m, 'Extensions') pass
def set_canvas_crs(epsg_id, enable_projection=False): """Helper to set the crs for the CANVAS before a test is run. :param epsg_id: Valid EPSG identifier :type epsg_id: int :param enable_projection: whether on the fly projections should be enabled on the CANVAS. Default to False. :type enable_projection: bool """ # Create CRS Instance crs = QgsCoordinateReferenceSystem() crs.createFromSrid(epsg_id) # Reproject all layers to WGS84 geographic CRS CANVAS.setDestinationCrs(crs)
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing) ms.setDestinationCrs(crs) ms.setCrsTransformEnabled(False) ms.setMapUnits(crs.mapUnits()) # meters ms.setExtent(cls.aoiExtent()) return ms
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) ms.setExtent(cls.aoiExtent()) return ms
def getWGS84resolution(layer): """Return resolution of raster layer in EPSG:4326. If input layer is already in EPSG:4326, simply return the resolution If not, work it out based on EPSG:4326 representations of its extent. :param layer: Raster layer :type layer: QgsRasterLayer or QgsMapLayer :returns: The resolution of the given layer. :rtype: float """ msg = tr( 'Input layer to getWGS84resolution must be a raster layer. ' 'I got: %s' % str(layer.type())[1:-1]) if not layer.type() == QgsMapLayer.RasterLayer: raise RuntimeError(msg) if layer.crs().authid() == 'EPSG:4326': myCellSize = layer.rasterUnitsPerPixelX() else: # Otherwise, work it out based on EPSG:4326 representations of # its extent # Reproject extent to EPSG:4326 myGeoCrs = QgsCoordinateReferenceSystem() myGeoCrs.createFromSrid(4326) myXForm = QgsCoordinateTransform(layer.crs(), myGeoCrs) myExtent = layer.extent() myProjectedExtent = myXForm.transformBoundingBox(myExtent) # Estimate cell size myColumns = layer.width() myGeoWidth = abs(myProjectedExtent.xMaximum() - myProjectedExtent.xMinimum()) myCellSize = myGeoWidth / myColumns return myCellSize
def prepareIteratorLayout(self): layer_path = os.path.join(TEST_DATA_DIR, 'france_parts.shp') layer = QgsVectorLayer(layer_path, 'test', "ogr") project = QgsProject() project.addMapLayers([layer]) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) project.setCrs(crs) layout = QgsPrintLayout(project) layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", "outline_width": "4", "outline_color": '255,255,255'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) layer.setRenderer(renderer) # the atlas map atlas_map = QgsLayoutItemMap(layout) atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlas_map.setFrameEnabled(True) atlas_map.setLayers([layer]) layout.addLayoutItem(atlas_map) # the atlas atlas = layout.atlas() atlas.setCoverageLayer(layer) atlas.setEnabled(True) atlas_map.setExtent( QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlas_map.setAtlasMargin(0.10) return project, layout
def rectangle_geo_array(rectangle, map_canvas): """Obtain the rectangle in EPSG:4326. :param rectangle: A rectangle instance. :type rectangle: QgsRectangle :param map_canvas: A map canvas instance. :type map_canvas: QgsMapCanvas :returns: A list in the form [xmin, ymin, xmax, ymax] where all coordinates provided are in Geographic / EPSG:4326. :rtype: list .. note:: Delegates to extent_to_array() """ destination_crs = QgsCoordinateReferenceSystem() destination_crs.createFromSrid(4326) source_crs = map_canvas.mapSettings().destinationCrs() return extent_to_array(rectangle, source_crs, destination_crs)
def run(self, layers): """Run the impact function. :param layers: List of layers expected to contain at least: H: Polygon layer of inundation areas E: Vector layer of roads :type layers: list :returns: A new line layer with inundated roads marked. :type: safe_layer """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] threshold_min = self.parameters['min threshold [m]'] threshold_max = self.parameters['max threshold [m]'] if threshold_min > threshold_max: message = tr( 'The minimal threshold is greater then the maximal specified ' 'threshold. Please check the values.') raise GetDataError(message) # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question( H.get_name(), E.get_name(), self) H = H.get_layer() E = E.get_layer() # reproject self.extent to the hazard projection hazard_crs = H.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.extent), geo_crs, hazard_crs) # Align raster extent and viewport # assuming they are both in the same projection raster_extent = H.dataProvider().extent() clip_xmin = raster_extent.xMinimum() # clip_xmax = raster_extent.xMaximum() clip_ymin = raster_extent.yMinimum() # clip_ymax = raster_extent.yMaximum() if viewport_extent[0] > clip_xmin: clip_xmin = viewport_extent[0] if viewport_extent[1] > clip_ymin: clip_ymin = viewport_extent[1] # TODO: Why have these two clauses when they are not used? # Commenting out for now. # if viewport_extent[2] < clip_xmax: # clip_xmax = viewport_extent[2] # if viewport_extent[3] < clip_ymax: # clip_ymax = viewport_extent[3] height = ((viewport_extent[3] - viewport_extent[1]) / H.rasterUnitsPerPixelY()) height = int(height) width = ((viewport_extent[2] - viewport_extent[0]) / H.rasterUnitsPerPixelX()) width = int(width) raster_extent = H.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / H.width() x = xmin for i in range(H.width()): if abs(x - clip_xmin) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / H.height() y = ymin for i in range(H.width()): if abs(y - clip_ymin) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip and polygonize small_raster = clip_raster( H, width, height, QgsRectangle(*clip_extent)) (flooded_polygon_inside, flooded_polygon_outside) = polygonize_gdal( small_raster, threshold_min, threshold_max) # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) if flooded_polygon_inside is None: message = tr( 'There are no objects in the hazard layer with "value">%s.' 'Please check the value or use other extent.' % ( threshold_min, )) raise GetDataError(message) # reproject the flood polygons to exposure projection exposure_crs = E.crs() exposure_authid = exposure_crs.authid() if hazard_authid != exposure_authid: flooded_polygon_inside = reproject_vector_layer( flooded_polygon_inside, E.crs()) flooded_polygon_outside = reproject_vector_layer( flooded_polygon_outside, E.crs()) # Clip exposure by the extent # extent_as_polygon = QgsGeometry().fromRect(extent) # no need to clip since It is using a bbox request # line_layer = clip_by_polygon( # E, # extent_as_polygon # ) # Find inundated roads, mark them line_layer = split_by_polygon_in_out( E, flooded_polygon_inside, flooded_polygon_outside, target_field, 1, request) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(E.crs(), output_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if road_type not in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow( [ tr('Road Type'), tr('Flooded in the threshold (m)'), tr('Total (m)')], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]), TableRow(tr('Breakdown by road type'), header=True)] for t, v in roads_by_type.iteritems(): table_body.append( TableRow([t, int(v['flooded']), int(v['total'])]) ) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict( label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict( label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5)] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector( data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field}, style_info=style_info) return line_layer
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create composition with composer map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.mComposition = QgsComposition(QgsProject.instance()) self.mComposition.setPaperSize(297, 210) # fix the renderer, fill with green props = {"color": "0,127,0"} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130) self.mAtlasMap.setFrameEnabled(True) self.mAtlasMap.setLayers([mVectorLayer]) self.mComposition.addComposerMap(self.mAtlasMap) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer(mVectorLayer) self.mAtlas.setEnabled(True) self.mComposition.setAtlasMode(QgsComposition.ExportAtlas) # an overview self.mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50) self.mOverview.setFrameEnabled(True) self.mOverview.overview().setFrameMap(self.mAtlasMap.id()) self.mOverview.setLayers([mVectorLayer]) self.mComposition.addComposerMap(self.mOverview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.mOverview.setNewExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127"} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.mOverview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15)) qWarning( "header label font: %s exactMatch:%s" % (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch())) # feature number label self.mLabel2 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel2) self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15)) qWarning("feature number label font: %s exactMatch:%s" % ( self.mLabel2.font().toString(), self.mLabel2.font().exactMatch())) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() shutil.rmtree(tmppath, True)
def run(self): """Run the impact function. :returns: A vector layer with affected areas marked. :type: safe_layer """ hazard_layer = self.hazard.layer exposure = self.exposure.layer # Thresholds for tsunami hazard zone breakdown. group_parameters = self.parameters['group_threshold'] ver_low_unit = group_parameters.value_map['very_low_threshold'].unit unit_abbrev = ver_low_unit.abbreviation unaffected_threshold = group_parameters.value_map[ 'unaffected_threshold'] unaffected_max = unaffected_threshold.value very_low_max = group_parameters.value_map['very_low_threshold'].value low_max = group_parameters.value_map['low_threshold'].value medium_max = group_parameters.value_map['moderate_threshold'].value high_max = group_parameters.value_map['high_threshold'].value ranges = ranges_according_thresholds_list( [None, unaffected_max, very_low_max, low_max, medium_max, high_max, None]) hazard_value_to_class = {} for i, interval in enumerate(ranges): hazard_value_to_class[interval] = self.hazard_classes[i] # Get parameters from layer's keywords class_field = self.exposure.keyword('field') # reproject self.extent to the hazard projection hazard_crs = hazard_layer.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.requested_extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.requested_extent), geo_crs, hazard_crs) small_raster = align_clip_raster(hazard_layer, viewport_extent) # Create vector features from the flood raster hazard_class_attribute = 'hazard' vector_file_path = reclassify_polygonize( small_raster.source(), ranges, name_field=hazard_class_attribute) hazard = QgsVectorLayer(vector_file_path, 'ash vector', 'ogr') # prepare objects for re-projection of geometries crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326') hazard_to_exposure = QgsCoordinateTransform( hazard.crs(), exposure.crs()) wgs84_to_hazard = QgsCoordinateTransform( crs_wgs84, hazard.crs()) wgs84_to_exposure = QgsCoordinateTransform( crs_wgs84, exposure.crs()) extent = QgsRectangle( self.requested_extent[0], self.requested_extent[1], self.requested_extent[2], self.requested_extent[3]) extent_hazard = wgs84_to_hazard.transformBoundingBox(extent) extent_exposure = wgs84_to_exposure.transformBoundingBox(extent) extent_exposure_geom = QgsGeometry.fromRect(extent_exposure) # make spatial index of hazard hazard_index = QgsSpatialIndex() hazard_features = {} for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)): f.geometry().transform(hazard_to_exposure) hazard_index.insertFeature(f) hazard_features[f.id()] = QgsFeature(f) # create impact layer filename = unique_filename(suffix='.shp') impact_fields = exposure.dataProvider().fields() impact_fields.append(QgsField(self.target_field, QVariant.String)) writer = QgsVectorFileWriter( filename, 'utf-8', impact_fields, QGis.WKBPolygon, exposure.crs()) # iterate over all exposure polygons and calculate the impact _calculate_landcover_impact( exposure, extent_exposure, extent_exposure_geom, hazard_class_attribute, hazard_features, hazard_index, hazard_value_to_class, impact_fields, writer) del writer impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr') # find unaffected features unaffected_feats = [] target_field_index = impact_layer.fieldNameIndex(self.target_field) for f in impact_layer.getFeatures(): haz_class = f.attributes()[target_field_index] if haz_class == self.hazard_classes[0]: unaffected_feats.append(f.id()) impact_layer.dataProvider().deleteFeatures(unaffected_feats) if impact_layer.featureCount() == 0: raise ZeroImpactException() zone_field = None if self.aggregator: zone_field = self.aggregator.exposure_aggregation_field impact_data = LandCoverReportMixin( question=self.question, impact_layer=impact_layer, target_field=self.target_field, ordered_columns=self.hazard_classes, affected_columns=self.affected_hazard_columns, land_cover_field=class_field, zone_field=zone_field ).generate_data() # Define style for the impact layer style_classes = [ dict( label=self.hazard_classes[1] + ': %.1f - %.1f %s' % ( unaffected_max, very_low_max, unit_abbrev), value=self.hazard_classes[1], colour='#2C6BA4', border_color='#000000', transparency=0), dict( label=self.hazard_classes[2] + ': %.1f - %.1f %s' % ( very_low_max + 0.1, low_max, unit_abbrev), value=self.hazard_classes[2], colour='#00A4D8', border_color='#000000', transparency=0), dict( label=self.hazard_classes[3] + ': %.1f - %.1f %s' % ( low_max + 0.1, medium_max, unit_abbrev), value=self.hazard_classes[3], colour='#FFEF36', border_color='#000000', transparency=0), dict( label=self.hazard_classes[4] + ': %.1f - %.1f %s' % ( medium_max + 0.1, high_max, unit_abbrev), value=self.hazard_classes[4], colour='#EFA951', border_color='#000000', transparency=0), dict( label=self.hazard_classes[5] + ': > %.1f %s' % ( high_max, unit_abbrev), value=self.hazard_classes[5], colour='#d62631', border_color='#000000', transparency=0), ] style_info = dict( target_field=self.target_field, style_classes=style_classes, style_type='categorizedSymbol') extra_keywords = { 'map_title': self.map_title(), 'target_field': self.target_field } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Create vector layer and return impact_layer = Vector( data=impact_layer, name=self.map_title(), keywords=impact_layer_keywords, style_info=style_info) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() vectorFileInfo = QFileInfo(self.TEST_DATA_DIR + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsMapLayerRegistry.instance().addMapLayers([mVectorLayer]) # create composition with composer map mMapRenderer = QgsMapRenderer() layerStringList = [] layerStringList.append(mVectorLayer.id()) mMapRenderer.setLayerSet(layerStringList) mMapRenderer.setProjectionsEnabled(True) mMapRenderer.setMapUnits(QGis.Meters) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) mMapRenderer.setDestinationCrs(crs) self.mComposition = QgsComposition(mMapRenderer) self.mComposition.setPaperSize(297, 210) # fix the renderer, fill with green props = {"color": "0,127,0"} fillSymbol = QgsFillSymbolV2.createSimple(props) renderer = QgsSingleSymbolRendererV2(fillSymbol) mVectorLayer.setRendererV2(renderer) # the atlas map self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130) self.mAtlasMap.setFrameEnabled(True) self.mComposition.addComposerMap(self.mAtlasMap) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer(mVectorLayer) self.mAtlas.setEnabled(True) self.mComposition.setAtlasMode(QgsComposition.ExportAtlas) # an overview mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50) mOverview.setFrameEnabled(True) mOverview.setOverviewFrameMap(self.mAtlasMap.id()) self.mComposition.addComposerMap(mOverview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) mOverview.setNewExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127"} fillSymbol2 = QgsFillSymbolV2.createSimple(props2) mOverview.setOverviewFrameMapSymbol(fillSymbol2) # header label self.mLabel1 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15)) qWarning( "header label font: %s exactMatch:%s" % (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch())) # feature number label self.mLabel2 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel2) self.mLabel2.setText("# [%$feature || ' / ' || $numfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15)) qWarning( "feature number label font: %s exactMatch:%s" % (self.mLabel2.font().toString(), self.mLabel2.font().exactMatch())) self.filename_test() self.autoscale_render_test() self.autoscale_render_test_old_api() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test()
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create layout with layout map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.layout = QgsPrintLayout(QgsProject.instance()) self.layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", 'outline_color': 'black'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.atlas_map = QgsLayoutItemMap(self.layout) self.atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) self.atlas_map.setFrameEnabled(True) self.atlas_map.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.atlas_map) # the atlas self.atlas = self.layout.atlas() self.atlas.setCoverageLayer(mVectorLayer) self.atlas.setEnabled(True) # an overview self.overview = QgsLayoutItemMap(self.layout) self.overview.attemptSetSceneRect(QRectF(180, 20, 50, 50)) self.overview.setFrameEnabled(True) self.overview.overview().setLinkedMap(self.atlas_map) self.overview.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.overview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.overview.setExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127", 'outline_color': 'black'} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.overview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.attemptSetSceneRect(QRectF(150, 5, 60, 15)) self.mLabel1.setMarginX(1) self.mLabel1.setMarginY(1) # feature number label self.mLabel2 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel2) self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.attemptSetSceneRect(QRectF(150, 200, 60, 15)) self.mLabel2.setMarginX(1) self.mLabel2.setMarginY(1) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() self.rotation_test() shutil.rmtree(tmppath, True)
def _clip_vector_layer( layer, extent, extra_keywords=None, explode_flag=True, hard_clip_flag=False, explode_attribute=None): """Clip a Hazard or Exposure layer to the extents provided. The layer must be a vector layer or an exception will be thrown. The output layer will always be in WGS84/Geographic. :param layer: A valid QGIS vector or raster layer :type layer: :param extent: Either an array representing the exposure layer extents in the form [xmin, ymin, xmax, ymax]. It is assumed that the coordinates are in EPSG:4326 although currently no checks are made to enforce this. or: A QgsGeometry of type polygon. **Polygon clipping is currently only supported for vector datasets.** :type extent: list(float, float, float, float) :param extra_keywords: Optional keywords dictionary to be added to output layer. :type extra_keywords: dict :param explode_flag: A bool specifying whether multipart features should be 'exploded' into singleparts. **This parameter is ignored for raster layer clipping.** :type explode_flag: bool :param hard_clip_flag: A bool specifying whether line and polygon features that extend beyond the extents should be clipped such that they are reduced in size to the part of the geometry that intersects the extent only. Default is False. **This parameter is ignored for raster layer clipping.** :type hard_clip_flag: bool :param explode_attribute: A str specifying to which attribute #1, #2 and so on will be added in case of explode_flag being true. The attribute is modified only if there are at least 2 parts. :type explode_attribute: str :returns: Clipped layer (placed in the system temp dir). The output layer will be reprojected to EPSG:4326 if needed. :rtype: QgsVectorLayer """ if not layer or not extent: myMessage = tr('Layer or Extent passed to clip is None.') raise InvalidParameterError(myMessage) if layer.type() != QgsMapLayer.VectorLayer: myMessage = tr('Expected a vector layer but received a %s.' % str(layer.type())) raise InvalidParameterError(myMessage) #myHandle, myFilename = tempfile.mkstemp('.sqlite', 'clip_', # temp_dir()) myHandle, myFilename = tempfile.mkstemp('.shp', 'clip_', temp_dir()) # Ensure the file is deleted before we try to write to it # fixes windows specific issue where you get a message like this # ERROR 1: c:\temp\inasafe\clip_jpxjnt.shp is not a directory. # This is because mkstemp creates the file handle and leaves # the file open. os.close(myHandle) os.remove(myFilename) # Get the clip extents in the layer's native CRS myGeoCrs = QgsCoordinateReferenceSystem() myGeoCrs.createFromSrid(4326) myXForm = QgsCoordinateTransform(myGeoCrs, layer.crs()) myAllowedClipTypes = [QGis.WKBPolygon, QGis.WKBPolygon25D] if type(extent) is list: myRect = QgsRectangle( extent[0], extent[1], extent[2], extent[3]) # noinspection PyCallByClass myClipPolygon = QgsGeometry.fromRect(myRect) elif (type(extent) is QgsGeometry and extent.wkbType in myAllowedClipTypes): myRect = extent.boundingBox().toRectF() myClipPolygon = extent else: raise InvalidClipGeometryError( tr( 'Clip geometry must be an extent or a single part' 'polygon based geometry.')) myProjectedExtent = myXForm.transformBoundingBox(myRect) # Get vector layer myProvider = layer.dataProvider() if myProvider is None: myMessage = tr('Could not obtain data provider from ' 'layer "%s"' % layer.source()) raise Exception(myMessage) # Get the layer field list, select by our extent then write to disk # .. todo:: FIXME - for different geometry types we should implement # different clipping behaviour e.g. reject polygons that # intersect the edge of the bbox. Tim myRequest = QgsFeatureRequest() if not myProjectedExtent.isEmpty(): myRequest.setFilterRect(myProjectedExtent) myRequest.setFlags(QgsFeatureRequest.ExactIntersect) myFieldList = myProvider.fields() myWriter = QgsVectorFileWriter( myFilename, 'UTF-8', myFieldList, layer.wkbType(), myGeoCrs, #'SQLite') # FIXME (Ole): This works but is far too slow 'ESRI Shapefile') if myWriter.hasError() != QgsVectorFileWriter.NoError: myMessage = tr('Error when creating shapefile: <br>Filename:' '%s<br>Error: %s' % (myFilename, myWriter.hasError())) raise Exception(myMessage) # Reverse the coordinate xform now so that we can convert # geometries from layer crs to geocrs. myXForm = QgsCoordinateTransform(layer.crs(), myGeoCrs) # Retrieve every feature with its geometry and attributes myCount = 0 myHasMultipart = False for myFeature in myProvider.getFeatures(myRequest): myGeometry = myFeature.geometry() # Loop through the parts adding them to the output file # we write out single part features unless explode_flag is False if explode_flag: myGeometryList = explode_multipart_geometry(myGeometry) else: myGeometryList = [myGeometry] for myPartIndex, myPart in enumerate(myGeometryList): myPart.transform(myXForm) if hard_clip_flag: # Remove any dangling bits so only intersecting area is # kept. myPart = clip_geometry(myClipPolygon, myPart) if myPart is None: continue myFeature.setGeometry(myPart) # There are multiple parts and we want to show it in the # explode_attribute if myPartIndex > 0 and explode_attribute is not None: myHasMultipart = True myWriter.addFeature(myFeature) myCount += 1 del myWriter # Flush to disk if myCount < 1: myMessage = tr( 'No features fall within the clip extents. Try panning / zooming ' 'to an area containing data and then try to run your analysis ' 'again. If hazard and exposure data doesn\'t overlap at all, it ' 'is not possible to do an analysis. Another possibility is that ' 'the layers do overlap but because they may have different ' 'spatial references, they appear to be disjointed. If this is the ' 'case, try to turn on reproject on-the-fly in QGIS.') raise NoFeaturesInExtentError(myMessage) myKeywordIO = KeywordIO() if extra_keywords is None: extra_keywords = {} extra_keywords['had multipart polygon'] = myHasMultipart myKeywordIO.copy_keywords( layer, myFilename, extra_keywords=extra_keywords) myBaseName = '%s clipped' % layer.name() myLayer = QgsVectorLayer(myFilename, myBaseName, 'ogr') return myLayer
class osmSearchDialog(QDockWidget , Ui_osmSearch ): def __init__(self,iface): self.iface = iface QDockWidget.__init__(self) self.setupUi(self) self.iface.addDockWidget(Qt.BottomDockWidgetArea,self) self.canvas = self.iface.mapCanvas() self.rb = QgsRubberBand(self.canvas, QGis.Point) self.rb.setColor(QColor( 255, 0, 0, 150 )) self.searchCacheLimit = 1000 self.wgs84 = QgsCoordinateReferenceSystem() self.wgs84.createFromSrid(4326) self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) self.bSearch.clicked.connect(self.startSearch) self.eOutput.currentItemChanged.connect(self.itemChanged) self.eOutput.clickedOutsideOfItems.connect(self.itemChanged) self.eText.cleared.connect(self.clearEdit) self.canvas.mapRenderer().destinationSrsChanged.connect(self.crsChanged) self.iface.newProjectCreated.connect(self.clearEdit) self.iface.projectRead.connect(self.clearEdit) self.cbCenter.stateChanged.connect(self.autocenter) db = cacheDB() self.autocompleteList = db.getAutocompleteList() db.closeConnection() self.completer = QCompleter(self.autocompleteList) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.eText.setCompleter(self.completer) def startSearch(self): text = self.eText.text().encode('utf-8') if text == "": self.clearEdit() #url = 'http://open.mapquestapi.com/nominatim/v1/search.php' url = 'http://nominatim.openstreetmap.org/search' params = urllib.urlencode({'q': text,'format': 'json','polygon_text':'1'}) response = json.load(urllib2.urlopen(url+'?'+params)) self.loadData(response) def loadData(self, data): self.rb.reset(QGis.Point) self.eOutput.clear() items = [] for d in data: try: geometry = d['geotext'] except KeyError: geometry = 'POINT(%s %s)' % (d['lon'], d['lat']) item = QTreeWidgetItem([d['display_name'], d['type']]) item.setData(0, Qt.UserRole, geometry) if geometry.lower().startswith('point'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPointLayer.svg')) elif geometry.lower().startswith('linestring'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconLineLayer.svg')) elif geometry.lower().startswith('polygon'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPolygonLayer.svg')) items.append(item) if items: self.eOutput.insertTopLevelItems(0, items) self.addSearchTerm(unicode(self.eText.text().lower())) else: self.iface.messageBar().pushMessage('Nothing was found!', QgsMessageBar.CRITICAL, 2) def itemChanged(self, current=None, previous=None): if current: wkt = str(current.data(0,Qt.UserRole)) geom = QgsGeometry.fromWkt(wkt) if self.proj.srsid() != 4326: try: geom.transform(self.transform) except: self.iface.messageBar().pushMessage('CRS transformation error!', QgsMessageBar.CRITICAL, 2) self.rb.reset(QGis.Point) return self.rb.setToGeometry(geom, None) if self.cbCenter.isChecked(): self.moveCanvas(geom.centroid().asPoint(), self.canvas.extent()) else: self.rb.reset(QGis.Point) self.eOutput.setCurrentItem(None) def crsChanged(self): self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) def clearEdit(self): self.eOutput.clear() self.eText.clear() if hasattr(self, 'rb'): self.rb.reset(QGis.Point) def setCompleter(self): self.completer.model().setStringList(self.autocompleteList) def addSearchTerm(self, text): if not text in self.autocompleteList: self.autocompleteList.append(text) self.setCompleter() while len(self.autocompleteList) > self.searchCacheLimit: self.autocompleteList.pop(0) def autocenter(self, state): if state and self.rb.size(): self.moveCanvas(self.rb.asGeometry().centroid().asPoint(), self.canvas.extent()) def moveCanvas(self, newCenter, oldExtent): newExtent = QgsRectangle(oldExtent) newExtent.scale(1, newCenter) self.canvas.setExtent(newExtent) self.canvas.refresh()
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob( os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create layout with layout map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.layout = QgsPrintLayout(QgsProject.instance()) self.layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", 'outline_color': 'black'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.atlas_map = QgsLayoutItemMap(self.layout) self.atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) self.atlas_map.setFrameEnabled(True) self.atlas_map.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.atlas_map) # the atlas self.atlas = self.layout.atlas() self.atlas.setCoverageLayer(mVectorLayer) self.atlas.setEnabled(True) # an overview self.overview = QgsLayoutItemMap(self.layout) self.overview.attemptSetSceneRect(QRectF(180, 20, 50, 50)) self.overview.setFrameEnabled(True) self.overview.overview().setLinkedMap(self.atlas_map) self.overview.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.overview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.overview.setExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127", 'outline_color': 'black'} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.overview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.attemptSetSceneRect(QRectF(150, 5, 60, 15)) self.mLabel1.setMarginX(1) self.mLabel1.setMarginY(1) # feature number label self.mLabel2 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel2) self.mLabel2.setText( "# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.attemptSetSceneRect(QRectF(150, 200, 60, 15)) self.mLabel2.setMarginX(1) self.mLabel2.setMarginY(1) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() self.rotation_test() shutil.rmtree(tmppath, True)
def run(self): """Run the impact function. :returns: A new line layer with inundated roads marked. :type: safe_layer """ self.validate() self.prepare() self.provenance.append_step( 'Calculating Step', 'Impact function is calculating the impact.') # Thresholds for tsunami hazard zone breakdown. low_max = self.parameters['low_threshold'].value medium_max = self.parameters['medium_threshold'].value high_max = self.parameters['high_threshold'].value target_field = self.target_field # Get parameters from layer's keywords road_class_field = self.exposure.keyword('road_class_field') # reproject self.extent to the hazard projection hazard_crs = self.hazard.layer.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.requested_extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.requested_extent), geo_crs, hazard_crs) # Align raster extent and viewport # assuming they are both in the same projection raster_extent = self.hazard.layer.dataProvider().extent() clip_xmin = raster_extent.xMinimum() # clip_xmax = raster_extent.xMaximum() clip_ymin = raster_extent.yMinimum() # clip_ymax = raster_extent.yMaximum() if viewport_extent[0] > clip_xmin: clip_xmin = viewport_extent[0] if viewport_extent[1] > clip_ymin: clip_ymin = viewport_extent[1] height = ((viewport_extent[3] - viewport_extent[1]) / self.hazard.layer.rasterUnitsPerPixelY()) height = int(height) width = ((viewport_extent[2] - viewport_extent[0]) / self.hazard.layer.rasterUnitsPerPixelX()) width = int(width) raster_extent = self.hazard.layer.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / self.hazard.layer.width() x = xmin for i in range(self.hazard.layer.width()): if abs(x - clip_xmin) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / self.hazard.layer.height() y = ymin for i in range(self.hazard.layer.width()): if abs(y - clip_ymin) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip hazard raster small_raster = clip_raster( self.hazard.layer, width, height, QgsRectangle(*clip_extent)) # Create vector features from the flood raster # For each raster cell there is one rectangular polygon # Data also get spatially indexed for faster operation ranges = OrderedDict() ranges[0] = [0.0, 0.0] ranges[1] = [0.0, low_max] ranges[2] = [low_max, medium_max] ranges[3] = [medium_max, high_max] ranges[4] = [high_max, None] index, flood_cells_map = _raster_to_vector_cells( small_raster, ranges, self.exposure.layer.crs()) # Filter geometry and data using the extent ct = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), self.exposure.layer.crs()) extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent)) request = QgsFeatureRequest() request.setFilterRect(extent) """ if len(low_max_flood_cells_map) == 0 and \ len(medium_max_flood_cells_map) == 0 and \ len(high_max_flood_cells_map) == 0 and \ len(high_min_flood_cells_map) == 0: message = tr( 'There are no objects in the hazard layer with "value" > 0. ' 'Please check the value or use other extent.' % ( threshold_min, )) raise GetDataError(message) """ # create template for the output layer line_layer_tmp = create_layer(self.exposure.layer) new_field = QgsField(target_field, QVariant.Int) line_layer_tmp.dataProvider().addAttributes([new_field]) line_layer_tmp.updateFields() # create empty output layer and load it filename = unique_filename(suffix='.shp') QgsVectorFileWriter.writeAsVectorFormat( line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile") line_layer = QgsVectorLayer(filename, "flooded roads", "ogr") # Do the heavy work - for each road get flood polygon for that area and # do the intersection/difference to find out which parts are flooded _intersect_lines_with_vector_cells( self.exposure.layer, request, index, flood_cells_map, line_layer, target_field) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform( self.exposure.layer.crs(), output_crs) # Roads breakdown self.road_lengths = OrderedDict() self.affected_road_categories = self.hazard_classes # Impacted roads breakdown self.affected_road_lengths = OrderedDict([ (self.hazard_classes[0], {}), (self.hazard_classes[1], {}), (self.hazard_classes[2], {}), (self.hazard_classes[3], {}), (self.hazard_classes[4], {}), ]) if line_layer.featureCount() < 1: raise ZeroImpactException() roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_class_field) for road in roads_data: attributes = road.attributes() affected = attributes[target_field_index] hazard_zone = self.hazard_classes[affected] road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() if road_type not in self.road_lengths: self.road_lengths[road_type] = 0 if hazard_zone not in self.affected_road_lengths: self.affected_road_lengths[hazard_zone] = {} if road_type not in self.affected_road_lengths[hazard_zone]: self.affected_road_lengths[hazard_zone][road_type] = 0 self.road_lengths[road_type] += length num_classes = len(self.hazard_classes) if attributes[target_field_index] in range(num_classes): self.affected_road_lengths[hazard_zone][road_type] += length impact_summary = self.html_report() # For printing map purpose map_title = tr('Roads inundated') legend_title = tr('Road inundated status') style_classes = [ # FIXME 0 - 0.1 dict( label=self.hazard_classes[0] + ': 0m', value=0, colour='#00FF00', transparency=0, size=1 ), dict( label=self.hazard_classes[1] + ': <0 - %.1f m' % low_max, value=1, colour='#FFFF00', transparency=0, size=1 ), dict( label=self.hazard_classes[2] + ': %.1f - %.1f m' % ( low_max + 0.1, medium_max), value=2, colour='#FFB700', transparency=0, size=1 ), dict( label=self.hazard_classes[3] + ': %.1f - %.1f m' % ( medium_max + 0.1, high_max), value=3, colour='#FF6F00', transparency=0, size=1 ), dict( label=self.hazard_classes[4] + ' > %.1f m' % high_max, value=4, colour='#FF0000', transparency=0, size=1 ), ] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') extra_keywords = { 'impact_summary': impact_summary, 'map_title': map_title, 'legend_title': legend_title, 'target_field': target_field } self.set_if_provenance() impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector( data=line_layer, name=tr('Flooded roads'), keywords=impact_layer_keywords, style_info=style_info) self._impact = line_layer return line_layer
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create composition with composer map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.mComposition = QgsComposition(QgsProject.instance()) self.mComposition.setPaperSize(297, 210) # fix the renderer, fill with green props = {"color": "0,127,0"} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130) self.mAtlasMap.setFrameEnabled(True) self.mAtlasMap.setLayers([mVectorLayer]) self.mComposition.addComposerMap(self.mAtlasMap) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer(mVectorLayer) self.mAtlas.setEnabled(True) self.mComposition.setAtlasMode(QgsComposition.ExportAtlas) # an overview self.mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50) self.mOverview.setFrameEnabled(True) self.mOverview.overview().setFrameMap(self.mAtlasMap.id()) self.mOverview.setLayers([mVectorLayer]) self.mComposition.addComposerMap(self.mOverview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.mOverview.setNewExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127"} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.mOverview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15)) qWarning( "header label font: %s exactMatch:%s" % (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch())) # feature number label self.mLabel2 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel2) self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15)) qWarning("feature number label font: %s exactMatch:%s" % ( self.mLabel2.font().toString(), self.mLabel2.font().exactMatch())) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() shutil.rmtree(tmppath, True)
def render(self, params): self.check_required_params(params) with change_directory(self.project_root): crs = QgsCoordinateReferenceSystem() crs.createFromSrid(params.get('srs')) img = QImage( QSize(*params.get('image_size')), QImage.Format_ARGB32_Premultiplied ) dpm = 1 / 0.00028 img.setDotsPerMeterX(dpm) img.setDotsPerMeterY(dpm) # set background color bgcolor = params.get('bgcolor') if params.get('transparent'): # fully transparent bgcolor.append(0) else: # fully opaque bgcolor.append(255) color = QColor(*bgcolor) img.fill(color) map_settings = QgsMapSettings() map_settings.setBackgroundColor(color) map_settings.setDestinationCrs(crs) map_settings.setCrsTransformEnabled(True) map_settings.setExtent(QgsRectangle(*params.get('bbox'))) map_settings.setOutputDpi(img.logicalDpiX()) map_settings.setOutputSize(img.size()) map_settings.setMapUnits(crs.mapUnits()) layers = params.get('layers') self.setTransparencies(layers, params.get('transparencies')) map_settings.setLayers(layers) p = QPainter() p.begin(img) job = QgsMapRendererCustomPainterJob(map_settings, p) job.start() job.waitForFinished() map_buffer = QBuffer() map_buffer.open(QIODevice.ReadWrite) if params.get('image_format') == 'jpeg': img.save(map_buffer, 'JPEG') elif params.get('image_format') == 'png8': png8 = img.convertToFormat(QImage.Format_Indexed8) png8.save(map_buffer, "PNG") else: img.save(map_buffer, 'PNG') # clean up p.end() map_buffer.close() return map_buffer.data()
from PyQt5.QtCore import Qt, pyqtSignal, QThread from PyQt5.QtGui import QCursor from qgis.core import (QgsCoordinateTransform, QgsCoordinateTransformContext, QgsFeature, QgsPoint, QgsCoordinateReferenceSystem) from qgis.gui import QgsMapToolEmitPoint from .res import resources CRS_2180 = QgsCoordinateReferenceSystem() CRS_2180.createFromSrid(2180) class MapPointSearch(QgsMapToolEmitPoint): # search_started = pyqtSignal() # found = pyqtSignal(QgsFeature) # not_found = pyqtSignal(Exception) # search_finished = pyqtSignal() def __init__(self, parent, uldk_api, result_collector): self.parent = parent self.iface = parent.iface self.canvas = parent.canvas super(QgsMapToolEmitPoint, self).__init__(self.canvas) self.canvasClicked.connect(self.__search) self.uldk_api = uldk_api self.result_collector = result_collector self.search_in_progress = False
def newEntranceLayer(self): vl = QgsVectorLayer("Point?crs=", "memory:Entrances", "memory") provider = vl.dataProvider() provider.addAttributes([ QgsField(EntranceTool.id_attribute, QVariant.Int), QgsField(EntranceTool.category_attribute, QVariant.String), QgsField(EntranceTool.subcat_attribute, QVariant.String), QgsField(EntranceTool.level_attribute, QVariant.Double) ]) if vl.crs().toWkt() == "": vl.setCrs(QgsProject.instance().crs()) vl.updateFields() if self.entrancedlg.e_shp_radioButton.isChecked( ): # layer_type == 'shapefile': path = self.entrancedlg.lineEditEntrances.text() if path and path != '': filename = os.path.basename(path) location = os.path.abspath(path) crs = QgsCoordinateReferenceSystem() crs.createFromSrid(3857) shph.createShapeFile(vl, path, crs) vl = self.iface.addVectorLayer(location, filename[:-4], "ogr") else: vl = 'invalid data source' elif self.entrancedlg.e_postgis_radioButton.isChecked(): db_path = self.entrancedlg.lineEditEntrances.text() if db_path and db_path != '': (database, schema, table_name) = db_path.split(':') db_con_info = self.entrancedlg.dbsettings_dlg.available_dbs[ database] uri = QgsDataSourceUri() # passwords, usernames need to be empty if not provided or else connection will fail if 'service' in list(db_con_info.keys()): uri.setConnection(db_con_info['service'], '', '', '') elif 'password' in list(db_con_info.keys()): uri.setConnection(db_con_info['host'], db_con_info['port'], db_con_info['dbname'], db_con_info['user'], db_con_info['password']) else: print(db_con_info) # db_con_info['host'] uri.setConnection('', db_con_info['port'], db_con_info['dbname'], '', '') uri.setDataSource(schema, table_name, "geom") error = QgsVectorLayerExporter.exportLayer( vl, uri.uri(), "postgres", vl.crs()) if error[0] != QgsVectorLayerExporter.NoError: print("Error when creating postgis layer: ", error[1]) vl = 'duplicate' else: vl = QgsVectorLayer(uri.uri(), table_name, "postgres") else: vl = 'invalid data source' if vl == 'invalid data source': msgBar = self.iface.messageBar() msg = msgBar.createMessage(u'Specify output path!') msgBar.pushWidget(msg, Qgis.Info, 10) elif vl == 'duplicate': msgBar = self.iface.messageBar() msg = msgBar.createMessage(u'Fronatges layer already exists!') msgBar.pushWidget(msg, Qgis.Info, 10) elif not vl: msgBar = self.iface.messageBar() msg = msgBar.createMessage(u'Entrance layer failed to load!') msgBar.pushWidget(msg, Qgis.Info, 10) else: QgsProject.instance().addMapLayer(vl) msgBar = self.iface.messageBar() msg = msgBar.createMessage(u'Entrances layer created!') msgBar.pushWidget(msg, Qgis.Info, 10) vl.startEditing() self.updateEntranceLayer() self.entrancedlg.closePopUpEntrances()
def run(self, layers): """Experimental impact function. :param layers: List of layers expected to contain at least: H: Polygon layer of inundation areas E: Vector layer of roads :type layers: list :returns: A new line layer with inundated roads marked. :type: safe_layer """ target_field = self.parameters['target_field'] road_type_field = self.parameters['road_type_field'] threshold_min = self.parameters['min threshold [m]'] threshold_max = self.parameters['max threshold [m]'] if threshold_min > threshold_max: message = tr( 'The minimal threshold is greater then the maximal specified ' 'threshold. Please check the values.') raise GetDataError(message) # Extract data H = get_hazard_layer(layers) # Flood E = get_exposure_layer(layers) # Roads question = get_question( H.get_name(), E.get_name(), self) H = H.get_layer() E = E.get_layer() #reproject self.extent to the hazard projection hazard_crs = H.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.extent), geo_crs, hazard_crs) #Align raster extent and viewport #assuming they are both in the same projection raster_extent = H.dataProvider().extent() clip_xmin = raster_extent.xMinimum() # clip_xmax = raster_extent.xMaximum() clip_ymin = raster_extent.yMinimum() # clip_ymax = raster_extent.yMaximum() if viewport_extent[0] > clip_xmin: clip_xmin = viewport_extent[0] if viewport_extent[1] > clip_ymin: clip_ymin = viewport_extent[1] # TODO: Why have these two clauses when they are not used? # Commenting out for now. # if viewport_extent[2] < clip_xmax: # clip_xmax = viewport_extent[2] # if viewport_extent[3] < clip_ymax: # clip_ymax = viewport_extent[3] height = ((viewport_extent[3] - viewport_extent[1]) / H.rasterUnitsPerPixelY()) height = int(height) width = ((viewport_extent[2] - viewport_extent[0]) / H.rasterUnitsPerPixelX()) width = int(width) raster_extent = H.dataProvider().extent() xmin = raster_extent.xMinimum() xmax = raster_extent.xMaximum() ymin = raster_extent.yMinimum() ymax = raster_extent.yMaximum() x_delta = (xmax - xmin) / H.width() x = xmin for i in range(H.width()): if abs(x - clip_xmin) < x_delta: # We have found the aligned raster boundary break x += x_delta _ = i y_delta = (ymax - ymin) / H.height() y = ymin for i in range(H.width()): if abs(y - clip_ymin) < y_delta: # We have found the aligned raster boundary break y += y_delta clip_extent = [x, y, x + width * x_delta, y + height * y_delta] # Clip and polygonize small_raster = clip_raster( H, width, height, QgsRectangle(*clip_extent)) (flooded_polygon_inside, flooded_polygon_outside) = polygonize_gdal( small_raster, threshold_min, threshold_max) # Filter geometry and data using the extent extent = QgsRectangle(*self.extent) request = QgsFeatureRequest() request.setFilterRect(extent) if flooded_polygon_inside is None: message = tr( 'There are no objects in the hazard layer with "value">%s.' 'Please check the value or use other extent.' % ( threshold_min, )) raise GetDataError(message) #reproject the flood polygons to exposure projection exposure_crs = E.crs() exposure_authid = exposure_crs.authid() if hazard_authid != exposure_authid: flooded_polygon_inside = reproject_vector_layer( flooded_polygon_inside, E.crs()) flooded_polygon_outside = reproject_vector_layer( flooded_polygon_outside, E.crs()) # Clip exposure by the extent #extent_as_polygon = QgsGeometry().fromRect(extent) #no need to clip since It is using a bbox request #line_layer = clip_by_polygon( # E, # extent_as_polygon #) # Find inundated roads, mark them line_layer = split_by_polygon_in_out( E, flooded_polygon_inside, flooded_polygon_outside, target_field, 1, request) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.extent[0], self.extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform(E.crs(), output_crs) road_len = flooded_len = 0 # Length of roads roads_by_type = dict() # Length of flooded roads by types roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_type_field) for road in roads_data: attributes = road.attributes() road_type = attributes[road_type_field_index] if road_type.__class__.__name__ == 'QPyNullVariant': road_type = tr('Other') geom = road.geometry() geom.transform(transform) length = geom.length() road_len += length if not road_type in roads_by_type: roads_by_type[road_type] = {'flooded': 0, 'total': 0} roads_by_type[road_type]['total'] += length if attributes[target_field_index] == 1: flooded_len += length roads_by_type[road_type]['flooded'] += length table_body = [ question, TableRow([ tr('Road Type'), tr('Flooded in the threshold (m)'), tr('Total (m)')], header=True), TableRow([tr('All'), int(flooded_len), int(road_len)]) ] table_body.append(TableRow( tr('Breakdown by road type'), header=True)) for t, v in roads_by_type.iteritems(): table_body.append( TableRow([t, int(v['flooded']), int(v['total'])]) ) impact_summary = Table(table_body).toNewlineFreeString() map_title = tr('Roads inundated') style_classes = [ dict( label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict( label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5)] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') # Convert QgsVectorLayer to inasafe layer and return it line_layer = Vector( data=line_layer, name=tr('Flooded roads'), keywords={ 'impact_summary': impact_summary, 'map_title': map_title, 'target_field': target_field}, style_info=style_info) return line_layer
def _clip_vector_layer(layer, extent, extra_keywords=None, explode_flag=True, hard_clip_flag=False, explode_attribute=None): """Clip a Hazard or Exposure layer to the extents provided. The layer must be a vector layer or an exception will be thrown. The output layer will always be in WGS84/Geographic. :param layer: A valid QGIS vector or raster layer :type layer: :param extent: Either an array representing the exposure layer extents in the form [xmin, ymin, xmax, ymax]. It is assumed that the coordinates are in EPSG:4326 although currently no checks are made to enforce this. or: A QgsGeometry of type polygon. **Polygon clipping is currently only supported for vector datasets.** :type extent: list(float, float, float, float) :param extra_keywords: Optional keywords dictionary to be added to output layer. :type extra_keywords: dict :param explode_flag: A bool specifying whether multipart features should be 'exploded' into singleparts. **This parameter is ignored for raster layer clipping.** :type explode_flag: bool :param hard_clip_flag: A bool specifying whether line and polygon features that extend beyond the extents should be clipped such that they are reduced in size to the part of the geometry that intersects the extent only. Default is False. **This parameter is ignored for raster layer clipping.** :type hard_clip_flag: bool :param explode_attribute: A str specifying to which attribute #1, #2 and so on will be added in case of explode_flag being true. The attribute is modified only if there are at least 2 parts. :type explode_attribute: str :returns: Clipped layer (placed in the system temp dir). The output layer will be reprojected to EPSG:4326 if needed. :rtype: QgsVectorLayer """ if not layer or not extent: message = tr('Layer or Extent passed to clip is None.') raise InvalidParameterError(message) if layer.type() != QgsMapLayer.VectorLayer: message = tr('Expected a vector layer but received a %s.' % str(layer.type())) raise InvalidParameterError(message) #handle, file_name = tempfile.mkstemp('.sqlite', 'clip_', # temp_dir()) handle, file_name = tempfile.mkstemp('.shp', 'clip_', temp_dir()) # Ensure the file is deleted before we try to write to it # fixes windows specific issue where you get a message like this # ERROR 1: c:\temp\inasafe\clip_jpxjnt.shp is not a directory. # This is because mkstemp creates the file handle and leaves # the file open. os.close(handle) os.remove(file_name) # Get the clip extents in the layer's native CRS geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) transform = QgsCoordinateTransform(geo_crs, layer.crs()) allowed_clip_values = [QGis.WKBPolygon, QGis.WKBPolygon25D] if type(extent) is list: rectangle = QgsRectangle(extent[0], extent[1], extent[2], extent[3]) # noinspection PyCallByClass #noinspection PyTypeChecker polygon = QgsGeometry.fromRect(rectangle) elif (type(extent) is QgsGeometry and extent.wkbType in allowed_clip_values): rectangle = extent.boundingBox().toRectF() polygon = extent else: raise InvalidClipGeometryError( tr('Clip geometry must be an extent or a single part' 'polygon based geometry.')) projected_extent = transform.transformBoundingBox(rectangle) # Get vector layer provider = layer.dataProvider() if provider is None: message = tr('Could not obtain data provider from ' 'layer "%s"' % layer.source()) raise Exception(message) # Get the layer field list, select by our extent then write to disk # .. todo:: FIXME - for different geometry types we should implement # different clipping behaviour e.g. reject polygons that # intersect the edge of the bbox. Tim request = QgsFeatureRequest() if not projected_extent.isEmpty(): request.setFilterRect(projected_extent) request.setFlags(QgsFeatureRequest.ExactIntersect) field_list = provider.fields() writer = QgsVectorFileWriter( file_name, 'UTF-8', field_list, layer.wkbType(), geo_crs, #'SQLite') # FIXME (Ole): This works but is far too slow 'ESRI Shapefile') if writer.hasError() != QgsVectorFileWriter.NoError: message = tr('Error when creating shapefile: <br>Filename:' '%s<br>Error: %s' % (file_name, writer.hasError())) raise Exception(message) # Reverse the coordinate xform now so that we can convert # geometries from layer crs to geocrs. transform = QgsCoordinateTransform(layer.crs(), geo_crs) # Retrieve every feature with its geometry and attributes count = 0 has_multipart = False for feature in provider.getFeatures(request): geometry = feature.geometry() # Loop through the parts adding them to the output file # we write out single part features unless explode_flag is False if explode_flag: geometry_list = explode_multipart_geometry(geometry) else: geometry_list = [geometry] for part_index, part in enumerate(geometry_list): part.transform(transform) if hard_clip_flag: # Remove any dangling bits so only intersecting area is # kept. part = clip_geometry(polygon, part) if part is None: continue feature.setGeometry(part) # There are multiple parts and we want to show it in the # explode_attribute if part_index > 0 and explode_attribute is not None: has_multipart = True writer.addFeature(feature) count += 1 del writer # Flush to disk if count < 1: message = tr( 'No features fall within the clip extents. Try panning / zooming ' 'to an area containing data and then try to run your analysis ' 'again. If hazard and exposure data doesn\'t overlap at all, it ' 'is not possible to do an analysis. Another possibility is that ' 'the layers do overlap but because they may have different ' 'spatial references, they appear to be disjointed. If this is the ' 'case, try to turn on reproject on-the-fly in QGIS.') raise NoFeaturesInExtentError(message) keyword_io = KeywordIO() if extra_keywords is None: extra_keywords = {} extra_keywords['had multipart polygon'] = has_multipart keyword_io.copy_keywords(layer, file_name, extra_keywords=extra_keywords) base_name = '%s clipped' % layer.name() layer = QgsVectorLayer(file_name, base_name, 'ogr') return layer
def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() vectorFileInfo = QFileInfo( self.TEST_DATA_DIR + "/france_parts.shp") mVectorLayer = QgsVectorLayer( vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" ) QgsMapLayerRegistry.instance().addMapLayers( [mVectorLayer] ) # create composition with composer map mMapRenderer = QgsMapRenderer() layerStringList = [] layerStringList.append( mVectorLayer.id() ) mMapRenderer.setLayerSet( layerStringList ) mMapRenderer.setProjectionsEnabled( True ) mMapRenderer.setMapUnits( QGis.Meters ) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid( 2154 ) mMapRenderer.setDestinationCrs( crs ) self.mComposition = QgsComposition( mMapRenderer ) self.mComposition.setPaperSize( 297, 210 ) # fix the renderer, fill with green props = { "color": "0,127,0" } fillSymbol = QgsFillSymbolV2.createSimple( props ) renderer = QgsSingleSymbolRendererV2( fillSymbol ) mVectorLayer.setRendererV2( renderer ) # the atlas map self.mAtlasMap = QgsComposerMap( self.mComposition, 20, 20, 130, 130 ) self.mAtlasMap.setFrameEnabled( True ) self.mComposition.addComposerMap( self.mAtlasMap ) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer( mVectorLayer ) self.mAtlas.setEnabled( True ) self.mComposition.setAtlasMode( QgsComposition.ExportAtlas ) # an overview mOverview = QgsComposerMap( self.mComposition, 180, 20, 50, 50 ) mOverview.setFrameEnabled( True ) mOverview.setOverviewFrameMap( self.mAtlasMap.id() ) self.mComposition.addComposerMap( mOverview ) nextent = QgsRectangle( 49670.718, 6415139.086, 699672.519, 7065140.887 ) mOverview.setNewExtent( nextent ) # set the fill symbol of the overview map props2 = { "color": "127,0,0,127" } fillSymbol2 = QgsFillSymbolV2.createSimple( props2 ) mOverview.setOverviewFrameMapSymbol( fillSymbol2 ) # header label self.mLabel1 = QgsComposerLabel( self.mComposition ) self.mComposition.addComposerLabel( self.mLabel1 ) self.mLabel1.setText( "[% \"NAME_1\" %] area" ) self.mLabel1.setFont( QgsFontUtils.getStandardTestFont() ) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect( QRectF( 150, 5, 60, 15 ) ) qWarning( "header label font: %s exactMatch:%s" % ( self.mLabel1.font().toString(), self.mLabel1.font().exactMatch() ) ) # feature number label self.mLabel2 = QgsComposerLabel( self.mComposition ) self.mComposition.addComposerLabel( self.mLabel2 ) self.mLabel2.setText( "# [%$feature || ' / ' || $numfeatures%]" ) self.mLabel2.setFont( QgsFontUtils.getStandardTestFont() ) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect( QRectF( 150, 200, 60, 15 ) ) qWarning( "feature number label font: %s exactMatch:%s" % ( self.mLabel2.font().toString(), self.mLabel2.font().exactMatch() ) ) self.filename_test() self.autoscale_render_test() self.autoscale_render_test_old_api() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test()
def run(self): """Run the impact function. :returns: A new line layer with inundated roads marked. :type: safe_layer """ target_field = self.target_field # Get parameters from layer's keywords road_class_field = self.exposure.keyword('road_class_field') exposure_value_mapping = self.exposure.keyword('value_mapping') # Get parameters from IF parameter threshold_min = self.parameters['min threshold'].value threshold_max = self.parameters['max threshold'].value if threshold_min > threshold_max: message = tr( 'The minimal threshold is greater than the maximal specified ' 'threshold. Please check the values.') raise GetDataError(message) # reproject self.extent to the hazard projection hazard_crs = self.hazard.layer.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.requested_extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.requested_extent), geo_crs, hazard_crs) # Clip hazard raster small_raster = align_clip_raster(self.hazard.layer, viewport_extent) # Filter geometry and data using the extent ct = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), self.exposure.layer.crs()) extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent)) request = QgsFeatureRequest() request.setFilterRect(extent) # create template for the output layer line_layer_tmp = create_layer(self.exposure.layer) new_field = QgsField(target_field, QVariant.Int) line_layer_tmp.dataProvider().addAttributes([new_field]) line_layer_tmp.updateFields() # create empty output layer and load it filename = unique_filename(suffix='.shp') QgsVectorFileWriter.writeAsVectorFormat( line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile") line_layer = QgsVectorLayer(filename, "flooded roads", "ogr") # Create vector features from the flood raster # For each raster cell there is one rectangular polygon # Data also get spatially indexed for faster operation index, flood_cells_map = _raster_to_vector_cells( small_raster, threshold_min, threshold_max, self.exposure.layer.crs()) if len(flood_cells_map) == 0: message = tr( 'There are no objects in the hazard layer with "value" > %s. ' 'Please check the value or use other extent.' % ( threshold_min, )) raise GetDataError(message) # Do the heavy work - for each road get flood polygon for that area and # do the intersection/difference to find out which parts are flooded _intersect_lines_with_vector_cells( self.exposure.layer, request, index, flood_cells_map, line_layer, target_field) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform( self.exposure.layer.crs(), output_crs) classes = [tr('Flooded in the threshold (m)')] self.init_report_var(classes) if line_layer.featureCount() < 1: raise ZeroImpactException() roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_class_field) for road in roads_data: attributes = road.attributes() usage = attributes[road_type_field_index] usage = main_type(usage, exposure_value_mapping) geom = road.geometry() geom.transform(transform) length = geom.length() affected = False if attributes[target_field_index] == 1: affected = True self.classify_feature(classes[0], usage, length, affected) self.reorder_dictionaries() style_classes = [ dict( label=tr('Not Inundated'), value=0, colour='#1EFC7C', transparency=0, size=0.5), dict( label=tr('Inundated'), value=1, colour='#F31A1C', transparency=0, size=0.5)] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'map_title': self.metadata().key('map_title'), 'legend_title': self.metadata().key('legend_title'), 'target_field': target_field } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Convert QgsVectorLayer to inasafe layer and return it impact_layer = Vector( data=line_layer, name=self.metadata().key('layer_name'), keywords=impact_layer_keywords, style_info=style_info) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
def print_map(self, tav_num): self.tav_num = tav_num p = QgsProject.instance() crs = QgsCoordinateReferenceSystem() crs.createFromSrid(self.SRS) p.setCrs(crs) l = QgsLayout(p) l.initializeDefaults() page = l.pageCollection().page(0) # map - this item tells the libraries where to put the map itself. Here we create a map and stretch it over the whole paper size: x, y = 0, 0 # angolo 0, o in alto a sx if (0 <= self.width <= 297) and (0 <= self.height <= 210): width, height = 297, 210 # Formato A4 Landscape elif (0 <= self.height <= 297) and (0 <= self.width <= 210): width, height = 210, 297 # Formato A4 elif (0 <= self.width <= 420) and (0 <= self.height <= 297): width, height = 297, 420 # Formato A3 Landscape elif (0 <= self.height <= 420) and (0 <= self.width <= 297): width, height = 240, 297 # Formato A4 elif (0 <= self.width <= 1189) and (0 <= self.height <= 841): width, height = 1189, 841 # Formato A0 Landscape elif (0 <= self.height <= 1189) and (0 <= self.width <= 841): width, height = 841, 1189 # Formato A0 else: width, height = self.width * 1.2, self.height * 1.2 # self.width*10, self.height*10 da un valore alla larghezza e altezza del foglio aumentato di 5 per dare un margine size = QgsLayoutSize(width, height) page.setPageSize(size) map = QgsLayoutItemMap(l) rect = self.getMapExtentFromMapCanvas(page.pageSize().width(), page.pageSize().height(), 20.0) map.attemptSetSceneRect( QRectF(0, 0, page.pageSize().width(), page.pageSize().height())) map.setExtent(rect) map.setLayers([self.layerUS]) l.setReferenceMap(map) l.addLayoutItem(map) intestazioneLabel = QgsLayoutItemLabel(l) txt = "Tavola %s - US:%d" % (self.tav_num + 1, self.us) intestazioneLabel.setText(txt) intestazioneLabel.adjustSizeToText() intestazioneLabel.attemptMove(QgsLayoutPoint(1, 0), page=0) intestazioneLabel.setFrameEnabled(False) l.addLayoutItem(intestazioneLabel) scaleLabel = QgsLayoutItemLabel(l) txt = "Scala: " scaleLabel.setText(txt) scaleLabel.adjustSizeToText() scaleLabel.attemptMove(QgsLayoutPoint(1, 5), page=0) scaleLabel.setFrameEnabled(False) l.addLayoutItem(scaleLabel) # aggiunge la scale bar scaleBarItem = QgsLayoutItemScaleBar(l) scaleBarItem.setStyle('Numeric') # optionally modify the style scaleBarItem.setLinkedMap(map) scaleBarItem.applyDefaultSize() scaleBarItem.attemptMove(QgsLayoutPoint(10, 5), page=0) scaleBarItem.setFrameEnabled(False) l.addLayoutItem(scaleBarItem) le = QgsLayoutExporter(l) settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 100 MAPS_path = '{}{}{}'.format(self.HOME, os.sep, "pyarchinit_MAPS_folder") tav_name = "Tavola_{}_us_{}.png".format(self.tav_num + 1, self.us) filename_png = '{}{}{}'.format(MAPS_path, os.sep, tav_name) le.exportToImage(filename_png, settings) self.remove_layer()
def processAlgorithm(self, parameters, context, feedback): pasta = self.parameterAsFile(parameters, self.FOLDER, context) if not pasta: raise QgsProcessingException( self.invalidSourceError(parameters, self.FOLDER)) fotos_nao_geo = self.parameterAsFile(parameters, self.NONGEO, context) lista = os.listdir(pasta) tam = len(lista) copy_ngeo = False if os.path.isdir(fotos_nao_geo): copy_ngeo = True # Funcao para transformar os dados do EXIF em coordenadas em graus decimais def coordenadas(exif): try: ref_lat = exif['GPSInfo'][1][0] ref_lon = exif['GPSInfo'][3][0] sinal_lat, sinal_lon = 0, 0 if ref_lat == 'S': sinal_lat = -1 elif ref_lat == 'N': sinal_lat = 1 if ref_lon == 'W': sinal_lon = -1 elif ref_lon == 'E': sinal_lon = 1 grausLat, grausLon = exif['GPSInfo'][2][0][0], exif['GPSInfo'][ 4][0][0] minLat, minLon = exif['GPSInfo'][2][1][0], exif['GPSInfo'][4][ 1][0] segLat = exif['GPSInfo'][2][2][0] / float( exif['GPSInfo'][2][2][1]) segLon = exif['GPSInfo'][4][2][0] / float( exif['GPSInfo'][4][2][1]) if sinal_lat != 0 and sinal_lon != 0: lat = sinal_lat * (float(grausLat) + minLat / 60.0 + segLat / 3600.0) lon = sinal_lon * (float(grausLon) + minLon / 60.0 + segLon / 3600.0) return lat, lon except: return 0, 0 # Funcao para pegar Azimute def azimute(exif): Az = exif['GPSInfo'][17] if isinstance(Az, tuple): Az = Az[0] / float(Az[1]) return Az else: return Az # Funcao para gerar o padrao data-hora def data_hora(texto): data_hora = texto.replace(' ', ':') data_hora = data_hora.split(':') ano = int(data_hora[0]) mes = int(data_hora[1]) dia = int(data_hora[2]) hora = int(data_hora[3]) minuto = int(data_hora[4]) segundo = int(data_hora[5]) data_hora = unicode( datetime.datetime(ano, mes, dia, hora, minuto, segundo)) return data_hora # Criando Output crs = QgsCoordinateReferenceSystem() crs.createFromSrid(4326) fields = QgsFields() fields.append(QgsField(self.tr('name', 'nome'), QVariant.String)) fields.append(QgsField(self.tr('azimuth', 'azimute'), QVariant.Int)) fields.append( QgsField(self.tr('date_time', 'data_hora'), QVariant.String)) fields.append(QgsField(self.tr('path', 'caminho'), QVariant.String)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, crs) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) Percent = 100.0 / tam if tam != 0 else 0 for index, arquivo in enumerate(lista): if (arquivo).lower().endswith(('.jpg', '.jpeg')): img = PIL.Image.open(os.path.join(pasta, arquivo)) if img._getexif(): exif = { PIL.ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in PIL.ExifTags.TAGS } else: exif = {} lon, lat = 0, 0 Az = None date_time = None if 'GPSInfo' in exif: lat, lon = coordenadas(exif) if 17 in exif['GPSInfo']: Az = azimute(exif) if 'DateTimeOriginal' in exif: date_time = data_hora(exif['DateTimeOriginal']) elif 'DateTime' in exif: date_time = data_hora(exif['DateTime']) if lon != 0: feature = QgsFeature(fields) feature.setGeometry( QgsGeometry.fromPointXY(QgsPointXY(lon, lat))) feature.setAttributes( [arquivo, Az, date_time, os.path.join(pasta, arquivo)]) sink.addFeature(feature, QgsFeatureSink.FastInsert) else: print() feedback.pushInfo( self.tr( 'The file "{}" has no geotag!'.format(arquivo), 'A imagem "{}" não possui geotag!'.format( arquivo))) if copy_ngeo: shutil.copy2(os.path.join(pasta, arquivo), os.path.join(fotos_nao_geo, arquivo)) if feedback.isCanceled(): break feedback.setProgress(int((index + 1) * Percent)) feedback.pushInfo( self.tr('Operation completed successfully!', 'Operação finalizada com sucesso!')) feedback.pushInfo( self.tr('Leandro Franca - Cartographic Engineer', 'Leandro França - Eng Cart')) return {self.OUTPUT: dest_id}
def run(self): """Run the impact function. :returns: A new line layer with inundated roads marked. :type: safe_layer """ # Thresholds for tsunami hazard zone breakdown. low_max = self.parameters['low_threshold'].value medium_max = self.parameters['medium_threshold'].value high_max = self.parameters['high_threshold'].value target_field = self.target_field # Get parameters from layer's keywords road_class_field = self.exposure.keyword('road_class_field') exposure_value_mapping = self.exposure.keyword('value_mapping') # reproject self.extent to the hazard projection hazard_crs = self.hazard.layer.crs() hazard_authid = hazard_crs.authid() if hazard_authid == 'EPSG:4326': viewport_extent = self.requested_extent else: geo_crs = QgsCoordinateReferenceSystem() geo_crs.createFromSrid(4326) viewport_extent = extent_to_geo_array( QgsRectangle(*self.requested_extent), geo_crs, hazard_crs) # Clip hazard raster small_raster = align_clip_raster(self.hazard.layer, viewport_extent) # Create vector features from the flood raster # For each raster cell there is one rectangular polygon # Data also get spatially indexed for faster operation ranges = ranges_according_thresholds(low_max, medium_max, high_max) index, flood_cells_map = _raster_to_vector_cells( small_raster, ranges, self.exposure.layer.crs()) # Filter geometry and data using the extent ct = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), self.exposure.layer.crs()) extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent)) request = QgsFeatureRequest() request.setFilterRect(extent) # create template for the output layer line_layer_tmp = create_layer(self.exposure.layer) new_field = QgsField(target_field, QVariant.Int) line_layer_tmp.dataProvider().addAttributes([new_field]) line_layer_tmp.updateFields() # create empty output layer and load it filename = unique_filename(suffix='.shp') QgsVectorFileWriter.writeAsVectorFormat( line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile") line_layer = QgsVectorLayer(filename, "flooded roads", "ogr") # Do the heavy work - for each road get flood polygon for that area and # do the intersection/difference to find out which parts are flooded _intersect_lines_with_vector_cells( self.exposure.layer, request, index, flood_cells_map, line_layer, target_field) target_field_index = line_layer.dataProvider().\ fieldNameIndex(target_field) # Generate simple impact report epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1]) output_crs = QgsCoordinateReferenceSystem(epsg) transform = QgsCoordinateTransform( self.exposure.layer.crs(), output_crs) # Roads breakdown self.init_report_var(self.hazard_classes) if line_layer.featureCount() < 1: raise ZeroImpactException() roads_data = line_layer.getFeatures() road_type_field_index = line_layer.fieldNameIndex(road_class_field) for road in roads_data: attributes = road.attributes() affected = attributes[target_field_index] if isinstance(affected, QPyNullVariant): continue else: hazard_zone = self.hazard_classes[affected] usage = attributes[road_type_field_index] usage = main_type(usage, exposure_value_mapping) geom = road.geometry() geom.transform(transform) length = geom.length() affected = False num_classes = len(self.hazard_classes) if attributes[target_field_index] in range(num_classes): affected = True self.classify_feature(hazard_zone, usage, length, affected) self.reorder_dictionaries() style_classes = [ # FIXME 0 - 0.1 dict( label=self.hazard_classes[0] + ': 0m', value=0, colour='#00FF00', transparency=0, size=1 ), dict( label=self.hazard_classes[1] + ': >0 - %.1f m' % low_max, value=1, colour='#FFFF00', transparency=0, size=1 ), dict( label=self.hazard_classes[2] + ': %.1f - %.1f m' % ( low_max + 0.1, medium_max), value=2, colour='#FFB700', transparency=0, size=1 ), dict( label=self.hazard_classes[3] + ': %.1f - %.1f m' % ( medium_max + 0.1, high_max), value=3, colour='#FF6F00', transparency=0, size=1 ), dict( label=self.hazard_classes[4] + ' > %.1f m' % high_max, value=4, colour='#FF0000', transparency=0, size=1 ), ] style_info = dict( target_field=target_field, style_classes=style_classes, style_type='categorizedSymbol') impact_data = self.generate_data() extra_keywords = { 'map_title': self.metadata().key('map_title'), 'legend_title': self.metadata().key('legend_title'), 'target_field': target_field } impact_layer_keywords = self.generate_impact_keywords(extra_keywords) # Convert QgsVectorLayer to inasafe layer and return it impact_layer = Vector( data=line_layer, name=self.metadata().key('layer_name'), keywords=impact_layer_keywords, style_info=style_info) impact_layer.impact_data = impact_data self._impact = impact_layer return impact_layer
from PyQt5.QtCore import QVariant from qgis.core import (QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsCoordinateTransformContext, QgsFeature, QgsGeometry, QgsPointXY, QgsWkbTypes) crs_2180 = QgsCoordinateReferenceSystem() crs_2180.createFromSrid(2180) def extract_lpis_bbox(lpis_response, target_crs, response_crs = crs_2180): response_points = lpis_response["geometry"]["coordinates"][0] wkt = "POLYGON (({}))" wkt_points = [] for point in response_points: wkt_point = "{} {}".format(*point) wkt_points.append(wkt_point) wkt_points_str = ", ".join(wkt_points) wkt = wkt.format(wkt_points_str) response_bbox = QgsGeometry().fromWkt(wkt) transformation = QgsCoordinateTransform(response_crs, target_crs, QgsCoordinateTransformContext()) target_bbox = transformation.transformBoundingBox(response_bbox.boundingBox()) return target_bbox