Exemple #1
0
def get_editable_layers() -> Set[str]:
    """Liste der Tabellen, für die in der Layerliste der Status editable aktiviert ist.
        Dient dazu, sicherzustellen, dass keine Datenbankoperationen auf editierbare
        Layer zugreifen."""

    elayers = set([])  # Zuerst leere Liste anlegen

    layers = [
        x.layer()
        for x in iface.layerTreeCanvasBridge().rootGroup().findLayers()
    ]
    # logger.debug(u'Layerliste erstellt')
    if len(layers) > 0:
        # über Layer iterieren
        for lay in layers:
            lyattr = {}

            # Attributstring für Layer splitten
            for le in lay.source().split(" "):
                if "=" in le:
                    key, value = le.split("=", 1)
                    lyattr[key] = value.strip('"').strip("'")

            # Falls Abschnitte 'table' und 'dbname' existieren, handelt es sich um einen Datenbank-Layer
            if "table" in lyattr and "dbname" in lyattr:
                if lay.isEditable():
                    elayers.add(lyattr["table"])
    return elayers
Exemple #2
0
    def processAlgorithm(self, parameters, context, feedback):
        # Set the standard CRS to GDA2020 (EPSG:7844)
        standardCRS = "EPSG:7844"
        #Parse the RE numbers
        res = re.sub(
            "[^0-9a-zA-Z.-]+", ',',
            self.parameterAsString(parameters, self.INPUT,
                                   context).lower()).split(',')
        res_message = "Regional ecosystem(s):" + ",".join(res)
        outputDIR = self.parameterAsFileOutput(parameters, self.OUTPUTDIR,
                                               context)
        PrimaryOnly = self.parameterAsBoolean(parameters, self.LOADPRIMARY,
                                              context)
        Exact = self.parameterAsBoolean(parameters, self.LOADEXACT, context)
        feedback.setProgress(5)
        feedback.setProgressText(res_message)
        # The following lines workaround an apparent QGIS bug where a temporary directory isn't actually made.
        try:
            os.mkdir(outputDIR)
        except FileExistsError as e:
            pass
        #Get RE polygon(s)
        RElayer = self.LoadRELayer(res, outputDIR, standardCRS, context,
                                   feedback, PrimaryOnly, Exact)
        #
        if RElayer == None or not RElayer.isValid(
        ) or RElayer.featureCount() < 1:
            feedback.reportError("Failed to load REs! Invalid REs?", True)
            return {}
        # Load layer to canvas
        project = QgsProject.instance()
        project.addMapLayer(RElayer, False)
        layerTree = iface.layerTreeCanvasBridge().rootGroup()
        layerTree.insertChildNode(0, QgsLayerTreeLayer(RElayer))
        feedback.setProgress(99)
        #
        #Zoom to extent
        canvas = iface.mapCanvas()
        canvasCRS = QgsCoordinateReferenceSystem(
            canvas.mapSettings().destinationCrs().authid())
        reCRS = QgsCoordinateReferenceSystem(RElayer.crs())
        xform = QgsCoordinateTransform(reCRS, canvasCRS, project)
        canvas.setExtent(xform.transform(RElayer.extent()))
        #
        #

        #
        feedback.setProgress(100)
        #
        return {}
# coding: utf-8
from qgis.gui import QgsCustomLayerOrderWidget
from qgis.utils import iface

layer_tree_canvas_bridge = iface.layerTreeCanvasBridge()
custom_layer_order_widget = QgsCustomLayerOrderWidget(
    layer_tree_canvas_bridge
)

custom_layer_order_widget.show()
Exemple #4
0
current_date_layer = create_current_date()


# Bar date
def create_bar_date():
    bar_today_layer = QgsVectorLayer(
        "Point?"
        "crs=epsg:3857&"
        "field=id:integer&"
        "index=yes", "Bar", "memory")
    QgsProject.instance().addMapLayer(bar_today_layer, False)
    bar_today_layer.loadNamedStyle(os.path.join(FOLDER, 'qml', 'bar.qml'))
    with edit(bar_today_layer):
        feat = QgsFeature()
        feat.setAttributes([1])
        feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(0, 0)))
        bar_today_layer.addFeature(feat)
    return bar_today_layer


bar_today_layer = create_bar_date()

# Insert in the correct order
layerTree = iface.layerTreeCanvasBridge().rootGroup()
layerTree.insertChildNode(-1, QgsLayerTreeLayer(current_date_layer))
layerTree.insertChildNode(-1, QgsLayerTreeLayer(releases_point_layer))
layerTree.insertChildNode(-1, QgsLayerTreeLayer(axes_layer))
layerTree.insertChildNode(-1, QgsLayerTreeLayer(releases_line_layer))
layerTree.insertChildNode(-1, QgsLayerTreeLayer(bar_today_layer))
Exemple #5
0
# coding: utf-8
from qgis.gui import QgsCustomLayerOrderWidget
from qgis.utils import iface

layer_tree_canvas_bridge = iface.layerTreeCanvasBridge()
custom_layer_order_widget = QgsCustomLayerOrderWidget(layer_tree_canvas_bridge)

