Example #1
0
    def testDateTimeTypes(self):
        vl = QgsVectorLayer('%s table="qgis_test"."date_times" sql=' %
                            (self.dbconn), "testdatetimes", "mssql")
        assert(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName(
            'date_field')).type(), QVariant.Date)
        self.assertEqual(fields.at(fields.indexFromName(
            'time_field')).type(), QVariant.Time)
        self.assertEqual(fields.at(fields.indexFromName(
            'datetime_field')).type(), QVariant.DateTime)

        f = vl.getFeatures(QgsFeatureRequest()).next()

        date_idx = vl.fieldNameIndex('date_field')
        assert isinstance(f.attributes()[date_idx], QDate)
        self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
        time_idx = vl.fieldNameIndex('time_field')
        assert isinstance(f.attributes()[time_idx], QTime)
        self.assertEqual(f.attributes()[time_idx], QTime(13, 41, 52))
        datetime_idx = vl.fieldNameIndex('datetime_field')
        assert isinstance(f.attributes()[datetime_idx], QDateTime)
        self.assertEqual(f.attributes()[datetime_idx], QDateTime(
            QDate(2004, 3, 4), QTime(13, 41, 52)))
    def testDateTimeWriteShapefile(self):
        """Check writing date and time fields to an ESRI shapefile."""
        ml = QgsVectorLayer(
            ('Point?crs=epsg:4326&field=id:int&'
             'field=date_f:date&field=time_f:time&field=dt_f:datetime'),
            'test',
            'memory')

        assert ml is not None, 'Provider not initialized'
        assert ml.isValid(), 'Source layer not valid'
        provider = ml.dataProvider()
        assert provider is not None

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
        ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))])
        res, features = provider.addFeatures([ft])
        assert res
        assert len(features) > 0

        dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp')
        print(dest_file_name)
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        write_result = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            dest_file_name,
            'utf-8',
            crs,
            'ESRI Shapefile')
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        # Open result and check
        created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')

        fields = created_layer.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('date_f')).type(), QVariant.Date)
        #shapefiles do not support time types, result should be string
        self.assertEqual(fields.at(fields.indexFromName('time_f')).type(), QVariant.String)
        #shapefiles do not support datetime types, result should be string
        self.assertEqual(fields.at(fields.indexFromName('dt_f')).type(), QVariant.String)

        f = created_layer.getFeatures(QgsFeatureRequest()).next()

        date_idx = created_layer.fieldNameIndex('date_f')
        assert isinstance(f.attributes()[date_idx], QDate)
        self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5))
        time_idx = created_layer.fieldNameIndex('time_f')
        #shapefiles do not support time types
        assert isinstance(f.attributes()[time_idx], basestring)
        self.assertEqual(f.attributes()[time_idx], '13:45:22')
        #shapefiles do not support datetime types
        datetime_idx = created_layer.fieldNameIndex('dt_f')
        assert isinstance(f.attributes()[datetime_idx], basestring)
        self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz"))
Example #3
0
    def testDateTimeWriteShapefile(self):
        """Check writing date and time fields to an ESRI shapefile."""
        ml = QgsVectorLayer(
            ("Point?crs=epsg:4326&field=id:int&" "field=date_f:date&field=time_f:time&field=dt_f:datetime"),
            "test",
            "memory",
        )

        assert ml is not None, "Provider not initialised"
        assert ml.isValid(), "Source layer not valid"
        provider = ml.dataProvider()
        assert provider is not None

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
        ft.setAttributes(
            [1, QDate(2014, 0o3, 0o5), QTime(13, 45, 22), QDateTime(QDate(2014, 0o3, 0o5), QTime(13, 45, 22))]
        )
        res, features = provider.addFeatures([ft])
        assert res
        assert len(features) > 0

        dest_file_name = os.path.join(str(QDir.tempPath()), "datetime.shp")
        print(dest_file_name)
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, dest_file_name, "utf-8", crs, "ESRI Shapefile")
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        # Open result and check
        created_layer = QgsVectorLayer(u"{}|layerid=0".format(dest_file_name), u"test", u"ogr")

        fields = created_layer.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName("date_f")).type(), QVariant.Date)
        # shapefiles do not support time types, result should be string
        self.assertEqual(fields.at(fields.indexFromName("time_f")).type(), QVariant.String)
        # shapefiles do not support datetime types, result should be date
        self.assertEqual(fields.at(fields.indexFromName("dt_f")).type(), QVariant.Date)

        f = created_layer.getFeatures(QgsFeatureRequest()).next()

        date_idx = created_layer.fieldNameIndex("date_f")
        assert isinstance(f.attributes()[date_idx], QDate)
        self.assertEqual(f.attributes()[date_idx], QDate(2014, 0o3, 0o5))
        time_idx = created_layer.fieldNameIndex("time_f")
        # shapefiles do not support time types
        assert isinstance(f.attributes()[time_idx], basestring)
        self.assertEqual(f.attributes()[time_idx], "13:45:22")
        # shapefiles do not support datetime types
        datetime_idx = created_layer.fieldNameIndex("dt_f")
        assert isinstance(f.attributes()[datetime_idx], QDate)
        self.assertEqual(f.attributes()[datetime_idx], QDate(2014, 0o3, 0o5))
    def add_flooded_field(self, shapefile_path):
        """Create the layer from the local shp adding the flooded field.

        .. versionadded:: 3.3

        Use this method to add a calculated field to a shapefile. The shapefile
        should have a field called 'count' containing the number of flood
        reports for the field. The field values will be set to 0 if the count
        field is < 1, otherwise it will be set to 1.

        :param shapefile_path: Path to the shapefile that will have the flooded
            field added.
        :type shapefile_path: basestring

        :return: A vector layer with the flooded field added.
        :rtype: QgsVectorLayer
        """
        layer = QgsVectorLayer(
            shapefile_path, self.tr('Jakarta Floods'), 'ogr')
        # Add a calculated field indicating if a poly is flooded or not
        # from PyQt4.QtCore import QVariant
        layer.startEditing()
        # Add field with integer from 0 to 4 which represents the flood
        # class. Its the same as 'state' field except that is being treated
        # as a string.
        # This is used for cartography
        flood_class_field = QgsField('floodclass', QVariant.Int)
        layer.dataProvider().addAttributes([flood_class_field])
        layer.commitChanges()
        layer.startEditing()
        flood_class_idx = layer.fieldNameIndex('floodclass')
        flood_class_expression = QgsExpression('to_int(state)')
        context = QgsExpressionContext()
        context.setFields(layer.pendingFields())
        flood_class_expression.prepare(context)

        # Add field with boolean flag to say if the area is flooded
        # This is used by the impact function
        flooded_field = QgsField('flooded', QVariant.Int)
        layer.dataProvider().addAttributes([flooded_field])
        layer.commitChanges()
        layer.startEditing()
        flooded_idx = layer.fieldNameIndex('flooded')
        flood_flag_expression = QgsExpression('state > 0')
        flood_flag_expression.prepare(context)
        for feature in layer.getFeatures():
            context.setFeature(feature)
            feature[flood_class_idx] = flood_class_expression.evaluate(context)
            feature[flooded_idx] = flood_flag_expression.evaluate(context)
            layer.updateFeature(feature)
        layer.commitChanges()
        return layer
    def testDateTimeWriteTabfile(self):
        """Check writing date and time fields to an MapInfo tabfile."""
        ml = QgsVectorLayer(
            ('Point?crs=epsg:4326&field=id:int&'
             'field=date_f:date&field=time_f:time&field=dt_f:datetime'),
            'test',
            'memory')

        self.assertIsNotNone(ml, 'Provider not initialized')
        self.assertTrue(ml.isValid(), 'Source layer not valid')
        provider = ml.dataProvider()
        self.assertIsNotNone(provider)

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
        ft.setAttributes([1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))])
        res, features = provider.addFeatures([ft])
        self.assertTrue(res)
        self.assertTrue(features)

        dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.tab')
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        write_result = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            dest_file_name,
            'utf-8',
            crs,
            'MapInfo File')
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        # Open result and check
        created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr')

        fields = created_layer.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('date_f')).type(), QVariant.Date)
        self.assertEqual(fields.at(fields.indexFromName('time_f')).type(), QVariant.Time)
        self.assertEqual(fields.at(fields.indexFromName('dt_f')).type(), QVariant.DateTime)

        f = next(created_layer.getFeatures(QgsFeatureRequest()))

        date_idx = created_layer.fieldNameIndex('date_f')
        self.assertIsInstance(f.attributes()[date_idx], QDate)
        self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5))
        time_idx = created_layer.fieldNameIndex('time_f')
        self.assertIsInstance(f.attributes()[time_idx], QTime)
        self.assertEqual(f.attributes()[time_idx], QTime(13, 45, 22))
        datetime_idx = created_layer.fieldNameIndex('dt_f')
        self.assertIsInstance(f.attributes()[datetime_idx], QDateTime)
        self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)))
Example #6
0
    def testHstore(self):
        vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.Map)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fieldNameIndex('value')
        self.assertTrue(isinstance(f.attributes()[value_idx], dict))
        self.assertEqual(f.attributes()[value_idx], {'a': 'b', '1': '2'})

        new_f = QgsFeature(vl.fields())
        new_f['pk'] = NULL
        new_f['value'] = {'simple': '1', 'doubleQuote': '"y"', 'quote': "'q'", 'backslash': '\\'}
        r, fs = vl.dataProvider().addFeatures([new_f])
        self.assertTrue(r)
        new_pk = fs[0]['pk']
        self.assertNotEqual(new_pk, NULL, fs[0].attributes())

        try:
            read_back = vl.getFeature(new_pk)
            self.assertEqual(read_back['pk'], new_pk)
            self.assertEqual(read_back['value'], new_f['value'])
        finally:
            self.assertTrue(vl.startEditing())
            self.assertTrue(vl.deleteFeatures([new_pk]))
            self.assertTrue(vl.commitChanges())
Example #7
0
    def testStringArray(self):
        vl = QgsVectorLayer('%s table="qgis_test"."string_array" sql=' % (self.dbconn), "teststringarray", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.StringList)
        self.assertEqual(fields.at(fields.indexFromName('value')).subType(), QVariant.String)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fieldNameIndex('value')
        self.assertTrue(isinstance(f.attributes()[value_idx], list))
        self.assertEqual(f.attributes()[value_idx], ['a', 'b', 'c'])

        new_f = QgsFeature(vl.fields())
        new_f['pk'] = NULL
        new_f['value'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash']
        r, fs = vl.dataProvider().addFeatures([new_f])
        self.assertTrue(r)
        new_pk = fs[0]['pk']
        self.assertNotEqual(new_pk, NULL, fs[0].attributes())

        try:
            read_back = vl.getFeature(new_pk)
            self.assertEqual(read_back['pk'], new_pk)
            self.assertEqual(read_back['value'], new_f['value'])
        finally:
            self.assertTrue(vl.startEditing())
            self.assertTrue(vl.deleteFeatures([new_pk]))
            self.assertTrue(vl.commitChanges())
    def add_flooded_field(self, shapefile_path):
        """Create the layer from the local shp adding the flooded field.

        .. versionadded:: 3.3

        Use this method to add a calculated field to a shapefile. The shapefile
        should have a field called 'count' containing the number of flood
        reports for the field. The field values will be set to 0 if the count
        field is < 1, otherwise it will be set to 1.

        :param shapefile_path: Path to the shapefile that will have the flooded
            field added.
        :type shapefile_path: basestring

        :return: A vector layer with the flooded field added.
        :rtype: QgsVectorLayer
        """
        layer = QgsVectorLayer(
            shapefile_path, self.tr('Jakarta Floods'), 'ogr')
        # Add a calculated field indicating if a poly is flooded or not
        # from PyQt4.QtCore import QVariant
        layer.startEditing()
        field = QgsField('flooded', QVariant.Int)
        layer.dataProvider().addAttributes([field])
        layer.commitChanges()
        layer.startEditing()
        idx = layer.fieldNameIndex('flooded')
        expression = QgsExpression('state > 0')
        expression.prepare(layer.pendingFields())
        for feature in layer.getFeatures():
            feature[idx] = expression.evaluate(feature)
            layer.updateFeature(feature)
        layer.commitChanges()
        return layer
Example #9
0
    def testDateTimeFormats(self):
        # check that date and time formats are correctly interpreted
        basetestfile = os.path.join(TEST_DATA_DIR, 'tab_file.tab')
        vl = QgsVectorLayer(u'{}|layerid=0'.format(basetestfile), u'test', u'ogr')

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('date')).type(), QVariant.Date)
        self.assertEqual(fields.at(fields.indexFromName('time')).type(), QVariant.Time)
        self.assertEqual(fields.at(fields.indexFromName('date_time')).type(), QVariant.DateTime)

        f = vl.getFeatures(QgsFeatureRequest()).next()

        date_idx = vl.fieldNameIndex('date')
        assert isinstance(f.attributes()[date_idx], QDate)
        time_idx = vl.fieldNameIndex('time')
        assert isinstance(f.attributes()[time_idx], QTime)
        datetime_idx = vl.fieldNameIndex('date_time')
        assert isinstance(f.attributes()[datetime_idx], QDateTime)
Example #10
0
    def testDateTimeTypes(self):
        vl = QgsVectorLayer('%s table="QGIS"."DATE_TIMES" sql=' %
                            (self.dbconn), "testdatetimes", "oracle")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName(
            'date_field')).type(), QVariant.Date)
        self.assertEqual(fields.at(fields.indexFromName(
            'datetime_field')).type(), QVariant.DateTime)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        date_idx = vl.fieldNameIndex('date_field')
        self.assertTrue(isinstance(f.attributes()[date_idx], QDate))
        self.assertEqual(f.attributes()[date_idx], QDate(2004, 3, 4))
        datetime_idx = vl.fieldNameIndex('datetime_field')
        self.assertTrue(isinstance(f.attributes()[datetime_idx], QDateTime))
        self.assertEqual(f.attributes()[datetime_idx], QDateTime(
            QDate(2004, 3, 4), QTime(13, 41, 52)))
 def test_query_attribute(dbconn, query, att, val, fidval):
     ql = QgsVectorLayer('%s table="%s" (g) key=\'%s\' sql=' % (dbconn, query.replace('"', '\\"'), att), "testgeom", "postgres")
     self.assertTrue(ql.isValid())
     features = ql.getFeatures()
     att_idx = ql.fieldNameIndex(att)
     count = 0
     for f in features:
         count += 1
         self.assertEqual(f.attributes()[att_idx], val)
         #self.assertEqual(f.id(), val)
     self.assertEqual(count, 1)
Example #12
0
    def testDoubleArray(self):
        vl = QgsVectorLayer('%s table="qgis_test"."double_array" sql=' % (self.dbconn), "testdoublearray", "postgres")
        self.assertTrue(vl.isValid())

        fields = vl.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.List)
        self.assertEqual(fields.at(fields.indexFromName('value')).subType(), QVariant.Double)

        f = next(vl.getFeatures(QgsFeatureRequest()))

        value_idx = vl.fieldNameIndex('value')
        self.assertTrue(isinstance(f.attributes()[value_idx], list))
        self.assertEqual(f.attributes()[value_idx], [1.1, 2, -5.12345])
Example #13
0
 def copySelected(self, layer, mem_layer, geom_type):
     ''' Copy from selected layer to memory layer 
     '''
     self.manageMemLayers()
     
     # Create memory layer if not already set
     if mem_layer is None: 
         uri = geom_type+"?crs=epsg:25831" 
         mem_layer = QgsVectorLayer(uri, "selected_"+layer.name(), "memory")                     
      
         # Copy attributes from main layer to memory layer
         attrib_names = layer.dataProvider().fields()
         names_list = attrib_names.toList()
         newattributeList = []
         for attrib in names_list:
             aux = mem_layer.fieldNameIndex(attrib.name())
             if aux == -1:
                 newattributeList.append(QgsField(attrib.name(), attrib.type()))
         mem_layer.dataProvider().addAttributes(newattributeList)
         mem_layer.updateFields()
         
         # Insert layer in the top of the TOC           
         root = QgsProject.instance().layerTreeRoot()           
         QgsMapLayerRegistry.instance().addMapLayer(mem_layer, False)
         node_layer = QgsLayerTreeLayer(mem_layer)
         root.insertChildNode(0, node_layer)                 
  
     # Prepare memory layer for editing
     mem_layer.startEditing()
     
     # Iterate over selected features   
     cfeatures = []
     for sel_feature in layer.selectedFeatures():
         attributes = []
         attributes.extend(sel_feature.attributes())
         cfeature = QgsFeature()    
         cfeature.setGeometry(sel_feature.geometry())
         cfeature.setAttributes(attributes)
         cfeatures.append(cfeature)
                  
     # Add features, commit changes and refresh canvas
     mem_layer.dataProvider().addFeatures(cfeatures)             
     mem_layer.commitChanges()
     self.iface.mapCanvas().refresh() 
     self.iface.mapCanvas().zoomToSelected(layer)
     
     # Make sure layer is always visible 
     self.iface.legendInterface().setLayerVisible(mem_layer, True)
                 
     return mem_layer
    def testInteger64WriteTabfile(self):
        """Check writing Integer64 fields to an MapInfo tabfile (which does not support that type)."""
        ml = QgsVectorLayer(
            ('Point?crs=epsg:4326&field=int8:int8'),
            'test',
            'memory')

        self.assertIsNotNone(ml, 'Provider not initialized')
        self.assertTrue(ml.isValid(), 'Source layer not valid')
        provider = ml.dataProvider()
        self.assertIsNotNone(provider)

        ft = QgsFeature()
        ft.setAttributes([2123456789])
        res, features = provider.addFeatures([ft])
        self.assertTrue(res)
        self.assertTrue(features)

        dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64.tab')
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        write_result = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            dest_file_name,
            'utf-8',
            crs,
            'MapInfo File')
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        # Open result and check
        created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr')

        fields = created_layer.dataProvider().fields()
        self.assertEqual(fields.at(fields.indexFromName('int8')).type(), QVariant.Double)

        f = next(created_layer.getFeatures(QgsFeatureRequest()))

        int8_idx = created_layer.fieldNameIndex('int8')
        self.assertEqual(f.attributes()[int8_idx], 2123456789)
Example #15
0
def checkCartoDBId(layer, convert=False):
    """Check if layer has cartodb_id field"""
    new_layer = layer

    if convert and layer.fieldNameIndex('cartodb_id') == -1:
        checkTempDir()
        temp = tempfile.NamedTemporaryFile()
        error = QgsVectorFileWriter.writeAsVectorFormat(layer, temp.name, 'utf-8', None, 'ESRI Shapefile')
        if error == QgsVectorFileWriter.NoError:
            new_layer = QgsVectorLayer(temp.name + '.shp', layer.name(), 'ogr')
            new_layer.dataProvider().addAttributes([QgsField('cartodb_id', QVariant.Int)])
            new_layer.updateFields()
            features = new_layer.getFeatures()
            i = 1
            for feature in features:
                fid = feature.id()
                aid = new_layer.fieldNameIndex('cartodb_id')
                attrs = {aid: i}
                new_layer.dataProvider().changeAttributeValues({fid : attrs})
                i = i + 1
                new_layer.updateFeature(feature)
    return new_layer
Example #16
0
from bokeh.models import HoverTool, PanTool, WheelZoomTool, ResetTool, BoxZoomTool, SaveTool
from qgis.core import QgsVectorLayer

# Set axis type
axis_type = ["auto", "linear", "log", "datetime"]
xtype = axis_type[x_type]
ytype = axis_type[y_type]

# Set Output file (the mode parameter can be cdn or inline, and cdn is default)
output_file(Bokeh, title='QGIS Vector Layer Plot by Klas Karlsson', mode='cdn')

# Create QGIS vector layer object
lyr = QgsVectorLayer(Plot_Layer, "Lager", "ogr")

# Get field index number for selected fields
idx = lyr.fieldNameIndex(x_axis)
idy = lyr.fieldNameIndex(y_axis)
idp = lyr.fieldNameIndex(PopUp)

# Create Bokeh ColumnDataSource
source = ColumnDataSource(data=dict(
    x = [i.attributes()[idx] for i in lyr.getFeatures()],
    y = [i.attributes()[idy] for i in lyr.getFeatures()],
    pop = [i.attributes()[idp] for i in lyr.getFeatures()]
))

# Create Hoover Tooltip
hover = HoverTool(tooltips='@pop')

