예제 #1
0
    def field_keyword_for_the_layer(self):
        """Return the proper keyword for field for the current layer.
        Expected values are: 'field', 'structure_class_field', road_class_field

        :returns: the field keyword
        :rtype: string
        """

        if self.step_kw_purpose.selected_purpose() == \
                layer_purpose_aggregation:
            # purpose: aggregation
            return 'aggregation attribute'
        elif self.step_kw_purpose.selected_purpose() == layer_purpose_hazard:
            # purpose: hazard
            if (self.step_kw_layermode.selected_layermode() ==
                    layer_mode_classified and
                    is_point_layer(self.layer)):
                # No field for classified point hazards
                return ''
        else:
            # purpose: exposure
            layer_mode_key = self.step_kw_layermode.selected_layermode()['key']
            layer_geometry_key = self.get_layer_geometry_id()
            exposure_key = self.step_kw_subcategory.\
                selected_subcategory()['key']
            exposure_class_fields = self.impact_function_manager.\
                exposure_class_fields(
                    layer_mode_key, layer_geometry_key, exposure_key)
            if exposure_class_fields and len(exposure_class_fields) == 1:
                return exposure_class_fields[0]['key']
        # Fallback to default
        return 'field'
예제 #2
0
    def field_keyword_for_the_layer(self):
        """Return the proper keyword for field for the current layer.
        Expected values are: 'field', 'structure_class_field', road_class_field

        :returns: the field keyword
        :rtype: string
        """

        if self.step_kw_purpose.selected_purpose() == \
                layer_purpose_aggregation:
            # purpose: aggregation
            return 'aggregation attribute'
        elif self.step_kw_purpose.selected_purpose() == layer_purpose_hazard:
            # purpose: hazard
            if (self.step_kw_layermode.selected_layermode()
                    == layer_mode_classified and is_point_layer(self.layer)):
                # No field for classified point hazards
                return ''
        else:
            # purpose: exposure
            layer_mode_key = self.step_kw_layermode.selected_layermode()['key']
            layer_geometry_key = self.get_layer_geometry_id()
            exposure_key = self.step_kw_subcategory.\
                selected_subcategory()['key']
            exposure_class_fields = self.impact_function_manager.\
                exposure_class_fields(
                    layer_mode_key, layer_geometry_key, exposure_key)
            if exposure_class_fields and len(exposure_class_fields) == 1:
                return exposure_class_fields[0]['key']
        # Fallback to default
        return 'field'
예제 #3
0
    def polygon_layers_to_combo(self):
        """Populate the combo with all polygon layers loaded in QGIS."""

        # noinspection PyArgumentList
        registry = QgsMapLayerRegistry.instance()
        layers = registry.mapLayers().values()
        found_flag = False
        for layer in layers:
            name = layer.name()
            source = layer.id()
            # check if layer is a vector polygon layer
            if is_polygon_layer(layer) or is_point_layer(layer):
                found_flag = True
                add_ordered_combo_item(self.cboPolygonLayers, name, source)
        if found_flag:
            self.cboPolygonLayers.setCurrentIndex(0)
예제 #4
0
    def polygon_layers_to_combo(self):
        """Populate the combo with all polygon layers loaded in QGIS."""

        # noinspection PyArgumentList
        registry = QgsMapLayerRegistry.instance()
        layers = registry.mapLayers().values()
        found_flag = False
        for layer in layers:
            name = layer.name()
            source = str(layer.id())
            # check if layer is a vector polygon layer
            if is_polygon_layer(layer) or is_point_layer(layer):
                found_flag = True
                add_ordered_combo_item(self.cboPolygonLayers, name, source)
        if found_flag:
            self.cboPolygonLayers.setCurrentIndex(0)
예제 #5
0
파일: tools.py 프로젝트: timlinux/inasafe
def geometry_type(layer):
    """Retrieve the geometry type: point, line, polygon or raster for a layer.

    :param layer: The layer.
    :type layer: QgsMapLayer

    :return: The definition key.
    :rtype: basestring
    """
    if is_raster_layer(layer):
        return layer_geometry_raster['key']
    elif is_point_layer(layer):
        return layer_geometry_point['key']
    elif is_line_layer(layer):
        return layer_geometry_line['key']
    elif is_polygon_layer(layer):
        return layer_geometry_polygon['key']
    else:
        return None
예제 #6
0
파일: tools.py 프로젝트: inasafe/inasafe
def geometry_type(layer):
    """Retrieve the geometry type: point, line, polygon or raster for a layer.

    :param layer: The layer.
    :type layer: QgsMapLayer

    :return: The definition key.
    :rtype: basestring
    """
    if is_raster_layer(layer):
        return layer_geometry_raster['key']
    elif is_point_layer(layer):
        return layer_geometry_point['key']
    elif is_line_layer(layer):
        return layer_geometry_line['key']
    elif is_polygon_layer(layer):
        return layer_geometry_polygon['key']
    else:
        return None
