def update_ee_image_layers(self): layers = QgsProject.instance().mapLayers().values() for eelayer in filter( lambda layer: layer.customProperty('ee-image') == 'XML', layers): extent = eelayer.customProperty('ee-image-wkt') bb = QgsRectangle.fromWkt(extent) eelayer.setExtent(bb) xml_file = eelayer.dataProvider().dataSourceUri() # ds = gdal.Open(xml_file) # if ds.ReadAsArray(xsize=1, ysize=1) is None: imageid = eelayer.customProperty('ee-image-id') bands = eelayer.customProperty('ee-image-bands') qml = eelayer.customProperty('ee-image-qml') palette = eelayer.customProperty('ee-image-palette') if not qml: b_min = list(map(int, eelayer.customProperty('ee-image-b_min'))) b_max = list(map(int, eelayer.customProperty('ee-image-b_max'))) else: b_min = None b_max = None if self.ee_uninitialized: ee.Initialize() new_tms = update_ee_image_layer(imageid, bands, b_min, b_max, palette) replace_tms(xml_file, new_tms)
def gee_layer_make_xml(self): eelayer = self.iface.activeLayer() dest_dir = QgsProject.instance().absolutePath() or os.getcwd() dest_name = eelayer.name().replace('/', '_') + '.xml' dest_file = os.path.join(dest_dir, dest_name) source_xml = eelayer.dataProvider().dataSourceUri() dest_xml, _ = QFileDialog.getSaveFileName(self.dlg, 'Select output file', dest_file, 'XML files (*.xml)') if dest_xml: shutil.copyfile(source_xml, dest_xml) newname = os.path.splitext(os.path.basename(dest_xml))[0] newlayer = QgsRasterLayer(dest_xml, newname) if newlayer.isValid(): imageid = eelayer.customProperty('ee-image-id') date = eelayer.customProperty('ee-image-date') qml = eelayer.customProperty('ee-image-qml') extent = eelayer.customProperty('ee-image-wkt') # load qml must be first since this clean all custom properties if qml is not None: if isfile(qml + '_' + QSettings().value('locale/userLocale') + '.qml'): newlayer.loadNamedStyle( qml + '_' + QSettings().value('locale/userLocale') + '.qml') else: newlayer.loadNamedStyle(qml + '.qml') newlayer.setCustomProperty('ee-image', 'XML') newlayer.setCustomProperty('ee-image-id', imageid) newlayer.setCustomProperty('ee-image-date', date) newlayer.setCustomProperty( 'ee-image-bands', eelayer.customProperty('ee-image-bands')) newlayer.setCustomProperty( 'ee-image-scale', eelayer.customProperty('ee-image-scale')) newlayer.setCustomProperty( 'ee-image-b_min', eelayer.customProperty('ee-image-b_min')) newlayer.setCustomProperty( 'ee-image-b_max', eelayer.customProperty('ee-image-b_max')) newlayer.setCustomProperty( 'ee-image-palette', eelayer.customProperty('ee-image-palette')) newlayer.setCustomProperty('ee-image-qml', qml) newlayer.setCustomProperty('ee-image-wkt', extent) if date is not None: newlayer.setAbstract( f"ee.Image('{imageid}') \n\nDate: {date}") else: newlayer.setAbstract(f"ee.Image('{imageid}')") bb = QgsRectangle.fromWkt(extent) newlayer.setExtent(bb) QgsProject.instance().addMapLayer(newlayer) QgsProject.instance().layerTreeRoot().findLayer( newlayer.id()).setItemVisibilityChecked(False)
def update_ee_image_layer(self, eelayer): extent = eelayer.customProperty('ee-image-wkt') bb = QgsRectangle.fromWkt(extent) eelayer.setExtent(bb) xml_file = eelayer.dataProvider().dataSourceUri() # ds = gdal.Open(xml_file) # if ds.ReadAsArray(xsize=1, ysize=1) is None: imageid = eelayer.customProperty('ee-image-id') bands = eelayer.customProperty('ee-image-bands') qml = eelayer.customProperty('ee-image-qml') palette = eelayer.customProperty('ee-image-palette') if not qml: b_min = list(map(int, eelayer.customProperty('ee-image-b_min'))) b_max = list(map(int, eelayer.customProperty('ee-image-b_max'))) else: b_min = None b_max = None if self.ee_uninitialized: ee.Initialize() new_xml = update_ee_image_xml(imageid, bands, b_min, b_max, palette) write_xmlfile(new_xml, name=None, dest=xml_file) eelayer.dataProvider().reloadData() eelayer.triggerRepaint() eelayer.reload()
def result(self, result): # See if OK was pressed if result: project = QgsProject.instance() # First get all the values of the GUI items crs_input = self.dlg.crs_input.crs() crs_out = QgsCoordinateReferenceSystem( 'EPSG:4326') # we need this to be WGS84 for Nominatim lineedit_text = self.dlg.lineedit_xy.value() # Protect the free text field for coordinates from generic user failure try: lineedit_yx = [ float(coord.strip()) for coord in lineedit_text.split(',') ] except: QMessageBox.critical( self.iface.mainWindow(), 'QuickAPI error', "Did you really specify a coordinate in comma-separated Lat/Long?\nExiting..." ) return # Create a Point and transform if necessary point = QgsPointXY(*reversed(lineedit_yx)) if crs_input.authid() != 'EPSG:4326': xform = QgsCoordinateTransform(crs_input, crs_out, project) point_transform = xform.transform(point) point = point_transform # Set up the GET Request to Nominatim query = QUrlQuery() query.addQueryItem('lat', str(point.y())) query.addQueryItem('lon', str(point.x())) query.addQueryItem('format', 'json') url = QUrl('https://nominatim.openstreetmap.org/reverse') url.setQuery(query) request = QNetworkRequest(url) request.setHeader(QNetworkRequest.UserAgentHeader, '*****@*****.**') nam = QgsNetworkAccessManager() response: QgsNetworkReplyContent = nam.blockingGet(request) # Only process if HTTP status code is 200 status_code = response.attribute( QNetworkRequest.HttpStatusCodeAttribute) if status_code == 200: # Get the content of the response and process it response_json = json.loads(bytes(response.content())) if response_json.get('error'): QMessageBox.critical( self.iface.mainWindow(), "Quick API error", "The request was not processed succesfully!\n\n" "Message:\n" "{}".format(response_json['error'])) return x = float(response_json['lon']) y = float(response_json['lat']) address = response_json['display_name'] license = response_json['licence'] # Create the output memory layer layer_out = QgsVectorLayer( "Point?crs=EPSG:4326&field=address:string&field=license:string", "Nominatim Reverse Geocoding", "memory") # Create the output feature (only one here) point_out = QgsPointXY(x, y) feature = QgsFeature() feature.setGeometry(QgsGeometry.fromPointXY(point_out)) feature.setAttributes([address, license]) # Add feature to layer and layer to map layer_out.dataProvider().addFeature(feature) layer_out.updateExtents() project.addMapLayer(layer_out) # build bbox for auto-zoom feature bbox = [float(coord) for coord in response_json['boundingbox']] min_y, max_y, min_x, max_x = bbox bbox_geom = QgsGeometry.fromRect( QgsRectangle(min_x, min_y, max_x, max_y)) # Transform bbox if map canvas has a different CRS if project.crs().authid() != 'EPSG:4326': xform = QgsCoordinateTransform(crs_out, project.crs(), project) bbox_geom.transform(xform) self.iface.mapCanvas().zoomToFeatureExtent( QgsRectangle.fromWkt(bbox_geom.asWkt()))
def from_dict(dict_data: dict): return LocationResult( QgsGeometry.fromWkt(dict_data['point']).asPoint(), QgsRectangle.fromWkt(dict_data['bbox']), dict_data['layer'], dict_data['feature_id'], dict_data['html_label'])
def add_ee_image_layer(imageid, name, date, bands, scale, b_min=None, b_max=None, palette=None, qml=None, extent=None, shown=False, destination=None): nbands = len(bands) # if nbands > 3: # rgb = ee.Image(imageid).select(bands[0:3]) # pan = ee.Image(imageid).select(bands[3]) # huesat = rgb.rgbToHsv().select('hue', 'saturation') # image = ee.Image.cat(huesat, pan).hsvToRgb().select([0, 1, 2], bands[0:3]) # nbands = 3 # else: image = ee.Image(imageid) if not any([b_min, b_max, palette, qml]): image_stats = image.select(bands[0:nbands]).reduceRegion(ee.Reducer.minMax(), None, scale, None, None, False, 1.0E13).getInfo() b_min = [image_stats[bands[n] + '_min'] for n in range(nbands)] b_max = [image_stats[bands[n] + '_max'] for n in range(nbands)] # b_min = [image_stats[bands[0] + '_min'], image_stats[bands[1] + '_min'], image_stats[bands[2] + '_min']] # b_max = [image_stats[bands[0] + '_max'], image_stats[bands[1] + '_max'], image_stats[bands[2] + '_max']] rgb = image.visualize(bands=bands[0:nbands], min=b_min, max=b_max, palette=palette) tms = get_ee_image_tms(rgb) if extent is None: image_geojson = get_ee_image_bb(rgb) extent = geojson_to_wkt(image_geojson) bb = QgsRectangle.fromWkt(extent) url = tms_to_gdalurl(tms) xml = get_gdal_xml(url, nbands=nbands+1) # vfn = write_vsimem_xml(xml) # changed to named temporary file tmp, fn = write_xmlfile(xml, name, dest=destination) layer = QgsRasterLayer(fn, name) if layer.isValid(): if qml is not None: if isfile(qml + '_' + QSettings().value('locale/userLocale') + '.qml'): layer.loadNamedStyle(qml + '_' + QSettings().value('locale/userLocale') + '.qml') else: layer.loadNamedStyle(qml + '.qml') layer.setExtent(bb) if tmp: layer.setCustomProperty('ee-image', 'MEM') else: layer.setCustomProperty('ee-image', 'XML') layer.setCustomProperty('ee-image-id', imageid) layer.setCustomProperty('ee-image-date', date) layer.setCustomProperty('ee-image-bands', bands) layer.setCustomProperty('ee-image-scale', scale) layer.setCustomProperty('ee-image-b_min', b_min) layer.setCustomProperty('ee-image-b_max', b_max) layer.setCustomProperty('ee-image-palette', palette) layer.setCustomProperty('ee-image-qml', qml) layer.setCustomProperty('ee-image-wkt', extent) # else: # layer.setAbstract(f"ee.Image('{imageid}')") # if len(bands) < 4: # try: # layer.setCustomProperty('ee-image-stats', image_stats) # except NameError: # pass if date is not None: layer.setAbstract(f"ee.Image('{imageid}') \n\nDate: {date}") else: layer.setAbstract(f"ee.Image('{imageid}')") QgsProject.instance().addMapLayer(layer) if not shown: QgsProject.instance().layerTreeRoot().findLayer(layer.id()).setItemVisibilityChecked(shown)
def result(self, result): if result: # save a project reference project = QgsProject.instance() # Save the user input lineedit_text = self.dlg.lineedit_xy.value() crs_input = self.dlg.crs_input.crs() crs_out = QgsCoordinateReferenceSystem( 4326) # we need this to be WGS84 for Nominatim # Protect the free text field for coordinates from generic user failure:) try: lineedit_yx = [ float(coord.strip()) for coord in lineedit_text.split(',') ] except: QMessageBox.critical( self.iface.mainWindow(), 'QuickAPI error', "Did you really specify a coordinate in comma-separated Lat/Long?\nExiting..." ) return # Create a Point and transform if necessary point = QgsPointXY(*reversed(lineedit_yx)) if crs_input.authid() != 'EPSG:4326': xform = QgsCoordinateTransform(crs_input, crs_out, project) point_transform = xform.transform(point) point = point_transform # Set up and fire Nominatim GET request user_agent = '*****@*****.**' base_url = 'https://nominatim.openstreetmap.org/reverse' params = {'lat': point.y(), 'lon': point.x(), 'format': 'json'} response = requests.get(url=base_url, params=params, headers={'User-Agent': user_agent}) response_json = response.json() # Only process response if HTTP 200 if response.status_code == 200: # Unfortunately Nominatim goes against protocol and responds with 200 even if an error occurred if response_json.get('error'): QMessageBox.critical( self.iface.mainWindow(), "Quick API error", "The request was not processed succesfully!\n\n" "Message:\n" "{}".format(response.json())) return # Capture relevant response fields x = float(response_json['lon']) y = float(response_json['lat']) address = response_json['display_name'] license = response_json['licence'] # Create the output memory layer layer_out = QgsVectorLayer( "Point?crs=EPSG:4326&field=address:string&field=license:string", "Nominatim Reverse Geocoding", "memory") # Create the output feature (only one here) point_out = QgsPointXY(x, y) feature = QgsFeature() feature.setGeometry(QgsGeometry.fromPointXY(point_out)) feature.setAttributes([address, license]) # Add feature to layer and layer to map layer_out.dataProvider().addFeature(feature) layer_out.updateExtents() project.addMapLayer(layer_out) # build bbox for auto-zoom feature bbox = [float(coord) for coord in response_json['boundingbox']] min_y, max_y, min_x, max_x = bbox bbox_geom = QgsGeometry.fromPolygonXY([[ QgsPointXY(min_x, min_y), QgsPointXY(min_x, max_y), QgsPointXY(max_x, max_y), QgsPointXY(max_x, min_y), ]]) # Transform bbox if map canvas has a different CRS if project.crs().authid() != 'EPSG:4326': xform = QgsCoordinateTransform(crs_out, project.crs(), project) bbox_geom.transform(xform) self.iface.mapCanvas().zoomToFeatureExtent( QgsRectangle.fromWkt(bbox_geom.asWkt()))