custom_layer_order_widget.show()
 def processAlgorithm(self, parameters, context, feedback):
     # Set the standard CRS to GDA2020 (EPSG:7844)
     standardCRS = "EPSG:7844"
     #Parse the lot plan numbers
     lots = re.sub(
         '[^0-9a-zA-Z]+', ',',
         self.parameterAsString(parameters, self.INPUT,
                                context).upper()).split(',')
     #
     lotplans_message = "Lot/Plan(s): " + ", ".join(lots)
     feedback.setProgressText(lotplans_message)
     #
     loadTenure = self.parameterAsBool(parameters, self.LOADTENURE, context)
     loadSupportingMap = self.parameterAsBool(parameters,
                                              self.LOADSUPPORTINGMAP,
                                              context)
     loadPreClearMap = self.parameterAsBool(parameters,
                                            self.LOADPRECLEARMAP, context)
     loadRVM = self.parameterAsBool(parameters, self.LOADRVM, context)
     loadPMAV = self.parameterAsBool(parameters, self.LOADPMAV, context)
     loadEssHab = self.parameterAsBool(parameters, self.LOADESSHAB, context)
     loadPPTM = self.parameterAsBool(parameters, self.LOADPPTM, context)
     loadWetlands = self.parameterAsBool(parameters, self.LOADWETLANDS,
                                         context)
     loadVMWater8 = self.parameterAsBool(parameters, self.LOADVMWATER8,
                                         context)
     loadVMWater7 = self.parameterAsBool(parameters, self.LOADVMWATER7,
                                         context)
     loadKoalaPA = self.parameterAsBool(parameters, self.LOADKPA, context)
     loadKoalaHA = self.parameterAsBool(parameters, self.LOADKHA, context)
     loadKoalaRA = self.parameterAsBool(parameters, self.LOADKRA, context)
     loadKoalaHAL = self.parameterAsBool(parameters, self.LOADKHAL, context)
     loadSLATS = self.parameterAsBool(parameters, self.LOADSLATS, context)
     outputDIR = self.parameterAsFileOutput(parameters, self.OUTPUTDIR,
                                            context)
     feedback.setProgress(1)
     # make directory
     try:
         os.mkdir(outputDIR)
     except FileExistsError as e:
         pass
     layerInfo = dict(
         lots=lots,
         layername='Property Boundary',
         layerstyle='LayerStyles/Property.qml',
         outputDIR=outputDIR,
         standardCRS=standardCRS,
     )
     #Get property polygon(s)
     PropertyVlayer = LoadPropertyLayer(layerInfo, context, feedback)
     if PropertyVlayer == None or not PropertyVlayer.isValid(
     ) or PropertyVlayer.featureCount() < 1:
         feedback.reportError(
             "Failed to load property boundary! Invalid lot/plan? Network or server problems?",
             True)
         return {}
     #
     feedback.setProgress(15)
     feedback.setProgressText("Property polygon(s) loaded")
     # Load property layer to canvas
     project = QgsProject.instance()
     project.addMapLayer(PropertyVlayer, False)
     layerTree = iface.layerTreeCanvasBridge().rootGroup()
     layerTree.insertChildNode(0, QgsLayerTreeLayer(PropertyVlayer))
     feedback.setProgress(20)
     #
     #Zoom to extent
     canvas = iface.mapCanvas()
     canvasCRS = QgsCoordinateReferenceSystem(
         canvas.mapSettings().destinationCrs().authid())
     PropertyCRS = QgsCoordinateReferenceSystem(PropertyVlayer.crs())
     xform = QgsCoordinateTransform(PropertyCRS, canvasCRS, project)
     canvas.setExtent(xform.transform(PropertyVlayer.extent()))
     #
     # Initialise dictionaries
     post = dict(serviceType="MapServer/", f='geojson')
     layerInfo = dict(vlayer=PropertyVlayer,
                      outputDIR=outputDIR,
                      standardCRS=standardCRS,
                      searchType='lotplan')
     #
     #Load Natural Resource layers
     if loadTenure:
         post.update(
             dict(service1="PlanningCadastre/",
                  service2="LandParcelPropertyFramework/",
                  serviceNumber=str(13)))
         layerInfo.update(
             dict(layername="Tenure",
                  layerstyle="LayerStyles/QldPropertyTenure.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(25)
     # Update server details
     post.update(dict(service1="Biota/", service2="VegetationManagement/"))
     if loadSupportingMap:
         post.update(dict(serviceNumber=str(134)))
         layerInfo.update(
             dict(layername="Regional ecosystem map (regulated)",
                  layerstyle="LayerStyles/SupportingMap.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(30)
     if loadPreClearMap:
         post.update(dict(serviceNumber=str(15)))
         layerInfo.update(
             dict(layername="Pre-clear RE map (VM edition)",
                  layerstyle="LayerStyles/PreClearMap.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(35)
     if loadRVM:
         post.update(dict(serviceNumber=str(109)))
         layerInfo.update(
             dict(layername="RVM",
                  layerstyle="LayerStyles/RVM.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(40)
     if loadPMAV:
         post.update(dict(serviceNumber=str(146)))
         layerInfo.update(
             dict(layername="PMAV",
                  layerstyle="LayerStyles/PMAV.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(50)
     if loadEssHab:
         post.update(dict(serviceNumber=str(5)))
         layerInfo.update(
             dict(layername="Essential Habitat",
                  layerstyle="LayerStyles/EssentialHabitat.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(60)
     if loadWetlands:
         post.update(dict(serviceNumber=str(4)))
         layerInfo.update(
             dict(layername="Wetlands",
                  layerstyle="LayerStyles/Wetlands.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(70)
     if loadVMWater8:
         post.update(dict(serviceNumber=str(8)))
         layerInfo.update(
             dict(layername="VM Watercourses-SEQ",
                  layerstyle="LayerStyles/VMWaterCourse.qml",
                  geomtype="MultiLineString"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(80)
     if loadVMWater7:
         post.update(dict(serviceNumber=str(7)))
         layerInfo.update(
             dict(layername="VM Watercourses QLD",
                  layerstyle="LayerStyles/VMWaterCourse.qml",
                  geomtype="MultiLineString"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(90)
     if loadPPTM:
         post.update(dict(serviceNumber=str(201)))
         layerInfo.update(
             dict(layername="Protected Plant Trigger Map",
                  layerstyle="LayerStyles/PPTM.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(94)
     # Update server details
     post.update(dict(service1="Environment/", service2="KoalaPlan/"))
     if loadKoalaPA:
         post.update(dict(serviceNumber=str(1)))
         layerInfo.update(
             dict(layername="Koala Priority Area",
                  layerstyle="LayerStyles/KoalaPriorityArea.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(95)
     if loadKoalaHA:
         post.update(dict(serviceNumber=str(3)))
         layerInfo.update(
             dict(layername="Koala Habitat Area-core",
                  layerstyle="LayerStyles/KoalaHabitatArea-core.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(96)
     if loadKoalaRA:
         post.update(dict(serviceNumber=str(6)))
         layerInfo.update(
             dict(layername="Koala Restoration Area",
                  layerstyle="LayerStyles/KoalaHabitatRestorationArea.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(97)
     if loadKoalaHAL:
         post.update(dict(serviceNumber=str(5)))
         layerInfo.update(
             dict(layername="Koala Habitat Area-locally refined",
                  layerstyle=
                  "LayerStyles/KoalaHabitatArea-LocallyRefined.qml",
                  geomtype="MultiPolygon"))
         self.getNRlayer(post, layerInfo, context, feedback)
         feedback.setProgress(98)
     if loadSLATS:
         # Update server details
         post.update(dict(service1="VegView/", service2="SLATS/"))
         for i in range(1, 24):
             post.update(dict(serviceNumber=str(i)))
             LayerName = json.loads(
                 GetGEOJSON(queryLayerName(post, context, feedback),
                            context, feedback))
             DefaultLayerName = str(i)
             LayerName = LayerName.get('name', DefaultLayerName)
             if i % 2 == 0:
                 colourCodeR = int((25 - i) / (30) * 250)
                 colourCodeG = int((i) / (30) * 250)
                 colourCodeB = int((i) / (30) * 250)
             else:
                 colourCodeR = int((i) / (26) * 250)
                 colourCodeG = int((i) / (26) * 250)
                 colourCodeB = int((25 - i) / (26) * 250)
             if i % 3 == 0:
                 colourCodeR = int((i) / (30) * 250)
                 colourCodeG = int((25 - i) / (30) * 250)
                 colourCodeB = int((i) / (30) * 250)
             if i % 4 == 0:
                 colourCodeR = int((25 - i) / (30) * 250)
                 colourCodeG = int((i) / (30) * 250)
                 colourCodeB = int((25 - i) / (30) * 250)
             if i % 5 == 0:
                 colourCodeR = int((i) / (30) * 250)
                 colourCodeG = int((25 - i) / (30) * 250)
                 colourCodeB = int((25 - i) / (30) * 250)
             if i % 6 == 0:
                 colourCodeR = int((25 - i) / (30) * 250)
                 colourCodeG = int((25 - i) / (30) * 250)
                 colourCodeB = int((i) / (30) * 250)
             colourCodeH = int(250)
             colourCodeRGB = (colourCodeR, colourCodeG, colourCodeB,
                              colourCodeH)
             #print(colourCodeRGB)
             layerInfo.update(dict(colour=colourCodeRGB))
             LayerName = 'SLATS - ' + LayerName
             layerInfo.update(
                 dict(layername=LayerName,
                      layerstyle="LayerStyles/SLATS" + str(i) + ".qml",
                      geomtype="MultiPolygon"))
             self.getNRlayer(post, layerInfo, context, feedback)
     #
     #
     feedback.setProgress(100)
     #
     return {}
    def processAlgorithm(self, parameters, context, feedback):
        #retrieve the layer inputs
        source1 = self.parameterAsSource(
            parameters,
            self.INPUT1,
            context
        )
        source2 = self.parameterAsSource(
            parameters,
            self.INPUT2,
            context
        )
        source3 = self.parameterAsSource(
            parameters,
            self.INPUT3,
            context
        )
        source4 = self.parameterAsSource(
            parameters,
            self.INPUT4,
            context
        )
        source5 = self.parameterAsSource(
            parameters,
            self.INPUT5,
            context
        )
        source6 = self.parameterAsSource(
            parameters,
            self.INPUT6,
            context
        )
        source7 = self.parameterAsSource(
            parameters,
            self.INPUT7,
            context
        )
        source8 = self.parameterAsSource(
            parameters,
            self.INPUT8,
            context
        )

        #if a layer was not found, throw an exception to indicate that the algorithm encountered a fatal error
        if source1 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT1))
        if source2 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT2))
        if source3 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT3))
        if source4 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT4))
        if source5 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT5))
        if source6 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT6))
        if source7 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT7))
        if source8 is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT8))
        
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("1/5 - Checking CRS...")
        feedback.pushInfo('--------------------------------------------------------------------------')
        
        #get crs of each layer
        crs1 = source1.sourceCrs().authid()
        crs2 = source2.sourceCrs().authid()
        crs3 = source3.sourceCrs().authid()
        crs4 = source4.sourceCrs().authid()
        crs5 = source5.sourceCrs().authid()
        crs6 = source6.sourceCrs().authid()
        crs7 = source7.sourceCrs().authid()
        crs8 = source8.sourceCrs().authid()
        
        #check crs of each layer and stop script if not all matching
        if crs1 == crs2 and crs1 == crs3 and crs1 == crs4 and crs1 == crs5 and crs1 == crs6 and crs1 == crs7 and crs1 == crs8:
            feedback.pushInfo('CRS is ' + (crs1))            
            feedback.pushInfo('CRS is matching for all layers')
        else:   
            feedback.pushInfo('Please ensure matching CRS for all layers')
            feedback.pushInfo('CRS for INPUT1 is ' + (crs1))
            feedback.pushInfo('CRS for INPUT2 is ' + (crs2))
            feedback.pushInfo('CRS for INPUT3 is ' + (crs3))
            feedback.pushInfo('CRS for INPUT4 is ' + (crs4))
            feedback.pushInfo('CRS for INPUT5 is ' + (crs5))
            feedback.pushInfo('CRS for INPUT6 is ' + (crs6))
            feedback.pushInfo('CRS for INPUT7 is ' + (crs7))
            feedback.pushInfo('CRS for INPUT8 is ' + (crs8))
            return{}
         
        #check if script has been cancelled before next stage
        if feedback.isCanceled():
            return{}   
        
        #output current stage of script
        feedback.pushInfo('--------------------------------------------------------------------------') 
        feedback.pushInfo("2/5 - Preparing Layer Data...")
        feedback.pushInfo('--------------------------------------------------------------------------')

        #get the layer data from the inputs
        lgaLayer = parameters['INPUT1']
        parcelsLayer = parameters['INPUT2']
        addressLayer = parameters['INPUT3']
        zonesLayer = parameters['INPUT4']
        overlaysLayer = parameters['INPUT5']
        floodLayer = parameters['INPUT6']
        coastLayer = parameters['INPUT7']
        watercourseLayer = parameters['INPUT8']
        
        #clip flood area to LGA
        result = processing.run('native:clip', { 'INPUT': floodLayer, 'OUTPUT': 'memory:', 'OVERLAY': lgaLayer }, context=context, feedback=feedback)
        floodLayer = result["OUTPUT"]
        
        #create a flood check layer (coast and waterways)
        floodCheckList = [coastLayer,watercourseLayer]
        result = processing.run('native:mergevectorlayers', {"LAYERS": floodCheckList, "OUTPUT": 'memory:' }, context=context, feedback=feedback)
        floodCheckLayer = result["OUTPUT"]
        
        #clean up flood layer (keep only areas that intersect with flood check layer)
        result = processing.run('native:extractbylocation', { 'INPUT': floodLayer, 'INTERSECT': floodCheckLayer, 'METHOD': 0, 'OUTPUT': 'memory:', 'PREDICATE': [0] }, context=context, feedback=feedback)
        floodCleanedLayer = result["OUTPUT"]
        
        #get total area of LGA
        result = processing.run('qgis:exportaddgeometrycolumns', { 'CALC_METHOD': 0, 'INPUT': lgaLayer, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        lgaAreaLayer = result["OUTPUT"]
        
        #get zone areas that intersect with flood layer
        result = processing.run('native:extractbylocation', { 'INPUT': zonesLayer, 'INTERSECT': floodCleanedLayer, 'METHOD': 0, 'OUTPUT': 'memory:', 'PREDICATE': [0] }, context=context, feedback=feedback)
        zonesLayer = result["OUTPUT"]
        
        #add "ZONE_CLASS" field to zones layer
        zonesLayer.startEditing()
        zonesLayer.dataProvider().addAttributes([QgsField("ZONE_CLASS", QVariant.String)])
        zonesLayer.updateFields()
        zonesLayer.commitChanges()
        
        #add "ZONE_CLASS" attribute for each feature ("ZONE_CODE" without numeric digit)
        zFeatures = zonesLayer.getFeatures()
        zonesLayer.startEditing()
        for feature in zFeatures:
            ini_string = feature["ZONE_CODE"]
            res = ''.join([i for i in ini_string if not i.isdigit()]) 
            feature["ZONE_CLASS"] = res
            zonesLayer.updateFeature(feature)
        zonesLayer.commitChanges()
        
        #check if script has been cancelled before next stage
        if feedback.isCanceled():
            return{}      
        
        #output current stage of script
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("3/5 - Calculating Flooded Area...")
        feedback.pushInfo('--------------------------------------------------------------------------')
        
        #clip zones layer to the flooded area
        #NOTE: must turn off invalid features filtering in QGIS - otherwise this process won't work as some geometry is invalid
        result = processing.run('native:clip', { 'INPUT': zonesLayer, 'OUTPUT': 'memory:', 'OVERLAY': floodCleanedLayer }, context=context, feedback=feedback)
        floodedZonesLayer = result["OUTPUT"]
        
        #group by "ZONE_CLASS"
        result = processing.run('native:dissolve', { 'FIELD': ['ZONE_CLASS'], 'INPUT': floodedZonesLayer, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        floodedZonesLayerDissolved = result["OUTPUT"]
        
        #add area for each "ZONE_CLASS"
        result = processing.run('qgis:exportaddgeometrycolumns', { 'CALC_METHOD': 0, 'INPUT': floodedZonesLayerDissolved, 'OUTPUT': 'memory:Flooded Area' }, context=context, feedback=feedback)
        floodedZonesAreaLayer = result["OUTPUT"]
        
        #add the "Flooded Area" layer to the layers panel
        #first add the layer without showing it
        QgsProject.instance().addMapLayer(floodedZonesAreaLayer, False)
        #obtain the layer tree of the top-level group in the project
        layerTree = iface.layerTreeCanvasBridge().rootGroup()
        #insert the layer - the position is a number starting from 0, with -1 an alias for the end
        layerTree.insertChildNode(-1, QgsLayerTreeLayer(floodedZonesAreaLayer))
        
        #customise the symbology for the "Flooded Area" layer
        layer = QgsProject.instance().mapLayersByName("Flooded Area")[0]
        single_symbol_renderer = layer.renderer()
        symbol = single_symbol_renderer.symbol()
        symbol.setColor(QColor.fromRgb(150, 206, 250))
        symbol.symbolLayer(0).setStrokeColor(QColor.fromRgb(70, 130, 180))
        symbol.setOpacity(0.3)
        layer.triggerRepaint()
        qgis.utils.iface.layerTreeView().refreshLayerSymbology(layer.id())
        
        #check if script has been cancelled before next stage
        if feedback.isCanceled():
            return{}
        
        #output current stage of script
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("4/5 - Calculating Flood-Affected Private Parcels...")
        feedback.pushInfo('--------------------------------------------------------------------------')
        
        #get all flood-affected parcels
        result = processing.run('native:extractbylocation', { 'INPUT': parcelsLayer, 'INTERSECT': floodCleanedLayer, 'METHOD': 0, 'OUTPUT': 'memory:', 'PREDICATE': [0] }, context=context, feedback=feedback)
        floodAffectedParcelsOriginal = result["OUTPUT"]
        
        #create inside buffer on zones layer (to avoid zones touching other parcels when intersecting)
        result = processing.run('native:buffer', { 'DISSOLVE': False, 'DISTANCE': -1, 'END_CAP_STYLE': 0, 'INPUT': zonesLayer, 'JOIN_STYLE': 0, 'MITER_LIMIT': 2, 'OUTPUT' : 'memory:', 'SEGMENTS': 200 }, context=context, feedback=feedback)
        zonesLayerClean = result["OUTPUT"]
        
        #exclude irrelevant zones (public zones, PZ and UFZ)
        request = QgsFeatureRequest().setFilterExpression("\"ZONE_CLASS\" = \'PCRZ\' OR \"ZONE_CLASS\" = \'PPRZ\' OR \"ZONE_CLASS\" = \'PUZ\' OR \"ZONE_CLASS\" = \'RDZ\' OR \"ZONE_CLASS\" = \'CA\' OR \"ZONE_CLASS\" = \'PZ\' OR \"ZONE_CLASS\" = \'UFZ\'")
        ids = [f.id() for f in zonesLayerClean.getFeatures(request)]
        zonesLayerClean.startEditing()
        for fid in ids:
            zonesLayerClean.deleteFeature(fid)
        zonesLayerClean.commitChanges()
        
        #add zone data to parcels
        result = processing.run('qgis:joinattributesbylocation', { 'DISCARD_NONMATCHING': True, 'INPUT': floodAffectedParcelsOriginal, 'JOIN': zonesLayerClean, 'METHOD': 1, 'OUTPUT': 'memory:', 'PREDICATE': [0] }, context=context, feedback=feedback)
        floodAffectedParcelsAll = result["OUTPUT"]
          
        #delete parcels with duplicate geometries - a work-around because 'qgis:deleteduplicategeometries' was causing crashes on return{}
        result = processing.run('qgis:exportaddgeometrycolumns', { 'CALC_METHOD': 0, 'INPUT': floodAffectedParcelsAll, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        floodAffectedParcelsArea = result["OUTPUT"]
        result = processing.run('native:removeduplicatesbyattribute', { 'FIELDS': ['area','perimeter'], 'INPUT': floodAffectedParcelsArea, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        floodAffectedParcels = result["OUTPUT"]

        #delete irrelevant parcels by attribute
        #"PC_LOTNO" LIKE 'CM%' = driveways, carparking and building surrounds
        #"PC_LOTNO" LIKE 'R%' = park reserves
        #"PC_STAT" = 'P' = proposed parcels
        #"PC_CRSTAT" = 'C' = crown parcels
        #"PC_CRSTAT" = 'G' = road reserves
        #"PC_SPIC" = '200' = shared driveways
        request = QgsFeatureRequest().setFilterExpression("\"PC_LOTNO\" LIKE \'CM%\' OR \"PC_LOTNO\" LIKE \'R%\' OR \"PC_STAT\" = \'P\' OR \"PC_CRSTAT\" = \'C\' OR \"PC_CRSTAT\" = \'G\' OR \"PC_SPIC\" = \'200\'")
        ids = [f.id() for f in floodAffectedParcels.getFeatures(request)]
        floodAffectedParcels.startEditing()
        for fid in ids:
            floodAffectedParcels.deleteFeature(fid)
        floodAffectedParcels.commitChanges()
        
        #remove address points without a specified address number
        result = processing.run('native:extractbyexpression', {'EXPRESSION': '(\"BUNIT_ID1\" != \'0\' OR \"BUNIT_ID2\" != \'0\' OR \"FLOOR_NO_1\" != \'0\' OR \"FLOOR_NO_2\" != \'0\' OR \"HSE_NUM1\" != \'0\' OR \"HSE_NUM2\" != \'0\' OR \"DISP_NUM1\" != \'0\' OR \"DISP_NUM2\" != \'0\')', 'INPUT': addressLayer, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        addressLayerClean = result["OUTPUT"]

        #get parcels with a valid address point
        result = processing.run('native:extractbylocation', { 'INPUT': floodAffectedParcels, 'INTERSECT': addressLayerClean, 'METHOD': 0, 'OUTPUT': 'memory:', 'PREDICATE': [0] }, context=context, feedback=feedback)
        floodAffectedPrivateParcels = result["OUTPUT"]
        
        #remove parcels under 40sqm (indicates it is not a regular private land parcel)
        result = processing.run('native:extractbyexpression', { 'EXPRESSION': '(\"area\" > \'40\')', 'INPUT': floodAffectedPrivateParcels, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        finalParcelsAreaClean = result["OUTPUT"]
        
        #delete parcels with inner rings (indicates it is not a regular private land parcel)
        #add "POLY_RING" field to parcels layer
        finalParcelsAreaClean.startEditing()
        finalParcelsAreaClean.dataProvider().addAttributes([QgsField("POLY_RING", QVariant.Double)])
        finalParcelsAreaClean.updateFields()
        finalParcelsAreaClean.commitChanges()
        
        #add "POLY_RING" attribute for each feature (count rings for each polygon within feature geometry)
        pFeatures = finalParcelsAreaClean.getFeatures()
        finalParcelsAreaClean.startEditing()
        for feature in pFeatures:
            geometry = feature.geometry()
            polyCount = 0
            ringCount = 0
            if geometry.isMultipart():
                polygons = geometry.asMultiPolygon()
            else:
                polygons = geometry.asPolygon()
            for polygon in polygons:
                polyCount = polyCount + 1
                for ring in polygon:
                    ringCount = ringCount + 1
                count = (ringCount/polyCount)
                feature["POLY_RING"] = count
                finalParcelsAreaClean.updateFeature(feature) 
        finalParcelsAreaClean.commitChanges()
        
        #delete features with more rings than polygons (indicates it has an inner ring)
        request = QgsFeatureRequest().setFilterExpression("\"POLY_RING\" > \'1\'")
        ids = [f.id() for f in finalParcelsAreaClean.getFeatures(request)]
        finalParcelsAreaClean.startEditing()
        for fid in ids:
            finalParcelsAreaClean.deleteFeature(fid)
        finalParcelsAreaClean.commitChanges()
        
        #get relevant flood control overlays
        result = processing.run('native:extractbyexpression', { 'EXPRESSION': '(\"ZONE_CODE\" = \'SBO\' OR \"ZONE_CODE\" = \'LSIO\' OR \"ZONE_CODE\" = \'FO\')', 'INPUT': overlaysLayer, 'OUTPUT': 'memory:' }, context=context, feedback=feedback)
        relevantOverlays = result["OUTPUT"]
        
        #assign parcels with relevant flood control overlays (if intersection)
        result = processing.run('qgis:joinattributesbylocation', { 'DISCARD_NONMATCHING': False, 'INPUT': finalParcelsAreaClean, 'JOIN': relevantOverlays, 'METHOD': 1, 'OUTPUT': 'memory:Flood-Affected Private Parcels', 'PREDICATE': [0] }, context=context, feedback=feedback)
        finalParcels = result["OUTPUT"]
        
        #add the "Flood-Affected Private Parcels" layer to the layers panel
        #first add the layer without showing it
        QgsProject.instance().addMapLayer(finalParcels, False)
        #obtain the layer tree of the top-level group in the project
        layerTree = iface.layerTreeCanvasBridge().rootGroup()
        #insert the layer - the position is a number starting from 0, with -1 an alias for the end
        layerTree.insertChildNode(-1, QgsLayerTreeLayer(finalParcels))
        
        #customise the symbology for the "Flood-Affected Private Parcels" layer
        layer = QgsProject.instance().mapLayersByName("Flood-Affected Private Parcels")[0]
        single_symbol_renderer = layer.renderer()
        symbol = single_symbol_renderer.symbol()
        symbol.setColor(QColor.fromRgb(225, 225, 225))
        symbol.symbolLayer(0).setStrokeColor(QColor.fromRgb(115, 115, 115))
        layer.triggerRepaint()
        qgis.utils.iface.layerTreeView().refreshLayerSymbology(layer.id())
        
        #check if script has been cancelled before next stage
        if feedback.isCanceled():
            return{}
        
        #output current stage of script
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("5/5 - Calculating statistics...")
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("FLOODED AREA (sqm):")
        feedback.pushInfo('--------------------------------------------------------------------------')

        #get lga area
        lgaFeatures = lgaAreaLayer.getFeatures()
        for feature in lgaFeatures:
            lgaArea = feature["area"]
        
        #get flooded lga area
        lgaFloodArea = 0
        zoneFeatures = floodedZonesAreaLayer.getFeatures()
        for feature in zoneFeatures:
            zoneArea = feature["area"]
            lgaFloodArea = lgaFloodArea + zoneArea
        
        #get flooded area percentage
        floodPercent = ((lgaFloodArea/lgaArea)*100)
        
        #ouput flooded lga area and percentage
        feedback.pushInfo('Flooded Area: ' + (str(round(lgaFloodArea, 2))))
        feedback.pushInfo((str(round(floodPercent, 2))) + '% of LGA Area')
        feedback.pushInfo('BY ZONE:')
        feedback.pushInfo('---------------------------------')
        
        #get and output flooded area for each "ZONE_CLASS"
        request = QgsFeatureRequest()
        clause = QgsFeatureRequest.OrderByClause('area', ascending=False)
        orderby = QgsFeatureRequest.OrderBy([clause])
        request.setOrderBy(orderby)
        zoneFeatures = floodedZonesAreaLayer.getFeatures(request)
        for feature in zoneFeatures:
            zoneName = feature["ZONE_CLASS"]
            zoneArea = feature["area"]
            feedback.pushInfo((zoneName) + ': ' + (str(round(zoneArea, 2))))
            lgaFloodArea = lgaFloodArea + zoneArea
        
        #output current stage of script
        feedback.pushInfo('--------------------------------------------------------------------------')
        feedback.pushInfo("FLOOD-AFFECTED PRIVATE PARCELS:")
        feedback.pushInfo('--------------------------------------------------------------------------')
        
        #get counts for ALL flood-affected private parcels and their flood overlays
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"area\" > \'0\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        allCount = finalParcels.selectedFeatureCount()
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        allCountSBO = finalParcels.selectedFeatureCount()
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        allCountLSIO = finalParcels.selectedFeatureCount()
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        allCountFO = finalParcels.selectedFeatureCount()
        
        #output total parcel counts and by flood overlay
        feedback.pushInfo('Flood-Affected Private Parcels: ' + (str(allCount)))
        feedback.pushInfo('With SBO Overlay: ' + (str(allCountSBO)))
        feedback.pushInfo('With LSIO Overlay: ' + (str(allCountLSIO)))
        feedback.pushInfo('With FO Overlay: ' + (str(allCountFO)))
        feedback.pushInfo('BY ZONE:')
        feedback.pushInfo('---------------------------------')
        
        #get counts for GRZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'GRZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        grzCount = finalParcels.selectedFeatureCount()
        if grzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'GRZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            grzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'GRZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            grzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'GRZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            grzCountFO = finalParcels.selectedFeatureCount()
        
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total General Residential (GRZ): ' + (str(grzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(grzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(grzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(grzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for RZ flood-affected private parcels and thier flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        rzCount = finalParcels.selectedFeatureCount()
        if rzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Residential (RZ): ' + (str(rzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(rzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(rzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(rzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for RGZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RGZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        rgzCount = finalParcels.selectedFeatureCount()
        if rgzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RGZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rgzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RGZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rgzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'RGZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            rgzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Residential Growth (RGZ): ' + (str(rgzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(rgzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(rgzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(rgzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for MUZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'MUZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        muzCount = finalParcels.selectedFeatureCount()
        if muzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'MUZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            muzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'MUZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            muzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'MUZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            muzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Mixed Use (MUZ): ' + (str(muzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(muzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(muzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(muzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for CZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        czCount = finalParcels.selectedFeatureCount()
        if czCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            czCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            czCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            czCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Commercial (CZ): ' + (str(czCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(czCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(czCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(czCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for BZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'BZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        bzCount = finalParcels.selectedFeatureCount()
        if bzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'BZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            bzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'BZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            bzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'BZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            bzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Commercial (BZ): ' + (str(bzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(bzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(bzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(bzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for INZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'INZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        inzCount = finalParcels.selectedFeatureCount()
        if inzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'INZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            inzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'INZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            inzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'INZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            inzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Industrial (INZ): ' + (str(inzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(inzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(inzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(inzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for SUZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'SUZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        suzCount = finalParcels.selectedFeatureCount()
        if suzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'SUZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            suzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'SUZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            suzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'SUZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            suzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Special Use (SUZ): ' + (str(suzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(suzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(suzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(suzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #get counts for CDZ flood-affected private parcels and their flood overlays (if applicable)
        processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CDZ\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
        cdzCount = finalParcels.selectedFeatureCount()
        if cdzCount > 0:
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CDZ\' AND \"ZONE_CODE_2\" = \'SBO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            cdzCountSBO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CDZ\' AND \"ZONE_CODE_2\" = \'LSIO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            cdzCountLSIO = finalParcels.selectedFeatureCount()
            processing.run('qgis:selectbyexpression', { 'EXPRESSION': '(\"ZONE_CLASS\" = \'CDZ\' AND \"ZONE_CODE_2\" = \'FO\')', 'INPUT': finalParcels, 'METHOD': 0 }, context=context)
            cdzCountFO = finalParcels.selectedFeatureCount()
            
            #output total parcel counts and by flood overlay
            feedback.pushInfo('Total Comprehensive Development (CDZ): ' + (str(cdzCount)))
            feedback.pushInfo('With SBO Overlay: ' + (str(cdzCountSBO)))
            feedback.pushInfo('With LSIO Overlay: ' + (str(cdzCountLSIO)))
            feedback.pushInfo('With FO Overlay: ' + (str(cdzCountFO)))
            feedback.pushInfo('---------------------------------')
        
        #end the script
        return{}
        
Exemple #8
0
    def run(self):
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result == 1:
            layers = iface.layerTreeCanvasBridge().rootGroup().layerOrder()
            if len(layers) != 0:
                #Check that there is a selected layer
                layer = iface.mapCanvas().currentLayer()
                if layer.type() == 0:
                    #check selected layer is a vector layer
                    if layer.geometryType() == 1:
                        #check to see if selected layer is a linestring geometry
                        if len(layer.selectedFeatures()) != 0:
                            #Dir = float(self.dlg.radLeft.isChecked()
                            layers = iface.layerTreeCanvasBridge().rootGroup(
                            ).layerOrder()
                            Lexists = "false"
                            #check to see if the virtual layer already exists
                            for layer in layers:
                                if layer.name() == "Parallel_Offset":
                                    Lexists = "true"
                                    vl = layer
                            #if it doesn't exist create it
                            if Lexists == "false":
                                vl = QgsVectorLayer(
                                    "Linestring?field=offset:integer&field=direction:string(10)&field=method:string(10)",
                                    "Parallel_Offset", "memory")
                                #vl = QgsVectorLayer("Linestring", "Parallel_Offset", "memory")
                                pr = vl.dataProvider()
                                vl.startEditing()
                                #pr.addAttributes( [ QgsField("offset", Double), QgsField("direction",  String), QgsField("method", String) ] )
                            else:
                                pr = vl.dataProvider()
                                vl.startEditing()

                            #get the direction
                            Dir = 'right'
                            if self.dlg.radLeft.isChecked():
                                Dir = 'left'
                            #get the method
                            if self.dlg.radRound.isChecked():
                                js = 1
                            if self.dlg.radMitre.isChecked():
                                js = 2
                            if self.dlg.radBevel.isChecked():
                                js = 3
                            #get the offset
                            #loffset = float(self.dlg.txtDistance.text())
                            loffset = self.dlg.sbDistance.value()

                            #create the new feature from the selection

                            for feature in layer.selectedFeatures():
                                geom = feature.geometry()
                                h = geom.asPolyline()
                                line = LineString(h)
                                for i in range(self.dlg.sbNumberLines.value()):
                                    nline = line.parallel_offset(
                                        loffset * (i + 1),
                                        Dir,
                                        resolution=16,
                                        join_style=js,
                                        mitre_limit=10.0)
                                    #turn nline back into a polyline and add it to the map as a new layer.
                                    fet = QgsFeature()
                                    fet.setGeometry(
                                        QgsGeometry.fromWkt(str(nline)))
                                    fet.setAttributes([loffset, Dir, js])
                                    pr.addFeatures([fet])
                                    vl.commitChanges()
                            QgsProject.instance().addMapLayer(vl)
                            mc = self.iface.mapCanvas()
                            mc.refresh()