예제 #7
0
    def get_layer_geometry_key(self, layer=None):
        """Obtain layer mode of a given layer.

        If no layer specified, the current layer is used

        :param layer : layer to examine
        :type layer: QgsMapLayer or None

        :returns: The layer mode.
        :rtype: str
        """
        if not layer:
            layer = self.layer
        if is_raster_layer(layer):
            return layer_geometry_raster['key']
        elif is_point_layer(layer):
            return layer_geometry_point['key']
        elif is_polygon_layer(layer):
            return layer_geometry_polygon['key']
        else:
            return layer_geometry_line['key']
예제 #8
0
    def get_layer_geometry_id(self, layer=None):
        """Obtain layer mode of a given layer.

        If no layer specified, the current layer is used

        :param layer : layer to examine
        :type layer: QgsMapLayer or None

        :returns: The layer mode.
        :rtype: str
        """
        if not layer:
            layer = self.layer
        if is_raster_layer(layer):
            return 'raster'
        elif is_point_layer(layer):
            return 'point'
        elif is_polygon_layer(layer):
            return 'polygon'
        else:
            return 'line'
예제 #9
0
    def polygon_layers_to_combo(self):
        """Populate the combo with all polygon layers loaded in QGIS."""

        # noinspection PyArgumentList
        registry = QgsMapLayerRegistry.instance()
        layers = registry.mapLayers().values()
        found_flag = False
        for layer in layers:
            name = layer.name()
            source = layer.id()
            # check if layer is a vector polygon layer
            if is_polygon_layer(layer) or is_point_layer(layer):
                found_flag = True
                add_ordered_combo_item(self.cboPolygonLayers, name, source)
        # Now disable the run button if no suitable layers were found
        # see #2206
        ok_button = self.button_box.button(QtGui.QDialogButtonBox.Ok)
        if found_flag:
            self.cboPolygonLayers.setCurrentIndex(0)
            ok_button.setEnabled(True)
        else:
            ok_button.setEnabled(False)
예제 #10
0
    def polygon_layers_to_combo(self):
        """Populate the combo with all polygon layers loaded in QGIS."""

        # noinspection PyArgumentList
        registry = QgsMapLayerRegistry.instance()
        layers = registry.mapLayers().values()
        found_flag = False
        for layer in layers:
            name = layer.name()
            source = layer.id()
            # check if layer is a vector polygon layer
            if is_polygon_layer(layer) or is_point_layer(layer):
                found_flag = True
                add_ordered_combo_item(self.cboPolygonLayers, name, source)
        # Now disable the run button if no suitable layers were found
        # see #2206
        ok_button = self.button_box.button(QtGui.QDialogButtonBox.Ok)
        if found_flag:
            self.cboPolygonLayers.setCurrentIndex(0)
            ok_button.setEnabled(True)
        else:
            ok_button.setEnabled(False)
예제 #11
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if self.parent.step_kw_layermode.\
                selected_layermode() == layer_mode_classified:
            if is_point_layer(self.parent.layer) \
                    and self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_hazard:
                # Skip FIELD and CLASSIFICATION for point volcanos
                new_step = self.parent.step_kw_extrakeywords
            elif self.parent.step_kw_classification.\
                    classifications_for_layer():
                new_step = self.parent.step_kw_classification
            elif is_raster_layer(self.parent.layer):
                new_step = self.parent.step_kw_extrakeywords
            else:
                new_step = self.parent.step_kw_field
        else:
            # CONTINUOUS DATA, ALL GEOMETRIES
            new_step = self.parent.step_kw_unit
        return new_step
예제 #12
0
    def get_next_step(self):
        """Find the proper step when user clicks the Next button.

        :returns: The step to be switched to
        :rtype: WizardStep instance or None
        """
        if self.parent.step_kw_layermode.\
                selected_layermode() == layer_mode_classified:
            if is_point_layer(self.parent.layer) \
                    and self.parent.step_kw_purpose.\
                    selected_purpose() == layer_purpose_hazard:
                # Skip FIELD and CLASSIFICATION for point volcanos
                new_step = self.parent.step_kw_extrakeywords
            elif self.parent.step_kw_classification.\
                    classifications_for_layer():
                new_step = self.parent.step_kw_classification
            elif is_raster_layer(self.parent.layer):
                new_step = self.parent.step_kw_extrakeywords
            else:
                new_step = self.parent.step_kw_field
        else:
            # CONTINUOUS DATA, ALL GEOMETRIES
            new_step = self.parent.step_kw_unit
        return new_step
