def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") daCRS = QgsCoordinateReferenceSystem() daCRS = da.sourceCrs() polygon = QgsGeometry.fromPolygon( [[ QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ]] ) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoidalMode(True) area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) # should always be in Meters Squared self.assertAlmostEqual(area, 37416879192.9, delta=0.1) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMiles) self.assertAlmostEqual(area, 14446.7378, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygon( [[ QgsPoint(1850000, 4423000), QgsPoint(1851000, 4423000), QgsPoint(1851000, 4424000), QgsPoint(1852000, 4424000), QgsPoint(1852000, 4425000), QgsPoint(1851000, 4425000), QgsPoint(1850000, 4423000) ]] ) da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.AreaSquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoidalMode(True) # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 184149.37, delta=1.0) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 220240.8172549, delta=1.0)
def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") polygon = QgsGeometry.fromPolygonXY( [[ QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(0, 2), QgsPointXY(0, 0), ]] ) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) # should always be in Meters Squared self.assertAlmostEqual(area, 36918093794.121284, delta=0.1) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMiles) self.assertAlmostEqual(area, 14254.155703182701, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygonXY( [[ QgsPointXY(1850000, 4423000), QgsPointXY(1851000, 4423000), QgsPointXY(1851000, 4424000), QgsPointXY(1852000, 4424000), QgsPointXY(1852000, 4425000), QgsPointXY(1851000, 4425000), QgsPointXY(1850000, 4423000) ]] ) da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.AreaSquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoid("WGS84") # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 185818.59096575077, delta=1.0) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222237.18521272976, delta=1.0)
def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") polygon = QgsGeometry.fromPolygonXY( [[ QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 2), QgsPointXY(0, 2), QgsPointXY(0, 0), ]] ) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) # should always be in Meters Squared self.assertAlmostEqual(area, 37416879192.9, delta=0.1) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMiles) self.assertAlmostEqual(area, 14446.7378, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygonXY( [[ QgsPointXY(1850000, 4423000), QgsPointXY(1851000, 4423000), QgsPointXY(1851000, 4424000), QgsPointXY(1852000, 4424000), QgsPointXY(1852000, 4425000), QgsPointXY(1851000, 4425000), QgsPointXY(1850000, 4423000) ]] ) da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.AreaSquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoid("WGS84") # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 184149.37, delta=1.0) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 220240.8172549, delta=1.0)
def processAlgorithm(self, parameters, context, model_feedback): # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the # overall progress through the model feedback = QgsProcessingMultiStepFeedback(25, model_feedback) results = {} outputs = {} nlcd_rast_output = self.parameterAsBool(parameters, "OutputNLCDLandCoverRaster", context) nlcd_vect_output = self.parameterAsBool(parameters, "OutputNLCDLandCoverVector", context) nlcd_rast_imp_output = self.parameterAsBool( parameters, "OutputNLCDImperviousRaster", context) soil_output = self.parameterAsBool(parameters, "OutputSoilLayer", context) curve_number_output = self.parameterAsBool(parameters, "OutputCurveNumberLayer", context) # Assiging Default CN_Lookup Table if parameters["cnlookup"] == None: csv_uri = ("file:///" + os.path.join(cmd_folder, "CN_Lookup.csv") + "?delimiter=,") csv = QgsVectorLayer(csv_uri, "CN_Lookup.csv", "delimitedtext") parameters["cnlookup"] = csv area_layer = self.parameterAsVectorLayer(parameters, "areaboundary", context) EPSGCode = area_layer.crs().authid() origEPSGCode = EPSGCode # preserve orignal EPSGCode to project back to it # feedback.pushInfo(str(EPSGCode)) if check_crs_acceptable(EPSGCode): pass else: # Reproject layer to EPSG:5070 alg_params = { "INPUT": parameters["areaboundary"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem("EPSG:5070"), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectLayer5070"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) area_layer = context.takeResultLayer( outputs["ReprojectLayer5070"]["OUTPUT"]) EPSGCode = area_layer.crs().authid() # Check if area of the extent is less than 100,000 Acres d = QgsDistanceArea() tr_cont = QgsCoordinateTransformContext() d.setSourceCrs(area_layer.crs(), tr_cont) # d.setEllipsoid(area_layer.crs().ellipsoidAcronym()) extent_area = d.measureArea(QgsGeometry().fromRect( area_layer.extent())) area_acres = d.convertAreaMeasurement(extent_area, QgsUnitTypes.AreaAcres) if area_acres > 500000: feedback.reportError( f"Area Boundary layer extent area should be less than 500,000 acres.\nArea Boundary layer extent area is {round(area_acres,4):,} acres.\n\nExecution Failed", True, ) return results elif area_acres > 100000: feedback.reportError( f"Your Area Boundary layer extent area is {round(area_acres,4):,} acres. The recommended extent area is 100,000 acres or less. If the Algorithm fails, rerun with a smaller input layer.\n", False, ) else: feedback.pushInfo( f"Area Boundary layer extent area is {round(area_acres,4):,} acres\n" ) # Get extent of the area boundary layer xmin = area_layer.extent().xMinimum() ymin = area_layer.extent().yMinimum() xmax = area_layer.extent().xMaximum() ymax = area_layer.extent().yMaximum() BBOX_width = (xmax - xmin) / 30 BBOX_height = (ymax - ymin) / 30 BBOX_width_int = round(BBOX_width) BBOX_height_int = round(BBOX_height) # NLCD Impervious Raster if nlcd_rast_imp_output == True: request_URL = f"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Impervious_L48/ows?version=1.3.0&service=WMS&layers=NLCD_2016_Impervious_L48&styles&crs={str(EPSGCode)}&format=image/geotiff&request=GetMap&width={str(BBOX_width_int)}&height={str(BBOX_height_int)}&BBOX={str(xmin)},{str(ymin)},{str(xmax)},{str(ymax)}&" # Download NLCD Impervious Raster try: ping_URL = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Impervious_L48/ows" r = requests.head(ping_URL, verify=False) r.raise_for_status() alg_params = { "URL": request_URL, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcdImp"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except (QgsProcessingException, requests.exceptions.HTTPError) as e: feedback.reportError( f"Error: {str(e)}\n\nError requesting land use data from 'www.mrlc.gov'. Most probably because either their server is down or there is a certification issue.\nThis should be temporary. Try again later.\n", True, ) return results feedback.setCurrentStep(1) if feedback.isCanceled(): return {} # reproject to original crs # Warp (reproject) if EPSGCode != origEPSGCode: alg_params = { "DATA_TYPE": 0, "EXTRA": "", "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "MULTITHREADING": False, "NODATA": None, "OPTIONS": "", "RESAMPLING": 0, "SOURCE_CRS": None, "TARGET_CRS": QgsCoordinateReferenceSystem(str(origEPSGCode)), "TARGET_EXTENT": None, "TARGET_EXTENT_CRS": None, "TARGET_RESOLUTION": None, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcdImp"] = processing.run( "gdal:warpreproject", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # Set layer style alg_params = { "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Raster_Imp.qml"), } try: # for QGIS Version later than 3.12 outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForRasterLayer"] = processing.run( "qgis:setstyleforrasterlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(2) if feedback.isCanceled(): return {} # NLCD Land Cover Data if (curve_number_output == True or nlcd_vect_output == True or nlcd_rast_output == True): request_URL = f"https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Land_Cover_L48/ows?version=1.3.0&service=WMS&layers=NLCD_2016_Land_Cover_L48&styles&crs={str(EPSGCode)}&format=image/geotiff&request=GetMap&width={str(BBOX_width_int)}&height={str(BBOX_height_int)}&BBOX={str(xmin)},{str(ymin)},{str(xmax)},{str(ymax)}&" # Download NLCD try: ping_URL = "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Land_Cover_L48/ows" r = requests.head(ping_URL, verify=False) r.raise_for_status() alg_params = { "URL": request_URL, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcd"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except (QgsProcessingException, requests.exceptions.HTTPError) as e: feedback.reportError( f"Error: {str(e)}\n\nError requesting land use data from 'www.mrlc.gov'. Most probably because either their server is down or there is a certification issue.\nThis should be temporary. Try again later.\n", True, ) return results feedback.setCurrentStep(3) if feedback.isCanceled(): return {} # reproject to original crs # Warp (reproject) if EPSGCode != origEPSGCode: alg_params = { "DATA_TYPE": 0, "EXTRA": "", "INPUT": outputs["DownloadNlcd"]["OUTPUT"], "MULTITHREADING": False, "NODATA": None, "OPTIONS": "", "RESAMPLING": 0, "SOURCE_CRS": None, "TARGET_CRS": QgsCoordinateReferenceSystem(str(origEPSGCode)), "TARGET_EXTENT": None, "TARGET_EXTENT_CRS": None, "TARGET_RESOLUTION": None, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadNlcd"] = processing.run( "gdal:warpreproject", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # Reclassify by table alg_params = { "DATA_TYPE": 5, "INPUT_RASTER": outputs["DownloadNlcd"]["OUTPUT"], "NODATA_FOR_MISSING": False, "NO_DATA": -9999, "RANGE_BOUNDARIES": 0, "RASTER_BAND": 1, "TABLE": QgsExpression( "'0,1,11,1,2,12,2,3,21,3,4,22,4,5,23,5,6,24,6,7,31,7,8,32,8,9,41,9,10,42,10,11,43,11,12,51,12,13,52,13,14,71,14,15,72,15,16,73,16,17,74,17,18,81,18,19,82,19,20,90,20,21,95'" ).evaluate(), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReclassifyByTable"] = processing.run( "native:reclassifybytable", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(4) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Raster.qml"), } try: # for QGIS Version later than 3.12 outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForRasterLayer"] = processing.run( "qgis:setstyleforrasterlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(5) if feedback.isCanceled(): return {} if curve_number_output == True or nlcd_vect_output == True: # Polygonize (raster to vector) alg_params = { "BAND": 1, "EIGHT_CONNECTEDNESS": False, "EXTRA": "", "FIELD": "VALUE", "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["PolygonizeRasterToVector"] = processing.run( "gdal:polygonize", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(6) if feedback.isCanceled(): return {} # Fix geometries alg_params = { "INPUT": outputs["PolygonizeRasterToVector"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["FixGeometries"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(7) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["FixGeometries"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "NLCD_Vector.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(8) if feedback.isCanceled(): return {} # Soil Layer if soil_output == True or curve_number_output == True: # Reproject layer alg_params = { "INPUT": parameters["areaboundary"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem("EPSG:4326"), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectLayer4326"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(9) if feedback.isCanceled(): return {} # Get Area Boundary layer extent in EPSG:4326 area_layer_reprojected = context.takeResultLayer( outputs["ReprojectLayer4326"]["OUTPUT"]) # Download Soil try: # request using post rest # create vector layer structure to store data feedback.pushInfo("Creating POST request...") uri = "Polygon?crs=epsg:4326" soil_layer = QgsVectorLayer(uri, "soil layer", "memory") provider = soil_layer.dataProvider() attributes = [] attr_dict = [ { "name": "musym", "type": "str" }, { "name": "muname", "type": "str" }, { "name": "mustatus", "type": "str" }, { "name": "slopegraddcp", "type": "str" }, { "name": "slopegradwta", "type": "str" }, { "name": "brockdepmin", "type": "str" }, { "name": "wtdepannmin", "type": "str" }, { "name": "wtdepaprjunmin", "type": "str" }, { "name": "flodfreqdcd", "type": "str" }, { "name": "flodfreqmax", "type": "str" }, { "name": "pondfreqprs", "type": "str" }, { "name": "aws025wta", "type": "str" }, { "name": "aws050wta", "type": "str" }, { "name": "aws0100wta", "type": "str" }, { "name": "aws0150wta", "type": "str" }, { "name": "drclassdcd", "type": "str" }, { "name": "drclasswettest", "type": "str" }, { "name": "hydgrpdcd", "type": "str" }, { "name": "iccdcd", "type": "str" }, { "name": "iccdcdpct", "type": "str" }, { "name": "niccdcd", "type": "str" }, { "name": "niccdcdpct", "type": "str" }, { "name": "engdwobdcd", "type": "str" }, { "name": "engdwbdcd", "type": "str" }, { "name": "engdwbll", "type": "str" }, { "name": "engdwbml", "type": "str" }, { "name": "engstafdcd", "type": "str" }, { "name": "engstafll", "type": "str" }, { "name": "engstafml", "type": "str" }, { "name": "engsldcd", "type": "str" }, { "name": "engsldcp", "type": "str" }, { "name": "englrsdcd", "type": "str" }, { "name": "engcmssdcd", "type": "str" }, { "name": "engcmssmp", "type": "str" }, { "name": "urbrecptdcd", "type": "str" }, { "name": "urbrecptwta", "type": "str" }, { "name": "forpehrtdcp", "type": "str" }, { "name": "hydclprs", "type": "str" }, { "name": "awmmfpwwta", "type": "str" }, { "name": "mukey", "type": "str" }, { "name": "mupolygonkey", "type": "str" }, { "name": "areasymbol", "type": "str" }, { "name": "nationalmusym", "type": "str" }, ] # initialize fields for field in attr_dict: attributes.append(QgsField(field["name"], QVariant.String)) provider.addAttributes(attributes) soil_layer.updateFields() # get area layer extent polygon as WKT in 4326 aoi_reproj_wkt = area_layer_reprojected.extent().asWktPolygon() # send post request body = { "format": "JSON", "query": f"select Ma.*, M.mupolygonkey, M.areasymbol, M.nationalmusym, M.mupolygongeo from mupolygon M, muaggatt Ma where M.mupolygonkey in (select * from SDA_Get_Mupolygonkey_from_intersection_with_WktWgs84('{aoi_reproj_wkt.lower()}')) and M.mukey=Ma.mukey", } url = "https://sdmdataaccess.sc.egov.usda.gov/TABULAR/post.rest" soil_response = requests.post(url, json=body).json() feedback.setCurrentStep(10) if feedback.isCanceled(): return {} for row in soil_response["Table"]: # None attribute for empty data row = [None if not attr else attr for attr in row] feat = QgsFeature(soil_layer.fields()) # populate data for index, col in enumerate(row): if index != len(attr_dict): feat.setAttribute(attr_dict[index]["name"], col) else: feat.setGeometry(QgsGeometry.fromWkt(col)) provider.addFeatures([feat]) feedback.setCurrentStep(11) if feedback.isCanceled(): return {} except: # try wfs request feedback.reportError( "Error getting soil data through post request. Your input layer maybe too large. Trying WFS download now.\nIf the Algorithm get stuck during download. Terminate the Algorithm and rerun with a smaller input layer.", False, ) xmin_reprojected = area_layer_reprojected.extent().xMinimum() ymin_reprojected = area_layer_reprojected.extent().yMinimum() xmax_reprojected = area_layer_reprojected.extent().xMaximum() ymax_reprojected = area_layer_reprojected.extent().yMaximum() request_URL_soil = f"https://sdmdataaccess.sc.egov.usda.gov/Spatial/SDMWGS84GEOGRAPHIC.wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=mapunitpolyextended&SRSNAME=EPSG:4326&BBOX={str(xmin_reprojected)},{str(ymin_reprojected)},{str(xmax_reprojected)},{str(ymax_reprojected)}" alg_params = { "URL": request_URL_soil, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DownloadSoil"] = processing.run( "native:filedownloader", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(12) if feedback.isCanceled(): return {} # Swap X and Y coordinates alg_params = { "INPUT": outputs["DownloadSoil"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["SwapXAndYCoordinates"] = processing.run( "native:swapxy", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(13) if feedback.isCanceled(): return {} soil_layer = outputs["SwapXAndYCoordinates"]["OUTPUT"] # Fix soil layer geometries alg_params = { "INPUT": soil_layer, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT } outputs["FixGeometries2"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(14) if feedback.isCanceled(): return {} # Clip Soil Layer alg_params = { "INPUT": outputs["FixGeometries2"]["OUTPUT"], "OVERLAY": parameters["areaboundary"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["Clip"] = processing.run( "native:clip", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(15) if feedback.isCanceled(): return {} # Reproject Soil alg_params = { "INPUT": outputs["Clip"]["OUTPUT"], "OPERATION": "", "TARGET_CRS": QgsCoordinateReferenceSystem(origEPSGCode), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["ReprojectSoil"] = processing.run( "native:reprojectlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(16) if feedback.isCanceled(): return {} # Fix soil layer geometries second time alg_params = { "INPUT": outputs["ReprojectSoil"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["FixGeometries3"] = processing.run( "native:fixgeometries", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(17) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "Soil_Layer.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(18) if feedback.isCanceled(): return {} # Curve Number Calculations if curve_number_output == True: feedback.pushInfo( "Generating Curve Number Layer. This may take a while. Do not cancel." ) # Intersection alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "INPUT_FIELDS": ["MUSYM", "HYDGRPDCD", "MUNAME"], "OVERLAY": outputs["FixGeometries"]["OUTPUT"], "OVERLAY_FIELDS": ["VALUE"], "OVERLAY_FIELDS_PREFIX": "", "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["Intersection"] = processing.run( "native:intersection", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(19) if feedback.isCanceled(): return {} # Create GDCodeTemp alg_params = { "FIELD_LENGTH": 5, "FIELD_NAME": "GDCodeTemp", "FIELD_PRECISION": 3, "FIELD_TYPE": 2, "FORMULA": 'IF ("HYDGRPDCD" IS NOT NULL, "Value" || "HYDGRPDCD", IF (("MUSYM" = \'W\' OR lower("MUSYM") = \'water\' OR lower("MUNAME") = \'water\' OR "MUNAME" = \'W\'), 11, "VALUE"))', "INPUT": outputs["Intersection"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateGdcodetemp"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(20) if feedback.isCanceled(): return {} # Create GDCode alg_params = { "FIELD_LENGTH": 5, "FIELD_NAME": "GDCode", "FIELD_PRECISION": 3, "FIELD_TYPE": 2, "FORMULA": "if( var('drainedsoilsleaveuncheckedifnotsure') = True,replace(\"GDCodeTemp\", '/D', ''),replace(\"GDCodeTemp\", map('A/', '', 'B/', '', 'C/', '')))", "INPUT": outputs["CreateGdcodetemp"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateGdcode"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(21) if feedback.isCanceled(): return {} # Create NLCD_LU alg_params = { "FIELD_LENGTH": 2, "FIELD_NAME": "NLCD_LU", "FIELD_PRECISION": 3, "FIELD_TYPE": 1, "FORMULA": '"Value"', "INPUT": outputs["CreateGdcode"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateNlcd_lu"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(22) if feedback.isCanceled(): return {} # Join with CNLookup alg_params = { "DISCARD_NONMATCHING": False, "FIELD": "GDCode", "FIELDS_TO_COPY": ["CN_Join"], "FIELD_2": "GDCode", "INPUT": outputs["CreateNlcd_lu"]["OUTPUT"], "INPUT_2": parameters["cnlookup"], "METHOD": 1, "PREFIX": "", "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["JoinWithCnlookup"] = processing.run( "native:joinattributestable", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(23) if feedback.isCanceled(): return {} # Create Integer CN alg_params = { "FIELD_LENGTH": 3, "FIELD_NAME": "CN", "FIELD_PRECISION": 0, "FIELD_TYPE": 1, "FORMULA": "CN_Join * 1", "INPUT": outputs["JoinWithCnlookup"]["OUTPUT"], "NEW_FIELD": True, "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["CreateIntegerCn"] = processing.run( "qgis:fieldcalculator", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(24) if feedback.isCanceled(): return {} # Drop field(s) alg_params = { "COLUMN": ["VALUE", "GDCodeTemp", "CN_Join"], "INPUT": outputs["CreateIntegerCn"]["OUTPUT"], "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["DropFields"] = processing.run( "qgis:deletecolumn", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) feedback.setCurrentStep(25) if feedback.isCanceled(): return {} # Set layer style alg_params = { "INPUT": outputs["DropFields"]["OUTPUT"], "STYLE": os.path.join(cmd_folder, "CN_Grid.qml"), } try: # for QGIS Version 3.12 and later outputs["SetLayerStyle"] = processing.run( "native:setlayerstyle", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) except: # for QGIS Version older than 3.12 outputs["SetStyleForVectorLayer"] = processing.run( "qgis:setstyleforvectorlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_rast_output: # Load NLCD Raster into project alg_params = { "INPUT": outputs["ReclassifyByTable"]["OUTPUT"], "NAME": "NLCD Land Cover Raster", } outputs["LoadLayerIntoProject1"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_vect_output: # Load NLCD Vector Layer into project alg_params = { "INPUT": outputs["FixGeometries"]["OUTPUT"], "NAME": "NLCD Land Cover Vector", } outputs["LoadLayerIntoProject2"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if nlcd_rast_imp_output: # Load NLCD Impervious Raster into project alg_params = { "INPUT": outputs["DownloadNlcdImp"]["OUTPUT"], "NAME": "NLCD Impervious Raster", } outputs["LoadLayerIntoProject3"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if soil_output: # Load Soil Layer into project alg_params = { "INPUT": outputs["FixGeometries3"]["OUTPUT"], "NAME": "SSURGO Soil Layer", } outputs["LoadLayerIntoProject4"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) if curve_number_output: # Load Curve Number Layer into project alg_params = { "INPUT": outputs["DropFields"]["OUTPUT"], "NAME": "Curve Number Layer", } outputs["LoadLayerIntoProject5"] = processing.run( "native:loadlayer", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) # log usage with open(os.path.join(cmd_folder, "usage_counter.log"), "r+") as f: counter = int(f.readline()) f.seek(0) f.write(str(counter + 1)) # check if counter is milestone if (counter + 1) % 25 == 0: appeal_file = NamedTemporaryFile("w", suffix=".html", delete=False) self.createHTML(appeal_file.name, counter + 1) results["Message"] = appeal_file.name return results
class MeasureSelectedFeatures: def __init__(self, iface): self.iface = iface self.window = self.iface.mainWindow() self.proj_close_action = [ a for a in self.iface.projectMenu().actions() if a.objectName() == 'mActionCloseProject' ][0] self.dlg = MeasureSelectedFeaturesDialog() self.toolbar = self.iface.pluginToolBar() self.folder_name = os.path.dirname(os.path.abspath(__file__)) self.icon_path = os.path.join(self.folder_name, 'msf_icon.png') self.action = QAction(QIcon(self.icon_path), 'Sum selected feature size', self.window) self.action.setToolTip('Display total dimensions of selected features') self.da = QgsDistanceArea() # self.da.setEllipsoid('WGS84') self.Distance_Units = { 0: 'm', 1: 'km', 2: 'Feet', 3: 'NM', 4: 'Yards', 5: 'Miles', 6: 'Degrees', 7: 'cm', 8: 'mm', 9: 'Unknown units' } self.Area_Units = { 0: 'm2', 1: 'km2', 2: 'Square feet', 3: 'Square yards', 4: 'Square miles', 5: 'Hectares', 6: 'Acres', 7: 'NM2', 8: 'Square degrees', 9: 'cm2', 10: 'mm2', 11: 'Unknown units' } self.cb_linear_items = [ 'meters', 'kilometers', 'feet', 'nautical miles', 'yards', 'miles', 'degrees', 'centimeters', 'millimeters' ] self.cb_area_items = [ 'square meters', 'square kilometers', 'square feet', 'square yards', 'square miles', 'hectares', 'acres', 'square nautical miles', 'square degrees', 'square centimeters', 'square millimeters' ] self.project = None self.layer = None def initGui(self): """This method is where we add the plugin action to the plugin toolbar.""" self.action.setObjectName('btnMSF') self.toolbar.addAction(self.action) if self.iface.activeLayer(): self.layer = self.iface.activeLayer() else: self.action.setEnabled(False) self.action.triggered.connect(self.action_triggered) self.iface.projectRead.connect(self.project_opened) self.iface.newProjectCreated.connect(self.project_opened) self.dlg.was_closed.connect(self.dockwidget_closed) self.dlg.topLevelChanged.connect(self.widget_moved) self.iface.projectMenu().aboutToShow.connect(self.project_menu_shown) self.proj_close_action.triggered.connect( self.project_closed_via_menu_action) self.dlg.rad_1.setChecked(True) # 03-06-21 #####31-05-21 self.dlg.rad_1.toggled.connect( self.radios_toggled) #############25-06-21 self.dlg.cb_units.currentIndexChanged.connect(self.total_length) def project_menu_shown(self): if self.dlg.isVisible(): self.dlg.close() def project_opened(self): if self.project is not None: self.project.layerWasAdded.disconnect(self.layer_added) self.project.layersRemoved.disconnect(self.layers_removed) self.project = QgsProject.instance() a = [a for a in self.toolbar.actions() if a.objectName() == 'btnMSF'][0] if self.iface.activeLayer(): self.layer = self.iface.activeLayer() if not a.isEnabled(): a.setEnabled(True) self.set_title() else: if a.isEnabled(): a.setEnabled(False) self.project.layerWasAdded.connect(self.layer_added) self.project.layersRemoved.connect(self.layers_removed) def layer_added(self, l): if self.layer is None: if isinstance(l, QgsVectorLayer): self.layer = l if len(self.project.mapLayers()) == 1: a = [ a for a in self.toolbar.actions() if a.objectName() == 'btnMSF' ][0] if not a.isEnabled(): a.setEnabled(True) def layers_removed(self, lyr_ids): if len(self.project.mapLayers()) == 0: self.layer = None if self.dlg.isVisible(): self.dlg.close() a = [ a for a in self.toolbar.actions() if a.objectName() == 'btnMSF' ][0] if a.isEnabled(): a.setEnabled(False) def project_closed_via_menu_action(self): a = [a for a in self.toolbar.actions() if a.objectName() == 'btnMSF'][0] a.setEnabled(False) QgsProject.instance().layerWasAdded.disconnect(self.layer_added) def widget_moved(self, top_level): if top_level is True: self.set_gui_geometry() def set_gui_geometry(self): self.dlg.setGeometry(750, 300, 750, 50) def action_triggered(self): self.window.addDockWidget(Qt.TopDockWidgetArea, self.dlg) self.dlg.setAllowedAreas(Qt.TopDockWidgetArea) self.dlg.show() if self.layer is not None: if isinstance(self.iface.activeLayer(), QgsVectorLayer): self.layer = self.iface.activeLayer() if isinstance(self.layer, QgsVectorLayer): self.layer.selectionChanged.connect(self.total_length) self.iface.currentLayerChanged.connect(self.active_changed) self.set_title() # V2 change self.total_length() # V2 change #####25-05-21 self.action.setEnabled(False) ##### def active_changed(self, new_layer): self.tool_reset(self.layer) self.set_title() # V3 change if isinstance(new_layer, QgsVectorLayer): if self.layer is not None: # print(self.layer.name()) if len(QgsProject.instance().mapLayers()) > 1: self.layer.selectionChanged.disconnect(self.total_length) self.layer = new_layer self.layer.selectionChanged.connect(self.total_length) self.total_length() # V2 change def tool_reset(self, layer): if layer is not None: if isinstance( layer, QgsVectorLayer) and layer.geometryType() == 0: # V2 change layer.selectByIds([]) for le in self.dlg.findChildren(QLineEdit): le.clear() for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) def set_title(self): self.dlg.lbl_1.setText('Total') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) active_layer = self.iface.activeLayer() if isinstance(active_layer, QgsVectorLayer): if active_layer.isSpatial(): #####25-05-21 if active_layer.geometryType() == 0: # points self.dlg.setWindowTitle('Point layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif active_layer.geometryType() in [1, 2]: # self.dlg.setWindowTitle('Measuring {} selected features from layer: {}'.format(active_layer.selectedFeatureCount(), active_layer.name())) # V2 change for le in self.dlg.findChildren(QLineEdit): le.setEnabled(True) self.dlg.cb_units.setEnabled(True) if active_layer.crs().isGeographic(): self.dlg.rad_1.setChecked(True) self.dlg.rad_1.setEnabled(True) self.dlg.rad_2.setEnabled(False) ###25-06-21 self.dlg.cb_units.clear() if active_layer.geometryType() == 1: # lines self.dlg.cb_units.addItems(self.cb_linear_items) elif active_layer.geometryType() == 2: # polygons self.dlg.cb_units.addItems(self.cb_area_items) else: # projected CRS for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(True) ###25-06-21 if active_layer.geometryType() == 1: # lines self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_linear_items) if self.dlg.rad_2.isChecked(): self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) elif active_layer.geometryType() == 2: # polygons self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_area_items) if self.dlg.rad_2.isChecked(): self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) ##### elif not active_layer.isSpatial(): self.dlg.setWindowTitle( 'Raster or non-spatial vector layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif isinstance(active_layer, QgsRasterLayer): self.dlg.setWindowTitle( 'Raster or non-spatial vector layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif active_layer is None: self.dlg.setWindowTitle('No layer selected') def radios_toggled(self): if self.iface.activeLayer().geometryType() == 1: # lines if self.dlg.rad_2.isChecked(): # planimetric if self.dlg.cb_units.currentText() == 'degrees': # reload combobox items without degree option self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_linear_items) self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) else: # just remove the degree option self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) elif self.dlg.rad_1.isChecked(): # ellipsoidal if self.dlg.cb_units.count() == 0: self.dlg.cb_units.addItems(self.cb_linear_items) if not self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(True) if self.layer.crs().mapUnits( ) != QgsUnitTypes.DistanceUnknownUnit: self.dlg.cb_units.setCurrentText( QgsUnitTypes.encodeUnit( self.layer.crs().mapUnits())) else: self.dlg.cb_units.insertItem(6, 'degrees') elif self.iface.activeLayer().geometryType() == 2: # polygons if self.dlg.rad_2.isChecked(): if self.dlg.cb_units.currentText() == 'square degrees': self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_area_items) self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) else: self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) elif self.dlg.rad_1.isChecked(): if self.dlg.cb_units.count() == 0: self.dlg.cb_units.addItems(self.cb_area_items) if not self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(True) if self.layer.crs().mapUnits( ) != QgsUnitTypes.DistanceUnknownUnit: self.dlg.cb_units.setCurrentText('square {}'.format( QgsUnitTypes.encodeUnit( self.layer.crs().mapUnits()))) else: self.dlg.cb_units.insertItem(8, 'square degrees') self.total_length() def geodetic_length(self, feat): geo_m = self.da.measureLength(feat.geometry()) return geo_m def geodetic_area(self, feat): geo_m2 = self.da.measureArea(feat.geometry()) return geo_m2 def planar_length(self, feat): proj_m = feat.geometry().length() return proj_m def planar_area(self, feat): proj_m2 = feat.geometry().area() return proj_m2 def total_length(self): # print('func called') layer = self.layer # self.set_title() if isinstance(layer, QgsVectorLayer) and layer.isSpatial(): #####04-06-21 self.da.setSourceCrs(layer.crs(), QgsProject.instance().transformContext()) self.da.setEllipsoid(layer.crs().ellipsoidAcronym()) #####04-06-21 select_fts = [f for f in layer.selectedFeatures()] epsg_code = layer.crs().authid() if layer.crs().isGeographic(): crs_type = 'Geographic' else: crs_type = 'Projected' l_units = layer.crs().mapUnits() if layer.geometryType() == 1: # Lines self.dlg.setWindowTitle( 'Measuring {} selected features from layer: {} - {} ({})'. format(layer.selectedFeatureCount(), layer.name(), epsg_code, crs_type)) self.dlg.lbl_1.setText('Total length of selected features: ') if layer.crs().isGeographic() or ( not layer.crs().isGeographic() and self.dlg.rad_1.isChecked()): total_geo_m = sum( [self.geodetic_length(f) for f in select_fts]) if self.dlg.cb_units.currentText() == 'meters': self.dlg.le_total.setText( str('{:.3f}m'.format(total_geo_m))) elif self.dlg.cb_units.currentText() == 'kilometers': total_geo_km = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceKilometers) self.dlg.le_total.setText( str('{:.3f}km'.format(total_geo_km))) elif self.dlg.cb_units.currentText() == 'feet': total_geo_ft = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceFeet) self.dlg.le_total.setText( str('{:.3f}ft'.format(total_geo_ft))) elif self.dlg.cb_units.currentText() == 'nautical miles': total_geo_nm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceNauticalMiles) self.dlg.le_total.setText( str('{:.3f}NM'.format(total_geo_nm))) elif self.dlg.cb_units.currentText() == 'yards': total_geo_yds = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceYards) self.dlg.le_total.setText( str('{:.3f}yds'.format(total_geo_yds))) elif self.dlg.cb_units.currentText() == 'miles': total_geo_mi = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceMiles) self.dlg.le_total.setText( str('{:.3f}mi'.format(total_geo_mi))) elif self.dlg.cb_units.currentText() == 'degrees': total_geo_deg = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceDegrees) self.dlg.le_total.setText( str('{:.3f}deg'.format(total_geo_deg))) elif self.dlg.cb_units.currentText() == 'centimeters': total_geo_cm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceCentimeters) self.dlg.le_total.setText( str('{:.3f}cm'.format(total_geo_cm))) elif self.dlg.cb_units.currentText() == 'millimeters': total_geo_mm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceMillimeters) self.dlg.le_total.setText( str('{:.3f}mm'.format(total_geo_mm))) else: # projected CRS total_length_proj = sum( [self.planar_length(f) for f in select_fts]) if l_units != 6: # Units are NOT degrees if self.dlg.cb_units.currentText() == 'meters': self.dlg.le_total.setText( str('{:.3f}m'.format( self.convert_planar_length( total_length_proj, l_units, 0)))) elif self.dlg.cb_units.currentText() == 'kilometers': self.dlg.le_total.setText( str('{:.3f}km'.format( self.convert_planar_length( total_length_proj, l_units, 1)))) elif self.dlg.cb_units.currentText() == 'feet': self.dlg.le_total.setText( str('{:.3f}ft'.format( self.convert_planar_length( total_length_proj, l_units, 2)))) elif self.dlg.cb_units.currentText( ) == 'nautical miles': self.dlg.le_total.setText( str('{:.3f}NM'.format( self.convert_planar_length( total_length_proj, l_units, 3)))) elif self.dlg.cb_units.currentText() == 'yards': self.dlg.le_total.setText( str('{:.3f}yd'.format( self.convert_planar_length( total_length_proj, l_units, 4)))) elif self.dlg.cb_units.currentText() == 'miles': self.dlg.le_total.setText( str('{:.3f}mi'.format( self.convert_planar_length( total_length_proj, l_units, 5)))) elif self.dlg.cb_units.currentText() == 'centimeters': self.dlg.le_total.setText( str('{:.3f}cm'.format( self.convert_planar_length( total_length_proj, l_units, 7)))) elif self.dlg.cb_units.currentText() == 'millimeters': self.dlg.le_total.setText( str('{:.3f}mm'.format( self.convert_planar_length( total_length_proj, l_units, 8)))) else: # degree units self.dlg.cb_units.clear() self.dlg.cb_units.setEnabled(False) self.dlg.le_total.setText( str('{:.3f}{}'.format( total_length_proj, self.Distance_Units[l_units]))) elif layer.geometryType() == 2: # Polygons self.dlg.setWindowTitle( 'Measuring {} selected features from layer: {} - {} ({})'. format(layer.selectedFeatureCount(), layer.name(), epsg_code, crs_type)) self.dlg.lbl_1.setText('Total area of selected features: ') if layer.crs().isGeographic() or ( not layer.crs().isGeographic() and self.dlg.rad_1.isChecked()): total_geo_m = sum( [self.geodetic_area(f) for f in select_fts]) if self.dlg.cb_units.currentText() == 'square meters': self.dlg.le_total.setText( str('{:.3f}m2'.format(total_geo_m))) elif self.dlg.cb_units.currentText( ) == 'square kilometers': total_geo_km = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareKilometers) self.dlg.le_total.setText( str('{:.3f}km2'.format(total_geo_km))) elif self.dlg.cb_units.currentText() == 'square feet': total_geo_ft = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareFeet) self.dlg.le_total.setText( str('{:.3f}ft2'.format(total_geo_ft))) elif self.dlg.cb_units.currentText() == 'square yards': total_geo_yds = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareYards) self.dlg.le_total.setText( str('{:.3f}yd2'.format(total_geo_yds))) elif self.dlg.cb_units.currentText() == 'square miles': total_geo_mi = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareMiles) self.dlg.le_total.setText( str('{:.3f}mi2'.format(total_geo_mi))) elif self.dlg.cb_units.currentText() == 'hectares': total_geo_ha = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaHectares) self.dlg.le_total.setText( str('{:.3f}ha'.format(total_geo_ha))) elif self.dlg.cb_units.currentText() == 'acres': total_geo_ac = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaAcres) self.dlg.le_total.setText( str('{:.3f}ac'.format(total_geo_ac))) elif self.dlg.cb_units.currentText( ) == 'square nautical miles': total_geo_nm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareNauticalMiles) self.dlg.le_total.setText( str('{:.3f}NM2'.format(total_geo_nm))) elif self.dlg.cb_units.currentText() == 'square degrees': total_geo_deg = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareDegrees) self.dlg.le_total.setText( str('{:.3f}deg2'.format(total_geo_deg))) elif self.dlg.cb_units.currentText( ) == 'square centimeters': total_geo_cm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareCentimeters) self.dlg.le_total.setText( str('{:.3f}cm2'.format(total_geo_cm))) elif self.dlg.cb_units.currentText( ) == 'square millimeters': total_geo_mm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareMillimeters) self.dlg.le_total.setText( str('{:.3f}mm2'.format(total_geo_mm))) else: # projected CRS total_area_proj = sum( [self.planar_area(f) for f in select_fts]) if l_units != 6: # Units are NOT degrees if self.dlg.cb_units.currentText() == 'square meters': self.dlg.le_total.setText( str('{:.3f}m2'.format( self.convert_planar_area( total_area_proj, l_units, 'square meters')))) elif self.dlg.cb_units.currentText( ) == 'square kilometers': self.dlg.le_total.setText( str('{:.3f}km2'.format( self.convert_planar_area( total_area_proj, l_units, 'square kilometers')))) elif self.dlg.cb_units.currentText() == 'square feet': self.dlg.le_total.setText( str('{:.3f}ft2'.format( self.convert_planar_area( total_area_proj, l_units, 'square feet')))) elif self.dlg.cb_units.currentText() == 'square yards': self.dlg.le_total.setText( str('{:.3f}yd2'.format( self.convert_planar_area( total_area_proj, l_units, 'square yards')))) elif self.dlg.cb_units.currentText() == 'square miles': self.dlg.le_total.setText( str('{:.3f}mi2'.format( self.convert_planar_area( total_area_proj, l_units, 'square miles')))) elif self.dlg.cb_units.currentText() == 'hectares': self.dlg.le_total.setText( str('{:.3f}ha'.format( self.convert_planar_area( total_area_proj, l_units, 'hectares')))) elif self.dlg.cb_units.currentText() == 'acres': self.dlg.le_total.setText( str('{:.3f}ac'.format( self.convert_planar_area( total_area_proj, l_units, 'acres')))) elif self.dlg.cb_units.currentText( ) == 'square nautical miles': self.dlg.le_total.setText( str('{:.3f}NM2'.format( self.convert_planar_area( total_area_proj, l_units, 'square nautical miles')))) elif self.dlg.cb_units.currentText( ) == 'square centimeters': self.dlg.le_total.setText( str('{:.3f}cm2'.format( self.convert_planar_area( total_area_proj, l_units, 'square centimeters')))) elif self.dlg.cb_units.currentText( ) == 'square millimeters': self.dlg.le_total.setText( str('{:.3f}mm2'.format( self.convert_planar_area( total_area_proj, l_units, 'square millimeters')))) else: # Degree units self.dlg.cb_units.clear() if self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(False) self.dlg.le_total.setText( str('{:.3f}{}2'.format( total_area_proj, self.Distance_Units[l_units]))) if layer.geometryType() in [3, 4]: self.iface.messageBar().pushMessage( 'Layer has unknown or Null geometry type', duration=2) ###########################UNIT CONVERSIONS FOR PROJECTED CRS'S##################################### def convert_planar_length(self, length, input_units, output_units): if input_units == 0: # Meters if output_units == 0: # Meters result = length elif output_units == 1: # Kilometers result = length / 1000 elif output_units == 2: # Imperial feet result = length * 3.28084 elif output_units == 3: # Nautical miles result = length / 1852 elif output_units == 4: # Imperial yards result = length * 1.09361 elif output_units == 5: # Terrestrial miles result = length / 1609.344 elif output_units == 7: # Centimeters result = length * 100 elif output_units == 8: # Millimeters result = length * 1000 elif input_units == 1: # Kilometers if output_units == 0: # Meters result = length * 1000 elif output_units == 1: # Kilometers result = length elif output_units == 2: # Imperial feet result = length * 3280.84 elif output_units == 3: # Nautical miles result = length / 1.852 elif output_units == 4: # Imperial yards result = length * 1093.61 elif output_units == 5: # Terrestrial miles result = length / 1.609 elif output_units == 7: # Centimeters result = length * 100000 elif output_units == 8: # Millimeters result = length * 1000000 elif input_units == 2: # Imperial feet if output_units == 0: # Meters result = length / 3.281 elif output_units == 1: # Kilometers result = length / 3281 elif output_units == 2: # Imperial feet result = length elif output_units == 3: # Nautical Miles result = length / 6076 elif output_units == 4: # Imperial yards result = length / 3 elif output_units == 5: # Terrestrial miles result = length / 5280 elif output_units == 7: # Centimeters result = length * 30.48 elif output_units == 8: # Millimeters result = length * 304.8 elif input_units == 3: # Nautical miles if output_units == 0: # Meters result = length * 1852 if output_units == 1: # Kilometers result = length * 1.852 elif output_units == 2: # Imperial feet result = length * 6076 elif output_units == 3: # Nautical miles result = length elif output_units == 4: # Imperial yards result = length * 2025.37 elif output_units == 5: # Terrestrial miles result = length * 1.15078 elif output_units == 7: # Centimeters result = length * 185200 elif output_units == 8: # Millimeters result = length * 1852000 elif input_units == 4: # Imperial yards if output_units == 0: # Meters result = length / 1.094 elif output_units == 1: # Kilometers result = length / 1094 elif output_units == 2: # Imperial feet result = length * 3 elif output_units == 3: # Nautical miles result = length / 2025 elif output_units == 4: # Imperial yards result = length elif output_units == 5: # Terrestrial miles result = length / 1760 elif output_units == 7: # Centimeters result = length * 91.44 elif output_units == 8: # Millimeters result = length * 914.4 elif input_units == 5: # Terrestrial miles if output_units == 0: # Meters result = length * 1609.34 elif output_units == 1: # Kilometers result = length * 1.609 elif output_units == 2: # Imperial feet result = length * 5280 elif output_units == 3: # Nautical miles result = length / 1.151 elif output_units == 4: # Imperial yards result = length * 1760 elif output_units == 5: # Terrestrial miles result = length elif output_units == 7: # Centimeters result = length * 160934 elif output_units == 8: # Millimeters result = length * 1609340 elif input_units == 7: # Centimeters if output_units == 0: # Meters result = length / 100 elif output_units == 1: # Kilometers result = length / 100000 elif output_units == 2: # Imperial feet result = length / 30.48 elif output_units == 3: # Nautical miles result = length / 185200 elif output_units == 4: # Imperial yards result = length / 91.44 elif output_units == 5: # Terrestrial miles result = length / 160934 elif output_units == 7: # Centimeters result = length elif output_units == 8: # Millimeters result = length * 10 elif input_units == 8: # Millimeters if output_units == 0: # Meters result = length / 1000 elif output_units == 1: # Kilometers result = length / 1000000 elif output_units == 2: # Imperial feet result = length / 305 elif output_units == 3: # Nautical miles result = length / 1852000 elif output_units == 4: # Imperial yards result = length / 914 elif output_units == 5: # Terrestrial miles result = length / 1609000 elif output_units == 7: # Centimeters result = length / 10 elif output_units == 8: # Millimeters result = length return result #####################################AREA UNITS##################################################### def convert_planar_area(self, area, input_units, output_units): if input_units == 0: # Meters if output_units == 'square meters': # Square meters result = area elif output_units == 'square kilometers': # Square kilometers result = area / 1000000 elif output_units == 'square feet': # Square feet result = area * 10.764 elif output_units == 'square yards': # Square yards result = area * 1.196 elif output_units == 'square miles': # Square miles result = area / 2589988.1 elif output_units == 'hectares': # Hectares result = area / 10000 elif output_units == 'acres': # Acres result = area / 4047 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3429904 elif output_units == 'square centimeters': # Square centimeters result = area * 10000 elif output_units == 'square millimeters': # Square millimeters result = area * 1000000 #-------------------------------------------------------------------- elif input_units == 1: # Kilometers if output_units == 'square meters': # Square meters result = area * 10000 elif output_units == 'square kilometers': # Square kilometers result = area elif output_units == 'square feet': # Square feet result = area * 10763910.417 elif output_units == 'square yards': # Square yards result = area * 1195990.05 elif output_units == 'square miles': # Square miles result = area / 2.59 elif output_units == 'hectares': # Hectares result = area * 100 elif output_units == 'acres': # Acres result = area * 247.105 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3.43 elif output_units == 'square centimeters': # Square centimeters result = area * 10000000000 elif output_units == 'square millimeters': # Square millimeters result = area * 1000000000000 #-------------------------------------------------------------------- elif input_units == 2: # Imperial feet if output_units == 'square meters': # Square meters result = area / 10.764 elif output_units == 'square kilometers': # Square kilometers result = area / 10763910.417 elif output_units == 'square feet': # Square feet result = area elif output_units == 'square yards': # Square yards result = area / 9 elif output_units == 'square miles': # Square miles result = area / 27878400 elif output_units == 'hectares': # Hectares result = area / 107639 elif output_units == 'acres': # Acres result = area / 43560 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 36920000 elif output_units == 'square centimeters': # Square centimeters result = area * 929 elif output_units == 'square millimeters': # Square millimeters result = area * 92903 #-------------------------------------------------------------------- elif input_units == 3: # Nautical miles if output_units == 'square meters': # Square meters result = area * 3430000 elif output_units == 'square kilometers': # Square kilometers result = area * 3.43 elif output_units == 'square feet': # Square feet result = area * 36920000 elif output_units == 'square yards': # Square yards result = area * 4102000 elif output_units == 'square miles': # Square miles result = area * 1.324 elif output_units == 'hectares': # Hectares result = area * 343 elif output_units == 'acres': # Acres result = area * 847.548 elif output_units == 'square nautical miles': # Square Nautical miles result = area elif output_units == 'square centimeters': # Square centimeters result = area * 34300000000 elif output_units == 'square millimeters': # Square millimeters result = area * 3430000000000 #-------------------------------------------------------------------- elif input_units == 4: # Imperial yards if output_units == 'square meters': # Square meters result = area / 1.196 elif output_units == 'square kilometers': # Square kilometers result = area / 1196000 elif output_units == 'square feet': # Square feet result = area * 9 elif output_units == 'square yards': # Square yards result = area elif output_units == 'square miles': # Square miles result = area / 3098000 elif output_units == 'hectares': # Hectares result = area / 11960 elif output_units == 'acres': # Acres result = area / 4840 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 4102000 elif output_units == 'square centimeters': # Square centimeters result = area * 8361 elif output_units == 'square millimeters': # Square millimeters result = area * 836127 #-------------------------------------------------------------------- elif input_units == 5: # Terrestrial miles if output_units == 'square meters': # Square meters result = area * 2590000 elif output_units == 'square kilometers': # Square kilometers result = area * 2.59 elif output_units == 'square feet': # Square feet result = area * 27880000 elif output_units == 'square yards': # Square yards result = area * 3098000 elif output_units == 'square miles': # Square miles result = area elif output_units == 'hectares': # Hectares result = area * 259 elif output_units == 'acres': # Acres result = length * 640 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 1.324 elif output_units == 'square centimeters': # Square centimeters result = area * 25900000000 elif output_units == 'square millimeters': # Square millimeters result = area * 2590000000000 #-------------------------------------------------------------------- elif input_units == 7: # Centimeters if output_units == 'square meters': # Square meters result = area / 10000 elif output_units == 'square kilometers': # Square kilometers result = area / 10000000000 elif output_units == 'square feet': # Square feet result = area / 929.03 elif output_units == 'square yards': # Square yards result = area / 8361.27 elif output_units == 'square miles': # Square miles result = area / 25899881103.36 elif output_units == 'hectares': # Hectares result = area / 100000000 elif output_units == 'acres': # Acres result = area / 40468564.224 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 34299040000 elif output_units == 'square centimeters': # Square centimeters result = area elif output_units == 'square millimeters': # Square millimeters result = area * 100 #-------------------------------------------------------------------- elif input_units == 8: # Millimeters if output_units == 'square meters': # Square meters result = area / 1000000 elif output_units == 'square kilometers': # Square kilometers result = area / 1000000000000 elif output_units == 'square feet': # Square feet result = area / 92903 elif output_units == 'square yards': # Square yards result = area / 836127 elif output_units == 'square miles': # Square miles result = area / 2589988110336 elif output_units == 'hectares': # Hectares result = area / 10000000000 elif output_units == 'acres': # Acres result = area / 4046856422 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3429904000000 elif output_units == 'square centimeters': # Square centimeters result = area / 100 elif output_units == 'square millimeters': # Square millimeters result = area return result #################################################################################################### def dockwidget_closed(self): # print('dockwidget closed!!') self.dlg.setFloating(False) if self.layer is not None: self.tool_reset(self.layer) if isinstance(self.layer, QgsVectorLayer): self.layer.selectionChanged.disconnect(self.total_length) self.iface.currentLayerChanged.disconnect(self.active_changed) #####25-05-21 self.action.setEnabled(True) def unload(self): self.toolbar.removeAction(self.action) del self.action
def processAlgorithm(self, parameters, context, feedback): # get input variables raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT, context) band_number = self.parameterAsInt(parameters, self.BAND, context) output = self.parameterAsFileOutput(parameters, self.OUTPUT, context) # layer name name = raster_layer.name() # layer provider provider = raster_layer.dataProvider() # get CRS crs_raster = raster_layer.crs() # set project ellipsoid (for measurements) to CRS ellipsoid ellipsoid = context.project().crs().ellipsoidAcronym() # get transform context from project trans_context = context.project().transformContext() # 5% done feedback.setProgress(5) # Initialize Area calculator class with ellipsoid da = QgsDistanceArea() da.setSourceCrs(crs_raster, trans_context) da.setEllipsoid(ellipsoid) # get raster extent extent = raster_layer.extent() extent = QgsGeometry().fromRect(extent) # 20% done feedback.setProgress(20) # get area of extent feedback.pushConsoleInfo( self.tr(f'Measuring area of raster rectangle...')) area = da.measureArea(extent) # convert area from area_m2 = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMeters) # 30% done feedback.setProgress(30) # check if NoData value is set if provider.sourceHasNoDataValue(band_number): feedback.pushConsoleInfo( self.tr(f'Calculating NoData percentage...')) # unique values parameters rastervalue_params = {'INPUT': raster_layer, 'BAND': band_number} # run unique values result = processing.run('native:rasterlayeruniquevaluesreport', rastervalue_params) # get total pixel and nodata count cells = result['TOTAL_PIXEL_COUNT'] nodata_cells = result['NODATA_PIXEL_COUNT'] # calculate nodata percentage nodata_percentage = nodata_cells / cells # calclate data coverage feedback.pushConsoleInfo( self.tr(f'Calculating data coverage...\n')) coverage_m2 = area_m2 * (1 - nodata_percentage) coverage_percentage = (1 - nodata_percentage) else: feedback.reportError(self.tr( 'Missing NoData value(s) detected. Check settings of the raster layer!' ), fatalError=False) coverage_m2 = area_m2 coverage_percentage = 1.0 # 80% done feedback.setProgress(80) # calculate area units area_km2 = area_m2 / (1000 * 1000) coverage_km2 = coverage_m2 / (1000 * 1000) feedback.pushConsoleInfo( self.tr(f'------------------------------------------\n')) feedback.pushConsoleInfo( self.tr(f'Raster Coverage of Layer [ {name} ]:\n')) feedback.pushConsoleInfo( self.tr(f'Raster Area [km2] ....... : {round(area_km2,3)}')) feedback.pushConsoleInfo( self.tr(f'Data Coverage [km2] ..... : {round(coverage_km2,3)}')) feedback.pushConsoleInfo( self.tr(f'Data Coverage [m2] ...... : {round(coverage_m2,2)}')) feedback.pushConsoleInfo( self. tr(f'Data Coverage [%] ....... : {round(coverage_percentage * 100,2)}\n' )) feedback.pushConsoleInfo( self. tr(f'This is {round(coverage_km2 / self.bremen_area,2)} times the area of Bremen\n' )) feedback.pushConsoleInfo( self.tr(f'------------------------------------------\n')) # 100% done feedback.setProgress(100) feedback.pushInfo( self.tr( f'{utils.return_success()}! Raster area has been calculated!\n' )) result = { self.RASTER_AREA_KM2: area_km2, self.DATA_COVERAGE_KM2: coverage_km2, self.DATA_COVERAGE_M2: coverage_m2, self.DATA_COVERAGE_PERCENT: coverage_percentage, self.OUTPUT: output } if output != '': self.write_output(name, result, output) return result