# Variables for labels in plot
title = 'Plotting ' + x_axis + ' vs ' + y_axis
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """
        self.validate()
        self.prepare()

        self.provenance.append_step(
            'Calculating Step',
            'Impact function is calculating the impact.')

        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value

        target_field = self.target_field
        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Align raster extent and viewport
        # assuming they are both in the same projection
        raster_extent = self.hazard.layer.dataProvider().extent()
        clip_xmin = raster_extent.xMinimum()
        # clip_xmax = raster_extent.xMaximum()
        clip_ymin = raster_extent.yMinimum()
        # clip_ymax = raster_extent.yMaximum()
        if viewport_extent[0] > clip_xmin:
            clip_xmin = viewport_extent[0]
        if viewport_extent[1] > clip_ymin:
            clip_ymin = viewport_extent[1]

        height = ((viewport_extent[3] - viewport_extent[1]) /
                  self.hazard.layer.rasterUnitsPerPixelY())
        height = int(height)
        width = ((viewport_extent[2] - viewport_extent[0]) /
                 self.hazard.layer.rasterUnitsPerPixelX())
        width = int(width)

        raster_extent = self.hazard.layer.dataProvider().extent()
        xmin = raster_extent.xMinimum()
        xmax = raster_extent.xMaximum()
        ymin = raster_extent.yMinimum()
        ymax = raster_extent.yMaximum()

        x_delta = (xmax - xmin) / self.hazard.layer.width()
        x = xmin
        for i in range(self.hazard.layer.width()):
            if abs(x - clip_xmin) < x_delta:
                # We have found the aligned raster boundary
                break
            x += x_delta
            _ = i

        y_delta = (ymax - ymin) / self.hazard.layer.height()
        y = ymin
        for i in range(self.hazard.layer.width()):
            if abs(y - clip_ymin) < y_delta:
                # We have found the aligned raster boundary
                break
            y += y_delta
        clip_extent = [x, y, x + width * x_delta, y + height * y_delta]

        # Clip hazard raster
        small_raster = clip_raster(
            self.hazard.layer, width, height, QgsRectangle(*clip_extent))

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        ranges = OrderedDict()
        ranges[0] = [0.0, 0.0]
        ranges[1] = [0.0, low_max]
        ranges[2] = [low_max, medium_max]
        ranges[3] = [medium_max, high_max]
        ranges[4] = [high_max, None]

        index, flood_cells_map = _raster_to_vector_cells(
            small_raster,
            ranges,
            self.exposure.layer.crs())

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        """
        if len(low_max_flood_cells_map) == 0 and \
            len(medium_max_flood_cells_map) == 0 and \
            len(high_max_flood_cells_map) == 0 and \
            len(high_min_flood_cells_map) == 0:
            message = tr(
                'There are no objects in the hazard layer with "value" > 0. '
                'Please check the value or use other extent.' % (
                    threshold_min, ))
            raise GetDataError(message)
        """

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(
            line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(
            self.exposure.layer,
            request,
            index,
            flood_cells_map,
            line_layer,
            target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(
            self.exposure.layer.crs(), output_crs)

        # Roads breakdown
        self.road_lengths = OrderedDict()
        self.affected_road_categories = self.hazard_classes
        # Impacted roads breakdown
        self.affected_road_lengths = OrderedDict([
            (self.hazard_classes[0], {}),
            (self.hazard_classes[1], {}),
            (self.hazard_classes[2], {}),
            (self.hazard_classes[3], {}),
            (self.hazard_classes[4], {}),
        ])

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)
        for road in roads_data:
            attributes = road.attributes()
            affected = attributes[target_field_index]
            hazard_zone = self.hazard_classes[affected]
            road_type = attributes[road_type_field_index]
            if road_type.__class__.__name__ == 'QPyNullVariant':
                road_type = tr('Other')
            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            if road_type not in self.road_lengths:
                self.road_lengths[road_type] = 0

            if hazard_zone not in self.affected_road_lengths:
                self.affected_road_lengths[hazard_zone] = {}

            if road_type not in self.affected_road_lengths[hazard_zone]:
                self.affected_road_lengths[hazard_zone][road_type] = 0

            self.road_lengths[road_type] += length
            num_classes = len(self.hazard_classes)
            if attributes[target_field_index] in range(num_classes):
                self.affected_road_lengths[hazard_zone][road_type] += length

        impact_summary = self.html_report()

        # For printing map purpose
        map_title = tr('Roads inundated')
        legend_title = tr('Road inundated status')

        style_classes = [
            # FIXME 0 - 0.1
            dict(
                label=self.hazard_classes[0] + ': 0m',
                value=0,
                colour='#00FF00',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[1] + ': <0 - %.1f m' % low_max,
                value=1,
                colour='#FFFF00',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f m' % (
                    low_max + 0.1, medium_max),
                value=2,
                colour='#FFB700',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f m' % (
                    medium_max + 0.1, high_max),
                value=3,
                colour='#FF6F00',
                transparency=0,
                size=1
            ),

            dict(
                label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                value=4,
                colour='#FF0000',
                transparency=0,
                size=1
            ),
        ]
        style_info = dict(
            target_field=target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'impact_summary': impact_summary,
            'map_title': map_title,
            'legend_title': legend_title,
            'target_field': target_field
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        line_layer = Vector(
            data=line_layer,
            name=tr('Flooded roads'),
            keywords=impact_layer_keywords,
            style_info=style_info)
        self._impact = line_layer
        return line_layer
Example #18
0
    def run(self):
        layer_list = []
        layers = self.iface.legendInterface().layers()
        self.dlg.comboBox.clear()
        for layer in layers:
            layer_list.append(layer.name())

        self.dlg.comboBox.addItems(layer_list)
        limit = self.dlg.lineEdit_2.text()
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:

            minimumarea = float(self.dlg.lineEdit_3.text())
            maximumdistance = float(self.dlg.lineEdit_2.text())

            selectedLayerIndex = self.dlg.comboBox.currentIndex()
            selectedLayer = layers[selectedLayerIndex]
            provider = selectedLayer.dataProvider()
            path = provider.dataSourceUri()
            tmp = path.split("|")
            path_to_shp_data = tmp[0]
            gdal.UseExceptions()
            driver = ogr.GetDriverByName('ESRI Shapefile')
            dataSource = driver.Open(
                path_to_shp_data,
                1)  #'C:/Program Files/QGIS Lyon/bin/ne_10m_land.shp'
            in_lyr = dataSource.GetLayer()
            outputshp = self.dlg.lineEdit.text()
            #outputshp = os.path.join(os.path.dirname(path),'auxpfile.shp')
            if os.path.exists(outputshp):
                driver.DeleteDataSource(outputshp)
            #out_ds = driver.CreateDataSource(outputshp)
            #out_lyr = out_ds.CreateLayer('poly', geom_type=ogr.wkbPolygon)

            geom = []
            polys = []
            landtypes = []

            listoflists = []
            for feat in selectedLayer.getFeatures():
                attrs = feat.attributes()
                listoflists.append([feat, attrs[1]])

            values = set(map(lambda x: x[1], listoflists))
            newlist = [[y[0] for y in listoflists if y[1] == x]
                       for x in values]

            filteredbyarea = []
            for polyatt in newlist:
                filteredbyarea.append(filterarea(polyatt, minimumarea))

            filterdbydistance = []
            for flist in filteredbyarea:
                filterdbydistance.append(filterdistance(
                    flist, maximumdistance))

            QgsMessageLog.logMessage(str(newlist), "Plugins",
                                     QgsMessageLog.INFO)

            srs = qgis.utils.iface.activeLayer().crs().authid()
            #srs = self.iface.mapCanvas().mapRenderer().destinationCrs().authid()
            layer = QgsVectorLayer(
                'Polygon?crs=' + str(srs) +
                '&field=id:integer&field=count:integer', 'newlayer', 'memory')

            hull_list = []
            geom = []
            for polys in filterdbydistance:
                geom = []
                for feat in polys:
                    geom.extend(concavehull.extract_points(feat.geometry()))
                    hull_list.append(concave(geom))

            provider = layer.dataProvider()
            # add hull geometry to data provider
            fid = 0
            for h in hull_list:
                for z in h:
                    feature = QgsFeature()
                    feature.setGeometry(z[0])
                    if layer.fieldNameIndex('id') > -1:
                        feature.setAttributes([fid, z[1]])
                        fid += 1
                    provider.addFeatures([feature])
            QgsVectorFileWriter.writeAsVectorFormat(layer, outputshp, str(srs),
                                                    None, 'ESRI Shapefile')
            base_name = os.path.splitext(os.path.basename(str(outputshp)))[0]
            layer_name = QgsVectorLayer(outputshp, base_name, 'ogr')
            QgsMapLayerRegistry.instance().addMapLayer(layer_name)
##Force Delete Table Column=name
##Vector_layer=vector
##Table_Field_to_Delete=field Vector_layer
# The script forcefully deletes named fields from a vector layer table.
# You get NO second chance, or opportunity to rollback.
# If you want that, you can use the much slower built in functions.

from qgis.core import QgsVectorLayer, QgsVectorDataProvider, QgsMapLayerRegistry, QgsMessageLog
QgsMessageLog.logMessage("Layer to process: %s" % Vector_layer, "ForceDelete")
QgsMessageLog.logMessage("Field to Force Delete: %s" % Table_Field_to_Delete,
                         "ForceDelete")

vectorLayer = QgsVectorLayer(Vector_layer, 'TEMP', "ogr")
vectorLayer.isValid()
QgsMessageLog.logMessage("Getting Field Index for: %s" % Table_Field_to_Delete,
                         "ForceDelete")
fieldID = vectorLayer.fieldNameIndex(Table_Field_to_Delete)
QgsMessageLog.logMessage("Deleting Field", "ForceDelete")
vectorLayer.dataProvider().deleteAttributes([fieldID])
vectorLayer.updateFields()
QgsMessageLog.logMessage("Reload Table...", "ForceDelete")
QgsMapLayerRegistry.instance().reloadAllLayers()
Example #20
0
    def run(self):
        """Experimental impact function."""
        self.validate()
        self.prepare()

        self.provenance.append_step(
            'Calculating Step',
            'Impact function is calculating the impact.')

        # Get parameters from layer's keywords
        self.hazard_class_attribute = self.hazard.keyword('field')
        self.hazard_class_mapping = self.hazard.keyword('value_map')
        self.exposure_class_attribute = self.exposure.keyword(
            'structure_class_field')

        # Prepare Hazard Layer
        hazard_provider = self.hazard.layer.dataProvider()

        # Check affected field exists in the hazard layer
        affected_field_index = hazard_provider.fieldNameIndex(
            self.hazard_class_attribute)
        if affected_field_index == -1:
            message = tr(
                'Field "%s" is not present in the attribute table of the '
                'hazard layer. Please change the Affected Field parameter in '
                'the IF Option.') % self.hazard_class_attribute
            raise GetDataError(message)

        srs = self.exposure.layer.crs().toWkt()
        exposure_provider = self.exposure.layer.dataProvider()
        exposure_fields = exposure_provider.fields()

        # Check self.exposure_class_attribute exists in exposure layer
        building_type_field_index = exposure_provider.fieldNameIndex(
            self.exposure_class_attribute)
        if building_type_field_index == -1:
            message = tr(
                'Field "%s" is not present in the attribute table of '
                'the exposure layer. Please change the Building Type '
                'Field parameter in the IF Option.'
            ) % self.exposure_class_attribute
            raise GetDataError(message)

        # If target_field does not exist, add it:
        if exposure_fields.indexFromName(self.target_field) == -1:
            exposure_provider.addAttributes(
                [QgsField(self.target_field, QVariant.Int)])
        target_field_index = exposure_provider.fieldNameIndex(
            self.target_field)
        exposure_fields = exposure_provider.fields()

        # Create layer to store the buildings from E and extent
        buildings_are_points = is_point_layer(self.exposure.layer)
        if buildings_are_points:
            building_layer = QgsVectorLayer(
                'Point?crs=' + srs, 'impact_buildings', 'memory')
        else:
            building_layer = QgsVectorLayer(
                'Polygon?crs=' + srs, 'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(exposure_fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the requested extent
        requested_extent = QgsRectangle(*self.requested_extent)

        # This is a hack - we should be setting the extent CRS
        # in the IF base class via safe/engine/core.py:calculate_impact
        # for now we assume the extent is in 4326 because it
        # is set to that from geo_extent
        # See issue #1857
        transform = QgsCoordinateTransform(
            self.requested_extent_crs, self.hazard.crs())
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        # make spatial index of affected polygons
        hazard_index = QgsSpatialIndex()
        hazard_geometries = {}  # key = feature id, value = geometry
        has_hazard_objects = False
        for feature in self.hazard.layer.getFeatures(request):
            value = feature[affected_field_index]
            if value not in self.hazard_class_mapping[self.wet]:
                continue
            hazard_index.insertFeature(feature)
            hazard_geometries[feature.id()] = QgsGeometry(feature.geometry())
            has_hazard_objects = True

        if not has_hazard_objects:
            message = tr(
                'There are no objects in the hazard layer with %s '
                'value in %s. Please check your data or use another '
                'attribute.') % (
                    self.hazard_class_attribute,
                    ', '.join(self.hazard_class_mapping[self.wet]))
            raise GetDataError(message)

        # Filter out just those EXPOSURE features in the analysis extents
        transform = QgsCoordinateTransform(
            self.requested_extent_crs, self.exposure.layer.crs())
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # We will use this transform to project each exposure feature into
        # the CRS of the Hazard.
        transform = QgsCoordinateTransform(
            self.exposure.crs(), self.hazard.crs())
        features = []
        for feature in self.exposure.layer.getFeatures(request):
            # Make a deep copy as the geometry is passed by reference
            # If we don't do this, subsequent operations will affect the
            # original feature geometry as well as the copy TS
            building_geom = QgsGeometry(feature.geometry())
            # Project the building geometry to hazard CRS
            building_bounds = transform.transform(building_geom.boundingBox())
            affected = False
            # get tentative list of intersecting hazard features
            # only based on intersection of bounding boxes
            ids = hazard_index.intersects(building_bounds)
            for fid in ids:
                # run (slow) exact intersection test
                building_geom.transform(transform)
                if hazard_geometries[fid].intersects(building_geom):
                    affected = True
                    break
            new_feature = QgsFeature()
            # We write out the original feature geom, not the projected one
            new_feature.setGeometry(feature.geometry())
            new_feature.setAttributes(feature.attributes())
            new_feature[target_field_index] = 1 if affected else 0
            features.append(new_feature)

            # every once in a while commit the created features
            # to the output layer
            if len(features) == 1000:
                (_, __) = building_provider.addFeatures(features)
                features = []

        (_, __) = building_provider.addFeatures(features)
        building_layer.updateExtents()

        # Generate simple impact report
        self.buildings = {}
        self.affected_buildings = OrderedDict([
            (tr('Flooded'), {})
        ])
        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(
            self.exposure_class_attribute)
        for building in buildings_data:
            record = building.attributes()
            building_type = record[building_type_field_index]
            if building_type in [None, 'NULL', 'null', 'Null']:
                building_type = 'Unknown type'
            if building_type not in self.buildings:
                self.buildings[building_type] = 0
                for category in self.affected_buildings.keys():
                    self.affected_buildings[category][
                        building_type] = OrderedDict([
                            (tr('Buildings Affected'), 0)])
            self.buildings[building_type] += 1

            if record[target_field_index] == 1:
                self.affected_buildings[tr('Flooded')][building_type][
                    tr('Buildings Affected')] += 1

        # Lump small entries and 'unknown' into 'other' category
        # Building threshold #2468
        postprocessors = self.parameters['postprocessors']
        building_postprocessors = postprocessors['BuildingType'][0]
        self.building_report_threshold = building_postprocessors.value[0].value
        self._consolidate_to_other()

        impact_summary = self.html_report()

        # For printing map purpose
        map_title = tr('Buildings inundated')
        legend_title = tr('Structure inundated status')

        style_classes = [
            dict(label=tr('Not Inundated'), value=0, colour='#1EFC7C',
                 transparency=0, size=0.5),
            dict(label=tr('Inundated'), value=1, colour='#F31A1C',
                 transparency=0, size=0.5)]
        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it.
        if building_layer.featureCount() < 1:
            raise ZeroImpactException(tr(
                'No buildings were impacted by this flood.'))

        extra_keywords = {
            'impact_summary': impact_summary,
            'map_title': map_title,
            'legend_title': legend_title,
            'target_field': self.target_field,
            'buildings_total': self.total_buildings,
            'buildings_affected': self.total_affected_buildings
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        building_layer = Vector(
            data=building_layer,
            name=tr('Flooded buildings'),
            keywords=impact_layer_keywords,
            style_info=style_info)
        self._impact = building_layer
        return building_layer
Example #21
0
    def run(self):
        """Run method that performs all the real work"""
        # Add items to Management Practices & Soil Type
        k_lists = []
        m_lists = []

        k_lists = self.k_list()
        m_lists = self.m_list()

        self.dlg.comboBox.addItems(k_lists)
        self.dlg.comboBox_2.addItems(m_lists)

        # show dialog box
        self.dlg.show()

        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:

            # Save paths of input directories
            selectedBoundary = self.dlg.lineEdit.text()
            selectedDEM = self.dlg.lineEdit_2.text()
            selectedRLayer = self.dlg.lineEdit_3.text()

            selectedOutput = self.dlg.lineEdit_4.text()
            for letter in selectedOutput:
                if letter == "\\":
                    selectedOutput = selectedOutput.replace(letter, "/")

            print(selectedBoundary)
            print(selectedDEM)
            print(selectedRLayer)
            print(selectedOutput)

            # Save indices for K and M
            selectedKLayer = self.dlg.comboBox.currentIndex()
            selectedMLayer = self.dlg.comboBox_2.currentIndex()

            boundary = QgsVectorLayer(selectedBoundary, 'Boundary', 'ogr')
            QgsMapLayerRegistry.instance().addMapLayer(boundary)

            entries = []

            # Retrieve K and M values

            k_value = self.k_index(selectedKLayer)
            m_value = self.m_index(selectedMLayer)

            km_value = k_value * m_value
            km_value = str(km_value)

            # Process R index

            ## CSV to Layer
            uri = 'file:///' + selectedRLayer + '?delimiter=%s&xField=%s&yField=%s&crs=%s' % (
                ",", "x", "y", "EPSG:4326")
            rainfall_unedited = QgsVectorLayer(uri, "rainfall",
                                               "delimitedtext")
            QgsMapLayerRegistry.instance().addMapLayer(rainfall_unedited)
            spatRef = QgsCoordinateReferenceSystem(
                4326, QgsCoordinateReferenceSystem.EpsgCrsId)

            ## CSV points to editable shapefile
            rainfall_edited = QgsVectorFileWriter(
                selectedOutput + '/rainfall_edited.shp', None,
                rainfall_unedited.pendingFields(), QGis.WKBPoint, spatRef)

            pt = QgsPoint()
            outFeature = QgsFeature()

            for feat in rainfall_unedited.getFeatures():
                attrs = feat.attributes()
                pt.setX(feat['x'])
                pt.setY(feat['y'])
                outFeature.setAttributes(attrs)
                outFeature.setGeometry(QgsGeometry.fromPoint(pt))
                rainfall_edited.addFeature(outFeature)
            del rainfall_edited

            rainfall_edited2 = QgsVectorLayer(
                selectedOutput + '/rainfall_edited.shp', 'rainfall_edited',
                'ogr')

            ## Add and calculate average field
            rainfall_edited2.startEditing()

            avgField = QgsField('average', QVariant.Double)
            rainfall_edited2.dataProvider().addAttributes([avgField])
            rainfall_edited2.updateFields()
            idx = rainfall_edited2.fieldNameIndex('average')

            time_count = idx - 2
            str_output = ''
            for i in range(1, time_count + 1):
                if i == 1:
                    a = str(i)
                    str_output += 'time' + a

                else:
                    a = str(i)
                    str_output += '+ time' + a

            e = QgsExpression(str_output)
            e.prepare(rainfall_edited2.pendingFields())

            for f in rainfall_edited2.getFeatures():
                f[idx] = e.evaluate(f) / time_count
                rainfall_edited2.updateFeature(f)

            rainfall_edited2.commitChanges()

            rainfall_edited3 = QgsVectorLayer(
                selectedOutput + '/rainfall_edited.shp', 'rainfall_edited',
                'ogr')
            QgsMapLayerRegistry.instance().addMapLayer(rainfall_edited3)

            ## Interpolating average using IDW
            ### Parameters for interpolation
            idx = rainfall_edited3.fieldNameIndex('average')

            layer_data = qgis.analysis.QgsInterpolator.LayerData()
            layer_data.vectorLayer = rainfall_edited3
            layer_data.zCoordInterpolation = False
            layer_data.interpolationAttribute = idx
            layer_data.mInputType = 1

            idw_interpolator = QgsIDWInterpolator([layer_data])

            ### Output parameter
            export_path = selectedOutput + "/interpolated_r_{}.asc".format(idx)
            rect = boundary.extent()
            res = 0.0001
            ncol = (rect.xMaximum() - rect.xMinimum()) / res
            nrows = (rect.yMaximum() - rect.yMinimum()) / res

            interpolated_r = QgsGridFileWriter(idw_interpolator,
                                               export_path, rect, int(ncol),
                                               int(nrows), res, res)
            interpolated_r.writeFile(True)

            interpolated_r2 = QgsRasterLayer(export_path, "interpolated_r")

            ## Clip output to boundary
            clippedR = processing.runandload(
                'gdalogr:cliprasterbymasklayer',
                interpolated_r2,  #INPUT <ParameterRaster>
                boundary,  #MASK <ParameterVector>
                "-9999",  #NO_DATA <ParameterString>
                False,  #ALPHA_BAND <ParameterBoolean>
                False,  #CROP_TO_CUTLINE <ParameterBoolean>
                False,  #KEEP_RESOLUTION <ParameterBoolean>
                5,  #RTYPE <ParameterSelection>
                4,  #COMPRESS <ParameterSelection>
                1,  #JPEGCOMPRESSION <ParameterNumber>
                6,  #ZLEVEL <ParameterNumber>
                1,  #PREDICTOR <ParameterNumber>
                False,  #TILED <ParameterBoolean>
                2,  #BIGTIFF <ParameterSelection>
                False,  #TFW <ParameterBoolean>
                "",  #EXTRA <ParameterString>
                selectedOutput +
                '/clip_interpolated_r.tif')  #OUTPUT <OutputRaster>

            r_layer = QgsRasterLayer(
                selectedOutput + '/clip_interpolated_r.tif', "R-index")
            boh4 = QgsRasterCalculatorEntry()
            boh4.ref = 'boh4@1'
            boh4.raster = r_layer
            boh4.bandNumber = 1
            entries.append(boh4)

            # Process S index
            ## Load DEM

            bohLayer1 = QgsRasterLayer(selectedDEM, "DEM")
            boh2 = QgsRasterCalculatorEntry()
            boh2.ref = 'boh2@1'
            boh2.raster = bohLayer1
            boh2.bandNumber = 1
            entries.append(boh2)

            ## Clip output to boundary
            clippedOutput2 = processing.runandload(
                'gdalogr:cliprasterbymasklayer',
                bohLayer1,  # INPUT <ParameterRaster>
                boundary,  # MASK <ParameterVector>
                "-9999",  # NO_DATA <ParameterString>
                False,  # ALPHA_BAND <ParameterBoolean>
                False,  # CROP_TO_CUTLINE <ParameterBoolean>
                False,  # KEEP_RESOLUTION <ParameterBoolean>
                5,  # RTYPE <ParameterSelection>
                4,  # COMPRESS <ParameterSelection>
                1,  # JPEGCOMPRESSION <ParameterNumber>
                6,  # ZLEVEL <ParameterNumber>
                1,  # PREDICTOR <ParameterNumber>
                False,  # TILED <ParameterBoolean>
                2,  # BIGTIFF <ParameterSelection>
                False,  # TFW <ParameterBoolean>
                "",  # EXTRA <ParameterString>
                selectedOutput + '/clip_dem.tif')  # OUTPUT <OutputRaster>

            bohLayer5 = QgsRasterLayer(selectedOutput + '/clip_dem.tif',
                                       "DEM-clipped")
            boh5 = QgsRasterCalculatorEntry()
            boh5.ref = 'boh5@1'
            boh5.raster = bohLayer5
            boh5.bandNumber = 1
            entries.append(boh5)

            ## GDAL algorithm for slope
            processing.runalg('gdalogr:slope', bohLayer5, 1, False, True, True,
                              111120, selectedOutput + '/slope(percent).tif')

            bohLayer6 = QgsRasterLayer(selectedOutput + '/slope(percent).tif',
                                       "slope(percent)")
            QgsMapLayerRegistry.instance().addMapLayer(bohLayer6)
            boh6 = QgsRasterCalculatorEntry()
            boh6.ref = 'boh6@1'
            boh6.raster = bohLayer6
            boh6.bandNumber = 1
            entries.append(boh6)

            # Process calculation with input extent and resolution
            calc = QgsRasterCalculator('(boh4@1 * boh6@1) *' + km_value,
                                       selectedOutput + '/soil_risk.tif',
                                       'GTiff', bohLayer6.extent(),
                                       bohLayer6.width(), bohLayer6.height(),
                                       entries)

            calc.processCalculation()
            bohLayer4 = QgsRasterLayer(selectedOutput + '/soil_risk.tif',
                                       "Soil_Risk")
            QgsMapLayerRegistry.instance().addMapLayer(bohLayer4)
Example #22
0
    def start_progress(self):

        if not self.outputfile:
            QMessageBox.critical(None, "Error", "Specify an output file")
            return

        # Acquiring geodata and attributed
        dsm_layer = self.layerComboManagerDSM.currentLayer()
        if dsm_layer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid raster layer is selected")
            return
        else:
            provider = dsm_layer.dataProvider()
            filepath_dsm = str(provider.dataSourceUri())

        point_layer = self.layerComboManagerPoint.currentLayer()
        if point_layer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid vector point layer is selected")
            return
        else:
            vlayer = QgsVectorLayer(point_layer.source(), "point", "ogr")

        point_field = self.layerComboManagerPointField.currentField()
        idx = vlayer.fieldNameIndex(point_field)
        if idx == -1:
            QMessageBox.critical(
                None, "Error",
                "An attribute with unique fields must be selected")
            return

        # Counts rows in vector layer
        h = vlayer.featureCount()
        newarray = np.zeros((h, 4))

        index = 0

        self.dlg.progressBar.setRange(index, h)

        for i in vlayer.getFeatures():
            self.dlg.progressBar.setValue(index + 1)
            geom = i.geometry()
            pp = geom.asPoint()
            x = pp[0]
            y = pp[1]
            rSquare = 100

            square = 'gdalwarp -dstnodata -9999 -q -overwrite -te ' + \
                     str(x - rSquare) + ' ' + str(y - rSquare) + ' ' + str(x + rSquare) + ' ' + str(y + rSquare) + \
                     ' -of GTiff ' + \
                     filepath_dsm + '' + self.plugin_dir + '/clipdsm.tif'

            si = subprocess.STARTUPINFO()
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            subprocess.call(square, startupinfo=si)

            area = gdal.Open(
                'C:/Users/xnygmi/Desktop/FREDRIK_GIS/London/clipdsm.tif')
            mat = np.array(area.ReadAsArray())

            max = np.max(mat)
            mean = np.mean(mat)
            min = np.min(mat)

            k = vlayer.fieldNameIndex('Id')
            newarray[index, 0] = i.attributes()[k]
            newarray[index, 1] = max
            newarray[index, 2] = mean
            newarray[index, 3] = min
            index += 1

        numformat = '%d ' + '%6.2f ' * 3
        headertext = 'ID    Mean    Max     Min'
        np.savetxt(self.outputfile,
                   newarray,
                   fmt=numformat,
                   header=headertext,
                   delimiter=' ')

        open(self.outputfile, 'r')

        self.iface.messageBar().pushMessage(
            'UAV Preparer. Operation Successful!',
            level=QgsMessageBar.INFO,
            duration=5)
Example #23
0
    def run(self, layers=None):
        """Experimental impact function.

        Input
          layers: List of layers expected to contain
              H: Polygon layer of inundation areas
              E: Vector layer of buildings
        """
        self.validate()
        self.prepare(layers)

        # Set the target field in impact layer
        target_field = 'INUNDATED'

        # Get the IF parameters
        building_type_field = self.parameters['building_type_field']
        affected_field = self.parameters['affected_field']
        affected_value = self.parameters['affected_value']

        # Extract data
        hazard_layer = self.hazard  # Flood
        exposure_layer = self.exposure  # Roads

        # Prepare Hazard Layer
        hazard_layer = hazard_layer.get_layer()
        hazard_provider = hazard_layer.dataProvider()

        # Check affected field exists in the hazard layer
        affected_field_index = hazard_provider.fieldNameIndex(affected_field)
        if affected_field_index == -1:
            message = tr('Field "%s" is not present in the attribute table of '
                         'the hazard layer. Please change the Affected Field '
                         'parameter in the IF Option.') % affected_field
            raise GetDataError(message)

        # Prepare Exposure Layer
        exposure_layer = exposure_layer.get_layer()
        srs = exposure_layer.crs().toWkt()
        exposure_provider = exposure_layer.dataProvider()
        exposure_fields = exposure_provider.fields()

        # Check building_type_field exists in exposure layer
        building_type_field_index = exposure_provider.fieldNameIndex(
            building_type_field)
        if building_type_field_index == -1:
            message = tr(
                'Field "%s" is not present in the attribute table of '
                'the exposure layer. Please change the Building Type '
                'Field parameter in the IF Option.') % building_type_field
            raise GetDataError(message)

        # If target_field does not exist, add it:
        if exposure_fields.indexFromName(target_field) == -1:
            exposure_provider.addAttributes(
                [QgsField(target_field, QVariant.Int)])
        target_field_index = exposure_provider.fieldNameIndex(target_field)
        exposure_fields = exposure_provider.fields()

        # Create layer to store the lines from E and extent
        building_layer = QgsVectorLayer('Polygon?crs=' + srs,
                                        'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(exposure_fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the requested extent
        requested_extent = QgsRectangle(*self.requested_extent)

        # This is a hack - we should be setting the extent CRS
        # in the IF base class via safe/engine/core.py:calculate_impact
        # for now we assume the extent is in 4326 because it
        # is set to that from geo_extent
        # See issue #1857
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem('EPSG:%i' %
                                         self._requested_extent_crs),
            hazard_layer.crs())
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        affected_field_type = hazard_provider.fields(
        )[affected_field_index].typeName()
        if affected_field_type in ['Real', 'Integer']:
            affected_value = float(affected_value)

        hazard_data = hazard_layer.getFeatures(request)
        hazard_poly = None
        for feature in hazard_data:
            record = feature.attributes()
            if record[affected_field_index] != affected_value:
                continue
            if hazard_poly is None:
                hazard_poly = QgsGeometry(feature.geometry())
            else:
                # Make geometry union of inundated polygons
                # But some polygon.geometry() could be invalid, skip them
                tmp_geometry = hazard_poly.combine(feature.geometry())
                try:
                    if tmp_geometry.isGeosValid():
                        hazard_poly = tmp_geometry
                except AttributeError:
                    pass

        if hazard_poly is None:
            message = tr('There are no objects in the hazard layer with %s '
                         'value=%s. Please check your data or use another '
                         'attribute.') % (affected_field, affected_value)
            raise GetDataError(message)

        exposure_data = exposure_layer.getFeatures(request)
        for feature in exposure_data:
            building_geom = feature.geometry()
            record = feature.attributes()
            l_feat = QgsFeature()
            l_feat.setGeometry(building_geom)
            l_feat.setAttributes(record)
            if hazard_poly.intersects(building_geom):
                l_feat.setAttribute(target_field_index, 1)
            else:
                l_feat.setAttribute(target_field_index, 0)
            (_, __) = building_layer.dataProvider().addFeatures([l_feat])
        building_layer.updateExtents()

        # Generate simple impact report
        self.buildings = {}
        self.affected_buildings = OrderedDict([(tr('Flooded'), {})])
        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(
            building_type_field)
        for building in buildings_data:
            record = building.attributes()
            building_type = record[building_type_field_index]
            if building_type in [None, 'NULL', 'null', 'Null']:
                building_type = 'Unknown type'
            if building_type not in self.buildings:
                self.buildings[building_type] = 0
                for category in self.affected_buildings.keys():
                    self.affected_buildings[category][
                        building_type] = OrderedDict([
                            (tr('Buildings Affected'), 0)
                        ])
            self.buildings[building_type] += 1

            if record[target_field_index] == 1:
                self.affected_buildings[tr('Flooded')][building_type][tr(
                    'Buildings Affected')] += 1

        # Lump small entries and 'unknown' into 'other' category
        self._consolidate_to_other()

        impact_summary = self.generate_html_report()
        map_title = tr('Buildings inundated')
        style_classes = [
            dict(label=tr('Not Inundated'),
                 value=0,
                 colour='#1EFC7C',
                 transparency=0,
                 size=0.5),
            dict(label=tr('Inundated'),
                 value=1,
                 colour='#F31A1C',
                 transparency=0,
                 size=0.5)
        ]
        style_info = dict(target_field=target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it.
        building_layer = Vector(data=building_layer,
                                name=tr('Flooded buildings'),
                                keywords={
                                    'impact_summary':
                                    impact_summary,
                                    'map_title':
                                    map_title,
                                    'target_field':
                                    target_field,
                                    'buildings_total':
                                    self.total_buildings,
                                    'buildings_affected':
                                    self.total_affected_buildings
                                },
                                style_info=style_info)
        self._impact = building_layer
        return building_layer
Example #24
0
class AutoFieldsTests( unittest.TestCase ):

    @classmethod
    def setUpClass( self ):
        self.msg = MessageManager( 'debug', None ) 
        self.msg.show( "Info! SetUp started", 'info', True )
        #Initialize QGIS app
        app = QgsApplication([], True)
        QgsApplication.setPrefixPath("/usr", True)
        QgsApplication.initQgis()
        
        #Configure QSettings (organization and application name)
        self.settings = QSettings("GeoTux", "QGIS-Plugin-Test") 

        #Load layer, add field f1, and add layer to Registry
        baseDir = os.path.dirname( os.path.realpath( __file__ ) )
        self.layerPath = os.path.join( baseDir, 'test_data', 'test_points.shp' )
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )   
        self.layer.dataProvider().addAttributes([QgsField('f1', QVariant.Double)])
        self.layer.updateFields()
        QgsMapLayerRegistry.instance().addMapLayer( self.layer )  
        
        #Instantiate AutoFieldManager
        self.autoFieldManager = AutoFieldManager( self.msg, None, '/AutoFieldsTest', 'GeoTux', 'QGIS-Plugin-Test' )
        
            
    def readStoredSettings( self, layer, fieldName ):
        """ Helper function to get a dictionary of stored QSettings for an AutoField """
        dictTmpProperties = {}
        autoFieldId = self.autoFieldManager.buildAutoFieldId( layer, fieldName )
        self.settings.beginGroup('/AutoFieldsTest/data/' + autoFieldId)
        dictTmpProperties['layer'] = self.settings.value( "layer", "", type=str )
        dictTmpProperties['field'] = self.settings.value( "field", u"", type=unicode )
        dictTmpProperties['expression'] = self.settings.value( "expression", u"", type=unicode )
        dictTmpProperties['layer2'] = self.settings.value( "layer2", "", type=str )
        dictTmpProperties['field2'] = self.settings.value( "field2", "", type=str )            
        dictTmpProperties['enabled'] = self.settings.value( "enabled", False, type=bool )
        self.settings.endGroup()
                
        return dictTmpProperties

    def test01CreateEnabledAutoField( self ):
        """ QSettings should be properly stored, AutoField should be enabled """
        self.msg.show( "Info! Test 1 started", 'info', True )

        self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'f1', 
            expression=u'$x'
        )

        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )      
        dictExpectedProperties = {
            'layer':self.layerPath,
            'field':u'f1',
            'expression':u'$x',
            'layer2':"",
            'field2':"",
            'enabled':True
        }
        
        self.assertEqual( dictTmpProperties, dictExpectedProperties )
        
        
    def test02AvoidTwoAutoFieldsOnSameField( self ):
        """ AutoField should not be created if another one already exists on the same field."""
        self.msg.show( "Info! Test 2 started", 'info', True )

        res = self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'f1', 
            expression=u'$y'
        )
        
        self.assertFalse( res )
        
        
    def test03EditAutoFieldLayer( self ):
        """ AutoField value should be updated if a feature is added.
            Note: It cannot handle the case when writing directly to the provider,
              as QGIS doesn't have a SIGNAL for that.
              self.layer.dataProvider().addFeatures( [ tmpFeature ] )        
         """
        self.msg.show( "Info! Test 3 started", 'info', True )

        tmpFeature = QgsFeature( self.layer.pendingFields() )
        tmpFeature.setGeometry( QgsGeometry.fromPoint( QgsPoint(-74.4, 4.5) ) )

        # Either 1:
        self.layer.startEditing()
        self.layer.addFeature( tmpFeature )
        self.layer.commitChanges()
        
        # Or 2:
        #with edit( self.layer ):
        #    self.layer.addFeature( tmpFeature )
            
        addedFeature = self.layer.getFeatures().next()
        self.assertEquals( addedFeature['f1'], -74.4 )


    def test04ChangeAttributeValue( self ):
        """ AutoField value should be updated if another AutoField value is changed """
        self.msg.show( "Info! Test 4 started", 'info', True )

        self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'modified', 
            expression=u'\'now: \' + to_string("f1")'
        )

        self.layer.startEditing()
        self.layer.changeAttributeValue( 0, self.layer.fieldNameIndex( u'id' ), 1 )
        self.layer.commitChanges()
            
        feature = self.layer.getFeatures().next()
        self.assertEquals( feature['modified'], 'now: -74.4' )

    
    def test05FieldRemovedThenDisableAutoField( self ):
        """ AutoField should be disabled if its base field is removed """
        self.msg.show( "Info! Test 5 started", 'info', True )

        fieldIndex = self.layer.fieldNameIndex( u'f1' )
        self.layer.startEditing()
        self.layer.deleteAttribute( fieldIndex )
        self.layer.commitChanges()
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertFalse( dictTmpProperties['enabled'] )        
            

    def test06MissingFieldAddedThenEnableAutoField( self ):
        """ AutoField should be enabled if missing field is added """
        self.msg.show( "Info! Test 6 started", 'info', True )    

        self.layer.startEditing()
        self.layer.addAttribute( QgsField( 'f1', QVariant.Double, len=10, prec=2 ) )
        self.layer.commitChanges()
        
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertTrue( dictTmpProperties['enabled'] )   

        
    def test07LayerRemovedThenDisableAutoField( self ):
        """ AutoField should be disabled if its base layer is removed """
        self.msg.show( "Info! Test 7 started", 'info', True )

        QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() )

        # removeMapLayer deletes the underlying object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )   
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertFalse( dictTmpProperties['enabled'] )
        
     
    def test08MissingLayerAddedThenEnableAutoField( self ):
        """ AutoField should be enabled if missing layer is added """
        self.msg.show( "Info! Test 8 started", 'info', True )

        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )
        QgsMapLayerRegistry.instance().addMapLayer( self.layer )  
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertTrue( dictTmpProperties['enabled'] )
           
        
    def test09RemoveAutoField( self ):
        """ QSettings should be deleted for the removed AutoField """
        self.msg.show( "Info! Test 9 started", 'info', True )

        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )
        autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'f1')
        self.autoFieldManager.removeAutoField( autoFieldId )
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) 
        
        self.assertEqual( dictTmpProperties, {'layer':"",'field':"",'expression':"",'layer2':"",'field2':"",'enabled':False} )
        

    @classmethod    
    def tearDownClass( self ):   
        self.msg.show( "Info! TearDown started", 'info', True )
    
        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )

        #Remove AutoField modified
        autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'modified' )
        self.autoFieldManager.removeAutoField( autoFieldId )

        #Delete field f1
        fieldIndex = self.layer.fieldNameIndex('f1')
        self.layer.dataProvider().deleteAttributes( [fieldIndex] )
        self.layer.updateFields()
        
        #Delete features from test layer
        fIds = self.layer.allFeatureIds()
        self.layer.dataProvider().deleteFeatures( fIds )
        
        #Remove layer from Registry
        QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() )
        self.msg.show( "Info! TearDown finished", 'info', True )

        QgsApplication.exitQgis()
Example #25
0
class InputNetworkTabManager(QtCore.QObject):
    ''' Class to hide managing of relative tab
    '''
    projectModified = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        '''constructor'''
        super(InputNetworkTabManager, self).__init__(parent)

        # parent is the dock widget with all graphical elements
        self.gui = parent
        
        # init some globals
        self.applicationPath = os.path.dirname(os.path.realpath(__file__))
        self.project = None
        self.projectPath = None
        self.roadLayer = None
        self.roadLayerId = None
        
        # retrieve the current tab index
        self.initTabTabIndex()
        
        # disable tab at the beginning
        self.gui.tabWidget.setTabEnabled(self.tabIndex, False)
        
        # set basic events
        self.gui.inputLayer_lineEdit.returnPressed.connect(self.loadLayer)
        self.gui.selectLayer_TButton.clicked.connect(self.askLayer)
        self.gui.selectFile_TButton.clicked.connect(self.askLayerFile)
        self.gui.inputNetwork_validate_PButton.clicked.connect(self.validateWithNotification)

    def initTabTabIndex(self):
        ''' Retrieve what tab index refer the current tab manager
        '''
        for tabIndex in range(self.gui.tabWidget.count()):
            if self.gui.tabWidget.tabText(tabIndex) == "Input Network":
                self.tabIndex = tabIndex
    
    def setProject(self, project=None):
        ''' setting the new project on which the tab is based
        '''
        self.project = project
        if self.project:
            # set some globals
            confFileName = self.project.fileName()
            self.projectPath = os.path.dirname(confFileName)
            
            # emit configurationLoaded with the status of loading
            self.setTabGUIBasingOnProject()
            
            # enable current tab because project has been loaded
            self.gui.tabWidget.setTabEnabled(self.tabIndex, True)
        
        else:
            # disable current tab because no project has been loaded yet
            self.gui.tabWidget.setTabEnabled(self.tabIndex, False)
    
    def setTabGUIBasingOnProject(self):
        '''Set tab basing on project conf 
        '''
        if not self.project:
            return
        
        # get conf parameters
        inputLayerFile = self.project.value('InputNetwork/inputLayer', '')
        columnRoadType = self.project.value('InputNetwork/columnRoadType', '')
        columnRoadLenght = self.project.value('InputNetwork/columnRoadLenght', '')
        columnRoadSlope = self.project.value('InputNetwork/columnRoadSlope', '')
        
        # if layer exist load it otherwise only reset comboboxes
        if os.path.exists(inputLayerFile):
            # check if layer is already loaded in layer list checking it's source
            # that would be equal to the inputLayerFile (for this reason is not simple 
            # to work with db data)
            found = False
            for layerName, layer in QgsMapLayerRegistry.instance().mapLayers().items():
                if inputLayerFile == layer.publicSource():
                    # set the found layer as roadLayer
                    self.roadLayer = layer
                    found = True
                    break
            
            # if layer is not loaded... load it
            if not found:
                # get layer name to set as public name in the legend
                layerName = os.path.splitext( os.path.basename(inputLayerFile) )[0]
                
                # load layer
                self.roadLayer = QgsVectorLayer(inputLayerFile, layerName, 'ogr')
                if not self.roadLayer.isValid():
                    message = self.tr("Error loading layer: %s" % self.roadLayer.error().message(QgsErrorMessage.Text))
                    iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
                    return
                
                # show layer in the canvas
                QgsMapLayerRegistry.instance().addMapLayer(self.roadLayer)
            
            # now layer is available
            self.roadLayerId = self.roadLayer.id()
        else:
            message = self.tr("Input network does not exist: %s" % inputLayerFile)
            iface.messageBar().pushMessage(message, QgsMessageBar.WARNING)
            
            self.roadLayer = None
            self.roadLayerId = None
        
        # avoid emitting signal in case of reset of indexes
        try:
            # to avoid add multiple listener, remove previous listener
            self.gui.inputLayer_lineEdit.returnPressed.disconnect(self.saveTabOnProject)
            self.gui.roadType_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.roadLenght_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.roadGradient_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
        except (Exception) as ex:
            pass
        
        # set text of loaded layer
        if self.roadLayer:
            self.gui.inputLayer_lineEdit.setText(self.roadLayer.publicSource())
        else:
            self.gui.inputLayer_lineEdit.setText(inputLayerFile)
            
        # now populare combo boxes with layer colums
        if self.roadLayer:
            fieldNames = sorted([field.name() for field in self.roadLayer.pendingFields().toList()])
        else:
            fieldNames = []
        unknownIndex = -1
        
        self.gui.roadType_CBox.clear()
        self.gui.roadLenght_CBox.clear()
        self.gui.roadGradient_CBox.clear()
        
        self.gui.roadType_CBox.addItems(fieldNames)
        self.gui.roadLenght_CBox.addItems(fieldNames)
        self.gui.roadGradient_CBox.addItems(fieldNames)
        
       # select the combobox item as in the project file... if not available then "Please select"
        index = self.gui.roadType_CBox.findText(columnRoadType)
        self.gui.roadType_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.roadLenght_CBox.findText(columnRoadLenght)
        self.gui.roadLenght_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.roadGradient_CBox.findText(columnRoadSlope)
        self.gui.roadGradient_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        # add all modification events to notify project modification
        self.gui.inputLayer_lineEdit.returnPressed.connect(self.saveTabOnProject)
        self.gui.roadType_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.roadLenght_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.roadGradient_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        
        
        #
        #  set parameters for vechicle count/speed columns
        #
        # get parameters fron project
        columnPassengerCars = self.project.value('VehicleCountSpeed/columnPassengerCars', '')
        columnLightDutyVehicle = self.project.value('VehicleCountSpeed/columnLightDutyVehicle', '')
        columnHeavyDutyVechicle = self.project.value('VehicleCountSpeed/columnHeavyDutyVechicle', '')
        columnUrbanBuses = self.project.value('VehicleCountSpeed/columnUrbanBuses', '')
        
        columnMotorcycle = self.project.value('VehicleCountSpeed/columnMotorcycle', '')
        columnCouch = self.project.value('VehicleCountSpeed/columnCouch', '')
        columnAverageSpeed = self.project.value('VehicleCountSpeed/columnAverageSpeed', '')
        
        # avoid emitting signal in case of reset of indexes
        try:
            # to avoid add multiple listener, remove previous listener
            self.gui.passengerCarsCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.lightDutyVehicleCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.heavyDutyVehicleCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.urbanBusesCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.coachesCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.motorcycleCount_CBox.currentIndexChanged.disconnect(self.saveTabOnProject)
            self.gui.averageVehicleSpeed_Cbox.currentIndexChanged.disconnect(self.saveTabOnProject)
        except (Exception) as ex:
            pass
        
        # now populare combo boxes with layer colums
        self.gui.passengerCarsCount_CBox.clear()
        self.gui.lightDutyVehicleCount_CBox.clear()
        self.gui.heavyDutyVehicleCount_CBox.clear()
        self.gui.urbanBusesCount_CBox.clear()
        self.gui.coachesCount_CBox.clear()
        self.gui.motorcycleCount_CBox.clear()
        self.gui.averageVehicleSpeed_Cbox.clear()
        
        self.gui.passengerCarsCount_CBox.addItems(fieldNames)
        self.gui.lightDutyVehicleCount_CBox.addItems(fieldNames)
        self.gui.heavyDutyVehicleCount_CBox.addItems(fieldNames)
        self.gui.urbanBusesCount_CBox.addItems(fieldNames)
        self.gui.coachesCount_CBox.addItems(fieldNames)
        self.gui.motorcycleCount_CBox.addItems(fieldNames)
        self.gui.averageVehicleSpeed_Cbox.addItems(fieldNames)
        
        # select the combobox item as in the project file... if not available then "Please select"
        index = self.gui.passengerCarsCount_CBox.findText(columnPassengerCars)
        self.gui.passengerCarsCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.lightDutyVehicleCount_CBox.findText(columnLightDutyVehicle)
        self.gui.lightDutyVehicleCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.heavyDutyVehicleCount_CBox.findText(columnHeavyDutyVechicle)
        self.gui.heavyDutyVehicleCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.urbanBusesCount_CBox.findText(columnUrbanBuses)
        self.gui.urbanBusesCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.coachesCount_CBox.findText(columnCouch)
        self.gui.coachesCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.motorcycleCount_CBox.findText(columnMotorcycle)
        self.gui.motorcycleCount_CBox.setCurrentIndex( index if index >= 0 else unknownIndex )
        
        index = self.gui.averageVehicleSpeed_Cbox.findText(columnAverageSpeed)
        self.gui.averageVehicleSpeed_Cbox.setCurrentIndex( index if index >= 0 else unknownIndex )
    
        # add all modification events to notify project modification
        self.gui.passengerCarsCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.lightDutyVehicleCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.heavyDutyVehicleCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.urbanBusesCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.coachesCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.motorcycleCount_CBox.currentIndexChanged.connect(self.saveTabOnProject)
        self.gui.averageVehicleSpeed_Cbox.currentIndexChanged.connect(self.saveTabOnProject)
    
    def saveTabOnProject(self):
        ''' Save tab configuration in the project basing on GUI values
        '''
        if self.sender():
            message = "QTraffic: saveTabOnProject by sender {}".format(self.sender().objectName())
            QgsLogger.debug(message, debuglevel=3)
        
        # get values from the GUI
        inputLayerFile = self.gui.inputLayer_lineEdit.text()
        columnRoadType = self.gui.roadType_CBox.currentText()
        columnRoadLenght = self.gui.roadLenght_CBox.currentText()
        columnRoadSlope = self.gui.roadGradient_CBox.currentText()
        
        # set conf parameters
        self.project.setValue('InputNetwork/inputLayer', inputLayerFile)
        self.project.setValue('InputNetwork/columnRoadType', columnRoadType)
        self.project.setValue('InputNetwork/columnRoadLenght', columnRoadLenght)
        self.project.setValue('InputNetwork/columnRoadSlope', columnRoadSlope)
        
        #
        #  save parameters for vechicle count/speed columns
        #
        # get values from the GUI
        columnPassengerCars = self.gui.passengerCarsCount_CBox.currentText()
        columnLightDutyVehicle = self.gui.lightDutyVehicleCount_CBox.currentText()
        columnHeavyDutyVechicle = self.gui.heavyDutyVehicleCount_CBox.currentText()
        columnUrbanBuses = self.gui.urbanBusesCount_CBox.currentText()
        
        columnCouch = self.gui.coachesCount_CBox.currentText()
        columnMotorcycle = self.gui.motorcycleCount_CBox.currentText()
        columnAverageSpeed = self.gui.averageVehicleSpeed_Cbox.currentText()
        
        # set conf parameters
        self.project.setValue('VehicleCountSpeed/columnPassengerCars', columnPassengerCars)
        self.project.setValue('VehicleCountSpeed/columnLightDutyVehicle', columnLightDutyVehicle)
        self.project.setValue('VehicleCountSpeed/columnHeavyDutyVechicle', columnHeavyDutyVechicle)
        self.project.setValue('VehicleCountSpeed/columnUrbanBuses', columnUrbanBuses)
        self.project.setValue('VehicleCountSpeed/columnMotorcycle', columnMotorcycle)
        self.project.setValue('VehicleCountSpeed/columnCouch', columnCouch)
        self.project.setValue('VehicleCountSpeed/columnAverageSpeed', columnAverageSpeed)
        
        # notify project modification
        self.projectModified.emit()
    
    def askLayer(self):
        ''' Ask for the layer to load
            Look for layer already loaded in the layer list 
        '''
        # create dialog to select layer
        dlg = SelectLayerDialog(self.gui)
        ret = dlg.exec_()
        if ret:
            # get selected layer
            newLayer = dlg.selectLayer_CBox.currentLayer()
            
            # set gui with the new layer name
            self.gui.inputLayer_lineEdit.setText(newLayer.publicSource())
            
            # then load layer
            self.loadLayer()
        
    def askLayerFile(self):
        ''' Ask for the layer file to load
            Don't load it if already loaded comparing source of tre layer
        '''
        if not self.project:
            return
        
        # if a layer is present in the project start from the path of that layer
        oldLayer = self.project.value('InputNetwork/inputLayer', '')
        if oldLayer:
            startPath = os.path.dirname(oldLayer)
        else:
            startPath = self.projectPath
        
        # get porject path
        layerFileName = QtGui.QFileDialog.getOpenFileName(self.gui, "Select road layer", startPath, 
                                                          self.tr("Shp (*.shp);;All (*)"))
        if not layerFileName:
            return
        
        # set gui with the new layer name
        self.gui.inputLayer_lineEdit.setText(layerFileName)
        
        # then load layer
        self.loadLayer()
    
    def loadLayer(self):
        ''' Load a shape layer 
        '''
        # get layer filename
        layerFileName = self.gui.inputLayer_lineEdit.text()
        if not layerFileName:
            return
        if not os.path.exists(layerFileName):
            title = self.tr("Warning")
            message = self.tr("Layer does not exist")
            iface.messageBar().pushMessage(message, QgsMessageBar.WARNING)
            return
        
        currentLayerFile = self.project.value('InputNetwork/inputLayer', '')
        if currentLayerFile != layerFileName:
            self.project.setValue('InputNetwork/inputLayer', layerFileName)
        self.setTabGUIBasingOnProject()
        
        # notify project modification if layer source is modified
        if currentLayerFile != layerFileName:
            self.projectModified.emit()
    
    def getRoadLayer(self):
        return self.roadLayer
    
    def getRoadLayerId(self):
        return self.roadLayerId
    
    def removeRoadLayer(self):
        ''' Remove current road layer from canvas
        '''
        if self.roadLayer and self.roadLayer.isValid():
            # do nothing if layer already removed by user
            QgsMapLayerRegistry.instance().removeMapLayer(self.roadLayer.id())
    
    def validateWithNotification(self):
        ''' Do validation and notify if it success
        ''' 
        if self.validate():
            message = self.tr("QTraffic: Input Network validation passed successfully")
            iface.messageBar().pushMessage(message, QgsMessageBar.SUCCESS)
    
    def validate(self):
        ''' Validate parameters inserted in the Input Network tab:
            Validation performed is:
            Mandatory parameters:
                Input layer
                Road Type
                Road lenght
                Road Gradient
                Average vehicle speed
                At least one of vehicle count
            Value validation:
                Road Type have to be integer
                Road lenght, lenght, Gradient have to be float
                Average vehicle speed have to be lfoat
                Count column have to be float or integer
            Inter tab validation
                Road type column values have to be present as categories in Fleet Distribution classes
            This method notify the error in case of validation failure
            This method notify success in case of correct validation
            @return: True is validated or False if not 
        '''
        if not self.project:
            return False
        
        inputLayerFile = self.gui.inputLayer_lineEdit.text()
        columnRoadType = self.gui.roadType_CBox.currentText()
        columnRoadLenght = self.gui.roadLenght_CBox.currentText()
        columnRoadSlope = self.gui.roadGradient_CBox.currentText()
        columnAverageSpeed = self.gui.averageVehicleSpeed_Cbox.currentText()

        columnPassengerCars = self.gui.passengerCarsCount_CBox.currentText()
        columnLightDutyVehicle = self.gui.lightDutyVehicleCount_CBox.currentText()
        columnHeavyDutyVechicle = self.gui.heavyDutyVehicleCount_CBox.currentText()
        columnUrbanBuses = self.gui.urbanBusesCount_CBox.currentText()
        columnCouch = self.gui.coachesCount_CBox.currentText()
        columnMotorcycle = self.gui.motorcycleCount_CBox.currentText()
        
        # mandatory fields
        if not inputLayerFile:
            message = self.tr("Validation error: Input shape have to be choosed")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        if not columnRoadType:
            message = self.tr("Validation error: Road type column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        if not columnRoadLenght:
            message = self.tr("Validation error: Road lenght column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        if not columnRoadSlope:
            message = self.tr("Validation error: Road gradient column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        if not columnRoadLenght:
            message = self.tr("Validation error: Road slope column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        if not columnAverageSpeed:
            message = self.tr("Validation error: Average vechicle speed column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        # at least one column count have to be selected
        if (not columnPassengerCars and
            not columnLightDutyVehicle and
            not columnHeavyDutyVechicle and
            not columnUrbanBuses and
            not columnCouch and
            not columnMotorcycle):
            message = self.tr("Validation error: At least a vehicle count column have to be selected from input layer")
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        # value validations
        fields = self.roadLayer.pendingFields()
        checkDict = {
            columnRoadType: [QtCore.QVariant.Int, QtCore.QVariant.LongLong],
            columnRoadLenght: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnRoadSlope: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnAverageSpeed: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnPassengerCars: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnLightDutyVehicle: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnHeavyDutyVechicle: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnUrbanBuses: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnCouch: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
            columnMotorcycle: [QtCore.QVariant.Int, QtCore.QVariant.Double, QtCore.QVariant.LongLong],
        }
        
        for columnName, admissibleTypes in checkDict.items():
            if not columnName:
                continue
            
            field = fields.field(columnName)
            if not field.type() in admissibleTypes:
                message = self.tr("Validation error: column {} has incompatible type {}".format(columnName, field.typeName()))
                iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
                return False
        
        # inter tab validation
        index = self.roadLayer.fieldNameIndex(columnRoadType)
        roadTypes = self.roadLayer.uniqueValues(index, -1)
        if len(roadTypes) == 0:
            message = self.tr("Validation error: column {} has no values".format(columnRoadType))
            iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
            return False
        
        # check if each road type is present in the list of road types in the fleet distribution tab
        fleetDistributionRoadTypes = self.gui.getRoadTypes()
        for roadType in roadTypes:
            if not str(roadType) in fleetDistributionRoadTypes:
                message = self.tr("Validation error: Road type value {} is not defined in Fleet Composition tab".format(roadType))
                iface.messageBar().pushMessage(message, QgsMessageBar.CRITICAL)
                return False
        
        return True
    
    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QtCore.QCoreApplication.translate('QTraffic', message)
Example #26
0
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """
        self.validate()
        self.prepare()

        target_field = self.target_field
        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')
        # Get parameters from IF parameter
        threshold_min = self.parameters['min threshold'].value
        threshold_max = self.parameters['max threshold'].value

        if threshold_min > threshold_max:
            message = tr(
                'The minimal threshold is greater than the maximal specified '
                'threshold. Please check the values.')
            raise GetDataError(message)

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Align raster extent and viewport
        # assuming they are both in the same projection
        raster_extent = self.hazard.layer.dataProvider().extent()
        clip_xmin = raster_extent.xMinimum()
        # clip_xmax = raster_extent.xMaximum()
        clip_ymin = raster_extent.yMinimum()
        # clip_ymax = raster_extent.yMaximum()
        if viewport_extent[0] > clip_xmin:
            clip_xmin = viewport_extent[0]
        if viewport_extent[1] > clip_ymin:
            clip_ymin = viewport_extent[1]
        # TODO: Why have these two clauses when they are not used?
        # Commenting out for now.
        # if viewport_extent[2] < clip_xmax:
        #     clip_xmax = viewport_extent[2]
        # if viewport_extent[3] < clip_ymax:
        #     clip_ymax = viewport_extent[3]

        height = ((viewport_extent[3] - viewport_extent[1]) /
                  self.hazard.layer.rasterUnitsPerPixelY())
        height = int(height)
        width = ((viewport_extent[2] - viewport_extent[0]) /
                 self.hazard.layer.rasterUnitsPerPixelX())
        width = int(width)

        raster_extent = self.hazard.layer.dataProvider().extent()
        xmin = raster_extent.xMinimum()
        xmax = raster_extent.xMaximum()
        ymin = raster_extent.yMinimum()
        ymax = raster_extent.yMaximum()

        x_delta = (xmax - xmin) / self.hazard.layer.width()
        x = xmin
        for i in range(self.hazard.layer.width()):
            if abs(x - clip_xmin) < x_delta:
                # We have found the aligned raster boundary
                break
            x += x_delta
            _ = i

        y_delta = (ymax - ymin) / self.hazard.layer.height()
        y = ymin
        for i in range(self.hazard.layer.width()):
            if abs(y - clip_ymin) < y_delta:
                # We have found the aligned raster boundary
                break
            y += y_delta
        clip_extent = [x, y, x + width * x_delta, y + height * y_delta]

        # Clip hazard raster
        small_raster = clip_raster(
            self.hazard.layer, width, height, QgsRectangle(*clip_extent))

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        index, flood_cells_map = _raster_to_vector_cells(
            small_raster,
            threshold_min,
            threshold_max,
            self.exposure.layer.crs())

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        if len(flood_cells_map) == 0:
            message = tr(
                'There are no objects in the hazard layer with "value" > %s. '
                'Please check the value or use other extent.' % (
                    threshold_min, ))
            raise GetDataError(message)

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(
            line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(
            self.exposure.layer,
            request,
            index,
            flood_cells_map,
            line_layer,
            target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(
            self.exposure.layer.crs(), output_crs)
        flooded_keyword = tr('Flooded in the threshold (m)')
        self.affected_road_categories = [flooded_keyword]
        self.affected_road_lengths = OrderedDict([
            (flooded_keyword, {})])
        self.road_lengths = OrderedDict()

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)
        for road in roads_data:
            attributes = road.attributes()
            road_type = attributes[road_type_field_index]
            if road_type.__class__.__name__ == 'QPyNullVariant':
                road_type = tr('Other')
            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            if road_type not in self.road_lengths:
                self.affected_road_lengths[flooded_keyword][road_type] = 0
                self.road_lengths[road_type] = 0

            self.road_lengths[road_type] += length
            if attributes[target_field_index] == 1:
                self.affected_road_lengths[
                    flooded_keyword][road_type] += length

        impact_summary = self.html_report()

        # For printing map purpose
        map_title = tr('Roads inundated')
        legend_title = tr('Road inundated status')

        style_classes = [
            dict(
                label=tr('Not Inundated'), value=0,
                colour='#1EFC7C', transparency=0, size=0.5),
            dict(
                label=tr('Inundated'), value=1,
                colour='#F31A1C', transparency=0, size=0.5)]
        style_info = dict(
            target_field=target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it
        line_layer = Vector(
            data=line_layer,
            name=tr('Flooded roads'),
            keywords={
                'impact_summary': impact_summary,
                'map_title': map_title,
                'legend_title': legend_title,
                'target_field': target_field},
            style_info=style_info)
        self._impact = line_layer
        return line_layer
Example #27
0
    def start_progress(self):

        if not self.outputfile:
            QMessageBox.critical(None, "Error", "Specify an output file")
            return

        # Acquiring geodata and attributes
        dsm_layer = self.layerComboManagerDSM.currentLayer()
        if dsm_layer is None:
            QMessageBox.critical(None, "Error", "No valid raster layer is selected")
            return
        else:
            provider = dsm_layer.dataProvider()
            filepath_dsm = str(provider.dataSourceUri())

        point_layer = self.layerComboManagerPoint.currentLayer()
        if point_layer is None:
            QMessageBox.critical(None, "Error", "No valid vector point layer is selected")
            return
        else:
            vlayer = QgsVectorLayer(point_layer.source(), "point", "ogr")

        point_field = self.layerComboManagerPointField.currentField()
        idx = vlayer.fieldNameIndex(point_field)
        if idx == -1:
            QMessageBox.critical(None, "Error", "An attribute with unique fields must be selected")
            return


        ### main code ###

        # set radius
        rSquare = int(self.dlg.spinBox.value()) # half picture size

        # finding ID column
        idx = vlayer.fieldNameIndex(point_field)

        numfeat = vlayer.featureCount()
        result = np.zeros([numfeat, 4])

        self.dlg.progressBar.setRange(0, numfeat)
        counter = 0
        for feature in vlayer.getFeatures():
            self.dlg.progressBar.setValue (counter + 1)
            geom = feature.geometry()
            pp = geom.asPoint()
            x = pp[0]
            y = pp[1]
            gdalclipdsm = "gdalwarp -dstnodata -9999 -q -overwrite -te " + str(x - rSquare) + " " + str(y - rSquare) + \
                          " " + str(x + rSquare) + " " + str(y + rSquare) + " -of GTiff " + filepath_dsm + " " + self.plugin_dir + "/clipdsm.tif"

            #QMessageBox.critical(None, "Bla", gdalclipdsm)

            # call the gdal function
            si = subprocess.STARTUPINFO() # used to suppress cmd window
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            subprocess.call(gdalclipdsm, startupinfo=si)
            #subprocess.call(gdalclipdsm)

            dataset = gdal.Open(self.plugin_dir + "/clipdsm.tif")
            dsm_array = dataset.ReadAsArray().astype(np.float)

            result[counter, 0] = int(feature.attributes()[idx])
            result[counter, 1] = np.mean(dsm_array)
            result[counter, 2] = np.max(dsm_array)
            result[counter, 3] = np.min(dsm_array)
            counter += 1

        numformat = "%d " + "%6.2f " * 3
        headertext = "id mean max min"
        np.savetxt(self.outputfile, result, fmt=numformat, header=headertext, comments="", delimiter="/t")

        self.iface.messageBar().pushMessage("UAV Preparer. Operation successful!", level=QgsMessageBar.INFO, duration=5)
Example #28
0
    def prepareReclassification(self, cl, areaLyr, centroidLyr, relateDict):
        """
        area without centroid: destid = -1
        area with conflicted centroid: destid = 0
        """
        destIdx = areaLyr.fieldNameIndex('destid')
        for id in relateDict[cl].keys():
            numberOfCentroids = len(relateDict[cl][id])
            if numberOfCentroids == 1:
                if relateDict[cl][id][0]['cl'] == cl:
                    # perfect case - must be reclassified
                    areaLyr.dataProvider().changeAttributeValues(
                        {id: {
                            destIdx: relateDict[cl][id][0]['featid']
                        }})
            elif numberOfCentroids == 0:
                # area without centroid - this must become a flag
                areaLyr.dataProvider().changeAttributeValues(
                    {id: {
                        destIdx: -1000
                    }})
            else:
                #first sweep: identify centroids with conflicted classes
                conflictedCentroids = [
                    feat for feat in relateDict[cl][id] if feat['cl'] <> cl
                ]
                conflictedChildCentroids = [
                    feat['child'] for feat in relateDict[cl][id]
                ]
                conflictedDict = dict()
                for conf in conflictedChildCentroids:
                    conflictedDict[conf] = 1
                if len(conflictedCentroids) > 0:
                    areaLyr.dataProvider().changeAttributeValues(
                        {id: {
                            destIdx: -2000
                        }})
                elif len(conflictedDict.keys()) > 1:
                    areaLyr.dataProvider().changeAttributeValues(
                        {id: {
                            destIdx: -2000
                        }})
                else:
                    sameClassCentroids = relateDict[cl][id]
                    #get original centroid layer
                    auxLyr = QgsVectorLayer(
                        self.abstractDb.getURI(cl,
                                               False,
                                               geomColumn='centroid').uri(),
                        relateDict[cl][id][0][0], "postgres")
                    #get all field names
                    fieldNames = [
                        field.name() for field in auxLyr.pendingFields()
                    ]
                    #we must not consider these fields
                    notAllowedFields = [
                        name for name in fieldNames
                        if (name in ['id', 'geom', 'centroid'] or 'id_' in name
                            )
                    ]
                    #check by index is easier, therefore, this step
                    notAllowedIndexes = []
                    for notAllowedField in notAllowedFields:
                        notAllowedIndexes.append(
                            auxLyr.fieldNameIndex(notAllowedField))

                    #comparing centroid attributes
                    duplicated = True  # aux variable
                    firstCentroid = [
                        feat for feat in auxLyr.dataProvider().getFeatures(
                            QgsFeatureRequest(relateDict[cl][id][0][1]))
                    ][0]
                    firstAttributes = firstCentroid.attributes()
                    for i in range(1, len(sameClassCentroids)):
                        centroid = [
                            feat for feat in auxLyr.dataProvider().getFeatures(
                                QgsFeatureRequest(sameClassCentroids[i][1]))
                        ][0]
                        attributes = centroid.attributes()
                        for j in range(len(attributes)):
                            if j not in notAllowedIndexes:
                                #in this case the attribute j is not equal, we must flag this out
                                if centroid[j] != firstCentroid[j]:
                                    duplicated = False
                                    break
                        break
                    if duplicated:
                        areaLyr.dataProvider().changeAttributeValues(
                            {id: {
                                destIdx: relateDict[cl][id][0]['featid']
                            }})
                    else:
                        areaLyr.dataProvider().changeAttributeValues(
                            {id: {
                                destIdx: -2000
                            }})
Example #29
0
    def run(self):
        """Run the impact function.

        :returns: A vector layer with affected areas marked.
        :type: safe_layer
        """
        hazard_layer = self.hazard.layer
        exposure = self.exposure.layer

        # Thresholds for tsunami hazard zone breakdown.
        group_parameters = self.parameters['group_threshold']
        ver_low_unit = group_parameters.value_map['very_low_threshold'].unit
        unit_abbrev = ver_low_unit.abbreviation
        unaffected_threshold = group_parameters.value_map[
            'unaffected_threshold']
        unaffected_max = unaffected_threshold.value
        very_low_max = group_parameters.value_map['very_low_threshold'].value
        low_max = group_parameters.value_map['low_threshold'].value
        medium_max = group_parameters.value_map['moderate_threshold'].value
        high_max = group_parameters.value_map['high_threshold'].value
        ranges = ranges_according_thresholds_list(
            [None, unaffected_max, very_low_max, low_max,
             medium_max, high_max, None])

        hazard_value_to_class = {}
        for i, interval in enumerate(ranges):
            hazard_value_to_class[interval] = self.hazard_classes[i]

        # Get parameters from layer's keywords
        class_field = self.exposure.keyword('field')

        # reproject self.extent to the hazard projection
        hazard_crs = hazard_layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        small_raster = align_clip_raster(hazard_layer, viewport_extent)

        # Create vector features from the flood raster
        hazard_class_attribute = 'hazard'
        vector_file_path = reclassify_polygonize(
            small_raster.source(), ranges, name_field=hazard_class_attribute)

        hazard = QgsVectorLayer(vector_file_path, 'ash vector', 'ogr')

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326')
        hazard_to_exposure = QgsCoordinateTransform(
            hazard.crs(), exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(
            crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(
            crs_wgs84, exposure.crs())

        extent = QgsRectangle(
            self.requested_extent[0], self.requested_extent[1],
            self.requested_extent[2], self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()
        hazard_features = {}
        for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            f.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(f)
            hazard_features[f.id()] = QgsFeature(f)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.String))
        writer = QgsVectorFileWriter(
            filename, 'utf-8', impact_fields, QGis.WKBPolygon, exposure.crs())

        # iterate over all exposure polygons and calculate the impact
        _calculate_landcover_impact(
            exposure, extent_exposure, extent_exposure_geom,
            hazard_class_attribute, hazard_features, hazard_index,
            hazard_value_to_class, impact_fields, writer)

        del writer
        impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr')

        # find unaffected features
        unaffected_feats = []
        target_field_index = impact_layer.fieldNameIndex(self.target_field)
        for f in impact_layer.getFeatures():
            haz_class = f.attributes()[target_field_index]
            if haz_class == self.hazard_classes[0]:
                unaffected_feats.append(f.id())

        impact_layer.dataProvider().deleteFeatures(unaffected_feats)

        if impact_layer.featureCount() == 0:
            raise ZeroImpactException()

        zone_field = None
        if self.aggregator:
            zone_field = self.aggregator.exposure_aggregation_field

        impact_data = LandCoverReportMixin(
            question=self.question,
            impact_layer=impact_layer,
            target_field=self.target_field,
            ordered_columns=self.hazard_classes,
            affected_columns=self.affected_hazard_columns,
            land_cover_field=class_field,
            zone_field=zone_field
        ).generate_data()

        # Define style for the impact layer
        style_classes = [
            dict(
                label=self.hazard_classes[1] + ': %.1f - %.1f %s' % (
                    unaffected_max, very_low_max, unit_abbrev),
                value=self.hazard_classes[1],
                colour='#2C6BA4',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f %s' % (
                    very_low_max + 0.1, low_max, unit_abbrev),
                value=self.hazard_classes[2],
                colour='#00A4D8',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f %s' % (
                    low_max + 0.1, medium_max, unit_abbrev),
                value=self.hazard_classes[3],
                colour='#FFEF36',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[4] + ': %.1f - %.1f %s' % (
                    medium_max + 0.1, high_max, unit_abbrev),
                value=self.hazard_classes[4],
                colour='#EFA951',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[5] + ': > %.1f %s' % (
                    high_max, unit_abbrev),
                value=self.hazard_classes[5],
                colour='#d62631',
                border_color='#000000',
                transparency=0),
        ]
        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'map_title': self.map_title(),
            'target_field': self.target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(
            data=impact_layer,
            name=self.map_title(),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """

        target_field = self.target_field

        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')
        exposure_value_mapping = self.exposure.keyword('value_mapping')

        # Get parameters from IF parameter
        threshold_min = self.parameters['min threshold'].value
        threshold_max = self.parameters['max threshold'].value

        if threshold_min > threshold_max:
            message = tr(
                'The minimal threshold is greater than the maximal specified '
                'threshold. Please check the values.')
            raise GetDataError(message)

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Clip hazard raster
        small_raster = align_clip_raster(self.hazard.layer, viewport_extent)

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(
            line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        index, flood_cells_map = _raster_to_vector_cells(
            small_raster,
            threshold_min,
            threshold_max,
            self.exposure.layer.crs())

        if len(flood_cells_map) == 0:
            message = tr(
                'There are no objects in the hazard layer with "value" > %s. '
                'Please check the value or use other extent.' % (
                    threshold_min, ))
            raise GetDataError(message)

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(
            self.exposure.layer,
            request,
            index,
            flood_cells_map,
            line_layer,
            target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(
            self.exposure.layer.crs(), output_crs)

        classes = [tr('Flooded in the threshold (m)')]
        self.init_report_var(classes)

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)

        for road in roads_data:
            attributes = road.attributes()

            usage = attributes[road_type_field_index]
            usage = main_type(usage, exposure_value_mapping)

            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            affected = False
            if attributes[target_field_index] == 1:
                affected = True

            self.classify_feature(classes[0], usage, length, affected)

        self.reorder_dictionaries()

        style_classes = [
            dict(
                label=tr('Not Inundated'), value=0,
                colour='#1EFC7C', transparency=0, size=0.5),
            dict(
                label=tr('Inundated'), value=1,
                colour='#F31A1C', transparency=0, size=0.5)]
        style_info = dict(
            target_field=target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        impact_data = self.generate_data()

        extra_keywords = {
            'map_title': self.metadata().key('map_title'),
            'legend_title': self.metadata().key('legend_title'),
            'target_field': target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        impact_layer = Vector(
            data=line_layer,
            name=self.metadata().key('layer_name'),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
    def run(self, layers):
        """Experimental impact function.

        Input
          layers: List of layers expected to contain
              H: Polygon layer of inundation areas
              E: Vector layer of roads
        """
        target_field = self.parameters['target_field']
        building_type_field = self.parameters['building_type_field']
        affected_field = self.parameters['affected_field']
        affected_value = self.parameters['affected_value']

        # Extract data
        H = get_hazard_layer(layers)    # Flood
        E = get_exposure_layer(layers)  # Roads

        question = get_question(H.get_name(),
                                E.get_name(),
                                self)

        H = H.get_layer()
        h_provider = H.dataProvider()
        affected_field_index = h_provider.fieldNameIndex(affected_field)
        if affected_field_index == -1:
            message = tr('''Parameter "Affected Field"(='%s')
                is not present in the
                attribute table of the hazard layer.''' % (affected_field, ))
            raise GetDataError(message)

        E = E.get_layer()
        srs = E.crs().toWkt()
        e_provider = E.dataProvider()
        fields = e_provider.fields()
        # If target_field does not exist, add it:
        if fields.indexFromName(target_field) == -1:
            e_provider.addAttributes([QgsField(target_field,
                                               QVariant.Int)])
        target_field_index = e_provider.fieldNameIndex(target_field)
        fields = e_provider.fields()

        # Create layer for store the lines from E and extent
        building_layer = QgsVectorLayer(
            'Polygon?crs=' + srs, 'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the extent
        extent = QgsRectangle(*self.extent)
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        affected_field_type = \
            h_provider.fields()[affected_field_index].typeName()
        if affected_field_type in ['Real', 'Integer']:
            affected_value = float(affected_value)

        h_data = H.getFeatures(request)
        hazard_poly = None
        for mpolygon in h_data:
            attrs = mpolygon.attributes()
            if attrs[affected_field_index] != affected_value:
                continue
            if hazard_poly is None:
                hazard_poly = QgsGeometry(mpolygon.geometry())
            else:
                # Make geometry union of inundated polygons

                # But some mpolygon.geometry() could be invalid, skip them
                tmp_geometry = hazard_poly.combine(mpolygon.geometry())
                try:
                    if tmp_geometry.isGeosValid():
                        hazard_poly = tmp_geometry
                except AttributeError:
                    pass

        if hazard_poly is None:
            message = tr('''There are no objects
                in the hazard layer with
                "Affected value"='%s'.
                Please check the value or use other
                extent.''' % (affected_value, ))
            raise GetDataError(message)

        e_data = E.getFeatures(request)
        for feat in e_data:
            building_geom = feat.geometry()
            attrs = feat.attributes()
            l_feat = QgsFeature()
            l_feat.setGeometry(building_geom)
            l_feat.setAttributes(attrs)
            if hazard_poly.intersects(building_geom):
                l_feat.setAttribute(target_field_index, 1)
            else:

                l_feat.setAttribute(target_field_index, 0)
            (_, __) = \
                    building_layer.dataProvider().addFeatures([l_feat])
        building_layer.updateExtents()

        # Generate simple impact report

        building_count = flooded_count = 0  # Count of buildings
        buildings_by_type = dict()      # Length of flooded roads by types

        buildings_data = building_layer.getFeatures()
        building_type_field_index = \
            building_layer.fieldNameIndex(building_type_field)
        for building in buildings_data:
            building_count += 1
            attrs = building.attributes()
            building_type = attrs[building_type_field_index]
            if building_type in [None,
                                 'NULL', 'null',
                                 'Null'
            ]:
                building_type = 'Unknown type'

            if not building_type in buildings_by_type:
                buildings_by_type[building_type] = {'flooded': 0, 'total': 0}
            buildings_by_type[building_type]['total'] += 1

            if attrs[target_field_index] == 1:
                flooded_count += 1
                buildings_by_type[building_type]['flooded'] += 1

        table_body = [question,
                      TableRow([tr('Building Type'),
                                tr('Flooded'),
                                tr('Total')],
                               header=True),
                      TableRow([tr('All'),
                                int(flooded_count),
                                int(building_count)])]
        table_body.append(TableRow(tr('Breakdown by building type'),
                                       header=True))
        for t, v in buildings_by_type.iteritems():
            table_body.append(
                TableRow([t, int(v['flooded']), int(v['total'])])
            )

        impact_summary = Table(table_body).toNewlineFreeString()
        map_title = tr('Buildings inundated')

        style_classes = [dict(label=tr('Not Inundated'), value=0,
                              colour='#1EFC7C', transparency=0, size=0.5),
                         dict(label=tr('Inundated'), value=1,
                              colour='#F31A1C', transparency=0, size=0.5)]
        style_info = dict(target_field=target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it.
        building_layer = Vector(data=building_layer,
                   name=tr('Flooded buildings'),
                   keywords={'impact_summary': impact_summary,
                             'map_title': map_title,
                             'target_field': target_field},
                   style_info=style_info)
        return building_layer
    def testDateTimeWriteShapefile(self):
        """Check writing date and time fields to an ESRI shapefile."""
        ml = QgsVectorLayer(
            ('Point?crs=epsg:4326&field=id:int&'
             'field=date_f:date&field=time_f:time&field=dt_f:datetime'),
            'test', 'memory')

        assert ml is not None, 'Provider not initialized'
        assert ml.isValid(), 'Source layer not valid'
        provider = ml.dataProvider()
        assert provider is not None

        ft = QgsFeature()
        ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
        ft.setAttributes([
            1,
            QDate(2014, 3, 5),
            QTime(13, 45, 22),
            QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))
        ])
        res, features = provider.addFeatures([ft])
        assert res
        assert len(features) > 0

        dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp')
        crs = QgsCoordinateReferenceSystem()
        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        write_result = QgsVectorFileWriter.writeAsVectorFormat(
            ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile')
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        # Open result and check
        created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name),
                                       u'test', u'ogr')

        fields = created_layer.dataProvider().fields()
        self.assertEqual(
            fields.at(fields.indexFromName('date_f')).type(), QVariant.Date)
        #shapefiles do not support time types, result should be string
        self.assertEqual(
            fields.at(fields.indexFromName('time_f')).type(), QVariant.String)
        #shapefiles do not support datetime types, result should be string
        self.assertEqual(
            fields.at(fields.indexFromName('dt_f')).type(), QVariant.String)

        f = created_layer.getFeatures(QgsFeatureRequest()).next()

        date_idx = created_layer.fieldNameIndex('date_f')
        assert isinstance(f.attributes()[date_idx], QDate)
        self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5))
        time_idx = created_layer.fieldNameIndex('time_f')
        #shapefiles do not support time types
        assert isinstance(f.attributes()[time_idx], basestring)
        self.assertEqual(f.attributes()[time_idx], '13:45:22')
        #shapefiles do not support datetime types
        datetime_idx = created_layer.fieldNameIndex('dt_f')
        assert isinstance(f.attributes()[datetime_idx], basestring)
        self.assertEqual(
            f.attributes()[datetime_idx],
            QDateTime(QDate(2014, 3, 5),
                      QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz"))
Example #33
0
    def start_progress(self):
        import datetime
        start = datetime.datetime.now()
        # Check OS and dep
        if sys.platform == 'darwin':
            gdal_os_dep = '/Library/Frameworks/GDAL.framework/Versions/Current/Programs/'
        else:
            gdal_os_dep = ''

        if self.dlg.canvasButton.isChecked():
            # Map Canvas
            extentCanvasCRS = self.iface.mapCanvas()
            srs = extentCanvasCRS.mapSettings().destinationCrs()
            crs = str(srs.authid())
            # old_crs = osr.SpatialReference()
            # old_crs.ImportFromEPSG(int(crs[5:]))
            can_crs = QgsCoordinateReferenceSystem(int(crs[5:]))
            # can_wkt = extentCanvasCRS.mapRenderer().destinationCrs().toWkt()
            # can_crs = osr.SpatialReference()
            # can_crs.ImportFromWkt(can_wkt)
            # Raster Layer
            dem_layer = self.layerComboManagerDEM.currentLayer()
            dem_prov = dem_layer.dataProvider()
            dem_path = str(dem_prov.dataSourceUri())
            dem_raster = gdal.Open(dem_path)
            projdsm = osr.SpatialReference(wkt=dem_raster.GetProjection())
            projdsm.AutoIdentifyEPSG()
            projdsmepsg = int(projdsm.GetAttrValue('AUTHORITY', 1))
            dem_crs = QgsCoordinateReferenceSystem(projdsmepsg)

            # dem_wkt = dem_raster.GetProjection()
            # dem_crs = osr.SpatialReference()
            # dem_crs.ImportFromWkt(dem_wkt)
            if can_crs != dem_crs:
                extentCanvas = self.iface.mapCanvas().extent()
                extentDEM = dem_layer.extent()

                transformExt = QgsCoordinateTransform(can_crs, dem_crs)
                # transformExt = osr.CoordinateTransformation(can_crs, dem_crs)

                canminx = extentCanvas.xMinimum()
                canmaxx = extentCanvas.xMaximum()
                canminy = extentCanvas.yMinimum()
                canmaxy = extentCanvas.yMaximum()

                canxymin = transformExt.TransformPoint(canminx, canminy)
                canxymax = transformExt.TransformPoint(canmaxx, canmaxy)

                extDiffminx = canxymin[0] - extentDEM.xMinimum(
                )  # If smaller than zero = warning
                extDiffminy = canxymin[1] - extentDEM.yMinimum(
                )  # If smaller than zero = warning
                extDiffmaxx = canxymax[0] - extentDEM.xMaximum(
                )  # If larger than zero = warning
                extDiffmaxy = canxymax[0] - extentDEM.yMaximum(
                )  # If larger than zero = warning

                if extDiffminx < 0 or extDiffminy < 0 or extDiffmaxx > 0 or extDiffmaxy > 0:
                    QMessageBox.warning(
                        None,
                        "Warning! Extent of map canvas is larger than raster extent.",
                        "Change to an extent equal to or smaller than the raster extent."
                    )
                    return

        # Extent
        self.yMax = self.dlg.lineEditNorth.text()
        self.yMin = self.dlg.lineEditSouth.text()
        self.xMin = self.dlg.lineEditWest.text()
        self.xMax = self.dlg.lineEditEast.text()

        if not self.DSMoutputfile:
            QMessageBox.critical(None, "Error", "Specify a raster output file")
            return

        if self.dlg.checkBoxPolygon.isChecked() and not self.OSMoutputfile:
            QMessageBox.critical(None, "Error",
                                 "Specify an output file for OSM data")
            return

        # Acquiring geodata and attributes
        dem_layer = self.layerComboManagerDEM.currentLayer()
        if dem_layer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid raster layer is selected")
            return
        else:
            provider = dem_layer.dataProvider()
            filepath_dem = str(provider.dataSourceUri())
        demRaster = gdal.Open(filepath_dem)
        dem_layer_crs = osr.SpatialReference()
        dem_layer_crs.ImportFromWkt(demRaster.GetProjection())
        self.dem_layer_unit = dem_layer_crs.GetAttrValue("UNIT")
        posUnits = [
            'metre', 'US survey foot', 'meter', 'm', 'ft', 'feet', 'foot',
            'ftUS', 'International foot'
        ]  # Possible units
        if not self.dem_layer_unit in posUnits:
            QMessageBox.critical(
                None, "Error",
                "Raster projection is not in metre or foot. Please reproject.")
            return

        polygon_layer = self.layerComboManagerPolygon.currentLayer()
        osm_layer = self.dlg.checkBoxOSM.isChecked()
        if polygon_layer is None and osm_layer is False:
            QMessageBox.critical(None, "Error",
                                 "No valid building height layer is selected")
            return
        elif polygon_layer:
            vlayer = QgsVectorLayer(polygon_layer.source(), "buildings", "ogr")
            fileInfo = QFileInfo(polygon_layer.source())
            polygon_ln = fileInfo.baseName()

            polygon_field = self.layerComboManagerPolygonField.currentField()
            idx = vlayer.fieldNameIndex(polygon_field)
            flname = vlayer.attributeDisplayName(idx)

            if idx == -1:
                QMessageBox.critical(
                    None, "Error",
                    "An attribute with unique fields must be selected")
                return

        ### main code ###

        self.dlg.progressBar.setRange(0, 5)

        self.dlg.progressBar.setValue(1)

        if self.dlg.checkBoxOSM.isChecked():
            # TODO replace osr.CoordinateTransformation with QgsCoordinateTransform
            dem_original = gdal.Open(filepath_dem)
            dem_wkt = dem_original.GetProjection()
            ras_crs = osr.SpatialReference()
            ras_crs.ImportFromWkt(dem_wkt)
            rasEPSG = ras_crs.GetAttrValue("PROJCS|AUTHORITY", 1)
            if self.dlg.layerButton.isChecked():
                old_crs = ras_crs
            elif self.dlg.canvasButton.isChecked():
                canvasCRS = self.iface.mapCanvas()
                outputWkt = canvasCRS.mapRenderer().destinationCrs().toWkt()
                old_crs = osr.SpatialReference()
                old_crs.ImportFromWkt(outputWkt)

            wgs84_wkt = """
            GEOGCS["WGS 84",
                DATUM["WGS_1984",
                    SPHEROID["WGS 84",6378137,298.257223563,
                        AUTHORITY["EPSG","7030"]],
                    AUTHORITY["EPSG","6326"]],
                PRIMEM["Greenwich",0,
                    AUTHORITY["EPSG","8901"]],
                UNIT["degree",0.01745329251994328,
                    AUTHORITY["EPSG","9122"]],
                AUTHORITY["EPSG","4326"]]"""

            new_crs = osr.SpatialReference()
            new_crs.ImportFromWkt(wgs84_wkt)

            transform = osr.CoordinateTransformation(old_crs, new_crs)

            minx = float(self.xMin)
            miny = float(self.yMin)
            maxx = float(self.xMax)
            maxy = float(self.yMax)
            lonlatmin = transform.TransformPoint(minx, miny)
            lonlatmax = transform.TransformPoint(maxx, maxy)

            if ras_crs != old_crs:
                rasTrans = osr.CoordinateTransformation(old_crs, ras_crs)
                raslonlatmin = rasTrans.TransformPoint(float(self.xMin),
                                                       float(self.yMin))
                raslonlatmax = rasTrans.TransformPoint(float(self.xMax),
                                                       float(self.yMax))
                #else:
                #raslonlatmin = [float(self.xMin), float(self.yMin)]
                #raslonlatmax = [float(self.xMax), float(self.yMax)]

                self.xMin = raslonlatmin[0]
                self.yMin = raslonlatmin[1]
                self.xMax = raslonlatmax[0]
                self.yMax = raslonlatmax[1]

            # Make data queries to overpass-api
            urlStr = 'http://overpass-api.de/api/map?bbox=' + str(
                lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str(
                    lonlatmax[0]) + ',' + str(lonlatmax[1])
            osmXml = urllib.urlopen(urlStr).read()
            #print urlStr

            # Make OSM building file
            osmPath = self.plugin_dir + '/temp/OSM_building.osm'
            osmFile = open(osmPath, 'w')
            osmFile.write(osmXml)
            if os.fstat(osmFile.fileno()).st_size < 1:
                urlStr = 'http://api.openstreetmap.org/api/0.6/map?bbox=' + str(
                    lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str(
                        lonlatmax[0]) + ',' + str(lonlatmax[1])
                osmXml = urllib.urlopen(urlStr).read()
                osmFile.write(osmXml)
                #print 'Open Street Map'
                if os.fstat(osmFile.fileno()).st_size < 1:
                    QMessageBox.critical(None, "Error",
                                         "No OSM data available")
                    return

            osmFile.close()

            outputshp = self.plugin_dir + '/temp/'

            osmToShape = gdal_os_dep + 'ogr2ogr --config OSM_CONFIG_FILE "' + self.plugin_dir + '/osmconf.ini" -skipfailures -t_srs EPSG:' + str(
                rasEPSG
            ) + ' -overwrite -nlt POLYGON -f "ESRI Shapefile" "' + outputshp + '" "' + osmPath + '"'

            if sys.platform == 'win32':
                si = subprocess.STARTUPINFO()
                si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                subprocess.call(osmToShape, startupinfo=si)
            else:
                os.system(osmToShape)

            driver = ogr.GetDriverByName('ESRI Shapefile')
            driver.DeleteDataSource(outputshp + 'lines.shp')
            driver.DeleteDataSource(outputshp + 'multilinestrings.shp')
            driver.DeleteDataSource(outputshp + 'other_relations.shp')
            driver.DeleteDataSource(outputshp + 'points.shp')

            osmPolygonPath = outputshp + 'multipolygons.shp'
            vlayer = QgsVectorLayer(osmPolygonPath, 'multipolygons', 'ogr')
            polygon_layer = vlayer
            fileInfo = QFileInfo(polygon_layer.source())
            polygon_ln = fileInfo.baseName()

            def renameField(srcLayer, oldFieldName, newFieldName):
                ds = gdal.OpenEx(srcLayer.source(),
                                 gdal.OF_VECTOR | gdal.OF_UPDATE)
                ds.ExecuteSQL('ALTER TABLE {} RENAME COLUMN {} TO {}'.format(
                    srcLayer.name(), oldFieldName, newFieldName))
                srcLayer.reload()

            vlayer.startEditing()
            renameField(vlayer, 'building_l', 'bld_levels')
            renameField(vlayer, 'building_h', 'bld_hght')
            renameField(vlayer, 'building_c', 'bld_colour')
            renameField(vlayer, 'building_m', 'bld_materi')
            renameField(vlayer, 'building_u', 'bld_use')
            vlayer.commitChanges()

            vlayer.startEditing()
            vlayer.dataProvider().addAttributes(
                [QgsField('bld_height', QVariant.Double, 'double', 3, 2)])
            vlayer.updateFields()
            bld_lvl = vlayer.fieldNameIndex('bld_levels')
            hght = vlayer.fieldNameIndex('height')
            bld_hght = vlayer.fieldNameIndex('bld_hght')
            bld_height = vlayer.fieldNameIndex('bld_height')

            bldLvlHght = float(self.dlg.doubleSpinBoxBldLvl.value())
            illegal_chars = string.ascii_letters + "!#$%&'*+^_`|~:" + " "
            counterNone = 0
            counter = 0
            #counterWeird = 0
            for feature in vlayer.getFeatures():
                if feature[hght]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[hght])))
                        feature[bld_height] = float(
                            str(feature[hght]).translate(None, illegal_chars))
                    except:
                        counterNone += 1
                elif feature[bld_hght]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[bld_hght])))
                        feature[bld_height] = float(
                            str(feature[bld_hght]).translate(
                                None, illegal_chars))
                    except:
                        counterNone += 1
                elif feature[bld_lvl]:
                    try:
                        #feature[bld_height] = float(re.sub("[^0-9]", "", str(feature[bld_lvl])))*bldLvlHght
                        feature[bld_height] = float(
                            str(feature[bld_lvl]).translate(
                                None, illegal_chars)) * bldLvlHght
                    except:
                        counterNone += 1
                else:
                    counterNone += 1
                vlayer.updateFeature(feature)
                counter += 1
            vlayer.commitChanges()
            flname = vlayer.attributeDisplayName(bld_height)
            counterDiff = counter - counterNone

        # Zonal statistics
        vlayer.startEditing()
        zoneStat = QgsZonalStatistics(vlayer, filepath_dem, "stat_", 1,
                                      QgsZonalStatistics.Mean)
        zoneStat.calculateStatistics(None)
        vlayer.dataProvider().addAttributes(
            [QgsField('height_asl', QVariant.Double)])
        vlayer.updateFields()
        e = QgsExpression('stat_mean + ' + flname)
        e.prepare(vlayer.pendingFields())
        idx = vlayer.fieldNameIndex('height_asl')

        for f in vlayer.getFeatures():
            f[idx] = e.evaluate(f)
            vlayer.updateFeature(f)

        vlayer.commitChanges()

        vlayer.startEditing()
        idx2 = vlayer.fieldNameIndex('stat_mean')
        vlayer.dataProvider().deleteAttributes([idx2])
        vlayer.updateFields()
        vlayer.commitChanges()

        self.dlg.progressBar.setValue(2)

        # Convert polygon layer to raster

        # Define pixel_size and NoData value of new raster
        pixel_size = self.dlg.spinBox.value()  # half picture size

        # Create the destination data source

        gdalrasterize = gdal_os_dep + 'gdal_rasterize -a ' + 'height_asl' + ' -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\
                        ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + ' -l "' + str(polygon_ln) + '" "' \
                         + str(polygon_layer.source()) + '" "' + self.plugin_dir + '/temp/clipdsm.tif"'

        # gdalclipdem = gdal_os_dep + 'gdalwarp -dstnodata -9999 -q -overwrite -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\
        #               ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + \
        #               ' -of GTiff ' + '"' + filepath_dem + '" "' + self.plugin_dir + '/temp/clipdem.tif"'

        # Rasterize
        if sys.platform == 'win32':
            si = subprocess.STARTUPINFO()
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            subprocess.call(gdalrasterize, startupinfo=si)
            # subprocess.call(gdalclipdem, startupinfo=si)
            gdal.Warp(self.plugin_dir + '/temp/clipdem.tif',
                      filepath_dem,
                      xRes=pixel_size,
                      yRes=pixel_size)
        else:
            os.system(gdalrasterize)
            # os.system(gdalclipdem)
            gdal.Warp(self.plugin_dir + '/temp/clipdem.tif',
                      filepath_dem,
                      xRes=pixel_size,
                      yRes=pixel_size)

        # Remove gdalwarp with gdal.Translate
        # bigraster = gdal.Open(filepath_dem)
        # bbox = (self.xMin, self.yMax, self.xMax, self.yMin)
        # gdal.Translate(self.plugin_dir + '/data/clipdem.tif', bigraster, projWin=bbox)

        self.dlg.progressBar.setValue(3)

        # Adding DSM to DEM
        # Read DEM
        dem_raster = gdal.Open(self.plugin_dir + '/temp/clipdem.tif')
        dem_array = np.array(dem_raster.ReadAsArray().astype(np.float))
        dsm_raster = gdal.Open(self.plugin_dir + '/temp/clipdsm.tif')
        dsm_array = np.array(dsm_raster.ReadAsArray().astype(np.float))

        indx = dsm_array.shape
        for ix in range(0, int(indx[0])):
            for iy in range(0, int(indx[1])):
                if int(dsm_array[ix, iy]) == 0:
                    dsm_array[ix, iy] = dem_array[ix, iy]

        if self.dlg.checkBoxPolygon.isChecked():
            vlayer.startEditing()
            idxHght = vlayer.fieldNameIndex('height_asl')
            idxBld = vlayer.fieldNameIndex('building')
            features = vlayer.getFeatures()
            #for f in vlayer.getFeatures():
            for f in features:
                geom = f.geometry()
                posUnitsMetre = ['metre', 'meter', 'm']  # Possible metre units
                posUnitsFt = [
                    'US survey foot', 'ft', 'feet', 'foot', 'ftUS',
                    'International foot'
                ]  # Possible foot units
                if self.dem_layer_unit in posUnitsMetre:
                    sqUnit = 1
                elif self.dem_layer_unit in posUnitsFt:
                    sqUnit = 10.76
                if int(geom.area()) > 50000 * sqUnit:
                    vlayer.deleteFeature(f.id())

                #if not f[idxHght]:
                #vlayer.deleteFeature(f.id())
                #elif not f[idxBld]:
                #vlayer.deleteFeature(f.id())
            vlayer.updateFields()
            vlayer.commitChanges()
            QgsVectorFileWriter.writeAsVectorFormat(vlayer,
                                                    str(self.OSMoutputfile),
                                                    "UTF-8", None,
                                                    "ESRI Shapefile")

        else:
            vlayer.startEditing()
            idx3 = vlayer.fieldNameIndex('height_asl')
            vlayer.dataProvider().deleteAttributes([idx3])
            vlayer.updateFields()
            vlayer.commitChanges()

        self.dlg.progressBar.setValue(4)

        # Save raster
        def saveraster(
            gdal_data, filename, raster
        ):  # gdal_data = raster extent, filename = output filename, raster = numpy array (raster to be saved)
            rows = gdal_data.RasterYSize
            cols = gdal_data.RasterXSize

            outDs = gdal.GetDriverByName("GTiff").Create(
                filename, cols, rows, int(1), gdal.GDT_Float32)
            outBand = outDs.GetRasterBand(1)

            # write the data
            outBand.WriteArray(raster, 0, 0)
            # flush data to disk, set the NoData value and calculate stats
            outBand.FlushCache()
            outBand.SetNoDataValue(-9999)

            # georeference the image and set the projection
            outDs.SetGeoTransform(gdal_data.GetGeoTransform())
            outDs.SetProjection(gdal_data.GetProjection())

        saveraster(dsm_raster, self.DSMoutputfile, dsm_array)

        # Load result into canvas
        rlayer = self.iface.addRasterLayer(self.DSMoutputfile)

        # Trigger a repaint
        if hasattr(rlayer, "setCacheImage"):
            rlayer.setCacheImage(None)
        rlayer.triggerRepaint()

        self.dlg.progressBar.setValue(5)

        #runTime = datetime.datetime.now() - start

        if self.dlg.checkBoxOSM.isChecked():
            QMessageBox.information(
                self.dlg, 'DSM Generator', 'Operation successful! ' +
                str(counterDiff) + ' building polygons out of ' +
                str(counter) + ' contained height values.')
            #self.iface.messageBar().pushMessage("DSM Generator. Operation successful! " + str(counterDiff) + " buildings out of " + str(counter) + " contained height values.", level=QgsMessageBar.INFO, duration=5)
        else:
            #self.iface.messageBar().pushMessage("DSM Generator. Operation successful!", level=QgsMessageBar.INFO, duration=5)
            QMessageBox.information(self.dlg, 'DSM Generator',
                                    'Operation successful!')

        self.resetPlugin()
Example #34
0
class SelectTrees(QObject):
    """QGIS Plugin Implementation."""

    #connectionEstablished = pyqtSignal()

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        super(SelectTrees, self).__init__()
        
        # Save reference to the QGIS interface
        self.iface = iface
        
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        self.pluginName = os.path.basename(self.plugin_dir)
        
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        self.locale_path = os.path.join(self.plugin_dir, 'i18n', 'SelectTrees_{}.qm'.format(locale))
        if os.path.exists(self.locale_path):
            self.translator = QTranslator()
            self.translator.load(self.locale_path)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        
        # load local settings of the plugin
        settingFile = os.path.join(self.plugin_dir, 'config', 'SelectTrees.config')
        self.settings = QSettings(settingFile, QSettings.IniFormat)
        #self.settings.setIniCodec(sys.stdout.encoding)
        
        # load plugin settings
        self.loadPluginSettings()
        
        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&SelectTrees')
        self.annotations = []
        self.mem_layer = None          
        self.layer = None  
        self.initialize = False
        
        # establish connection when all is completely running 
        self.iface.initializationCompleted.connect(self.populateGui)

    
    def loadPluginSettings(self):
        ''' Load plugin settings
        '''       
        # Get main credentials
        self.TOTAL = 6
        self.SECTION = "main/"
        
        # Get layer name
        self.layer_name = self.settings.value(self.SECTION+'LAYER_NAME', 'Arbres')
        self.mem_layer_name = self.settings.value(self.SECTION+'MEM_LAYER_NAME', 'Arbres seleccionats')
        
        # Get field alias
        self.field_alias = []
        for i in range(0, self.TOTAL):
            cur_value = self.settings.value(self.SECTION+'FIELD_ALIAS_'+str(i), '')
            self.field_alias.append(cur_value)
         
        # Get field names
        self.field_name = []
        for i in range(0, self.TOTAL):
            cur_value = self.settings.value(self.SECTION+'FIELD_NAME_'+str(i), '')
            self.field_name.append(cur_value)
        
        # Get default zoom scale
        self.minZoomScale = int(self.settings.value('status/minZoomScale', 500))
        
        # Get path to QML file
        self.path_qml = self.settings.value(self.SECTION+'PATH_QML', 'styles/arbres.qml') 
        self.path_qml = self.plugin_dir+"/"+self.path_qml
        if not os.path.exists(self.path_qml):
            QgsMessageLog.logMessage(u"QML file not found at: "+self.path_qml, "selectTrees", QgsMessageLog.WARNING)            
        
    
    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('SelectTrees', message)


    def add_action(self, icon_path, text, callback, parent, shortcut=None,
        enabled_flag=True, add_to_menu=True, add_to_toolbar=False, status_tip=None, whats_this=None):

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        
        if shortcut is not None:
            self.iface.registerMainWindowAction(action, shortcut)         

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)
        else:
            self.iface.addToolBarIcon(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)

        return action
        
    
    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/SelectTrees/icon_selecttrees.png'
        self.add_action(icon_path, self.tr(u'Selecció arbres'), self.run, self.iface.mainWindow(), "F8")       

        # Create the dock widget and dock it but hide it waiting the end of qgis loading
        self.dlg = SelectTreesDockWidget(self.iface.mainWindow())
        self.iface.mainWindow().addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        self.dlg.setVisible(False)
        
        # Set signals
        self.dlg.findChild(QPushButton, "btnReset").clicked.connect(self.reset)
        btnZoom = self.dlg.findChild(QPushButton, "btnZoom")
        if btnZoom:
            btnZoom.clicked.connect(self.zoom)        
        for i in range(0, self.TOTAL):       
            combo = self.dlg.findChild(QComboBox, "cboField"+str(i))     
            combo.currentIndexChanged.connect(self.performSelect)                   
    
    
    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&SelectTrees'), action)
            self.iface.removeToolBarIcon(action)
        
        if self.dlg:
            self.dlg.deleteLater()
            del self.dlg
   
    
    def checkLayer(self):
    
        if self.layer is not None:
            return self.iface.setActiveLayer(self.layer)
           
        # Iterate over all layers to get the one set in config file
        layers = self.iface.mapCanvas().layers()
        for cur_layer in layers:
            if cur_layer.name() == self.layer_name:
                self.layer = cur_layer
                self.feature_count = self.layer.featureCount()           
                return self.iface.setActiveLayer(self.layer)
            if cur_layer.name() == self.mem_layer_name:
                self.mem_layer = cur_layer
        
        return False
            

    def populateGui(self):
        ''' Populate the interface with values get from active layer
        '''           
        #QgsMessageLog.logMessage(u"populateGui: init", "selectTrees", QgsMessageLog.INFO)
        
        # Check if layer exists
        if not self.checkLayer():
            QgsMessageLog.logMessage(u"populateGui: Error getting layer of trees", "selectTrees", QgsMessageLog.INFO)
            self.iface.mainWindow().removeDockWidget(self.dlg)          
            return 
            
        # Get counter label
        self.lblCountSelect = self.dlg.findChild(QLabel, "lblCountSelect")  
                
        # Load field labels
        for i in range(0, self.TOTAL):             
            label = self.dlg.findChild(QLabel, "lblField"+str(i))       
            label.setText(self.field_alias[i])
                    
        # Load field combos
        for i in range(0, self.TOTAL):       
            values = set()
            field_name = self.field_name[i]
            for feature in self.layer.getFeatures():
                if type(feature[field_name]) is not QPyNullVariant:
                    values.add(feature[field_name])
            combo = self.dlg.findChild(QComboBox, "cboField"+str(i))
            combo.blockSignals(True)
            combo.clear()
            combo.addItem('')            
            for elem in sorted(values):    
                if type(elem) is int or type(elem) is long:
                    elem = str(elem)
                combo.addItem(elem)
            combo.blockSignals(False)      

        # Update counter
        self.updateCounter()
        
        self.initialize = True   
        

    def updateCounter(self):
        
        msg = "Seleccionats "+str(self.layer.selectedFeatureCount())+" de "+str(self.feature_count)+" arbres"    
        self.lblCountSelect.setText(msg)        
          
    
    def run(self):
        """Run method activated by the toolbar action button"""      
        
        if not self.initialize:
            self.populateGui()
        else:  
            # Get layer set in config file
            if not self.checkLayer():
                self.dlg.setVisible(False)
                return                 
        
        if self.dlg and not self.dlg.isVisible():  
            # check if the plugin is active
            if not self.pluginName in active_plugins:
                pass
               
        # Not working: Try to set plugin to left dock widget area by default               
        self.iface.mainWindow().addDockWidget(Qt.LeftDockWidgetArea, self.dlg)                
        self.dlg.show() 
        
        
    def deleteFeatures(self, layer):
    
        if layer is not None:
            it = layer.getFeatures()
            ids = [i.id() for i in it]
            layer.dataProvider().deleteFeatures(ids)    
    
    
    # Copy from Arbres to memory layer
    def copySelected(self):
    
        # Create memory layer if not already set
        if self.mem_layer is None:       
            uri = "Point?crs=epsg:25831"        
            self.mem_layer = QgsVectorLayer(uri, self.mem_layer_name, "memory")          
            self.mem_layer.loadNamedStyle(self.path_qml)            
 
            # Copy attributes from main layer to memory layer
            attrib_names = self.layer.dataProvider().fields()
            names_list = attrib_names.toList()
            newattributeList=[]
            for attrib in names_list:
                aux = self.mem_layer.fieldNameIndex(attrib.name())
                if aux == -1:
                    newattributeList.append(QgsField(attrib.name(), attrib.type()))
            self.mem_layer.dataProvider().addAttributes(newattributeList)
            self.mem_layer.updateFields()
            QgsMapLayerRegistry.instance().addMapLayer(self.mem_layer)                

        # Prepare memoory layer for editing
        self.mem_layer.startEditing()

        # Delete previous features
        self.deleteFeatures(self.mem_layer)
        
        # Iterate over selected features
        cfeatures = []
        for sel_feature in self.layer.selectedFeatures():
            attributes = []
            attributes.extend(sel_feature.attributes())
            cfeature = QgsFeature()    
            cfeature.setGeometry(sel_feature.geometry())
            cfeature.setAttributes(attributes)
            cfeatures.append(cfeature)
                     
        # Add features, commit changes and refresh canvas
        self.mem_layer.dataProvider().addFeatures(cfeatures)             
        self.mem_layer.commitChanges()
        self.iface.mapCanvas().refresh()        

        
    # Signals
    def performSelect(self):

        # Get values from every combo
        expr_list = []
        for i in range(0, self.TOTAL):   
            combo = self.dlg.findChild(QComboBox, "cboField"+str(i))  
            value = combo.currentText()
            if value != '':
                field_name = self.field_name[i]
                value = value.replace("'", "\\'")
                aux = field_name+" = '"+value+"'"       
                expr_list.append(aux)
    
        # Build new expression
        aux = ''
        for i in range(len(expr_list)):
            if aux != '':
                aux+= ' and '
            aux+= expr_list[i]
        expr = QgsExpression(aux)
        if expr.hasParserError():
            QgsMessageLog.logMessage(expr.parserErrorString() + ": " + aux, "selectTrees", QgsMessageLog.INFO)  
            return      
        
        # Get a featureIterator from an expression
        # Build a list of feature Ids from the previous result       
        # Select features with the ids obtained
        it = self.layer.getFeatures(QgsFeatureRequest(expr))
        ids = [i.id() for i in it]
        self.layer.setSelectedFeatures(ids)
        
        # Update counter
        self.updateCounter()
        
        # Copy selected features to memory layer
        self.copySelected()
    
    
    def reset(self):
    
        # Reset combos, remove selection and update counter
        for i in range(0, self.TOTAL):   
            combo = self.dlg.findChild(QComboBox, "cboField"+str(i))  
            combo.blockSignals(True)                
            combo.setCurrentIndex(0)
            combo.blockSignals(False)                
        self.layer.removeSelection()
        self.deleteFeatures(self.mem_layer)    
        self.updateCounter()        
        self.iface.mapCanvas().refresh()

    
    def zoom(self):
  
        if self.checkLayer():
            action = self.iface.actionZoomToSelected()
            action.trigger()
            if self.iface.mapCanvas().scale() < self.minZoomScale:
                self.iface.mapCanvas().zoomScale(self.minZoomScale)
Example #35
0
    def save_hazard_data(self):
        hazard_geojson = PetaJakartaAPI.get_aggregate_report(
            self.duration, self.level)

        if not hazard_geojson:
            raise PetaJakartaAPIError("Can't access PetaJakarta REST API")

        with open(self.hazard_path, 'w+') as f:
            f.write(hazard_geojson)

        # Save the layer as shp
        file_info = QFileInfo(self.hazard_path)
        hazard_layer = QgsVectorLayer(self.hazard_path, file_info.baseName(),
                                      'ogr', False)

        target_name = 'flood_data.shp'
        self.hazard_path = os.path.join(self.report_path, target_name)
        QgsVectorFileWriter.writeAsVectorFormat(hazard_layer, self.hazard_path,
                                                'CP1250', None,
                                                'ESRI Shapefile')

        file_info = QFileInfo(self.hazard_path)
        hazard_layer = QgsVectorLayer(self.hazard_path, file_info.baseName(),
                                      'ogr')

        hazard_layer.startEditing()
        field = QgsField('flooded', QVariant.Int)
        hazard_layer.dataProvider().addAttributes([field])
        hazard_layer.commitChanges()
        idx = hazard_layer.fieldNameIndex('flooded')
        expression = QgsExpression('count > 0')
        expression.prepare(hazard_layer.pendingFields())

        hazard_layer.startEditing()
        for feature in hazard_layer.getFeatures():
            feature[idx] = expression.evaluate(feature)
            hazard_layer.updateFeature(feature)

        hazard_layer.commitChanges()

        # writing keywords
        keyword_io = KeywordIO()

        keywords = {
            'field': 'flooded',
            'hazard': 'flood',
            'hazard_category': 'single_event',
            'keyword_version': '3.3',
            'layer_geometry': 'polygon',
            'layer_mode': 'classified',
            'layer_purpose': 'hazard',
            'title': 'Flood',
            'value_map': '{"wet": [1], "dry": [0]}',
            'vector_hazard_classification': 'flood_vector_hazard_classes'
        }

        keyword_io.write_keywords(hazard_layer, keywords)

        # archiving hazard layer
        with ZipFile(self.hazard_zip_path, 'w') as zf:
            for root, dirs, files in os.walk(self.report_path):
                for f in files:
                    _, ext = os.path.splitext(f)
                    if 'flood_data' in f:
                        filename = os.path.join(root, f)
                        zf.write(filename, arcname=f)
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """
        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value

        target_field = self.target_field
        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')
        exposure_value_mapping = self.exposure.keyword('value_mapping')

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Clip hazard raster
        small_raster = align_clip_raster(self.hazard.layer, viewport_extent)

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        ranges = ranges_according_thresholds(low_max, medium_max, high_max)

        index, flood_cells_map = _raster_to_vector_cells(
            small_raster,
            ranges,
            self.exposure.layer.crs())

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(
            line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(
            self.exposure.layer,
            request,
            index,
            flood_cells_map,
            line_layer,
            target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(
            self.exposure.layer.crs(), output_crs)

        # Roads breakdown
        self.init_report_var(self.hazard_classes)

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)

        for road in roads_data:
            attributes = road.attributes()

            affected = attributes[target_field_index]
            if isinstance(affected, QPyNullVariant):
                continue
            else:
                hazard_zone = self.hazard_classes[affected]

            usage = attributes[road_type_field_index]
            usage = main_type(usage, exposure_value_mapping)

            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            affected = False
            num_classes = len(self.hazard_classes)
            if attributes[target_field_index] in range(num_classes):
                affected = True
            self.classify_feature(hazard_zone, usage, length, affected)

        self.reorder_dictionaries()

        style_classes = [
            # FIXME 0 - 0.1
            dict(
                label=self.hazard_classes[0] + ': 0m',
                value=0,
                colour='#00FF00',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[1] + ': >0 - %.1f m' % low_max,
                value=1,
                colour='#FFFF00',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f m' % (
                    low_max + 0.1, medium_max),
                value=2,
                colour='#FFB700',
                transparency=0,
                size=1
            ),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f m' % (
                    medium_max + 0.1, high_max),
                value=3,
                colour='#FF6F00',
                transparency=0,
                size=1
            ),

            dict(
                label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                value=4,
                colour='#FF0000',
                transparency=0,
                size=1
            ),
        ]
        style_info = dict(
            target_field=target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        impact_data = self.generate_data()

        extra_keywords = {
            'map_title': self.metadata().key('map_title'),
            'legend_title': self.metadata().key('legend_title'),
            'target_field': target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        impact_layer = Vector(
            data=line_layer,
            name=self.metadata().key('layer_name'),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
    def run(self, layers):
        """Experimental impact function.

        Input
          layers: List of layers expected to contain
              H: Polygon layer of inundation areas
              E: Vector layer of roads
        """
        target_field = self.parameters['target_field']
        building_type_field = self.parameters['building_type_field']
        affected_field = self.parameters['affected_field']
        affected_value = self.parameters['affected_value']

        # Extract data
        H = get_hazard_layer(layers)  # Flood
        E = get_exposure_layer(layers)  # Roads

        question = get_question(H.get_name(), E.get_name(), self)

        H = H.get_layer()
        h_provider = H.dataProvider()
        affected_field_index = h_provider.fieldNameIndex(affected_field)
        if affected_field_index == -1:
            message = tr('''Parameter "Affected Field"(='%s')
                is not present in the
                attribute table of the hazard layer.''' % (affected_field, ))
            raise GetDataError(message)

        E = E.get_layer()
        srs = E.crs().toWkt()
        e_provider = E.dataProvider()
        fields = e_provider.fields()
        # If target_field does not exist, add it:
        if fields.indexFromName(target_field) == -1:
            e_provider.addAttributes([QgsField(target_field, QVariant.Int)])
        target_field_index = e_provider.fieldNameIndex(target_field)
        fields = e_provider.fields()

        # Create layer for store the lines from E and extent
        building_layer = QgsVectorLayer('Polygon?crs=' + srs,
                                        'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the extent
        extent = QgsRectangle(*self.extent)
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        affected_field_type = h_provider.fields(
        )[affected_field_index].typeName()
        if affected_field_type in ['Real', 'Integer']:
            affected_value = float(affected_value)

        h_data = H.getFeatures(request)
        hazard_poly = None
        for mpolygon in h_data:
            attributes = mpolygon.attributes()
            if attributes[affected_field_index] != affected_value:
                continue
            if hazard_poly is None:
                hazard_poly = QgsGeometry(mpolygon.geometry())
            else:
                # Make geometry union of inundated polygons

                # But some mpolygon.geometry() could be invalid, skip them
                tmp_geometry = hazard_poly.combine(mpolygon.geometry())
                try:
                    if tmp_geometry.isGeosValid():
                        hazard_poly = tmp_geometry
                except AttributeError:
                    pass

        if hazard_poly is None:
            message = tr(
                '''There are no objects in the hazard layer with "Affected
                value"='%s'. Please check the value or use other extent.''' %
                (affected_value, ))
            raise GetDataError(message)

        e_data = E.getFeatures(request)
        for feat in e_data:
            building_geom = feat.geometry()
            attributes = feat.attributes()
            l_feat = QgsFeature()
            l_feat.setGeometry(building_geom)
            l_feat.setAttributes(attributes)
            if hazard_poly.intersects(building_geom):
                l_feat.setAttribute(target_field_index, 1)
            else:

                l_feat.setAttribute(target_field_index, 0)
            (_, __) = building_layer.dataProvider().addFeatures([l_feat])
        building_layer.updateExtents()

        # Generate simple impact report

        building_count = flooded_count = 0  # Count of buildings
        buildings_by_type = dict()  # Length of flooded roads by types

        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(
            building_type_field)
        for building in buildings_data:
            building_count += 1
            attributes = building.attributes()
            building_type = attributes[building_type_field_index]
            if building_type in [None, 'NULL', 'null', 'Null']:
                building_type = 'Unknown type'
            if building_type not in buildings_by_type:
                buildings_by_type[building_type] = {'flooded': 0, 'total': 0}
            buildings_by_type[building_type]['total'] += 1

            if attributes[target_field_index] == 1:
                flooded_count += 1
                buildings_by_type[building_type]['flooded'] += 1

        table_body = [
            question,
            TableRow([tr('Building Type'),
                      tr('Flooded'),
                      tr('Total')],
                     header=True),
            TableRow([tr('All'),
                      int(flooded_count),
                      int(building_count)]),
            TableRow(tr('Breakdown by building type'), header=True)
        ]
        for t, v in buildings_by_type.iteritems():
            table_body.append(TableRow([t,
                                        int(v['flooded']),
                                        int(v['total'])]))

        impact_summary = Table(table_body).toNewlineFreeString()
        map_title = tr('Buildings inundated')

        style_classes = [
            dict(label=tr('Not Inundated'),
                 value=0,
                 colour='#1EFC7C',
                 transparency=0,
                 size=0.5),
            dict(label=tr('Inundated'),
                 value=1,
                 colour='#F31A1C',
                 transparency=0,
                 size=0.5)
        ]
        style_info = dict(target_field=target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it.
        building_layer = Vector(data=building_layer,
                                name=tr('Flooded buildings'),
                                keywords={
                                    'impact_summary': impact_summary,
                                    'map_title': map_title,
                                    'target_field': target_field
                                },
                                style_info=style_info)
        return building_layer
Example #38
0
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """

        target_field = self.target_field

        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')
        exposure_value_mapping = self.exposure.keyword('value_mapping')

        # Get parameters from IF parameter
        threshold_min = self.parameters['min threshold'].value
        threshold_max = self.parameters['max threshold'].value

        if threshold_min > threshold_max:
            message = tr(
                'The minimal threshold is greater than the maximal specified '
                'threshold. Please check the values.')
            raise GetDataError(message)

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Clip hazard raster
        small_raster = align_clip_raster(self.hazard.layer, viewport_extent)

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(
            line_layer_tmp, filename, "utf-8", None, "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        index, flood_cells_map = _raster_to_vector_cells(
            small_raster,
            threshold_min,
            threshold_max,
            self.exposure.layer.crs())

        if len(flood_cells_map) == 0:
            message = tr(
                'There are no objects in the hazard layer with "value" > %s. '
                'Please check the value or use other extent.' % (
                    threshold_min, ))
            raise GetDataError(message)

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(
            self.exposure.layer,
            request,
            index,
            flood_cells_map,
            line_layer,
            target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(
            self.exposure.layer.crs(), output_crs)

        classes = [tr('Flooded in the threshold (m)')]
        self.init_report_var(classes)

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)

        for road in roads_data:
            attributes = road.attributes()

            usage = attributes[road_type_field_index]
            usage = main_type(usage, exposure_value_mapping)

            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            affected = False
            if attributes[target_field_index] == 1:
                affected = True

            self.classify_feature(classes[0], usage, length, affected)

        self.reorder_dictionaries()

        style_classes = [
            dict(
                label=tr('Not Inundated'), value=0,
                colour='#1EFC7C', transparency=0, size=0.5),
            dict(
                label=tr('Inundated'), value=1,
                colour='#F31A1C', transparency=0, size=0.5)]
        style_info = dict(
            target_field=target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        impact_data = self.generate_data()

        extra_keywords = {
            'map_title': self.map_title(),
            'legend_title': self.metadata().key('legend_title'),
            'target_field': target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        impact_layer = Vector(
            data=line_layer,
            name=self.map_title(),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
Example #39
0
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """
        self.validate()
        self.prepare()

        self.provenance.append_step(
            'Calculating Step', 'Impact function is calculating the impact.')

        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value

        target_field = self.target_field
        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Align raster extent and viewport
        # assuming they are both in the same projection
        raster_extent = self.hazard.layer.dataProvider().extent()
        clip_xmin = raster_extent.xMinimum()
        # clip_xmax = raster_extent.xMaximum()
        clip_ymin = raster_extent.yMinimum()
        # clip_ymax = raster_extent.yMaximum()
        if viewport_extent[0] > clip_xmin:
            clip_xmin = viewport_extent[0]
        if viewport_extent[1] > clip_ymin:
            clip_ymin = viewport_extent[1]

        height = ((viewport_extent[3] - viewport_extent[1]) /
                  self.hazard.layer.rasterUnitsPerPixelY())
        height = int(height)
        width = ((viewport_extent[2] - viewport_extent[0]) /
                 self.hazard.layer.rasterUnitsPerPixelX())
        width = int(width)

        raster_extent = self.hazard.layer.dataProvider().extent()
        xmin = raster_extent.xMinimum()
        xmax = raster_extent.xMaximum()
        ymin = raster_extent.yMinimum()
        ymax = raster_extent.yMaximum()

        x_delta = (xmax - xmin) / self.hazard.layer.width()
        x = xmin
        for i in range(self.hazard.layer.width()):
            if abs(x - clip_xmin) < x_delta:
                # We have found the aligned raster boundary
                break
            x += x_delta
            _ = i

        y_delta = (ymax - ymin) / self.hazard.layer.height()
        y = ymin
        for i in range(self.hazard.layer.width()):
            if abs(y - clip_ymin) < y_delta:
                # We have found the aligned raster boundary
                break
            y += y_delta
        clip_extent = [x, y, x + width * x_delta, y + height * y_delta]

        # Clip hazard raster
        small_raster = clip_raster(self.hazard.layer, width, height,
                                   QgsRectangle(*clip_extent))

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        ranges = OrderedDict()
        ranges[0] = [0.0, 0.0]
        ranges[1] = [0.0, low_max]
        ranges[2] = [low_max, medium_max]
        ranges[3] = [medium_max, high_max]
        ranges[4] = [high_max, None]

        index, flood_cells_map = _raster_to_vector_cells(
            small_raster, ranges, self.exposure.layer.crs())

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4326"),
                                    self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)
        """
        if len(low_max_flood_cells_map) == 0 and \
            len(medium_max_flood_cells_map) == 0 and \
            len(high_max_flood_cells_map) == 0 and \
            len(high_min_flood_cells_map) == 0:
            message = tr(
                'There are no objects in the hazard layer with "value" > 0. '
                'Please check the value or use other extent.' % (
                    threshold_min, ))
            raise GetDataError(message)
        """

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(line_layer_tmp, filename,
                                                "utf-8", None,
                                                "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(self.exposure.layer, request, index,
                                           flood_cells_map, line_layer,
                                           target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(self.exposure.layer.crs(),
                                           output_crs)

        # Roads breakdown
        self.road_lengths = OrderedDict()
        self.affected_road_categories = self.hazard_classes
        # Impacted roads breakdown
        self.affected_road_lengths = OrderedDict([
            (self.hazard_classes[0], {}),
            (self.hazard_classes[1], {}),
            (self.hazard_classes[2], {}),
            (self.hazard_classes[3], {}),
            (self.hazard_classes[4], {}),
        ])

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)
        for road in roads_data:
            attributes = road.attributes()
            affected = attributes[target_field_index]
            hazard_zone = self.hazard_classes[affected]
            road_type = attributes[road_type_field_index]
            if road_type.__class__.__name__ == 'QPyNullVariant':
                road_type = tr('Other')
            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            if road_type not in self.road_lengths:
                self.road_lengths[road_type] = 0

            if hazard_zone not in self.affected_road_lengths:
                self.affected_road_lengths[hazard_zone] = {}

            if road_type not in self.affected_road_lengths[hazard_zone]:
                self.affected_road_lengths[hazard_zone][road_type] = 0

            self.road_lengths[road_type] += length
            num_classes = len(self.hazard_classes)
            if attributes[target_field_index] in range(num_classes):
                self.affected_road_lengths[hazard_zone][road_type] += length

        impact_summary = self.html_report()

        # For printing map purpose
        map_title = tr('Roads inundated')
        legend_title = tr('Road inundated status')

        style_classes = [
            # FIXME 0 - 0.1
            dict(label=self.hazard_classes[0] + ': 0m',
                 value=0,
                 colour='#00FF00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[1] + ': <0 - %.1f m' % low_max,
                 value=1,
                 colour='#FFFF00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[2] + ': %.1f - %.1f m' %
                 (low_max + 0.1, medium_max),
                 value=2,
                 colour='#FFB700',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[3] + ': %.1f - %.1f m' %
                 (medium_max + 0.1, high_max),
                 value=3,
                 colour='#FF6F00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                 value=4,
                 colour='#FF0000',
                 transparency=0,
                 size=1),
        ]
        style_info = dict(target_field=target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        extra_keywords = {
            'impact_summary': impact_summary,
            'map_title': map_title,
            'legend_title': legend_title,
            'target_field': target_field
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        line_layer = Vector(data=line_layer,
                            name=tr('Flooded roads'),
                            keywords=impact_layer_keywords,
                            style_info=style_info)
        self._impact = line_layer
        return line_layer
Example #40
0
def geojson_to_memory(path, name):
    my_WkbType = {
        'Unknown': 0,
         'Point': 1,
         'LineString': 2,
         'Polygon': 3,
         'MultiPoint': 4,
         'MultiLineString': 5,
         'MultiPolygon': 6,
         'NoGeometry': 7,
         'Point25D': 8,
         'LineString25D': 9,
         'Polygon25D': 10,
         'MultiPoint25D': 11,
         'MultiLineString25D': 12,
         'MultiPolygon25D': 13}

    # for i,j in my_WkbType.items():
    #     #print i + " : " + str(j)
    my_rev_WkbType = {v: k for k, v in my_WkbType.items()}
    # for i,j in my_WkbType.items():
    #     #print i + " : " + str(j)
    #print 'Path to geojson: %s' % path
    input_layer=QgsVectorLayer(path,
                               "input_layer", "ogr")
    print 'path: %s' % path
    print 'input_layer %s' % input_layer.name()
    dp = input_layer.dataProvider()
    QGisWKBType = dp.geometryType()
    #print 'QGisWKBType: ' + str(QGisWKBType)
    EPSG_code = int(dp.crs().authid().split(":")[1])
    print str(EPSG_code)

    destination_layer = QgsVectorLayer(
        my_rev_WkbType[QGisWKBType] + '?crs=epsg:' + str(EPSG_code) + '&index=yes',
        name,
        'memory')
    destination_layer_data_provider = destination_layer.dataProvider()

    input_layer_attrib_names = input_layer.dataProvider().fields()

    oldattributeList = input_layer.dataProvider().fields().toList()
    newattributeList = []
    for attrib in oldattributeList:
        if destination_layer.fieldNameIndex(attrib.name()) == -1:
            newattributeList.append(QgsField(attrib.name(), attrib.type()))

    destination_layer_data_provider.addAttributes(newattributeList)
    destination_layer.updateFields()

    destination_layer.startEditing()
    # cfeature = QgsFeature()
    cfeatures = []
    xfeatures = input_layer.getFeatures()
    for xfeature in xfeatures:
        xgeometry = xfeature.geometry()
        cfeature_Attributes = []
        cfeature_Attributes.extend(xfeature.attributes())
        cfeature = QgsFeature()
        cfeature.setGeometry(xgeometry)
        cfeature.setAttributes(cfeature_Attributes)
        cfeatures.append(cfeature)

    destination_layer.addFeatures(cfeatures)
    destination_layer.commitChanges()
    return destination_layer
Example #41
0
    def run(self):
        """Experimental impact function."""
        self.validate()
        self.prepare()

        # Get parameters from layer's keywords
        self.hazard_class_attribute = self.hazard.keyword("field")
        self.hazard_class_mapping = self.hazard.keyword("value_map")
        self.exposure_class_attribute = self.exposure.keyword("structure_class_field")

        # Prepare Hazard Layer
        hazard_provider = self.hazard.layer.dataProvider()

        # Check affected field exists in the hazard layer
        affected_field_index = hazard_provider.fieldNameIndex(self.hazard_class_attribute)
        if affected_field_index == -1:
            message = (
                tr(
                    'Field "%s" is not present in the attribute table of the '
                    "hazard layer. Please change the Affected Field parameter in "
                    "the IF Option."
                )
                % self.hazard_class_attribute
            )
            raise GetDataError(message)

        srs = self.exposure.layer.crs().toWkt()
        exposure_provider = self.exposure.layer.dataProvider()
        exposure_fields = exposure_provider.fields()

        # Check self.exposure_class_attribute exists in exposure layer
        building_type_field_index = exposure_provider.fieldNameIndex(self.exposure_class_attribute)
        if building_type_field_index == -1:
            message = (
                tr(
                    'Field "%s" is not present in the attribute table of '
                    "the exposure layer. Please change the Building Type "
                    "Field parameter in the IF Option."
                )
                % self.exposure_class_attribute
            )
            raise GetDataError(message)

        # If target_field does not exist, add it:
        if exposure_fields.indexFromName(self.target_field) == -1:
            exposure_provider.addAttributes([QgsField(self.target_field, QVariant.Int)])
        target_field_index = exposure_provider.fieldNameIndex(self.target_field)
        exposure_fields = exposure_provider.fields()

        # Create layer to store the lines from E and extent
        building_layer = QgsVectorLayer("Polygon?crs=" + srs, "impact_buildings", "memory")
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(exposure_fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the requested extent
        requested_extent = QgsRectangle(*self.requested_extent)

        # This is a hack - we should be setting the extent CRS
        # in the IF base class via safe/engine/core.py:calculate_impact
        # for now we assume the extent is in 4326 because it
        # is set to that from geo_extent
        # See issue #1857
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:%i" % self._requested_extent_crs), self.hazard.layer.crs()
        )
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        # make spatial index of affected polygons
        hazard_index = QgsSpatialIndex()
        hazard_geometries = {}  # key = feature id, value = geometry
        has_hazard_objects = False
        for feature in self.hazard.layer.getFeatures(request):
            value = feature[affected_field_index]
            if value not in self.hazard_class_mapping[self.wet]:
                continue
            hazard_index.insertFeature(feature)
            hazard_geometries[feature.id()] = QgsGeometry(feature.geometry())
            has_hazard_objects = True

        if not has_hazard_objects:
            message = tr(
                "There are no objects in the hazard layer with %s "
                "value in %s. Please check your data or use another "
                "attribute."
            ) % (self.hazard_class_attribute, ", ".join(self.hazard_class_mapping[self.wet]))
            raise GetDataError(message)

        features = []
        for feature in self.exposure.layer.getFeatures(request):
            building_geom = feature.geometry()
            affected = False
            # get tentative list of intersecting hazard features
            # only based on intersection of bounding boxes
            ids = hazard_index.intersects(building_geom.boundingBox())
            for fid in ids:
                # run (slow) exact intersection test
                if hazard_geometries[fid].intersects(building_geom):
                    affected = True
                    break
            f = QgsFeature()
            f.setGeometry(building_geom)
            f.setAttributes(feature.attributes())
            f[target_field_index] = 1 if affected else 0
            features.append(f)

            # every once in a while commit the created features
            # to the output layer
            if len(features) == 1000:
                (_, __) = building_provider.addFeatures(features)
                features = []

        (_, __) = building_provider.addFeatures(features)
        building_layer.updateExtents()

        # Generate simple impact report
        self.buildings = {}
        self.affected_buildings = OrderedDict([(tr("Flooded"), {})])
        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(self.exposure_class_attribute)
        for building in buildings_data:
            record = building.attributes()
            building_type = record[building_type_field_index]
            if building_type in [None, "NULL", "null", "Null"]:
                building_type = "Unknown type"
            if building_type not in self.buildings:
                self.buildings[building_type] = 0
                for category in self.affected_buildings.keys():
                    self.affected_buildings[category][building_type] = OrderedDict([(tr("Buildings Affected"), 0)])
            self.buildings[building_type] += 1

            if record[target_field_index] == 1:
                self.affected_buildings[tr("Flooded")][building_type][tr("Buildings Affected")] += 1

        # Lump small entries and 'unknown' into 'other' category
        self._consolidate_to_other()

        impact_summary = self.generate_html_report()

        # For printing map purpose
        map_title = tr("Buildings inundated")
        legend_title = tr("Structure inundated status")

        style_classes = [
            dict(label=tr("Not Inundated"), value=0, colour="#1EFC7C", transparency=0, size=0.5),
            dict(label=tr("Inundated"), value=1, colour="#F31A1C", transparency=0, size=0.5),
        ]
        style_info = dict(target_field=self.target_field, style_classes=style_classes, style_type="categorizedSymbol")

        # Convert QgsVectorLayer to inasafe layer and return it.
        if building_layer.featureCount() < 1:
            raise ZeroImpactException(tr("No buildings were impacted by this flood."))
        building_layer = Vector(
            data=building_layer,
            name=tr("Flooded buildings"),
            keywords={
                "impact_summary": impact_summary,
                "map_title": map_title,
                "legend_title": legend_title,
                "target_field": self.target_field,
                "buildings_total": self.total_buildings,
                "buildings_affected": self.total_affected_buildings,
            },
            style_info=style_info,
        )
        self._impact = building_layer
        return building_layer
def identify_features(input_layer, threshold=0, callback=None):
    """Identify all features in one functions and put it in a layer.

    This function will find node that is an unseparated or ungetrennter (
    germany). The definition of this type is a node that located in a line (
    not in the start or end of a line).

    :param input_layer: A vector line layer.
    :type input_layer: QGISVectorLayer

    :param threshold: Distance threshold for node snapping. Defaults to 1.
    :type threshold: float

    :param callback: A function to all to indicate progress. The function
        should accept params 'current' (int) and 'maximum' (int). Defaults to
        None.
    :type callback: function

    :returns: A tuple of an intermediate layer that contains nodes and Map
    layer (memory layer) containing identified features.
    :rtype: tuple

    """
    intermediate_layer = create_intermediate_layer(
        input_layer, threshold, callback)
    authority_id = input_layer.crs().authid()

    index = 1
    rule_count = 4
    # Find self intersections
    message = tr('Finding self intersections...')
    callback(current=index, maximum=rule_count, message=message)
    self_intersections = identify_self_intersections_layer(input_layer)
    index += 1

    # Find segment centers
    message = tr('Finding segment centers...')
    callback(current=index, maximum=rule_count, message=message)
    segment_centers = identify_segment_centers(input_layer)
    index += 1

    # Find intersections
    message = tr('Finding intersections...')
    callback(current=index, maximum=rule_count, message=message)
    intersections = identify_intersections(input_layer)
    index += 1

    # create output layer
    layer_name = tr('Stream Features')
    field_id = 'field=id:integer'
    field_x = 'field=x:double'
    field_y = 'field=y:double'
    field_type = 'field=type:string(30)'

    uri = ('Point?crs=%s&index=yes&%s&%s&%s&%s' % (
        authority_id, field_id, field_x, field_y, field_type))

    output_layer = QgsVectorLayer(uri, layer_name, 'memory')

    # Start edit layer
    output_data_provider = output_layer.dataProvider()
    output_layer.startEditing()

    type_index = output_layer.fieldNameIndex('type')

    new_features = create_new_features(
        intermediate_layer, self_intersections, intersections, segment_centers)

    output_data_provider.addFeatures(new_features)
    output_layer.updateFields()
    output_layer.commitChanges()

    message = tr('Finding Unseparated...')
    callback(current=index, maximum=rule_count, message=message)
    # How to find unseparated
    # Basically, unseparated is an intersection point in well or sink. So,
    # we find duplicate points, and replace it with Unseparated.
    unique_features, duplicated_features = get_duplicate_points(
        output_layer, threshold)

    # Deleting duplicated features
    duplicated_features = [int(x) for x in duplicated_features]
    output_data_provider.deleteFeatures(duplicated_features)

    # Replacing them with unseparated
    dictionary_attributes = {}
    attributes = {type_index: tr('Unseparated')}

    for true_feature in unique_features:
        dictionary_attributes[true_feature] = attributes
    output_data_provider.changeAttributeValues(dictionary_attributes)
    output_layer.updateFields()

    # Re write the id
    features = output_layer.getFeatures()
    dictionary_attributes = {}
    i = 1
    for feature in features:
        attributes = {0: i}
        dictionary_attributes[feature.id()] = attributes
        feature.setFeatureId(i - 1)
        i += 1
    output_data_provider.changeAttributeValues(dictionary_attributes)

    output_layer.updateFields()
    output_layer.commitChanges()

    return intermediate_layer, output_layer
Example #43
0
def geojson_to_memory(path, name):
    my_WkbType = {
        'Unknown': 0,
        'Point': 1,
        'LineString': 2,
        'Polygon': 3,
        'MultiPoint': 4,
        'MultiLineString': 5,
        'MultiPolygon': 6,
        'NoGeometry': 7,
        'Point25D': 8,
        'LineString25D': 9,
        'Polygon25D': 10,
        'MultiPoint25D': 11,
        'MultiLineString25D': 12,
        'MultiPolygon25D': 13
    }

    # for i,j in my_WkbType.items():
    #     #print i + " : " + str(j)
    my_rev_WkbType = {v: k for k, v in my_WkbType.items()}
    # for i,j in my_WkbType.items():
    #     #print i + " : " + str(j)
    #print 'Path to geojson: %s' % path
    input_layer = QgsVectorLayer(path, "input_layer", "ogr")
    print 'path: %s' % path
    print 'input_layer %s' % input_layer.name()
    dp = input_layer.dataProvider()
    QGisWKBType = dp.geometryType()
    #print 'QGisWKBType: ' + str(QGisWKBType)
    EPSG_code = int(dp.crs().authid().split(":")[1])
    print str(EPSG_code)

    destination_layer = QgsVectorLayer(
        my_rev_WkbType[QGisWKBType] + '?crs=epsg:' + str(EPSG_code) +
        '&index=yes', name, 'memory')
    destination_layer_data_provider = destination_layer.dataProvider()

    input_layer_attrib_names = input_layer.dataProvider().fields()

    oldattributeList = input_layer.dataProvider().fields().toList()
    newattributeList = []
    for attrib in oldattributeList:
        if destination_layer.fieldNameIndex(attrib.name()) == -1:
            newattributeList.append(QgsField(attrib.name(), attrib.type()))

    destination_layer_data_provider.addAttributes(newattributeList)
    destination_layer.updateFields()

    destination_layer.startEditing()
    # cfeature = QgsFeature()
    cfeatures = []
    xfeatures = input_layer.getFeatures()
    for xfeature in xfeatures:
        xgeometry = xfeature.geometry()
        cfeature_Attributes = []
        cfeature_Attributes.extend(xfeature.attributes())
        cfeature = QgsFeature()
        cfeature.setGeometry(xgeometry)
        cfeature.setAttributes(cfeature_Attributes)
        cfeatures.append(cfeature)

    destination_layer.addFeatures(cfeatures)
    destination_layer.commitChanges()
    return destination_layer
Example #44
0
    def run(self):
        """Run the impact function.

        :returns: A new line layer with inundated roads marked.
        :type: safe_layer
        """
        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value

        target_field = self.target_field
        # Get parameters from layer's keywords
        road_class_field = self.exposure.keyword('road_class_field')
        exposure_value_mapping = self.exposure.keyword('value_mapping')

        # reproject self.extent to the hazard projection
        hazard_crs = self.hazard.layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        # Clip hazard raster
        small_raster = align_clip_raster(self.hazard.layer, viewport_extent)

        # Create vector features from the flood raster
        # For each raster cell there is one rectangular polygon
        # Data also get spatially indexed for faster operation
        ranges = ranges_according_thresholds(low_max, medium_max, high_max)

        index, flood_cells_map = _raster_to_vector_cells(
            small_raster, ranges, self.exposure.layer.crs())

        # Filter geometry and data using the extent
        ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4326"),
                                    self.exposure.layer.crs())
        extent = ct.transformBoundingBox(QgsRectangle(*self.requested_extent))
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # create template for the output layer
        line_layer_tmp = create_layer(self.exposure.layer)
        new_field = QgsField(target_field, QVariant.Int)
        line_layer_tmp.dataProvider().addAttributes([new_field])
        line_layer_tmp.updateFields()

        # create empty output layer and load it
        filename = unique_filename(suffix='.shp')
        QgsVectorFileWriter.writeAsVectorFormat(line_layer_tmp, filename,
                                                "utf-8", None,
                                                "ESRI Shapefile")
        line_layer = QgsVectorLayer(filename, "flooded roads", "ogr")

        # Do the heavy work - for each road get flood polygon for that area and
        # do the intersection/difference to find out which parts are flooded
        _intersect_lines_with_vector_cells(self.exposure.layer, request, index,
                                           flood_cells_map, line_layer,
                                           target_field)

        target_field_index = line_layer.dataProvider().\
            fieldNameIndex(target_field)

        # Generate simple impact report
        epsg = get_utm_epsg(self.requested_extent[0], self.requested_extent[1])
        output_crs = QgsCoordinateReferenceSystem(epsg)
        transform = QgsCoordinateTransform(self.exposure.layer.crs(),
                                           output_crs)

        # Roads breakdown
        self.init_report_var(self.hazard_classes)

        if line_layer.featureCount() < 1:
            raise ZeroImpactException()

        roads_data = line_layer.getFeatures()
        road_type_field_index = line_layer.fieldNameIndex(road_class_field)

        for road in roads_data:
            attributes = road.attributes()

            affected = attributes[target_field_index]
            if isinstance(affected, QPyNullVariant):
                continue
            else:
                hazard_zone = self.hazard_classes[affected]

            usage = attributes[road_type_field_index]
            usage = main_type(usage, exposure_value_mapping)

            geom = road.geometry()
            geom.transform(transform)
            length = geom.length()

            affected = False
            num_classes = len(self.hazard_classes)
            if attributes[target_field_index] in range(num_classes):
                affected = True
            self.classify_feature(hazard_zone, usage, length, affected)

        self.reorder_dictionaries()

        style_classes = [
            # FIXME 0 - 0.1
            dict(label=self.hazard_classes[0] + ': 0m',
                 value=0,
                 colour='#00FF00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[1] + ': >0 - %.1f m' % low_max,
                 value=1,
                 colour='#FFFF00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[2] + ': %.1f - %.1f m' %
                 (low_max + 0.1, medium_max),
                 value=2,
                 colour='#FFB700',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[3] + ': %.1f - %.1f m' %
                 (medium_max + 0.1, high_max),
                 value=3,
                 colour='#FF6F00',
                 transparency=0,
                 size=1),
            dict(label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                 value=4,
                 colour='#FF0000',
                 transparency=0,
                 size=1),
        ]
        style_info = dict(target_field=target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        impact_data = self.generate_data()

        extra_keywords = {
            'map_title': self.map_title(),
            'legend_title': self.metadata().key('legend_title'),
            'target_field': target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Convert QgsVectorLayer to inasafe layer and return it
        impact_layer = Vector(data=line_layer,
                              name=self.map_title(),
                              keywords=impact_layer_keywords,
                              style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
    def run(self):
        """Run the impact function."""
        # First fo any generic run work defined in the ABC.
        self.prepare()

        target_field = self.parameters['target_field']
        building_type_field = self.parameters['building_type_field']
        affected_value = self.parameters['affected_value']

        crs = self.exposure.crs().toWkt()
        exposure_provider = self.exposure.dataProvider()
        fields = exposure_provider.fields()
        # If target_field does not exist, add it:
        if fields.indexFromName(target_field) == -1:
            exposure_provider.addAttributes(
                [QgsField(target_field, QVariant.Int)])
        target_field_index = exposure_provider.fieldNameIndex(target_field)
        fields = exposure_provider.fields()

        # Create layer for store the lines from exposure and extent
        building_layer = QgsVectorLayer(
            'Polygon?crs=' + crs, 'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the extent
        extent = QgsRectangle(*self.extent)
        request = QgsFeatureRequest()
        request.setFilterRect(extent)

        # Split building_layer by hazard and save as result:
        #   1) Filter from hazard inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        affected_field_type = self.hazard_provider.fields()[
            self.affected_field_index].typeName()
        if affected_field_type in ['Real', 'Integer']:
            affected_value = float(affected_value)

        hazard_data = self.hazard.getFeatures(request)
        hazard_poly = None
        for multi_polygon in hazard_data:
            attributes = multi_polygon.attributes()
            if attributes[self.affected_field_index] != affected_value:
                continue
            if hazard_poly is None:
                hazard_poly = QgsGeometry(multi_polygon.geometry())
            else:
                # Make geometry union of inundated polygons
                # But some multi_polygon.geometry() could be invalid, skip them
                tmp_geometry = hazard_poly.combine(multi_polygon.geometry())
                try:
                    if tmp_geometry.isGeosValid():
                        hazard_poly = tmp_geometry
                except AttributeError:
                    pass

        if hazard_poly is None:
            message = tr(
                '''There are no objects in the hazard layer with "Affected
                value"='%s'. Please check the value or use other extent.''' %
                (affected_value, ))
            raise GetDataError(message)

        exposure_features = self.exposure.getFeatures(request)
        for feature in exposure_features:
            building_geometry = feature.geometry()
            attributes = feature.attributes()
            l_feat = QgsFeature()
            l_feat.setGeometry(building_geometry)
            l_feat.setAttributes(attributes)
            if hazard_poly.intersects(building_geometry):
                l_feat.setAttribute(target_field_index, 1)
            else:

                l_feat.setAttribute(target_field_index, 0)
            # Synctactic sugar to discard return values
            (_, __) = building_layer.dataProvider().addFeatures([l_feat])
        building_layer.updateExtents()

        # Generate simple impact report

        building_count = flooded_count = 0  # Count of buildings
        buildings_by_type = dict()      # Length of flooded roads by types

        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(
            building_type_field)
        for building in buildings_data:
            building_count += 1
            attributes = building.attributes()
            building_type = attributes[building_type_field_index]
            if building_type in [None, 'NULL', 'null', 'Null']:
                building_type = 'Unknown type'
            if not building_type in buildings_by_type:
                buildings_by_type[building_type] = {'flooded': 0, 'total': 0}
            buildings_by_type[building_type]['total'] += 1

            if attributes[target_field_index] == 1:
                flooded_count += 1
                buildings_by_type[building_type]['flooded'] += 1

        self._tabulate(building_count, buildings_by_type, flooded_count)

        self._style(target_field)

        self._impact = building_layer
Example #46
0
c_ymax = c_ext.yMaximum()

ymin=min(r_ymin,c_ymin)
ymax=max(r_ymax,c_ymax)
xmin=min(r_xmin,c_xmin)
xmax=max(r_xmax,c_xmax)

coords = "%f,%f,%f,%f" %(xmin, xmax, ymin, ymax)

out1=processing.runalg('qgis:addfieldtoattributestable', sites,random_name,0,10.0,0.0,None)

out2=processing.runalg('grass7:v.what.rast.points', out1['OUTPUT_LAYER'],classified,random_name,'1=1',False,coords,-1.0,0.0001,0,os.path.join(output_folder,"newpts.shp"))

vlayer = QgsVectorLayer(out2['output'], random_name, "ogr")

idx_1 = vlayer.fieldNameIndex(sites_field)
idx_2 = vlayer.fieldNameIndex(random_name)

list_combinations = []
list_class = []
list_ref = []

features =  vlayer.getFeatures()

for ft in features:
    if ft.attributes()[idx_2]!=None and ft.attributes()[idx_1]!=None:
        list_class.append(ft.attributes()[idx_2])
        list_ref.append(ft.attributes()[idx_1])
        list_combinations.append([ft.attributes()[idx_1],ft.attributes()[idx_2]])

class_ucat = list(set(list_class))