예제 #13
0
def layer_description_html(layer, keywords=None):
    """Form a html description of a given layer based on the layer
       parameters and keywords if provided

    :param layer: The layer to get the description
    :type layer: QgsMapLayer

    :param keywords: The layer keywords
    :type keywords: None, dict

    :returns: The html description in tabular format,
        ready to use in a label or tool tip.
    :rtype: str
    """

    if keywords and 'keyword_version' in keywords:
        keyword_version = str(keywords['keyword_version'])
    else:
        keyword_version = None

    if (keywords and keyword_version
            and is_keyword_version_supported(keyword_version)):
        # The layer has valid keywords
        purpose = keywords.get('layer_purpose')
        if purpose == layer_purpose_hazard['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Hazard'), keywords.get(purpose))
            unit = keywords.get('continuous_hazard_unit')
        elif purpose == layer_purpose_exposure['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Exposure'), keywords.get(purpose))
            unit = keywords.get('exposure_unit')
        else:
            subcategory = ''
            unit = None
        if keywords.get('layer_mode') == layer_mode_classified['key']:
            unit = tr('classified data')
        if unit:
            unit = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (tr('Unit'),
                                                                 unit)

        description = """
            <table border="0" width="100%%">
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            %s
            %s
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            </table>
        """ % (tr('Title'), keywords.get('title'), tr('Purpose'),
               keywords.get('layer_purpose'), subcategory, unit, tr('Source'),
               keywords.get('source'))
    elif keywords:
        # The layer has keywords, but the version is wrong
        layer_version = keyword_version or tr('No Version')
        description = tr(
            'Your layer\'s keyword\'s version ({layer_version}) does not '
            'match with your InaSAFE version ({inasafe_version}). If you wish '
            'to use it as an exposure, hazard, or aggregation layer in an '
            'analysis, please update the keywords. Click Next if you want to '
            'assign keywords now.').format(layer_version=layer_version,
                                           inasafe_version=get_version())
    else:
        # The layer is keywordless
        if is_point_layer(layer):
            geom_type = layer_geometry_point['key']
        elif is_polygon_layer(layer):
            geom_type = layer_geometry_polygon['key']
        else:
            geom_type = layer_geometry_line['key']

        # hide password in the layer source
        source = layer.publicSource()
        description = """
            %s<br/><br/>
            <b>%s</b>: %s<br/>
            <b>%s</b>: %s<br/><br/>
            %s
        """ % (tr('This layer has no valid keywords assigned'), tr('SOURCE'),
               source, tr('TYPE'), is_raster_layer(layer) and 'raster'
               or 'vector (%s)' % geom_type,
               tr('In the next step you will be able' +
                  ' to assign keywords to this layer.'))
    return description
예제 #14
0
def layer_description_html(layer, keywords=None):
    """Form a html description of a given layer based on the layer
       parameters and keywords if provided

    :param layer: The layer to get the description
    :type layer: QgsMapLayer

    :param keywords: The layer keywords
    :type keywords: None, dict

    :returns: The html description in tabular format,
        ready to use in a label or tool tip.
    :rtype: str
    """

    if keywords and 'keyword_version' in keywords:
        keyword_version = str(keywords['keyword_version'])
    else:
        keyword_version = None

    if (keywords and
            keyword_version and
            is_keyword_version_supported(keyword_version)):
        # The layer has valid keywords
        purpose = keywords.get('layer_purpose')
        if purpose == layer_purpose_hazard['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Hazard'), keywords.get(purpose))
            unit = keywords.get('continuous_hazard_unit')
        elif purpose == layer_purpose_exposure['key']:
            subcategory = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Exposure'), keywords.get(purpose))
            unit = keywords.get('exposure_unit')
        else:
            subcategory = ''
            unit = None
        if keywords.get('layer_mode') == layer_mode_classified['key']:
            unit = tr('classified data')
        if unit:
            unit = '<tr><td><b>%s</b>: </td><td>%s</td></tr>' % (
                tr('Unit'), unit)

        desc = """
            <table border="0" width="100%%">
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            %s
            %s
            <tr><td><b>%s</b>: </td><td>%s</td></tr>
            </table>
        """ % (tr('Title'), keywords.get('title'),
               tr('Purpose'), keywords.get('layer_purpose'),
               subcategory,
               unit,
               tr('Source'), keywords.get('source'))
    elif keywords:
        # The layer has keywords, but the version is wrong
        layer_version = keyword_version or tr('No Version')
        desc = tr(
            'Your layer\'s keyword\'s version ({layer_version}) does not '
            'match with your InaSAFE version ({inasafe_version}). If you wish '
            'to use it as an exposure, hazard, or aggregation layer in an '
            'analysis, please update the keywords. Click Next if you want to '
            'assign keywords now.').format(
            layer_version=layer_version, inasafe_version=get_version())
    else:
        # The layer is keywordless
        if is_point_layer(layer):
            geom_type = 'point'
        elif is_polygon_layer(layer):
            geom_type = 'polygon'
        else:
            geom_type = 'line'

        # hide password in the layer source
        source = layer.publicSource()
        desc = """
            %s<br/><br/>
            <b>%s</b>: %s<br/>
            <b>%s</b>: %s<br/><br/>
            %s
        """ % (tr('This layer has no valid keywords assigned'),
               tr('SOURCE'), source,
               tr('TYPE'), is_raster_layer(layer) and 'raster' or
               'vector (%s)' % geom_type,
               tr('In the next step you will be able' +
                  ' to assign keywords to this layer.'))
    return desc
예제 #15
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