コード例 #1
0
    def testSignals(self):
        QgsProject.instance().clear()
        m = QgsMapLayerComboBox()
        l1 = QgsVectorLayer(
            "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer",
            'layer 1', "memory")
        QgsProject.instance().addMapLayer(l1)
        l2 = QgsVectorLayer(
            "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer",
            'lAyEr 2', "memory")
        QgsProject.instance().addMapLayer(l2)
        spy = QSignalSpy(m.layerChanged)

        m.setLayer(l2)
        self.assertEqual(len(spy), 1)
        self.assertEqual(m.currentLayer(), l2)
        m.setLayer(l1)
        self.assertEqual(len(spy), 2)
        self.assertEqual(m.currentLayer(), l1)
        # no signal if same layer
        m.setLayer(l1)
        self.assertEqual(len(spy), 2)

        m.setAllowEmptyLayer(True)
        m.setLayer(None)
        self.assertEqual(len(spy), 3)
        self.assertIsNone(m.currentLayer())
        m.setLayer(None)
        self.assertEqual(len(spy), 3)
        self.assertIsNone(m.currentLayer())

        m.setLayer(l1)
        self.assertEqual(len(spy), 4)
        self.assertEqual(m.currentLayer(), l1)
コード例 #2
0
ファイル: overlap_dialog.py プロジェクト: giscan/footprint
class OverlapDialog(QDialog, FORM_CLASS):
    def __init__(self, parent=None, iface=None):
        """Constructor."""
        super(OverlapDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        QDialog.__init__(self, parent)
        self.parent = parent
        self.iface = iface
        self.setupUi(self)

        # layer
        self.layer = QgsMapLayerComboBox(parent)
        self.layer.setFilters(QgsMapLayerProxyModel.PolygonLayer)
        # self.layer.layerChanged.connect(self.check_form_validation)

        # output
        self.result.setStorageMode(storageMode=QgsFileWidget.SaveFile)
        self.result.setDialogTitle("Save File")

        # Set up things for ok button
        self.ok_button = self.button_ovelap.button(QDialogButtonBox.Ok)
        # self.ok_button.setEnabled(False)
        self.ok_button.clicked.connect(self.accept)

        # Set up things for cancel button
        self.cancel_button = self.button_ovelap.button(QDialogButtonBox.Cancel)
        self.cancel_button.clicked.connect(self.reject)

    def check_form_validation(self):
        """Slot for in form modif"""

        input_layer = self.layer.currentLayer()
        if input_layer is None:
            self.ok_button.setEnabled(True)
        else:
            self.ok_button.setEnabled(False)

    def accept(self):
        """Method invoked when OK button is clicked."""

        input_layer = self.layer.currentLayer()
        out = self.result.filePath()
        file_out = QgsFileWidget.splitFilePaths(out)
        count_overlap_action(input_layer, out)
        QgsMessageLog.logMessage(
            "Input layer: {} and Output: {}".format(input_layer.name(),
                                                    file_out), 'Footprint',
            Qgis.Info)
        self.close()
コード例 #3
0
class LayerSelectionDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr('Select Extent'))

        vl = QVBoxLayout()
        vl.addWidget(QLabel(self.tr('Use extent from')))
        self.combo = QgsMapLayerComboBox()
        self.combo.setFilters(QgsMapLayerProxyModel.HasGeometry
                              | QgsMapLayerProxyModel.RasterLayer
                              | QgsMapLayerProxyModel.MeshLayer)
        self.combo.setShowCrs(
            ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF))
        vl.addWidget(self.combo)

        self.button_box = QDialogButtonBox()
        self.button_box.setStandardButtons(QDialogButtonBox.Cancel
                                           | QDialogButtonBox.Ok)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        vl.addWidget(self.button_box)
        self.setLayout(vl)

    def selected_layer(self):
        return self.combo.currentLayer()
コード例 #4
0
ファイル: layerselectdialog.py プロジェクト: a70/Qgis2threejs
class SingleLayerSelectDialog(QDialog):
    def __init__(self, parent=None, label=""):

        QDialog.__init__(self, parent)

        vl = QVBoxLayout()
        if label:
            vl.addWidget(QLabel(label))

        self.comboBox = QgsMapLayerComboBox()
        self.comboBox.setFilters(QgsMapLayerProxyModel.HasGeometry
                                 | QgsMapLayerProxyModel.RasterLayer
                                 | QgsMapLayerProxyModel.MeshLayer)
        vl.addWidget(self.comboBox)

        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        vl.addWidget(self.buttonBox)

        self.setLayout(vl)

    def selectedLayer(self):
        return self.comboBox.currentLayer()
コード例 #5
0
    def testProject(self):
        QgsProject.instance().clear()
        lA = create_layer('lA')
        lB = create_layer('lB')

        projectA = QgsProject.instance()
        projectB = QgsProject()

        projectA.addMapLayer(lA)
        projectB.addMapLayer(lB)
        cb = QgsMapLayerComboBox()

        self.assertEqual(cb.currentLayer(), lA)

        cb.setProject(projectB)
        self.assertEqual(cb.currentLayer(), lB)

        cb.setProject(projectA)
        self.assertEqual(cb.currentLayer(), lA)

        QgsProject.instance().clear()
コード例 #6
0
class load_layer_dialog(QDialog):
    def __init__(self, parent=None, routes=[]):
        super(QDialog, self).__init__(parent)
        self.setModal(True)  #modal blocks other stuff
        self.layer_box = QgsMapLayerComboBox()
        self.ok_button = QtGui.QPushButton('Ok')
        self.cancel_button = QtGui.QPushButton('Cancel')

        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.layer_box)
        layout.addWidget(self.ok_button)
        layout.addWidget(self.cancel_button)

        self.routes = routes
        self.ok_button.clicked.connect(self.load)
        self.cancel_button.clicked.connect(self.reject)

    def load(self):
        load_layer(self.layer_box.currentLayer(), self.routes)
        self.accept()
コード例 #7
0
class LayerSelectionDialog(QDialog):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr('Select Extent'))

        vl = QVBoxLayout()
        vl.addWidget(QLabel(self.tr('Use extent from')))
        self.combo = QgsMapLayerComboBox()
        self.combo.setFilters(
            QgsMapLayerProxyModel.HasGeometry | QgsMapLayerProxyModel.RasterLayer | QgsMapLayerProxyModel.MeshLayer)
        self.combo.setShowCrs(ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF))
        vl.addWidget(self.combo)

        self.button_box = QDialogButtonBox()
        self.button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        vl.addWidget(self.button_box)
        self.setLayout(vl)

    def selected_layer(self):
        return self.combo.currentLayer()
コード例 #8
0
class CatchmentsModule(QDockWidget, FORM_CLASS):
    def __init__(self, parent, parents=None):
        super(CatchmentsModule, self).__init__(parents)
        self.setupUi(self)
        self.parent = parent
        self.iface = parent.iface
        self.fillDialog()

    def fillDialog(self):
        self.layerComboBox = QgsMapLayerComboBox(self)
        self.layerComboBox.setObjectName('layerComboBox')
        self.layerComboBox.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.layersLayout.addWidget(self.layerComboBox)
        self.providersComboBox.addItems(['Skobbler', 'HERE'])
        self.modesComboBox.addItems(['Car', 'Bike', 'Pedestrian'])
        self.unitsComboBox.addItems(['Minutes', 'Meters'])
        self.valueSpinBox.setMinimum(1)
        self.valueSpinBox.setMaximum(99999)
        self.valueSpinBox.setValue(10)
        self.getCatchments.setEnabled(False)
        self.getKeyLabel.setText('<html><head/><body><p>\
            <a href="https://developer.skobbler.com/getting-started/web#sec3">\
            <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
        )
        self.connectFunctions()
        self.loadKey()

    def connectFunctions(self):
        self.providersComboBox.currentIndexChanged.connect(self.changeProvider)
        self.keyLineEdit.textChanged.connect(self.saveKey)
        self.layerComboBox.currentIndexChanged.connect(self.changeLayerEvent)
        self.modesComboBox.currentIndexChanged.connect(self.disableUnnecessaryParams)
        self.selectCheckBox.stateChanged.connect(self.updateFeaturesQuantity)
        self.getCatchments.clicked.connect(self.run)

    def disableUnnecessaryParams(self):
        if self.modesComboBox.currentText() == 'Pedestrian':
            self.trafficCheckBox.setEnabled(False)
            self.highwaysCheckBox.setEnabled(False)
            self.tollsCheckBox.setEnabled(False)
            self.highwaysCheckBox.setChecked(False)
            self.tollsCheckBox.setChecked(False)
            self.trafficCheckBox.setChecked(False)
        elif self.providersComboBox.currentText() == 'Skobbler':
            self.trafficCheckBox.setEnabled(False)
            self.highwaysCheckBox.setEnabled(True)
            self.tollsCheckBox.setEnabled(True)
        elif self.providersComboBox.currentText() == 'HERE':
            self.trafficCheckBox.setEnabled(True)
            self.highwaysCheckBox.setEnabled(False)
            self.tollsCheckBox.setEnabled(False)

    def changeProvider(self):
        self.modesComboBox.clear()
        if self.providersComboBox.currentText() == 'Skobbler':
            items = ['Car', 'Bike', 'Pedestrian']
            self.highwaysCheckBox.setEnabled(True)
            self.tollsCheckBox.setEnabled(True)
            self.trafficCheckBox.setEnabled(False)
            self.trafficCheckBox.setChecked(False)
            self.getKeyLabel.setText('<html><head/><body><p>\
                <a href="https://developer.skobbler.com/apikeys">\
                <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
            )
            self.keyLineEdit.setPlaceholderText('Insert Api Code')
        elif self.providersComboBox.currentText() == 'HERE':
            items = ['Car', 'Pedestrian', 'Truck']
            self.trafficCheckBox.setEnabled(True)
            self.highwaysCheckBox.setEnabled(False)
            self.highwaysCheckBox.setChecked(False)
            self.tollsCheckBox.setChecked(False)
            self.tollsCheckBox.setEnabled(False)
            self.getKeyLabel.setText('<html><head/><body><p>\
                <a href="https://developer.here.com/?create=Evaluation&keepState=true&step=account">\
                <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
            )
            self.keyLineEdit.setPlaceholderText('Insert App ID and App Code separated by \':\'')
        self.modesComboBox.addItems(items)
        self.loadKey()

    def saveKey(self):
        value = 'gissupport/location_lab/{}'.format(self.providersComboBox.currentText())
        QSettings().setValue(value, self.keyLineEdit.text())

    def loadKey(self):
        value = 'gissupport/location_lab/{}'.format(self.providersComboBox.currentText())
        self.keyLineEdit.setText(QSettings().value(value) or '')

    def getPoints(self, vl, features):
        trans = QgsCoordinateTransform(vl.crs(), QgsCoordinateReferenceSystem(4326))
        points = []
        for f in features:
            geom = f.geometry()
            geom.transform(trans)
            if geom.isMultipart():
                points.append(geom.asMultiPoint()[0])
            else:
                points.append(geom.asPoint())
        return points

    def requestApi(self, points):
        polygons = []
        not_found = 0
        if self.providersComboBox.currentText() == 'Skobbler':
            """
            Skobbler options:
            start           string      Center of RealReach™ in GPS coordinates: Latitude, Longitude
            transport       string      You can pick one of the transport options: pedestrian, bike, car
            range           int         The range for which we calculate RealReach™
            units           string      You can choose between sec and meter. 'Sec' is for time and 'Meter' is for distance
            toll            boolean     You can specify whether to avoid or not the use of toll roads in route calculation
            highways        boolean     Specifies whether to avoid or not the use of highways in route calculation
            """
            for p in points:
                params = {
                    'source': self.providersComboBox.currentText(),
                    'url': 'tor.skobbler.net/tor/RSngx/RealReach/json/20_5/en',
                    'key': self.keyLineEdit.text().strip(),
                    'start': '{x},{y}'.format(x=p[1], y=p[0]),
                    'transport': self.modesComboBox.currentText().lower(),
                    'range': self.valueSpinBox.value() if self.unitsComboBox.currentText() == 'Meters' else self.valueSpinBox.value() * 60,
                    'units': 'meter' if self.unitsComboBox.currentText() == 'Meters' else 'sec',
                    'nonReachable': '0',
                    'toll': '1' if self.tollsCheckBox.isChecked() else '0',
                    'highways': '1' if self.highwaysCheckBox.isChecked() else '0',
                    'response_type': 'gps'
                }
                link = 'http://{key}.{url}/{key}\
                    ?start={start}\
                    &transport={transport}\
                    &range={range}\
                    &units={units}\
                    &nonReachable={nonReachable}\
                    &toll={toll}\
                    &highways={highways}\
                    &response_type={response_type}'.replace(' ', '').format(**params)
                try:
                    r = urllib2.urlopen(link)
                except urllib2.HTTPError as e:
                    return 'invalid key'
                    continue
                data = json.loads(r.read())
                if data['status']['apiMessage'] == 'Route cannot be calculated.':
                    not_found += 1
                    continue
                params['coordinates'] = data['realReach']['gpsPoints']
                polygons.append(params)
        elif self.providersComboBox.currentText() == 'HERE':
            """
            HERE options:
            start           string      lat and lng
            mode            string      car, pedestrian or truck
            range           int         range for calculations
            rangetype       string      distance, time, consumption
            traffic         boolean     takes traffic
            """
            for p in points:
                params = {
                    'source': self.providersComboBox.currentText(),
                    'url': 'http://isoline.route.cit.api.here.com/routing/7.2/calculateisoline.json',
                    'key': self.keyLineEdit.text().strip().split(':'),
                    'start': '{x},{y}'.format(x=p[1], y=p[0]),
                    'transport': HERE_PARAMS[self.modesComboBox.currentText()],
                    'range': self.valueSpinBox.value() if self.unitsComboBox.currentText() == 'Meters' else self.valueSpinBox.value() * 60,
                    'units': 'distance' if self.unitsComboBox.currentText() == 'Meters' else 'time',
                    'traffic': 'enabled' if self.trafficCheckBox.isChecked() else 'disabled'
                }
                link = '{url}\
                    ?app_id={key[0]}\
                    &app_code={key[1]}\
                    &mode=fastest;{transport};traffic:{traffic}\
                    &start=geo!{start}\
                    &range={range}\
                    &rangetype={units}'.replace(' ', '').format(**params)
                try:
                    r = urllib2.urlopen(link)
                except urllib2.HTTPError as e:
                    return 'invalid key'
                    continue
                if r.getcode() == 403:
                    return 'forbidden'
                params['coordinates'] = json.loads(r.read())['response']['isoline'][0]['component'][0]['shape']
                polygons.append(params)
        if polygons and not_found:
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'{} catchments not found'.format(not_found),
                level=QgsMessageBar.INFO)
        return polygons

    def addPolygonsToMap(self, polygons):
        if not QgsMapLayerRegistry.instance().mapLayersByName('Location Lab - catchments'):
            vl = QgsVectorLayer('Polygon?crs=EPSG:4326', 'Location Lab - catchments', 'memory')
            pr = vl.dataProvider()
            vl.startEditing()
            pr.addAttributes(
                [
                    QgsField('id', QVariant.Int),
                    QgsField('provider', QVariant.String),
                    QgsField('mode', QVariant.String),
                    QgsField('value', QVariant.Int),
                    QgsField('units', QVariant.String),
                    QgsField('lat', QVariant.Double),
                    QgsField('lon', QVariant.Double),
                    QgsField('params', QVariant.String)
                ]
            )
            vl.commitChanges()
            QgsMapLayerRegistry.instance().addMapLayer(vl)
        vl = QgsMapLayerRegistry.instance().mapLayersByName('Location Lab - catchments')[0]
        pr = vl.dataProvider()
        next_id = len(vl.allFeatureIds()) + 1
        for p in polygons:
            feature = QgsFeature()
            points = []
            if p['source'] == 'Skobbler':
                coordinates_x = [c for c in p['coordinates'][8::2]]
                coordinates_y = [c for c in p['coordinates'][9::2]]
                for x, y in zip(coordinates_x, coordinates_y):
                    points.append(QgsPoint(x, y))
            elif p['source'] == 'HERE':
                coordinates = [c.split(',') for c in p['coordinates']]
                for xy in coordinates:
                    points.append(QgsPoint(float(xy[1]), float(xy[0])))
            feature = QgsFeature()
            feature.setGeometry(QgsGeometry.fromPolygon([points]))
            lat, lon = p['start'].split(',')
            for key in ['key', 'url', 'coordinates', 'start']: #unnecessary params
                p.pop(key)
            feature.setAttributes([
                next_id,
                self.providersComboBox.currentText(),
                self.modesComboBox.currentText().lower(),
                self.valueSpinBox.value(),
                self.unitsComboBox.currentText(),
                float(lat),
                float(lon),
                str(p)
            ])
            pr.addFeatures([feature])
            next_id += 1
        vl.updateExtents()
        self.iface.mapCanvas().setExtent(
            QgsCoordinateTransform(
                vl.crs(),
                self.iface.
                mapCanvas().
                mapRenderer().
                destinationCrs()).
            transform(vl.extent()))
        self.iface.mapCanvas().refresh()

    def changeLayerEvent(self):
        vl = self.layerComboBox.currentLayer()
        if not vl:
            return
        self.updateFeaturesQuantity()
        vl.selectionChanged.connect(self.updateFeaturesQuantity)

    def updateFeaturesQuantity(self):
        vl = self.layerComboBox.currentLayer()
        if not vl:
            return
        if self.selectCheckBox.isChecked():
            features = [f for f in vl.selectedFeatures()]
        else:
            features = [f for f in vl.getFeatures()]
        self.pointsLabel.setText('Number of points: {}'.format(len(features)))
        if len(features) > 5:
            self.getCatchments.setEnabled(False)
            self.pointsLabel.setText('Number of points: {} (limit is 5)'.format(len(features)))
        elif len(features) == 0:
            self.getCatchments.setEnabled(False)
        else:
            self.getCatchments.setEnabled(True)

    def show(self):
        self.changeLayerEvent()
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self)
        super(CatchmentsModule, self).show()

    def checkApiKey(self):
        if self.providersComboBox.currentText() == 'HERE':
            if len(self.keyLineEdit.text().split(':')) != 2:
                self.iface.messageBar().pushMessage(
                    u'Catchments',
                    u'Invalid api key format, required app_id:app_code',
                    level=QgsMessageBar.WARNING)
                return False
        return True

    def run(self):
        vl = self.layerComboBox.currentLayer()
        if self.selectCheckBox.isChecked():
            features = [f for f in vl.selectedFeatures()]
        else:
            features = [f for f in vl.getFeatures()]
        if not features:
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'No geometry',
                level=QgsMessageBar.WARNING)
            return
        points = self.getPoints(vl, features)
        if not self.checkApiKey():
            return
        polygons = self.requestApi(points)
        if not polygons:
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'Catchments not found',
                level=QgsMessageBar.WARNING)
            return
        elif polygons == 'invalid key':
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'Invalid API key',
                level=QgsMessageBar.WARNING)
            return 
        elif polygons == 'forbidden':
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'These credentials do not authorize access',
                level=QgsMessageBar.WARNING)
            return 
        self.addPolygonsToMap(polygons)
コード例 #9
0
class FieldMappingDialog(QDialog, FORM_CLASS):

    """Dialog implementation class for the InaSAFE field mapping tool."""

    def __init__(self, parent=None, iface=None, setting=None):
        """Constructor."""
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE Field Mapping Tool'))
        icon = resources_path('img', 'icons', 'show-mapping-tool.svg')
        self.setWindowIcon(QIcon(icon))
        self.parent = parent
        self.iface = iface
        if setting is None:
            setting = QSettings()
        self.setting = setting

        self.keyword_io = KeywordIO()

        self.layer = None
        self.metadata = {}

        self.layer_input_layout = QHBoxLayout()
        self.layer_label = QLabel(tr('Layer'))
        self.layer_combo_box = QgsMapLayerComboBox()
        # Filter only for Polygon and Point
        self.layer_combo_box.setFilters(
            QgsMapLayerProxyModel.PolygonLayer |
            QgsMapLayerProxyModel.PointLayer)
        # Filter out a layer that don't have layer groups
        excepted_layers = []
        for i in range(self.layer_combo_box.count()):
            layer = self.layer_combo_box.layer(i)
            try:
                keywords = self.keyword_io.read_keywords(layer)
            except (KeywordNotFoundError, NoKeywordsFoundError):
                excepted_layers.append(layer)
                continue
            layer_purpose = keywords.get('layer_purpose')
            if not layer_purpose:
                excepted_layers.append(layer)
                continue
            if layer_purpose == layer_purpose_exposure['key']:
                layer_subcategory = keywords.get('exposure')
            elif layer_purpose == layer_purpose_hazard['key']:
                layer_subcategory = keywords.get('hazard')
            else:
                layer_subcategory = None

            field_groups = get_field_groups(layer_purpose, layer_subcategory)
            if len(field_groups) == 0:
                excepted_layers.append(layer)
                continue
        self.layer_combo_box.setExceptedLayerList(excepted_layers)

        # Select the active layer.
        if self.iface.activeLayer():
            found = self.layer_combo_box.findText(
                self.iface.activeLayer().name())
            if found > -1:
                self.layer_combo_box.setLayer(self.iface.activeLayer())

        self.field_mapping_widget = None
        self.main_stacked_widget.setCurrentIndex(1)

        # Input
        self.layer_input_layout.addWidget(self.layer_label)
        self.layer_input_layout.addWidget(self.layer_combo_box)

        self.header_label = QLabel()
        self.header_label.setWordWrap(True)
        self.main_layout.addWidget(self.header_label)
        self.main_layout.addLayout(self.layer_input_layout)

        # Signal
        self.layer_combo_box.layerChanged.connect(self.set_layer)

        if self.layer_combo_box.currentLayer():
            self.set_layer(self.layer_combo_box.currentLayer())

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)

        # Set up things for ok button
        self.ok_button = self.button_box.button(QDialogButtonBox.Ok)
        self.ok_button.clicked.connect(self.accept)

        # Set up things for cancel button
        self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel)
        self.cancel_button.clicked.connect(self.reject)

    def set_layer(self, layer=None, keywords=None):
        """Set layer and update UI accordingly.

        :param layer: A QgsVectorLayer.
        :type layer: QgsVectorLayer

        :param keywords: Keywords for the layer.
        :type keywords: dict, None
        """
        if self.field_mapping_widget is not None:
            self.field_mapping_widget.setParent(None)
            self.field_mapping_widget.close()
            self.field_mapping_widget.deleteLater()
            self.main_layout.removeWidget(self.field_mapping_widget)

        if layer:
            self.layer = layer
        else:
            self.layer = self.layer_combo_box.currentLayer()
        if not self.layer:
            return

        if keywords is not None:
            self.metadata = keywords
        else:
            # Always read from metadata file.
            try:
                self.metadata = self.keyword_io.read_keywords(self.layer)
            except (
                    NoKeywordsFoundError,
                    KeywordNotFoundError,
                    MetadataReadError) as e:
                raise e
        if 'inasafe_default_values' not in self.metadata:
            self.metadata['inasafe_default_values'] = {}
        if 'inasafe_fields' not in self.metadata:
            self.metadata['inasafe_fields'] = {}
        self.field_mapping_widget = FieldMappingWidget(
            parent=self, iface=self.iface)
        self.field_mapping_widget.set_layer(self.layer, self.metadata)
        self.field_mapping_widget.show()
        self.main_layout.addWidget(self.field_mapping_widget)

        # Set header label
        group_names = [
            self.field_mapping_widget.tabText(i) for i in range(
                self.field_mapping_widget.count())]
        if len(group_names) == 0:
            header_text = tr(
                'There is no field group for this layer. Please select '
                'another layer.')
            self.header_label.setText(header_text)
            return
        elif len(group_names) == 1:
            pretty_group_name = group_names[0]
        elif len(group_names) == 2:
            pretty_group_name = group_names[0] + tr(' and ') + group_names[1]
        else:
            pretty_group_name = ', '.join(group_names[:-1])
            pretty_group_name += tr(', and {0}').format(group_names[-1])
        header_text = tr(
            'Please fill the information for every tab to determine the '
            'attribute for {0} group.').format(pretty_group_name)
        self.header_label.setText(header_text)

    @pyqtSlot()
    @pyqtSignature('bool')  # prevents actions being handled twice
    def help_toggled(self, flag):
        """Show or hide the help tab in the stacked widget.

        .. versionadded: 3.2.1

        :param flag: Flag indicating whether help should be shown or hidden.
        :type flag: bool
        """
        if flag:
            self.help_button.setText(self.tr('Hide Help'))
            self.show_help()
        else:
            self.help_button.setText(self.tr('Show Help'))
            self.hide_help()

    def hide_help(self):
        """Hide the usage info from the user.

        .. versionadded: 3.2.1
        """
        self.main_stacked_widget.setCurrentIndex(1)

    def show_help(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        self.main_stacked_widget.setCurrentIndex(0)
        header = html_header()
        footer = html_footer()

        string = header

        message = field_mapping_help()

        string += message.to_html()
        string += footer

        self.help_web_view.setHtml(string)

    def save_metadata(self):
        """Save metadata based on the field mapping state."""
        metadata = self.field_mapping_widget.get_field_mapping()
        for key, value in metadata['fields'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_default_values']:
                self.metadata['inasafe_default_values'].pop(key)
            if value is None or value == []:
                if key in self.metadata['inasafe_fields']:
                    self.metadata['inasafe_fields'].pop(key)
            else:
                self.metadata['inasafe_fields'][key] = value

        for key, value in metadata['values'].items():
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_fields']:
                self.metadata['inasafe_fields'].pop(key)
            if value is None:
                if key in self.metadata['inasafe_default_values']:
                    self.metadata['inasafe_default_values'].pop(key)
            else:
                self.metadata['inasafe_default_values'][key] = value

        # Save metadata
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=self.metadata)
        except InaSAFEError, e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))

        # Update setting fir recent value
        if self.metadata.get('inasafe_default_values'):
            for key, value in \
                    self.metadata['inasafe_default_values'].items():
                set_inasafe_default_value_qsetting(
                    self.setting, key, RECENT, value)
コード例 #10
0
class PerimeterPuCaWidget(PuCaWidget):
    """A widget for 'perimeter' check."""
    def _build_widgets(self):
        """Builds own widgets."""

        self.lastPerimeterLayer = None

        self.perimeterMapLayerComboBox = QgsMapLayerComboBox(self)
        self.perimeterMapLayerComboBox.setObjectName(
            u'perimeterMapLayerComboBox')
        self.perimeterMapLayerComboBox.setFilters(
            QgsMapLayerProxyModel.PolygonLayer)
        self.perimeterMapLayerComboBox.activated.connect(
            self._sync_perimeter_map_layer_combo_box)
        QgsMapLayerRegistry.instance().layersAdded.connect(
            self._rollback_perimeter_layer)
        QgsMapLayerRegistry.instance().layersRemoved.connect(
            self._reset_perimeter_layer)
        self.set_perimeter_layer(self.lastPerimeterLayer)
        self.vBoxLayout.addWidget(self.perimeterMapLayerComboBox)

    def set_perimeter_layer(self, perimeterLayer, lastPerimeterLayer=True):
        """Sets the perimeter layer in the perimeterMapLayerComboBox.
        
        Args:
            perimeterLayer (QgsVectorLayer): A reference to the perimeter layer.
            lastPerimeterLayer (bool): True to set self.lastPerimeterLayer,
                False otherwise.
        
        """

        if lastPerimeterLayer:
            self.lastPerimeterLayer = perimeterLayer

        self.perimeterMapLayerComboBox.setLayer(perimeterLayer)

    def _sync_perimeter_map_layer_combo_box(self):
        """Synchronizes perimeter map layer combo boxes.
        
        Synchronizes with the perimeterMapLayerComboBox in the editPuWidget.
        
        """

        perimeterLayer = self.perimeterMapLayerComboBox.currentLayer()

        if perimeterLayer != self.lastPerimeterLayer:
            self.lastPerimeterLayer = perimeterLayer

            self.dW.stackedWidget.editPuWidget.set_perimeter_layer(
                perimeterLayer)

    def _reset_perimeter_layer(self):
        """Resets the perimeter layer."""

        layers = self.iface.legendInterface().layers()

        if self.lastPerimeterLayer not in layers:
            self.set_perimeter_layer(None)

    def _rollback_perimeter_layer(self):
        """Rolls the perimeter layer back."""

        if self.lastPerimeterLayer == None:
            self.set_perimeter_layer(self.lastPerimeterLayer, False)
        else:
            self.lastPerimeterLayer = \
                self.perimeterMapLayerComboBox.currentLayer()

    def execute(self, layer):
        """Executes the check.
        
        Args:
            layer (QgsVectorLayer): A reference to the active layer.
        
        """

        try:
            perimeterLayer = self.perimeterMapLayerComboBox.currentLayer()

            if not self.dW.check_perimeter_layer(perimeterLayer, layer,
                                                 self.pW):
                return

            if perimeterLayer.featureCount() == 0:
                self.pW.set_text_statusbar.emit(
                    u'Vrstva obvodu neobsahuje žádný prvek.', 10, True)
                return

            self.pW.set_text_statusbar.emit(u'Provádím kontrolu - obvodem...',
                                            0, False)

            layer.removeSelection()
            perimeterLayer.removeSelection()

            processing.runalg('qgis:selectbylocation', layer, perimeterLayer,
                              u'within', 0, 0)

            layer.invertSelection()

            featureCount = layer.selectedFeatureCount()

            duration = 10
            warning = False

            if featureCount == 0:
                self.pW.set_text_statusbar.emit(
                    u'Uvnitř obvodu jsou všechny parcely.', duration, warning)
            elif featureCount == 1:
                self.pW.set_text_statusbar.emit(
                    u'Uvnitř obvodu není {} parcela'.format(featureCount),
                    duration, warning)
            elif 1 < featureCount < 5:
                self.pW.set_text_statusbar.emit(
                    u'Uvnitř obvodu nejsou {} parcely.'.format(featureCount),
                    duration, warning)
            elif 5 <= featureCount:
                self.pW.set_text_statusbar.emit(
                    u'Uvnitř obvodu není {} parcel.'.format(featureCount),
                    duration, warning)
        except self.dW.puError:
            QgsApplication.processEvents()
        except:
            QgsApplication.processEvents()

            currentCheckAnalysisName = \
                self.pW.checkAnalysisComboBox.currentText()

            self.dW.display_error_messages(
                self.pW,
                u'Error executing "{}".'.format(currentCheckAnalysisName),
                u'Chyba při provádění "{}".'.format(currentCheckAnalysisName))
コード例 #11
0
class DSMGenerator:
    """QGIS Plugin Implementation."""
    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
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'DSMGenerator_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Create the dialog (after translation) and keep reference
        self.dlg = DSMGeneratorDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&DSM Generator')
        # TODO: We are going to let the user set this up in a future iteration
        # self.toolbar = self.iface.addToolBar(u'DSMGenerator')
        # self.toolbar.setObjectName(u'DSMGenerator')

        # Declare variables
        self.OSMoutputfile = None
        self.DSMoutputfile = None

        if not (os.path.isdir(self.plugin_dir + '/temp')):
            os.mkdir(self.plugin_dir + '/temp')

        # Access the raster layer
        self.layerComboManagerDEM = QgsMapLayerComboBox(self.dlg.widgetRaster)
        self.layerComboManagerDEM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDEM.setFixedWidth(175)
        self.layerComboManagerDEM.setCurrentIndex(-1)

        # Access the vector layer and an attribute field
        self.layerComboManagerPolygon = QgsMapLayerComboBox(
            self.dlg.widgetPolygon)
        self.layerComboManagerPolygon.setCurrentIndex(-1)
        self.layerComboManagerPolygon.setFilters(
            QgsMapLayerProxyModel.PolygonLayer)
        self.layerComboManagerPolygon.setFixedWidth(175)
        self.layerComboManagerPolygonField = QgsFieldComboBox(
            self.dlg.widgetField)
        self.layerComboManagerPolygonField.setFilters(
            QgsFieldProxyModel.Numeric)
        self.layerComboManagerPolygonField.setFixedWidth(150)
        self.layerComboManagerPolygon.layerChanged.connect(
            self.layerComboManagerPolygonField.setLayer)

        # Set up of DSM file save dialog
        self.DSMfileDialog = QFileDialog()
        self.dlg.saveButton.clicked.connect(self.savedsmfile)

        # Set up of OSM polygon file save dialog
        self.OSMfileDialog = QFileDialog()
        self.dlg.savePolygon.clicked.connect(self.saveosmfile)

        # Set up for the Help button
        self.dlg.helpButton.clicked.connect(self.help)

        # Set up for the Close button
        self.dlg.closeButton.clicked.connect(self.resetPlugin)

        # Set up for the Run button
        self.dlg.runButton.clicked.connect(self.start_progress)

        # Set up extent
        self.dlg.canvasButton.toggled.connect(self.checkbox_canvas)
        # self.dlg.layerButton.toggled.connect(self.checkbox_layer)

        self.layerComboManagerExtent = QgsMapLayerComboBox(
            self.dlg.widgetLayerExtent)
        self.layerComboManagerExtent.setCurrentIndex(-1)
        self.layerComboManagerExtent.layerChanged.connect(self.checkbox_layer)
        self.layerComboManagerExtent.setFixedWidth(175)

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        return QCoreApplication.translate('DSMGenerator', message)

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

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        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)

        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/DSMGenerator/icon.png'
        self.add_action(icon_path,
                        text=self.tr(u'DSM Generator'),
                        callback=self.run,
                        parent=self.iface.mainWindow())

    def savedsmfile(self):
        self.DSMoutputfile = self.DSMfileDialog.getSaveFileName(
            None, "Save File As:", None, "Raster Files (*.tif)")
        self.dlg.DSMtextOutput.setText(self.DSMoutputfile)

    def saveosmfile(self):
        self.OSMoutputfile = self.OSMfileDialog.getSaveFileName(
            None, "Save File As:", None, "Shapefiles (*.shp)")
        self.dlg.OSMtextOutput.setText(self.OSMoutputfile)

    def checkbox_canvas(self):
        extent = self.iface.mapCanvas().extent()
        self.dlg.lineEditNorth.setText(str(extent.yMaximum()))
        self.dlg.lineEditSouth.setText(str(extent.yMinimum()))
        self.dlg.lineEditWest.setText(str(extent.xMinimum()))
        self.dlg.lineEditEast.setText(str(extent.xMaximum()))

    def checkbox_layer(self):
        dem_layer_extent = self.layerComboManagerExtent.currentLayer()
        if dem_layer_extent:
            extent = dem_layer_extent.extent()
            self.dlg.lineEditNorth.setText(str(extent.yMaximum()))
            self.dlg.lineEditSouth.setText(str(extent.yMinimum()))
            self.dlg.lineEditWest.setText(str(extent.xMinimum()))
            self.dlg.lineEditEast.setText(str(extent.xMaximum()))

    # Help button
    def help(self):
        url = "http://umep-docs.readthedocs.io/en/latest/pre-processor/Spatial%20Data%20DSM%20Generator.html"
        webbrowser.open_new_tab(url)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&DSM Generator'), action)
            # self.iface.removeToolBarIcon(action)
        # remove the toolbar
        # del self.toolbar

    def run(self):
        self.dlg.show()
        self.dlg.exec_()

    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()

        #print "finished run: %s\n\n" % (datetime.datetime.now() - start)

    def resetPlugin(self):  # Reset plugin
        self.dlg.canvasButton.setAutoExclusive(False)
        self.dlg.canvasButton.setChecked(False)
        self.dlg.layerButton.setAutoExclusive(False)
        self.dlg.layerButton.setChecked(False)
        self.dlg.checkBoxOSM.setCheckState(0)
        self.dlg.checkBoxPolygon.setCheckState(0)

        # Extent
        self.layerComboManagerExtent.setCurrentIndex(-1)
        self.dlg.lineEditNorth.setText("")
        self.dlg.lineEditSouth.setText("")
        self.dlg.lineEditWest.setText("")
        self.dlg.lineEditEast.setText("")

        # Output boxes
        self.dlg.OSMtextOutput.setText("")
        self.dlg.DSMtextOutput.setText("")

        # Input raster
        self.layerComboManagerDEM.setCurrentIndex(-1)

        # Input polygon
        self.layerComboManagerPolygon.setCurrentIndex(-1)

        # Progress bar
        self.dlg.progressBar.setValue(0)

        # Spin boxes
        self.dlg.spinBox.setValue(2)
        self.dlg.doubleSpinBoxBldLvl.setValue(2.5)
コード例 #12
0
class IntersectLPISModule(QDialog, FORM_CLASS):
    def __init__(self, parent, parents=None):
        """Constructor."""
        super(IntersectLPISModule, self).__init__(parents)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

        self.layerComboBox = QgsMapLayerComboBox(self)
        self.layerComboBox.setObjectName("layerComboBox")
        self.verticalLayout.addWidget(self.layerComboBox)
        self.verticalLayout_2.addLayout(self.verticalLayout)

        self.parent = parent
        self.iface = parent.iface
        self.keyLineEdit.setText(QSettings().value('gissupport/api/key'))
        self.saveKeyButton.clicked.connect(self.saveKey)
        self.addWMSButton.clicked.connect(self.addWMS)
        self.layerComboBox.setFocus()

    def addWMS(self):
        if not QgsProject.instance().mapLayersByName('Dzialki LPIS'):
            url = ("contextualWMSLegend=0&"
                   "crs=EPSG:2180&"
                   "dpiMode=7&"
                   "featureCount=10&"
                   "format=image/png8&"
                   "layers=NumeryDzialek&layers=Dzialki&"
                   "styles=&styles=&"
                   "url=http://mapy.geoportal.gov.pl"
                   "/wss/service/pub/guest/G2_GO_WMS/MapServer/WMSServer")
            layer = QgsRasterLayer(url, 'Dzialki LPIS', 'wms')
            QgsProject.instance().addMapLayer(layer)
        else:
            pass

    def saveKey(self):
        QSettings().setValue('gissupport/api/key', self.keyLineEdit.text())

    def createOutputLayer(self, resp):
        if not QgsProject.instance().mapLayersByName('Przeciecia LPIS'):
            vl = QgsVectorLayer("MultiPolygon?crs=EPSG:2180",
                                "Przeciecia LPIS", "memory")
            pr = vl.dataProvider()
            vl.startEditing()
            pr.addAttributes([
                QgsField("id", QVariant.String),
                QgsField("objectid", QVariant.String),
                QgsField("identyfika", QVariant.String),
                QgsField("powierzchn", QVariant.String),
                QgsField("teryt", QVariant.String),
                QgsField("numer", QVariant.String),
                QgsField("obreb", QVariant.String),
                QgsField("wojewodztw", QVariant.String),
                QgsField("powiat", QVariant.String),
                QgsField("gmina", QVariant.String),
                QgsField("data_od", QVariant.String),
                QgsField("shape_leng", QVariant.String),
                QgsField("shape_area", QVariant.String)
            ])
            vl.commitChanges()
            QgsProject.instance().addMapLayer(vl)
        for wkt in resp['data']:
            feature = QgsFeature()
            feature.setGeometry(QgsGeometry.fromWkt(wkt[0]))
            feature.setAttributes([a for a in wkt[1:]])
            vl = QgsProject.instance().mapLayersByName('Przeciecia LPIS')[0]
            pr = vl.dataProvider()
            pr.addFeatures([feature])
        vl.updateExtents()
        self.iface.mapCanvas().setExtent(
            QgsCoordinateTransform(
                vl.crs(),
                self.iface.mapCanvas().mapSettings().destinationCrs(),
                QgsProject.instance()).transform(vl.extent()))
        self.iface.mapCanvas().refresh()
        if resp['status'] == 'limited':
            self.iface.messageBar().pushMessage(
                'Przeciecia LPIS',
                u'Wynik został ograniczony do %d działek \
                ze względu na ograniczenia serwera' % len(resp['data']),
                level=Qgis.Warning)
        else:
            self.iface.messageBar().pushMessage('Przeciecia LPIS',
                                                u'Liczba działek przeciętych \
                przez warstwę: %d' % len(resp['data']),
                                                level=Qgis.Info)

    def findPlots(self):
        vl = self.layerComboBox.currentLayer()
        trans = QgsCoordinateTransform(vl.crs(),
                                       QgsCoordinateReferenceSystem(2180),
                                       QgsProject.instance())
        if not self.selectCheckBox.isChecked():
            geom = QgsGeometry().unaryUnion(
                [QgsGeometry(f.geometry()) for f in vl.getFeatures()])
            geom.transform(trans)
            if geom.isEmpty():
                self.iface.messageBar().pushMessage(
                    'Przeciecia LPIS',
                    u'Brak obiektów na warstwie',
                    level=Qgis.Warning)
                return False
        else:
            geom = QgsGeometry().unaryUnion(
                [QgsGeometry(f.geometry()) for f in vl.selectedFeatures()])
            geom.transform(trans)
            if geom.isEmpty():
                self.iface.messageBar().pushMessage(
                    'Przeciecia LPIS',
                    u'Brak zaznaczonych obiektów',
                    level=Qgis.Warning)
                return False
        params = {'wkt': geom.asWkt(), 'key': self.keyLineEdit.text().strip()}
        data = ''
        try:
            r = urllib.request.urlopen(
                'http://api.gis-support.pl/intersect?key=' + params['key'],
                json.dumps(params).encode('utf-8'))
            if r.getcode() == 403:
                self.iface.messageBar().pushMessage(
                    u'Przecięcia LPIS',
                    u'Nieprawidłowy klucz GIS Support',
                    level=Qgis.Critical)
                return False
            resp = json.loads(r.read().decode())
            data = resp['data']
        except:
            data = 'app connection problem'
        if not data:
            self.iface.messageBar().pushMessage(
                u'Przecięcia LPIS',
                u'Warstwa nie przecina żadnej działki',
                level=Qgis.Warning)
        elif data == 'db connection problem':
            self.iface.messageBar().pushMessage(u'Przecięcia LPIS',
                                                u'Problem połączenia z bazą',
                                                level=Qgis.Critical)
        elif data == 'app connection problem':
            self.iface.messageBar().pushMessage(
                u'Przecięcia LPIS',
                u'Problem połączenia z aplikacją',
                level=Qgis.Critical)
        else:
            self.createOutputLayer(resp)
            return True
        return False

    def accept(self):
        if not self.layerComboBox.currentLayer():
            self.iface.messageBar().pushMessage(u'Przecięcia LPIS',
                                                u'Podaj warstwę do przecięcia',
                                                level=Qgis.Warning)
        elif self.findPlots():
            super(IntersectLPISModule, self).accept()
コード例 #13
0
class Catchments(QDockWidget, FORM_CLASS):
    def __init__(self, parent, parents=None):
        super(Catchments, self).__init__(parents)
        self.setupUi(self)
        self.parent = parent
        self.iface = parent.iface
        self.HERE_PARAMS = {
            self.tr('Car'): 'car',
            self.tr('Pedestrian'): 'pedestrian',
            self.tr('Truck'): 'truck'
        }
        self.OPENROUTE_PARAMS = {
            self.tr('Bike'): 'cycling-regular',
            self.tr('Car'): 'driving-car',
            self.tr('Pedestrian'): 'foot-walking',
            self.tr('Truck'): 'driving-hgv'
        }
        self.fillDialog()

    def tr(self, message):
        return QCoreApplication.translate('Catchments', message)

    def fillDialog(self):
        self.layerComboBox = QgsMapLayerComboBox(self)
        self.layerComboBox.setObjectName('layerComboBox')
        self.layerComboBox.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.fieldsComboBox.setFilters(QgsFieldProxyModel.Int
                                       | QgsFieldProxyModel.LongLong)
        self.layersLayout.addWidget(self.layerComboBox)
        self.providersComboBox.addItems(['HERE', 'OpenRouteService'])
        self.modesComboBox.addItems(
            [self.tr('Car'),
             self.tr('Pedestrian'),
             self.tr('Truck')])
        self.trafficCheckBox.setEnabled(True)
        self.unitsComboBox.addItems([self.tr('Minutes'), self.tr('Meters')])
        self.valueSpinBox.setMinimum(1)
        self.valueSpinBox.setMaximum(99999)
        self.valueSpinBox.setValue(10)
        self.getCatchments.setEnabled(False)
        self.getKeyLabel.setText('<html><head/><body><p>\
            <a href="https://developer.here.com/?create=Evaluation&keepState=true&step=account">\
            <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
                                 )
        self.connectFunctions()
        self.loadKey()

    def connectFunctions(self):
        self.providersComboBox.currentIndexChanged.connect(self.changeProvider)
        self.keyLineEdit.textChanged.connect(self.saveKey)
        self.layerComboBox.currentIndexChanged.connect(self.changeLayerEvent)
        self.modesComboBox.currentIndexChanged.connect(
            self.disableUnnecessaryParams)
        self.selectCheckBox.stateChanged.connect(self.updateFeaturesQuantity)
        self.getCatchments.clicked.connect(self.run)

    def disableUnnecessaryParams(self):
        if self.modesComboBox.currentText() == self.tr('Pedestrian'):
            self.trafficCheckBox.setEnabled(False)
            self.trafficCheckBox.setChecked(False)
        elif self.providersComboBox.currentText() == 'HERE':
            self.trafficCheckBox.setEnabled(True)

    def changeProvider(self):
        self.modesComboBox.clear()
        if self.providersComboBox.currentText() == 'HERE':
            self.getCatchments.setToolTip('')
            items = [self.tr('Car'), self.tr('Pedestrian'), self.tr('Truck')]
            self.trafficCheckBox.setEnabled(True)
            self.getKeyLabel.setText('<html><head/><body><p>\
                <a href="https://developer.here.com/?create=Evaluation&keepState=true&step=account">\
                <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
                                     )
            self.keyLineEdit.setPlaceholderText(
                self.tr('Insert App ID:App Code or apiKey'))
        elif self.providersComboBox.currentText() == 'OpenRouteService':
            self.getCatchments.setToolTip(
                self.
                tr('Free Plan Directions (2.000 requests per day @40 requests per minute)'
                   ))
            items = [
                self.tr('Bike'),
                self.tr('Car'),
                self.tr('Pedestrian'),
                self.tr('Truck')
            ]
            self.trafficCheckBox.setEnabled(False)
            self.getKeyLabel.setText('<html><head/><body><p>\
                <a href="https://openrouteservice.org/plans/">\
                <span style=" text-decoration: underline; color:#0000ff;">Get key</span></a></p></body></html>'
                                     )
            self.keyLineEdit.setPlaceholderText(self.tr('Insert API key'))
        self.updateFeaturesQuantity()
        self.modesComboBox.addItems(items)
        self.loadKey()

    def saveKey(self):
        value = 'gissupport/location_lab/{}'.format(
            self.providersComboBox.currentText())
        QSettings().setValue(value, self.keyLineEdit.text())

    def loadKey(self):
        value = 'gissupport/location_lab/{}'.format(
            self.providersComboBox.currentText())
        self.keyLineEdit.setText(QSettings().value(value) or '')

    def getPoints(self, vl, features):
        trans = QgsCoordinateTransform(vl.crs(),
                                       QgsCoordinateReferenceSystem(4326),
                                       QgsProject().instance())
        points = []
        for f in features:
            geom = f.geometry()
            geom.transform(trans)
            if geom.isMultipart():
                points.append(geom.asMultiPoint()[0])
            else:
                points.append(geom.asPoint())
        return points

    def requestApi(self, points):

        polygons = []
        not_found = 0
        if self.providersComboBox.currentText() == 'HERE':
            """
            HERE options:
            start           string      lat and lng
            mode            string      car, pedestrian or truck
            range           int         range for calculations
            rangetype       string      distance, time, consumption
            traffic         boolean     takes traffic
            """

            key = self.keyLineEdit.text().strip().split(':')
            with_id = False
            if len(key) == 1:
                url = 'https://isoline.route.ls.hereapi.com/routing/7.2/calculateisoline.json'
            else:
                url = 'https://isoline.route.cit.api.here.com/routing/7.2/calculateisoline.json'
                with_id = True
            for p in points:
                params = {
                    'source':
                    self.providersComboBox.currentText(),
                    'url':
                    url,
                    'key':
                    key,
                    'coords':
                    '{x},{y}'.format(x=p[1], y=p[0]),
                    'transport':
                    self.HERE_PARAMS[self.modesComboBox.currentText()],
                    'range':
                    self.valueSpinBox.value()
                    if self.unitsComboBox.currentText() == self.tr('Meters')
                    else self.valueSpinBox.value() * 60,
                    'units':
                    'distance' if self.unitsComboBox.currentText()
                    == self.tr('Meters') else 'time',
                    'traffic':
                    'enabled'
                    if self.trafficCheckBox.isChecked() else 'disabled'
                }
                if not with_id:
                    link = '{url}\
                        ?apiKey={key[0]}\
                        &mode=fastest;{transport};traffic:{traffic}\
                        &range={range}\
                        &rangetype={units}'.replace(' ', '').format(**params)
                else:
                    link = '{url}\
                        ?app_id={key[0]}\
                        &app_code={key[1]}\
                        &mode=fastest;{transport};traffic:{traffic}\
                        &range={range}\
                        &rangetype={units}'.replace(' ', '').format(**params)
                coords = params['coords']
                if self.pointsRouteStartCheckBox.isChecked():
                    link += f'&start=geo!{coords}'
                else:
                    link += f'&destination=geo!{coords}'
                try:
                    r = urllib.request.urlopen(link)
                except urllib.error.HTTPError as e:
                    if e.code == 401:
                        return 'invalid key'
                    elif e.code == 403:
                        return 'forbidden'
                    else:
                        continue
                except urllib.error.URLError as e:
                    return f'URLError: {str(e)}'
                params['coordinates'] = json.loads(r.read().decode(
                ))['response']['isoline'][0]['component'][0]['shape']
                polygons.append(params)
        elif self.providersComboBox.currentText() == 'OpenRouteService':
            """
            OpenRouteService options:
            locations      array       lng
            range          array(int)  seconds for time, meters for distance
            range_type     string      time/distance
            profile        string      driving-car/driving-hgv/foot-walking (query parameter)
            """

            location_coords = [[p[0], p[1]] for p in points]
            data = {
                'range': [self.valueSpinBox.value()] if self.unitsComboBox.currentText() == self.tr('Meters')\
                    else [self.valueSpinBox.value() * 60],
                'range_type': 'distance' if self.unitsComboBox.currentText() == self.tr('Meters') else 'time',
                'attributes': ['reachfactor']
            }
            if self.pointsRouteStartCheckBox.isChecked():
                data['location_type'] = 'destination'

            locations_div = [
                location_coords[i:i + 5]
                for i in range(0, len(location_coords), 5)
            ]
            for chunk in locations_div:
                self._requestORS(data, chunk, polygons)

        if polygons and not_found:
            self.iface.messageBar().pushMessage(
                u'Catchments',
                u'{} {}'.format(not_found, self.tr('catchments not found')),
                level=Qgis.Info)
        return polygons

    def addPolygonsToMap(self, polygons):
        if not QgsProject.instance().mapLayersByName(
                'Location Lab - catchments'):
            vl = QgsVectorLayer('Polygon?crs=EPSG:4326',
                                'Location Lab - catchments', 'memory')
            pr = vl.dataProvider()
            vl.startEditing()
            pr.addAttributes([
                QgsField('id', QVariant.Int),
                QgsField(self.tr('provider'), QVariant.String),
                QgsField(self.tr('mode'), QVariant.String),
                QgsField(self.tr('value'), QVariant.Int),
                QgsField(self.tr('units'), QVariant.String),
                QgsField(self.tr('lat'), QVariant.Double),
                QgsField(self.tr('lon'), QVariant.Double),
                QgsField('params', QVariant.String)
            ])
            vl.commitChanges()
            QgsProject.instance().addMapLayer(vl)
        vl = QgsProject.instance().mapLayersByName(
            'Location Lab - catchments')[0]
        pr = vl.dataProvider()
        next_id = len(vl.allFeatureIds()) + 1
        id_field = self.fieldsComboBox.currentField()
        if id_field:
            layer = self.layerComboBox.currentLayer()
            new_ids = [
                feature.attribute(id_field)
                for feature in list(layer.getFeatures())
            ]
        for index, p in enumerate(polygons):
            feature = QgsFeature()
            points = []
            if p['source'] == 'HERE' or p['source'] == 'OpenRouteService':
                coordinates = [c.split(',') for c in p['coordinates']]
                for xy in coordinates:
                    points.append(QgsPointXY(float(xy[1]), float(xy[0])))
            feature = QgsFeature()
            feature.setGeometry(QgsGeometry.fromPolygonXY([points]))
            lat, lon = p['coords'].split(',')
            for key in ['key', 'url', 'coordinates',
                        'start']:  #unnecessary params
                if key in p.keys():
                    p.pop(key)
            feature.setAttributes([
                next_id if not id_field else new_ids[index],
                self.providersComboBox.currentText(),
                self.modesComboBox.currentText().lower(),
                self.valueSpinBox.value(),
                self.unitsComboBox.currentText(),
                float(lat),
                float(lon),
                str(p)
            ])
            pr.addFeatures([feature])
            next_id += 1
        vl.updateExtents()
        self.iface.mapCanvas().setExtent(
            QgsCoordinateTransform(
                vl.crs(),
                self.iface.mapCanvas().mapSettings().destinationCrs(),
                QgsProject().instance()).transform(vl.extent()))
        self.iface.mapCanvas().refresh()

    def changeLayerEvent(self):
        vl = self.layerComboBox.currentLayer()
        self.fieldsComboBox.setLayer(vl)
        if not vl:
            return
        self.updateFeaturesQuantity()
        vl.selectionChanged.connect(self.updateFeaturesQuantity)
        vl.layerModified.connect(self.updateFeaturesQuantity)

    def updateFeaturesQuantity(self):
        vl = self.layerComboBox.currentLayer()
        if not vl:
            return
        if self.selectCheckBox.isChecked():
            features = [f for f in vl.selectedFeatures()]
        else:
            features = [f for f in vl.getFeatures()]
        self.pointsLabel.setText('{} {}'.format(self.tr('Number of points:'),
                                                len(features)))
        if len(features) == 0:
            self.getCatchments.setEnabled(False)
        else:
            self.getCatchments.setEnabled(True)

    def show(self):
        self.changeLayerEvent()
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self)
        super(Catchments, self).show()

    def run(self):
        vl = self.layerComboBox.currentLayer()
        if self.selectCheckBox.isChecked():
            features = [f for f in vl.selectedFeatures()]
        else:
            features = [f for f in vl.getFeatures()]
        if not features:
            self.iface.messageBar().pushMessage(u'Catchments',
                                                self.tr(u'No geometry'),
                                                level=Qgis.Warning)
            return
        points = self.getPoints(vl, features)
        polygons = self.requestApi(points)
        if not polygons:
            self.iface.messageBar().pushMessage(
                u'Catchments',
                self.tr(u'Catchments not found'),
                level=Qgis.Warning)
            return
        elif polygons == 'invalid key':
            self.iface.messageBar().pushMessage(u'Catchments',
                                                self.tr(u'Invalid API key'),
                                                level=Qgis.Warning)
            return
        elif polygons == 'forbidden':
            self.iface.messageBar().pushMessage(
                u'Catchments',
                self.tr(u'These credentials do not authorize access'),
                level=Qgis.Warning)
            return
        elif polygons == 'Daily quota reached or API key unauthorized':
            self.iface.messageBar().pushMessage(
                u'Catchments',
                self.
                tr(u'Openservice API daily quota reached or API key unauthorized'
                   ),
                level=Qgis.Warning)
            return
        elif "URLError" in polygons:
            error_message = polygons.split("URLError: ")[1].replace(
                ">", "").replace("<", "")
            error_info = self.tr(
                f'An error occured while executing HERE API request. Error Message: '
            )
            self.iface.messageBar().pushMessage(u'Catchments',
                                                error_info + error_message,
                                                level=Qgis.Warning)
            return
        self.addPolygonsToMap(polygons)

    @sleep_and_retry
    @RateLimitDecorator(calls=20, period=60)
    def _requestORS(self, data, locations, output):
        url = 'https://api.openrouteservice.org/v2/isochrones'
        data['locations'] = locations
        r = requests.post(
            '{}/{}'.format(
                url, self.OPENROUTE_PARAMS[self.modesComboBox.currentText()]),
            json=data,
            headers={'Authorization': self.keyLineEdit.text().strip()})
        data.pop('locations')
        if r.status_code == 403:
            output = r.json()['error']
        elif r.status_code == 200:
            data.update({
                'source': self.providersComboBox.currentText(),
                'url': url
            })
            features = r.json()['features']
            for index, feature in enumerate(features):
                feature_coords = feature['geometry']['coordinates'][0]
                feature_data = dict(data)
                feature_data.update({
                    'coords':
                    f'{locations[index][0]}, {locations[index][1]}'
                })
                feature_data['coordinates'] = [
                    str(c[1]) + ',' + str(c[0]) for c in feature_coords
                ]
                output.append(feature_data)
コード例 #14
0
class QpalsLM(object):
    def __init__(self, project, layerlist, iface):
        self.tabs = None
        self.project = project
        self.layerlist = layerlist
        self.iface = iface
        self.pcfile = None
        self.multirunner = None

    def switchToNextTab(self):
        curridx = self.tabs.currentIndex()
        self.tabs.setCurrentIndex(curridx + 1)
        self.updateTabs()

    def updateTabs(self):
        curridx = self.tabs.currentIndex()
        # update tabs
        infile = self.settings['settings']['inFile'].currentText()

        if self.names[curridx] == "DTM":
            self.pcfile = "pointcloud.odm"
            if infile.endswith(".tif"):
                self.widgets['dtmGrid'].setEnabled(False)
                self.widgets['dtmImp'].setEnabled(True)
                self.modules['dtmImp'].setParam('inFile', infile)
                self.modules['dtmImp'].setParam('tileSize', '120')
                self.modules['dtmShade'].setParam('inFile', infile)
                self.modules['slope'].setParam('inFile', infile)
                self.modules['dtmGrid'].setParam('outFile', infile)
                self.addDtm()
            elif infile.endswith(".odm"):
                self.widgets['dtmGrid'].setEnabled(True)
                self.widgets['dtmImp'].setEnabled(False)
                self.modules['dtmGrid'].setParam('inFile', infile)
                self.pcfile = infile
            else:
                self.widgets['dtmImp'].setEnabled(True)
                self.widgets['dtmGrid'].setEnabled(True)
                self.modules['dtmImp'].setParam('inFile', infile)
                self.modules['dtmGrid'].setParam('inFile', "pointcloud.odm")

            tempf = self.settings['settings']['tempFolder'].currentText()
            if not os.path.isdir(tempf):
                try:
                    os.makedirs(tempf)
                except:
                    tempf = self.project.tempdir
                    self.settings['settings']['tempFolder'].setText(tempf)

            self.project.tempdir = tempf
            self.project.workdir = tempf

        if self.names[curridx] == "3D-Modelling":
            self.modules['lm'].setParam('inFile', self.pcfile)

        if self.names[curridx] != "Editing" or "Editing (3D)":
            if self.section.ltool.rb:
                self.section.ltool.canvas.scene().removeItem(
                    self.section.ltool.rb)
            self.iface.actionPan().trigger()

        if self.names[curridx] == "Export":
            outdir = self.settings['settings']['outFolder'].currentText()
            self.modules['exp'].setParam('outFile',
                                         os.path.join(outdir, '3DSTRULI.shp'))
            if not os.path.isdir(outdir) and outdir:
                os.makedirs(outdir)

    def switchToPrevTab(self):
        curridx = self.tabs.currentIndex()
        self.tabs.setCurrentIndex(curridx - 1)

    def snapToDtm(self):
        player = self.edit3d_pointlayerbox.currentLayer()
        llayer = self.edit3d_linelayerbox.currentLayer()
        rlayer = self.edit3d_dtmlayerbox.currentLayer()
        llayer.startEditing()
        points = list(player.getFeatures())
        pointid = self.edit3d_currPointId.value()
        if points:
            point = points[pointid]
            pointGeom = point.geometry()
            if pointGeom.asMultiPoint():
                pointGeom = pointGeom.asMultiPoint()[0]
            else:
                pointGeom = pointGeom.asPoint()
            pid, feat = closestpoint(llayer, QgsGeometry.fromPoint(pointGeom))
            linegeom = feat.geometry().asWkb().data()
            olinegeom = ogr.CreateGeometryFromWkb(linegeom)
            dx = rlayer.rasterUnitsPerPixelX()
            dy = rlayer.rasterUnitsPerPixelY()
            xpos = pointGeom.x()
            ypos = pointGeom.y()
            # assume pixel = center
            xll = rlayer.extent().xMinimum() + 0.5 * dx
            yll = rlayer.extent().yMinimum() + 0.5 * dy
            xoffs = (pointGeom.x() - xll) % dx
            yoffs = (pointGeom.y() - yll) % dy
            dtm_val_ll = rlayer.dataProvider().identify(
                QgsPoint(xpos - dx / 2, ypos - dy / 2),
                QgsRaster.IdentifyFormatValue).results()[1]
            dtm_val_ur = rlayer.dataProvider().identify(
                QgsPoint(xpos + dx / 2, ypos + dy / 2),
                QgsRaster.IdentifyFormatValue).results()[1]
            dtm_val_lr = rlayer.dataProvider().identify(
                QgsPoint(xpos + dx / 2, ypos - dy / 2),
                QgsRaster.IdentifyFormatValue).results()[1]
            dtm_val_ul = rlayer.dataProvider().identify(
                QgsPoint(xpos - dx / 2, ypos + dy / 2),
                QgsRaster.IdentifyFormatValue).results()[1]
            a00 = dtm_val_ll
            a10 = dtm_val_lr - dtm_val_ll
            a01 = dtm_val_ul - dtm_val_ll
            a11 = dtm_val_ur + dtm_val_ll - (dtm_val_lr + dtm_val_ul)
            dtm_bilinear = a00 + a10 * xoffs + a01 * yoffs + a11 * xoffs * yoffs
            x, y = olinegeom.GetPoint_2D(pid)
            olinegeom.SetPoint(pid, x, y, dtm_bilinear)
            llayer.beginEditCommand("Snap point height to DTM")
            updatedGeom = QgsGeometry()
            updatedGeom.fromWkb(olinegeom.ExportToWkb())
            llayer.dataProvider().changeGeometryValues(
                {feat.id(): updatedGeom})
            llayer.endEditCommand()
            # refresh vertex editor
            self.showProblemPoint()

    def removeNode(self):
        player = self.edit3d_pointlayerbox.currentLayer()
        llayer = self.edit3d_linelayerbox.currentLayer()
        llayer.startEditing()
        points = list(player.getFeatures())
        pointid = self.edit3d_currPointId.value()
        if points:
            point = points[pointid]
            pointGeom = point.geometry()
            pid, feat = closestpoint(llayer, pointGeom)
            llayer.beginEditCommand("Vertex removed")
            llayer.deleteVertex(feat.id(), pid)
            llayer.endEditCommand()

    def nextProblemPoint(self):
        pointid = self.edit3d_currPointId.value()
        self.edit3d_currPointId.setValue(pointid + 1)

    def showProblemPoint(self):
        player = self.edit3d_pointlayerbox.currentLayer()
        llayer = self.edit3d_linelayerbox.currentLayer()
        self.iface.setActiveLayer(llayer)

        mc = self.iface.mapCanvas()
        # get first layer
        #llayer.startEditing()
        #self.iface.actionVertexTool().trigger()

        # get point position
        points = list(player.getFeatures())
        pointid = self.edit3d_currPointId.value()
        if points:
            point = points[pointid]
            pointGeom = point.geometry().asMultiPoint()[0] if point.geometry(
            ).asMultiPoint() else point.geometry().asPoint()

            t = QgsCoordinateTransform(llayer.crs(),
                                       mc.mapSettings().destinationCrs(),
                                       QgsCoordinateTransformContext())
            tCenter = t.transform(pointGeom)
            rect = QgsRectangle(tCenter, tCenter)
            mc.setExtent(rect)
            #pos = QgsMapTool(self.iface.mapCanvas()).toCanvasCoordinates(tCenter)
            #click = QMouseEvent(QEvent.MouseButtonPress, pos, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
            #mc.mousePressEvent(click)
            #mc.mousePressEvent(click)
            mc.refresh()
            #vertexDock = \
            #    [ch for ch in self.iface.mainWindow().findChildren(QDockWidget, "") if
            #     ch.windowTitle() == u'Vertex Editor']
            #if vertexDock:
            #    vertexDock = vertexDock[0]
            #    self.editingls.addWidget(vertexDock)
            mc.refresh()

    def nodeLayerChanged(self):
        if self.edit3d_pointlayerbox.currentLayer():
            self.selectNodeBtn.setText("Next point")
            self.selectNodeBtn.setEnabled(True)
            cnt = self.edit3d_pointlayerbox.currentLayer().featureCount() - 1
            self.edit3d_countLabel.setText(str(cnt))
            self.edit3d_currPointId.setMaximum(cnt)

    def createWidget(self):
        self.scrollwidget = QtWidgets.QScrollArea()
        self.scrollwidget.setWidgetResizable(True)
        self.tabs = QtWidgets.QTabWidget()
        self.scrollwidget.setWidget(self.tabs)
        self.names = [
            'Settings', 'DTM', 'Slope', '2D-Approximation',
            'Topologic correction', 'Editing', '3D-Modelling', 'Editing (3D)',
            'Export'
        ]
        self.widgets = {}
        self.settings = {}
        self.modules = {}

        for idx, name in enumerate(self.names):
            self.widgets[name] = QtWidgets.QDialog()
            ls = QtWidgets.QFormLayout()
            # Tab-specific options
            if name == "Settings":
                desc = QtWidgets.QLabel(
                    "Welcome to the qpals LineModeler GUI! \nThis tool will help you to detect and "
                    "model breaklines based on a DTM and/or a point cloud using the opals module "
                    "opalsLineModeler.\nThe process includes manual editing in QGIS (\"Editing\") "
                    "as well as automatic dectection and modelling.\n\n"
                    "To begin, please enter some basic information.")
                desc.setWordWrap(True)
                ls.addRow(desc)
                boxRun = QtWidgets.QGroupBox(
                    "Run multiple steps automatically:")
                boxVL = QtWidgets.QVBoxLayout()
                boxRun.setLayout(boxVL)
                self.settings['settings'] = OrderedDict([
                    ('name', QtWidgets.QLineEdit()),
                    ('inFile',
                     QpalsDropTextbox.QpalsDropTextbox(
                         layerlist=self.layerlist)),
                    ('tempFolder', QpalsDropTextbox.QpalsDropTextbox()),
                    ('outFolder', QpalsDropTextbox.QpalsDropTextbox()),
                    ('chkDTM', QtWidgets.QCheckBox("DTM")),
                    ('chkSlope', QtWidgets.QCheckBox("Slope")),
                    ('chk2D', QtWidgets.QCheckBox("2D-Approximation")),
                    ('chktopo2D',
                     QtWidgets.QCheckBox("Topological correction")),
                    ('chkEditing2d',
                     QtWidgets.QLabel(
                         "--- Manual editing of 2D-Approximations ---")),
                    ('chk3Dmodel', QtWidgets.QCheckBox("3D-Modelling")),
                    ('chkEditing3d',
                     QtWidgets.QLabel("--- Manual editing of 3D-Lines ---")),
                    ('chkExport', QtWidgets.QCheckBox("Export")),
                ])
                for key, value in list(self.settings['settings'].items()):
                    if isinstance(value, QpalsDropTextbox.QpalsDropTextbox):
                        value.setMinimumContentsLength(20)
                        value.setSizeAdjustPolicy(
                            QtWidgets.QComboBox.AdjustToMinimumContentsLength)
                    if key.startswith("chk"):
                        boxVL.addWidget(value)

                ls.addRow(QtWidgets.QLabel("Project name"),
                          self.settings['settings']['name'])
                hbox_wrap = QtWidgets.QHBoxLayout()
                hbox_wrap.addWidget(self.settings['settings']['inFile'],
                                    stretch=1)
                ls.addRow(QtWidgets.QLabel("Input file (TIFF/LAS/ODM)"),
                          hbox_wrap)
                hbox_wrap = QtWidgets.QHBoxLayout()
                hbox_wrap.addWidget(self.settings['settings']['tempFolder'],
                                    stretch=1)
                self.settings['settings']['tempFolder'].setPlaceholderText(
                    "drop folder here (will be created if not exists)")
                ls.addRow(QtWidgets.QLabel("Folder for temporary files"),
                          hbox_wrap)
                hbox_wrap = QtWidgets.QHBoxLayout()
                self.settings['settings']['outFolder'].setPlaceholderText(
                    "drop folder here (will be created if not exists)")
                hbox_wrap.addWidget(self.settings['settings']['outFolder'],
                                    stretch=1)
                ls.addRow(QtWidgets.QLabel("Folder for output files"),
                          hbox_wrap)
                ls.addRow(QtWidgets.QLabel(""))
                boxBtnRun = QtWidgets.QPushButton("Run selected steps now")
                boxBtnRun.clicked.connect(lambda: self.run_step("all"))
                boxBtnExp = QtWidgets.QPushButton(
                    "Export selected steps to .bat")
                boxBtnExp.clicked.connect(self.createBatFile)
                # saveBtn = QtWidgets.QPushButton("Save to project file")
                # saveBtn.clicked.connect(self.save)
                boxVL.addWidget(boxBtnRun)
                boxVL.addWidget(boxBtnExp)
                # boxVL.addWidget(saveBtn)
                ls.addRow(boxRun)

            if name == "DTM":
                desc = QtWidgets.QLabel(
                    "This first step will create a digital terrain model (DTM) from your point cloud data. "
                    "Also, a shading of your DTM "
                    "will be created for visualisation purposes. If the input file is not an ODM, one has to be "
                    "created for the modelling process later on.")
                desc.setWordWrap(True)
                ls.addRow(desc)

                impmod, impscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsImport", "opalsImport", self.project,
                    {'outFile': 'pointcloud.odm'}, ["inFile", "outFile"])
                self.modules['dtmImp'] = impmod
                self.widgets['dtmImp'] = impscroll
                ls.addRow(impscroll)

                dtmmod, dtmscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsGrid", "opalsGrid", self.project, {
                        'interpolation': 'movingPlanes',
                        'gridSize': '1',
                        'outFile': 'DTM_1m.tif'
                    }, [
                        "inFile", "outFile", "neighbours", "searchRadius",
                        "interpolation"
                    ])
                self.modules['dtmGrid'] = dtmmod
                self.widgets['dtmGrid'] = dtmscroll
                dtmmod.afterRun = self.addDtm
                ls.addRow(dtmscroll)

                shdmod, shdscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsShade", "opalsShade", self.project, {
                        'inFile': 'DTM_1m.tif',
                        'outFile': 'DTM_1m_shd.tif'
                    }, [
                        "inFile",
                        "outFile",
                    ])
                self.modules['dtmShade'] = shdmod
                shdmod.afterRun = self.addShd
                ls.addRow(shdscroll)

            if name == "Slope":
                desc = QtWidgets.QLabel(
                    "To automatically detect breaklines, a slope map is calculated. This map uses the neighboring 9"
                    " pixels to estimate a plane. The gradient (steepest slope) is then taken, converted to a slope"
                    "in degrees, and assigned to the pixel.")
                desc.setWordWrap(True)
                ls.addRow(desc)

                gfmod, gfscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsGridFeature", "opalsGridFeature", self.project, {
                        'feature': 'slpDeg',
                        'inFile': 'DTM_1m.tif',
                        'outFile': 'DTM_1m_slope.tif'
                    }, ["inFile", "outFile", "feature"])
                self.modules['slope'] = gfmod
                ls.addRow(gfscroll)

            if name == "2D-Approximation":
                desc = QtWidgets.QLabel(
                    "The slope map is used to detect breaklines. For this, the algorithm by Canny (1986) is used.\n"
                    "First, the slope map is convoluted with a gaussian kernel for smoothing, then the derivative "
                    "is calculated. The two threshold parameters represent the upper and lower values for the "
                    "binarization of the derivative map. Edges that have at least one pixel > upper threshold will be "
                    "followed until they have a pixel < lower threshold.")
                desc.setWordWrap(True)
                ls.addRow(desc)

                edgeDmod, edgeDscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsEdgeDetect", "opalsEdgeDetect", self.project, {
                        'threshold': '2;4',
                        'sigmaSmooth': '1.8',
                        'inFile': 'DTM_1m_slope_slpDeg.tif',
                        'outFile': 'detected_edges.tif'
                    }, ["inFile", "outFile", "threshold", "sigmaSmooth"])
                self.modules['edgeDetect'] = edgeDmod
                ls.addRow(edgeDscroll)

                desc = QtWidgets.QLabel(
                    "Since the output of opalsEdgeDetect is still a raster, we need to vectorize it:"
                )
                desc.setWordWrap(True)
                ls.addRow(desc)

                vecmod, vecscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsVectorize", "opalsVectorize", self.project, {
                        'inFile': 'detected_edges.tif',
                        'outFile': 'detected_edges.shp'
                    }, ["inFile", "outFile"])
                self.modules['vectorize'] = vecmod
                ls.addRow(vecscroll)

            if name == "Topologic correction":
                desc = QtWidgets.QLabel(
                    "Vectorized binary rasters usually need some topological cleaning. Here, this is done in three steps: \n"
                    "1) Find the longest line and remove all lines < 10m\n"
                    "2) Merge lines iteratively\n"
                    "3) Clean up")
                desc.setWordWrap(True)
                ls.addRow(desc)

                lt1mod, lt1scroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsLineTopology", "opalsLineTopology (1)", self.project,
                    {
                        'method': 'longest',
                        'minLength': '10',
                        'snapRadius': '0',
                        'maxTol': '0.5',
                        'maxAngleDev': '75;15',
                        'avgDist': '3',
                        'inFile': 'detected_edges.shp',
                        'outFile': 'edges1.shp'
                    }, ["inFile", "outFile", "method", "minLength", "maxTol"])
                self.modules['lt1'] = lt1mod
                ls.addRow(lt1scroll)

                lt2mod, lt2scroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsLineTopology", "opalsLineTopology (2)", self.project,
                    {
                        'method': 'merge',
                        'minLength': '10',
                        'snapRadius': '3',
                        'maxTol': '0',
                        'maxAngleDev': '150;15',
                        'avgDist': '3',
                        'merge.minWeight': '0.75',
                        'merge.relWeightLead': '0',
                        'merge.maxIter': '10',
                        'merge.revertDist': '5',
                        'merge.revertInterval': '1',
                        'merge.searchGeneration': '4',
                        'merge.preventIntersection': '1',
                        'inFile': 'edges1.shp',
                        'outFile': 'edges2.shp'
                    }, [
                        "inFile", "outFile", "method", "maxAngleDev",
                        "snapRadius", "merge\..*"
                    ])
                lt2scroll.setFixedHeight(lt2scroll.height() - 200)
                self.modules['lt2'] = lt2mod
                ls.addRow(lt2scroll)

                lt3mod, lt3scroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsLineTopology", "opalsLineTopology (3)", self.project,
                    {
                        'method': 'longest',
                        'minLength': '25',
                        'snapRadius': '0',
                        'maxTol': '0',
                        'maxAngleDev': '90;15',
                        'avgDist': '3',
                        'inFile': 'edges2.shp',
                        'outFile': 'edges3.shp'
                    }, ["inFile", "outFile", "method", "minLength", "maxTol"])
                self.modules['lt3'] = lt3mod
                ls.addRow(lt3scroll)
                lt3mod.afterRun = self.add2DLines

            if name == "Editing":
                desc = QtWidgets.QLabel(
                    "Please start editing the 2D approximations that have been loaded into qgis. Here are some tools "
                    "that might help:")
                desc.setWordWrap(True)
                ls.addRow(desc)

                box1 = QtWidgets.QGroupBox("QuickLineModeller")
                from . import QpalsQuickLM
                self.quicklm = QpalsQuickLM.QpalsQuickLM(
                    project=self.project,
                    layerlist=self.layerlist,
                    iface=self.iface)
                box1.setLayout(self.quicklm.fl)
                ls.addRow(box1)
                box2 = QtWidgets.QGroupBox("qpalsSection")
                from . import QpalsSection
                self.section = QpalsSection.QpalsSection(
                    project=self.project,
                    layerlist=self.layerlist,
                    iface=self.iface)
                self.section.createWidget()
                box2.setLayout(self.section.ls)
                box2.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
                ls.addRow(box2)

            if name == "3D-Modelling":
                desc = QtWidgets.QLabel(
                    "The 2D approximations can now be used to model 3D breaklines in the pointcloud/the DTM."
                )
                desc.setWordWrap(True)
                ls.addRow(desc)

                lmmod, lmscroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsLineModeler",
                    "opalsLineModeler",
                    self.project,
                    {  #"filter": "Class[Ground]",
                        "approxFile": "edges3.shp",
                        "outFile": "modelled_lines.shp"
                    },
                    [
                        "inFile", "approxFile", "outFile", "filter",
                        "patchLength", "patchWidth", "overlap", "angle",
                        "minLength", "pointCount", "sigmaApriori"
                    ])
                self.modules['lm'] = lmmod
                ls.addRow(lmscroll)

                lmmod.afterRun = self.add3DLines

            if name == "Editing (3D)":
                desc = QtWidgets.QLabel(
                    "Before exporting the final product, there are a few tools to check the "
                    "quality of the result. This includes a topological check as well as a search"
                    "for points that have a big height difference to the DTM - and might be erraneous."
                )

                desc.setWordWrap(True)
                ls.addRow(desc)

                self.startQualityCheckBtn = QtWidgets.QPushButton(
                    "Start calculation")
                self.startQualityCheckBtn.clicked.connect(
                    self.runProblemSearchAsync)
                self.QualityCheckbar = QtWidgets.QProgressBar()
                self.QualityCheckDtm = QgsMapLayerComboBox()
                self.QualityCheckDtm.setFilters(
                    QgsMapLayerProxyModel.RasterLayer)
                self.QualityCheckThreshold = QtWidgets.QLineEdit("0.5")
                ls.addRow(
                    QtWidgets.QLabel("DTM Layer to compare heights with"),
                    self.QualityCheckDtm)
                ls.addRow(
                    QtWidgets.QLabel("Set height difference threshold [m]"),
                    self.QualityCheckThreshold)
                hb = QtWidgets.QHBoxLayout()
                hb.addWidget(self.QualityCheckbar)
                hb.addWidget(self.startQualityCheckBtn)
                ls.addRow(hb)
                line = QtWidgets.QFrame()
                line.setFrameShape(QtWidgets.QFrame.HLine)
                line.setFrameShadow(QtWidgets.QFrame.Sunken)
                ls.addRow(line)

                self.editingls = ls

                self.edit3d_linelayerbox = QgsMapLayerComboBox()
                self.edit3d_linelayerbox.setFilters(
                    QgsMapLayerProxyModel.LineLayer)
                self.edit3d_pointlayerbox = QgsMapLayerComboBox()
                self.edit3d_pointlayerbox.setFilters(
                    QgsMapLayerProxyModel.PointLayer)
                self.edit3d_dtmlayerbox = QgsMapLayerComboBox()
                self.edit3d_dtmlayerbox.setFilters(
                    QgsMapLayerProxyModel.RasterLayer)
                self.edit3d_pointlayerbox.currentIndexChanged.connect(
                    self.nodeLayerChanged)

                self.edit3d_currPointId = QSpinBox()
                self.edit3d_currPointId.setMinimum(0)
                self.edit3d_currPointId.valueChanged.connect(
                    self.showProblemPoint)

                ls.addRow("Select Line Layer:", self.edit3d_linelayerbox)
                ls.addRow("Select Problem Point layer:",
                          self.edit3d_pointlayerbox)

                self.selectNodeBtn = QtWidgets.QPushButton("Next point")
                self.selectNodeBtn.clicked.connect(
                    lambda: self.edit3d_currPointId.setValue(
                        self.edit3d_currPointId.value() + 1))

                self.selectPrevNodeBtn = QtWidgets.QPushButton("Prev point")
                self.selectPrevNodeBtn.clicked.connect(
                    lambda: self.edit3d_currPointId.setValue(
                        self.edit3d_currPointId.value() - 1))
                self.edit3d_countLabel = QtWidgets.QLabel()

                self.snapToDtmBtn = QtWidgets.QPushButton("Snap to:")
                self.snapToDtmBtn.clicked.connect(self.snapToDtm)
                self.remonveNodeBtn = QtWidgets.QPushButton("Remove")
                self.remonveNodeBtn.clicked.connect(self.removeNode)

                nextBox = QtWidgets.QHBoxLayout()
                nextBox.addWidget(QtWidgets.QLabel("Current point:"))
                nextBox.addWidget(self.edit3d_currPointId)
                nextBox.addWidget(QtWidgets.QLabel("/"))
                nextBox.addWidget(self.edit3d_countLabel)
                nextBox.addStretch()

                nextBox.addWidget(self.snapToDtmBtn)
                nextBox.addWidget(self.edit3d_dtmlayerbox)
                nextBox.addWidget(self.remonveNodeBtn)
                nextBox.addWidget(self.selectPrevNodeBtn)
                nextBox.addWidget(self.selectNodeBtn)

                ls.addRow(nextBox)
                self.nodeLayerChanged()

            if name == "Export":
                exp2mod, exp2scroll = QpalsModuleBase.QpalsModuleBase.createGroupBox(
                    "opalsTranslate", "opalsTranslate", self.project, {
                        'oformat': 'shp',
                        'inFile': 'modelled_lines.shp',
                        'outFile': 'STRULI3D.shp',
                    }, ["inFile", "outFile"])

                self.modules['exp'] = exp2mod
                ls.addRow(exp2scroll)

            vl = QtWidgets.QVBoxLayout()
            vl.addLayout(ls, 1)
            navbar = QtWidgets.QHBoxLayout()
            next = QtWidgets.QPushButton("Next step >")
            next.clicked.connect(self.switchToNextTab)
            prev = QtWidgets.QPushButton("< Previous step")
            prev.clicked.connect(self.switchToPrevTab)
            runcurr = QtWidgets.QPushButton(
                "Run this step (all modules above)")
            runcurr.clicked.connect(lambda: self.run_step(None))
            if idx > 0:
                navbar.addWidget(prev)
            navbar.addStretch()
            if name in [
                    "DTM", "Slope", "2D-Approximation", "Topologic correction",
                    "3D-Modelling", "Export"
            ]:
                navbar.addWidget(runcurr)
            navbar.addStretch()
            if idx < len(self.names):
                navbar.addWidget(next)
            vl.addLayout(navbar)
            self.widgets[name].setLayout(vl)
            self.tabs.addTab(self.widgets[name], name)

        # set up connections

        self.tabs.currentChanged.connect(self.updateTabs)
        return self.scrollwidget

    def run_step(self, step_name=None):
        curridx = self.tabs.currentIndex()
        if step_name is None:
            step_name = self.names[curridx]

        modules = self.get_step_modules(step_name=step_name)

        self.multirunner = qMMR()
        for mod in modules:
            self.multirunner.add_module(mod, mod.updateBar,
                                        mod.run_async_finished, mod.errorBar)
        self.multirunner.start()

    def get_step_modules(self, step_name=None):
        steps_modules = {
            "DTM": [
                self.modules['dtmImp'], self.modules['dtmGrid'],
                self.modules['dtmShade']
            ],
            "Slope": [self.modules['slope']],
            "2D-Approximation":
            [self.modules['edgeDetect'], self.modules['vectorize']],
            "Topologic correction":
            [self.modules['lt1'], self.modules['lt2'], self.modules['lt3']],
            "3D-Modelling": [self.modules['lm']],
            "Export": [self.modules['exp']]
        }
        if step_name == "all":
            modules = []
            if self.settings['settings']['chkDTM'].isChecked():
                modules += steps_modules["DTM"]
            if self.settings['settings']['chkSlope'].isChecked():
                modules += steps_modules["Slope"]
            if self.settings['settings']['chk2D'].isChecked():
                modules += steps_modules["2D-Approximation"]
            if self.settings['settings']['chktopo2D'].isChecked():
                modules += steps_modules["Topologic correction"]
            if self.settings['settings']['chk3Dmodel'].isChecked():
                modules += steps_modules["3D-Modelling"]
            if self.settings['settings']['chkExport'].isChecked():
                modules += steps_modules["Export"]
        else:
            modules = steps_modules[step_name]
        return modules

    def createBatFile(self):
        saveTo = QtWidgets.QFileDialog.getSaveFileName(None,
                                                       caption='Save to file')
        try:
            f = open(saveTo, 'w')
            f.write("rem BATCH FILE CREATED WITH QPALS\r\n")
            modules = self.get_step_modules("all")
            for module in modules:
                f.write(str(module) + "\r\n")
            f.close()
        except Exception as e:
            raise Exception("Saving to batch failed.", e)

    def updateBar(self, message):
        out_lines = [item for item in re.split("[\n\r\b]", message) if item]
        percentage = out_lines[-1]
        # print percentage
        if r"%" in percentage:
            perc = QpalsModuleBase.get_percentage(percentage)
            self.secInst.progress.setValue(int(perc))

    def addDtm(self):
        file = self.modules['dtmGrid'].getParam('outFile').val
        if not os.path.isabs(file):
            file = os.path.join(self.project.workdir, file)
        self.iface.addRasterLayer(file, "DTM")

    def addShd(self):
        file = self.modules['dtmShade'].getParam('outFile').val
        if not os.path.isabs(file):
            file = os.path.join(self.project.workdir, file)
        self.iface.addRasterLayer(file, "DTM-Shading")

    def add2DLines(self):
        file = self.modules['lt3'].getParam('outFile').val
        if not os.path.isabs(file):
            file = os.path.join(self.project.workdir, file)
        self.iface.addVectorLayer(file, "2D-Approximations", "ogr")

    def add3DLines(self):
        file = self.modules['lm'].getParam('outFile').val
        if not os.path.isabs(file):
            file = os.path.join(self.project.workdir, file)
        self.iface.addVectorLayer(file, "3D Modelled Lines", "ogr")

    def runProblemSearchAsync(self):
        linefile = self.modules['lm'].getParam('outFile').val
        if not os.path.isabs(linefile):
            linefile = os.path.join(self.project.workdir, linefile)
        dtm = self.QualityCheckDtm.currentLayer()
        dtm_thres = self.QualityCheckThreshold.text()
        try:
            dtm_thres = float(dtm_thres)
        except:
            dtm_thres = 0
        self.QualityWorker = findDoubleSegments.RunWorker(
            linefile, os.path.join(self.project.workdir, "quality"), dtm,
            dtm_thres, 50, 1000)
        self.QualityWorker.progress.connect(self.updateQualityBar)
        self.QualityWorker.finished.connect(self.QualityFinished)
        self.QualityWorker.error.connect(self.problemSearchError)
        self.QualityThread = QtCore.QThread()
        self.QualityWorker.moveToThread(self.QualityThread)
        self.QualityThread.started.connect(self.QualityWorker.run)
        self.QualityThread.start()
        self.startQualityCheckBtn.setEnabled(False)
        self.startQualityCheckBtn.setText("processing...")

    def problemSearchError(self, err):
        (msg, e, mod) = err
        print(msg)

    def updateQualityBar(self, fl):
        self.QualityCheckbar.setValue(fl)

    def QualityFinished(self):
        self.startQualityCheckBtn.setEnabled(True)
        self.startQualityCheckBtn.setText("Start calculation")
        self.updateQualityBar(100)
        file = os.path.join(self.project.workdir, "quality", "problems.shp")
        self.iface.addVectorLayer(file, "Problems", "ogr")

    # def save(self):
    #     import cPickle
    #     proj = QgsProject.instance()
    #     tabs = cPickle.dumps(self.tabs, -1)
    #     proj.writeEntry("qpals", "linemodelerinst", tabs)
    #     print tabs

    def close(self):
        # remove rubber band if present
        if self.section.ltool.rb:
            self.section.ltool.canvas.scene().removeItem(self.section.ltool.rb)
        self.iface.actionPan().trigger()
コード例 #15
0
class AddConnectorsDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, iface, project):
        QtWidgets.QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)

        self.NewLinks = False
        self.NewNodes = False
        self.project = project
        if project is not None:
            self.conn = project.conn
            self.path_to_file = project.path_to_file

        self._run_layout = QGridLayout()
        spacer = QSpacerItem(5, 5, QSizePolicy.Expanding, QSizePolicy.Minimum)

        # Centroid layer
        frm1 = QHBoxLayout()
        frm1.addItem(spacer)
        self.CentroidLayer = QgsMapLayerComboBox()
        self.CentroidLayer.layerChanged.connect(self.set_fields)
        clabel = QLabel()
        clabel.setText("Centroids layer")
        frm1.addWidget(clabel)
        frm1.addWidget(self.CentroidLayer)
        self.CentroidLayer.setMinimumSize(450, 30)
        wdgt1 = QWidget()
        wdgt1.setLayout(frm1)

        self.CentroidField = QgsFieldComboBox()
        self.CentroidField.setMinimumSize(450, 30)
        frm2 = QHBoxLayout()
        frm2.addItem(spacer)
        flabel = QLabel()
        flabel.setText("Centroid ID field")
        frm2.addWidget(flabel)
        frm2.addWidget(self.CentroidField)
        wdgt2 = QWidget()
        wdgt2.setLayout(frm2)

        self.CentroidLayer.setFilters(QgsMapLayerProxyModel.PointLayer)

        frm3 = QHBoxLayout()
        self.IfMaxLength = QCheckBox()
        self.IfMaxLength.setChecked(True)
        self.IfMaxLength.setText("Connector maximum length")
        self.IfMaxLength.toggled.connect(self.allows_distance)
        frm3.addWidget(self.IfMaxLength)
        frm3.addItem(spacer)

        self.MaxLength = QLineEdit()
        frm3.addWidget(self.MaxLength)
        frm3.addItem(spacer)

        lblmeters = QLabel()
        lblmeters.setText(" meters")
        frm3.addWidget(lblmeters)
        frm3.addItem(spacer)

        lblnmbr = QLabel()
        lblnmbr.setText("Connectors per centroid")
        frm3.addWidget(lblnmbr)

        self.NumberConnectors = QComboBox()
        for i in range(1, 40):
            self.NumberConnectors.addItem(str(i))
        frm3.addWidget(self.NumberConnectors)

        wdgt3 = QWidget()
        wdgt3.setLayout(frm3)

        layer_frame = QVBoxLayout()
        layer_frame.addWidget(wdgt1)
        layer_frame.addWidget(wdgt2)
        layer_frame.addWidget(wdgt3)
        lyrfrm = QWidget()
        lyrfrm.setLayout(layer_frame)

        # action buttons
        self.but_process = QPushButton()
        if self.project is None:
            self.but_process.setText("Project not loaded")
            self.but_process.setEnabled(False)
        else:
            self.but_process.setText("Run!")
        self.but_process.clicked.connect(self.run)

        self.but_cancel = QPushButton()
        self.but_cancel.setText("Cancel")
        self.but_cancel.clicked.connect(self.exit_procedure)

        self.progressbar = QProgressBar()
        self.progress_label = QLabel()
        self.progress_label.setText("...")

        but_frame = QHBoxLayout()
        but_frame.addWidget(self.progressbar, 1)
        but_frame.addWidget(self.progress_label, 1)
        but_frame.addWidget(self.but_cancel, 1)
        but_frame.addItem(spacer)
        but_frame.addWidget(self.but_process, 1)
        self.but_widget = QWidget()
        self.but_widget.setLayout(but_frame)

        # Progress bars and messagers
        self.progress_frame = QVBoxLayout()
        self.status_bar_files = QProgressBar()
        self.progress_frame.addWidget(self.status_bar_files)

        self.status_label_file = QLabel()
        self.status_label_file.setText("Extracting: ")
        self.progress_frame.addWidget(self.status_label_file)

        self.status_bar_chunks = QProgressBar()
        self.progress_frame.addWidget(self.status_bar_chunks)

        self.progress_widget = QWidget()
        self.progress_widget.setLayout(self.progress_frame)
        self.progress_widget.setVisible(False)

        self._run_layout.addWidget(lyrfrm)
        self._run_layout.addWidget(self.but_widget)
        self._run_layout.addWidget(self.progress_widget)

        list = QWidget()
        listLayout = QVBoxLayout()
        self.list_types = QTableWidget()
        self.list_types.setMinimumSize(180, 80)

        lbl = QLabel()
        lbl.setText("Allowed link types")
        listLayout.addWidget(lbl)
        listLayout.addWidget(self.list_types)
        list.setLayout(listLayout)

        if self.project is not None:
            curr = self.conn.cursor()
            curr.execute(
                "SELECT DISTINCT link_type FROM links ORDER BY link_type")
            ltypes = curr.fetchall()
            self.list_types.setRowCount(len(ltypes))
            self.list_types.setColumnCount(1)
            for i, lt in enumerate(ltypes):
                self.list_types.setItem(i, 0, QTableWidgetItem(lt[0]))
            self.list_types.selectAll()

        allStuff = QWidget()
        allStuff.setLayout(self._run_layout)
        allLayout = QHBoxLayout()
        allLayout.addWidget(allStuff)
        allLayout.addWidget(list)

        self.setLayout(allLayout)
        self.resize(700, 135)

        # default directory
        self.path = standard_path()
        self.set_fields()
        self.IfMaxLength.setChecked(False)

    def allows_distance(self):
        self.MaxLength.setEnabled(False)
        if self.IfMaxLength.isChecked():
            self.MaxLength.setEnabled(True)

    def run_thread(self):
        self.worker_thread.ProgressValue.connect(
            self.progress_value_from_thread)
        self.worker_thread.ProgressText.connect(self.progress_text_from_thread)
        self.worker_thread.ProgressMaxValue.connect(
            self.progress_range_from_thread)
        self.worker_thread.jobFinished.connect(self.job_finished_from_thread)
        self.worker_thread.start()
        self.show()

    def progress_range_from_thread(self, val):
        self.progressbar.setRange(0, val)

    def progress_value_from_thread(self, value):
        self.progressbar.setValue(value)

    def progress_text_from_thread(self, value):
        self.progress_label.setText(value)

    def set_fields(self):
        self.CentroidField.setLayer(self.CentroidLayer.currentLayer())

    def job_finished_from_thread(self, success):
        self.but_process.setEnabled(True)
        if self.worker_thread.error is not None:
            qgis.utils.iface.messageBar().pushMessage(
                "Error during procedure: ",
                self.worker_thread.error,
                level=Qgis.Warning,
                duration=6)
        self.exit_procedure()

    def run(self):
        if self.MaxLength.isEnabled():
            max_length = float(self.MaxLength.text())
        else:
            max_length = 1000000000000

        self.link_types = []
        for i in range(self.list_types.rowCount()):
            if self.list_types.item(i, 0).isSelected():
                self.link_types.append(self.list_types.item(i, 0).text())

        # If we selected all, we don;t need to filter by it
        if len(self.link_types) == self.list_types.rowCount():
            self.link_types = []

        parameters = [
            self.project.path_to_file,
            self.CentroidLayer.currentText(),
            self.CentroidField.currentText(), max_length,
            int(self.NumberConnectors.currentText()), self.link_types
        ]

        self.but_process.setEnabled(False)
        self.worker_thread = AddsConnectorsProcedure(
            qgis.utils.iface.mainWindow(), *parameters)
        self.run_thread()

    def exit_procedure(self):
        self.close()
コード例 #16
0
class FieldMappingDialog(QDialog, FORM_CLASS):

    """Dialog implementation class for the InaSAFE field mapping tool."""

    def __init__(self, parent=None, iface=None, setting=None):
        """Constructor."""
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE Field Mapping Tool'))
        icon = resources_path('img', 'icons', 'show-mapping-tool.svg')
        self.setWindowIcon(QIcon(icon))
        self.parent = parent
        self.iface = iface
        if setting is None:
            setting = QSettings()
        self.setting = setting

        self.keyword_io = KeywordIO()

        self.layer = None
        self.metadata = {}

        self.layer_input_layout = QHBoxLayout()
        self.layer_label = QLabel(tr('Layer'))
        self.layer_combo_box = QgsMapLayerComboBox()
        # Filter only for Polygon and Point
        self.layer_combo_box.setFilters(
            QgsMapLayerProxyModel.PolygonLayer
            | QgsMapLayerProxyModel.PointLayer)
        # Filter out a layer that don't have layer groups
        excepted_layers = []
        for i in range(self.layer_combo_box.count()):
            layer = self.layer_combo_box.layer(i)
            try:
                keywords = self.keyword_io.read_keywords(layer)
            except (KeywordNotFoundError, NoKeywordsFoundError):
                excepted_layers.append(layer)
                continue
            layer_purpose = keywords.get('layer_purpose')
            if not layer_purpose:
                excepted_layers.append(layer)
                continue
            if layer_purpose == layer_purpose_exposure['key']:
                layer_subcategory = keywords.get('exposure')
            elif layer_purpose == layer_purpose_hazard['key']:
                layer_subcategory = keywords.get('hazard')
            else:
                layer_subcategory = None

            field_groups = get_field_groups(layer_purpose, layer_subcategory)
            if len(field_groups) == 0:
                excepted_layers.append(layer)
                continue
        self.layer_combo_box.setExceptedLayerList(excepted_layers)

        # Select the active layer.
        if self.iface.activeLayer():
            found = self.layer_combo_box.findText(
                self.iface.activeLayer().name())
            if found > -1:
                self.layer_combo_box.setLayer(self.iface.activeLayer())

        self.field_mapping_widget = None
        self.main_stacked_widget.setCurrentIndex(1)

        # Input
        self.layer_input_layout.addWidget(self.layer_label)
        self.layer_input_layout.addWidget(self.layer_combo_box)

        self.header_label = QLabel()
        self.header_label.setWordWrap(True)
        self.main_layout.addWidget(self.header_label)
        self.main_layout.addLayout(self.layer_input_layout)

        # Signal
        self.layer_combo_box.layerChanged.connect(self.set_layer)

        if self.layer_combo_box.currentLayer():
            self.set_layer(self.layer_combo_box.currentLayer())

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)

        # Set up things for ok button
        self.ok_button = self.button_box.button(QDialogButtonBox.Ok)
        self.ok_button.clicked.connect(self.accept)

        # Set up things for cancel button
        self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel)
        self.cancel_button.clicked.connect(self.reject)

    def set_layer(self, layer=None, keywords=None):
        """Set layer and update UI accordingly.

        :param layer: A QgsVectorLayer.
        :type layer: QgsVectorLayer

        :param keywords: Keywords for the layer.
        :type keywords: dict, None
        """
        if self.field_mapping_widget is not None:
            self.field_mapping_widget.setParent(None)
            self.field_mapping_widget.close()
            self.field_mapping_widget.deleteLater()
            self.main_layout.removeWidget(self.field_mapping_widget)
            self.field_mapping_widget = None

        if layer:
            self.layer = layer
        else:
            self.layer = self.layer_combo_box.currentLayer()
        if not self.layer:
            return

        if keywords is not None:
            self.metadata = keywords
        else:
            # Always read from metadata file.
            try:
                self.metadata = self.keyword_io.read_keywords(self.layer)
            except (
                    NoKeywordsFoundError,
                    KeywordNotFoundError,
                    MetadataReadError) as e:
                raise e
        if 'inasafe_default_values' not in self.metadata:
            self.metadata['inasafe_default_values'] = {}
        if 'inasafe_fields' not in self.metadata:
            self.metadata['inasafe_fields'] = {}
        self.field_mapping_widget = FieldMappingWidget(
            parent=self, iface=self.iface)
        self.field_mapping_widget.set_layer(self.layer, self.metadata)
        self.field_mapping_widget.show()
        self.main_layout.addWidget(self.field_mapping_widget)

        # Set header label
        group_names = [
            self.field_mapping_widget.tabText(i) for i in range(
                self.field_mapping_widget.count())]
        if len(group_names) == 0:
            header_text = tr(
                'There is no field group for this layer. Please select '
                'another layer.')
            self.header_label.setText(header_text)
            return
        elif len(group_names) == 1:
            pretty_group_name = group_names[0]
        elif len(group_names) == 2:
            pretty_group_name = group_names[0] + tr(' and ') + group_names[1]
        else:
            pretty_group_name = ', '.join(group_names[:-1])
            pretty_group_name += tr(', and {0}').format(group_names[-1])
        header_text = tr(
            'Please fill the information for every tab to determine the '
            'attribute for {0} group.').format(pretty_group_name)
        self.header_label.setText(header_text)

    @pyqtSlot(bool)  # prevents actions being handled twice
    def help_toggled(self, flag):
        """Show or hide the help tab in the stacked widget.

        .. versionadded: 3.2.1

        :param flag: Flag indicating whether help should be shown or hidden.
        :type flag: bool
        """
        if flag:
            self.help_button.setText(self.tr('Hide Help'))
            self.show_help()
        else:
            self.help_button.setText(self.tr('Show Help'))
            self.hide_help()

    def hide_help(self):
        """Hide the usage info from the user.

        .. versionadded: 3.2.1
        """
        self.main_stacked_widget.setCurrentIndex(1)

    def show_help(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        self.main_stacked_widget.setCurrentIndex(0)
        header = html_header()
        footer = html_footer()

        string = header

        message = field_mapping_help()

        string += message.to_html()
        string += footer

        self.help_web_view.setHtml(string)

    def save_metadata(self):
        """Save metadata based on the field mapping state."""
        metadata = self.field_mapping_widget.get_field_mapping()
        for key, value in list(metadata['fields'].items()):
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_default_values']:
                self.metadata['inasafe_default_values'].pop(key)
            if value is None or value == []:
                if key in self.metadata['inasafe_fields']:
                    self.metadata['inasafe_fields'].pop(key)
            else:
                self.metadata['inasafe_fields'][key] = value

        for key, value in list(metadata['values'].items()):
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_fields']:
                self.metadata['inasafe_fields'].pop(key)
            if value is None:
                if key in self.metadata['inasafe_default_values']:
                    self.metadata['inasafe_default_values'].pop(key)
            else:
                self.metadata['inasafe_default_values'][key] = value

        # Save metadata
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=self.metadata)
        except InaSAFEError as e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))

        # Update setting fir recent value
        if self.metadata.get('inasafe_default_values'):
            for key, value in \
                    list(self.metadata['inasafe_default_values'].items()):
                set_inasafe_default_value_qsetting(
                    self.setting, key, RECENT, value)

    def accept(self):
        """Method invoked when OK button is clicked."""
        try:
            self.save_metadata()
        except InvalidValidationException as e:
            display_warning_message_box(
                self, tr('Invalid Field Mapping'), str(e))
            return
        super(FieldMappingDialog, self).accept()
コード例 #17
0
ファイル: tin_tools.py プロジェクト: jalmmor/TIN-tools
class TinTools:
    def __init__(self, iface):
        self.iface = iface
        self.toolbar = None
        self.highlight = None
        self.msgBar = iface.messageBar()
        self.plugin_dir = os.path.dirname(__file__)
        print('plugin init en ' + self.plugin_dir)

    def initGui(self):
        self.toolbar = self.iface.addToolBar(u'TIN Tools')
        self.toolbar.setObjectName(u'tintools')
        label = QLabel('Capa TIN:')
        self.toolbar.addWidget(label)
        self.tin_cb = QgsMapLayerComboBox()
        self.tin_cb.setMinimumWidth(200)
        self.tin_cb.setFilters(QgsMapLayerProxyModel.VectorLayer)
        self.tin_cb.layerChanged.connect(self.tinLayerChanged)
        self.toolbar.addWidget(self.tin_cb)

        #        icon_path = self.plugin_dir +'/icon.png'
        #        icon = QIcon(icon_path)
        #'\u0394 \u2B16  \u20E4  \u2350 \u21C8 \u2963 \u2B7F \u2b85 \u23C4  \u25e9'
        self.calc_plane_action = QAction('\u0394', self.iface.mainWindow())
        self.calc_plane_action.triggered.connect(self.calcPlaneEquation)
        self.toolbar.addAction(self.calc_plane_action)

        self.calc_z = QAction('\u21C8', self.iface.mainWindow())
        self.calc_z.triggered.connect(self.calcZ)
        self.toolbar.addAction(self.calc_z)

        self.adjust_to_tin = QAction('\u25e9', self.iface.mainWindow())
        self.adjust_to_tin.triggered.connect(self.adjustToTin)
        self.toolbar.addAction(self.adjust_to_tin)

        self.tinLayerChanged(self.tin_cb.currentLayer())

    def unload(self):
        self.planeCalc = None
        self.setHighlight(None, None)
        self.iface.removeToolBarIcon(self.calc_plane_action)
        self.iface.removeToolBarIcon(self.calc_z)
        self.iface.removeToolBarIcon(self.adjust_to_tin)
        del self.toolbar
        print('unload toolbar5')

    def msg(self, text):
        self.msgBar.pushWarning('TIN tool', text)

    def info(self, text):
        self.msgBar.pushInfo('TIN tool', text)

    def setHighlight(self, ly, vertex):
        if self.highlight:
            self.highlight.hide()
            self.highlight = None
        if vertex:
            color = QColor(255, 0, 100, 255)
            lv = vertex + [vertex[0]]
            g = QgsGeometry.fromPolyline(lv).convertToType(2)

            print(g.asWkt(3))
            self.highlight = QgsHighlight(self.iface.mapCanvas(), g, ly)
            self.highlight.setColor(color)
            self.highlight.setWidth(5)
            color.setAlpha(50)
            self.highlight.setFillColor(color)
            self.highlight.show()

    def tinLayerChanged(self, layer):
        self.calc_plane_action.setEnabled(layer is not None)
        self.adjust_to_tin.setEnabled(layer is not None)
        self.calc_z.setEnabled(False)
        self.planeCalc = None
        self.setHighlight(None, None)

    def calcPlaneEquation(self):
        ly = self.tin_cb.currentLayer()
        self.setHighlight(None, None)
        if not ly:
            self.msg('No hay ninguna capa seleccionada')
            return
        ver = None
        feat = ly.selectedFeatures()
        geometry_type = ly.geometryType()
        if geometry_type == 0:  # point
            if len(feat) == 3:
                ver = [f.geometry().vertexAt(0) for f in feat]
            else:
                self.msg('Hay que seleccionar 3 puntos')
        elif geometry_type == 2:  #polygon
            if len(feat) == 1:
                geom = feat[0].geometry()
                ver = list(geom.vertices())
                if len(ver) == 4:
                    ver = ver[:3]
                else:
                    self.msg('El polígono tiene que ser un triángulo')
            else:
                self.msg('Seleccionar solo un triángulo')
        else:
            self.msg('seleccionar tres puntos o un triángulo')
        if ver:
            self.planeCalc = PlaneCalc(ver)
            self.info(
                'Selecciona los elementos de una capa para calcular su Z en el plano'
            )
            self.calc_z.setEnabled(True)
            self.setHighlight(ly, ver)
        else:
            self.planeCalc = None
            self.calc_z.setEnabled(False)

    def calcZ(self):

        layer = self.iface.activeLayer()
        if not layer:
            QMessageBox.warning(None, 'TIN Tools',
                                'Selecciona elemenos de una capa')
            return
        if not layer.isEditable():
            QMessageBox.information(None, 'TIN cal',
                                    'La capa no está en modo edición')
            return
        for f in layer.getSelectedFeatures():
            geom = f.geometry()
            n = 0
            v = geom.vertexAt(0)
            while (v != QgsPoint(0, 0)):
                z = self.planeCalc.cal_z(v.x(), v.y())
                v.setZ(z)
                geom.moveVertex(v, n)
                n += 1
                v = geom.vertexAt(n)
            layer.changeGeometry(f.id(), geom)

    def adjustToTin(self):
        print('calc tin')
コード例 #18
0
class UAVPreparer:
    """QGIS Plugin Implementation."""

    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
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'UAVPreparer_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)


        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&UAV Preparer')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'UAVPreparer')
        self.toolbar.setObjectName(u'UAVPreparer')

        # Declare variables
        self.outputfile = None

    # 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('UAVPreparer', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        # Create the dialog (after translation) and keep reference
        self.dlg = UAVPreparerDialog()

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        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)

        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/UAVPreparer/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(self.tr(u'Unmanned Aerial Vehicle Preparer')),
            callback=self.run,
            parent=self.iface.mainWindow())

        # Access the raster layer
        self.layerComboManagerDSM = QgsMapLayerComboBox(self.dlg.widgetDSM)
        self.layerComboManagerDSM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDSM.setFixedWidth(175)
        self.layerComboManagerDSM.setCurrentIndex(-1)

        # Access the vector layer and an attribute field
        self.layerComboManagerPoint = QgsMapLayerComboBox(self.dlg.widgetPoint)
        self.layerComboManagerPoint.setCurrentIndex(-1)
        self.layerComboManagerPoint.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.layerComboManagerPoint.setFixedWidth(175)
        self.layerComboManagerPointField = QgsFieldComboBox(self.dlg.widgetField)
        self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerPointField.setLayer)

        # Set up of file save dialog
        self.fileDialog = QFileDialog()
        self.dlg.selectButton.clicked.connect(self.savefile)

        # Set up for the Help button
        self.dlg.helpButton.clicked.connect(self.help)

        # Set up for the Run button
        self.dlg.runButton.clicked.connect(self.start_progress)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&UAV Preparer'),
                action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar


    def run(self):
        """Run method that performs all the real work"""
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass

    def savefile(self):
        self.outputfile = self.fileDialog.getSaveFileName(None, "Save File As:", None, "Text Files (*.txt)")
        self.dlg.textOutput.setText(self.outputfile)

    def help(self):
        url = "https://github.com/nilswallenberg/UAVPreparer"
        webbrowser.open_new_tab(url)

    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)
コード例 #19
0
class DistancePuCaWidget(PuCaWidget):
    """A widget for 'distance' analysis."""
    
    def _build_widgets(self):
        """Builds own widgets."""
        
        self.lastRefPointLayer = None
        
        self.refPointMapLayerComboBox = QgsMapLayerComboBox(self)
        self.refPointMapLayerComboBox.setObjectName(
            u'refPointMapLayerComboBox')
        self.refPointMapLayerComboBox.setFilters(
            QgsMapLayerProxyModel.PointLayer)
        self.refPointMapLayerComboBox.activated.connect(
            self._set_last_ref_point_layer)
        QgsMapLayerRegistry.instance().layersAdded.connect(
            self._rollback_ref_point_layer)
        QgsMapLayerRegistry.instance().layersRemoved.connect(
            self._reset_ref_point_layer)
        self._set_ref_point_layer(self.lastRefPointLayer)
        self.vBoxLayout.addWidget(self.refPointMapLayerComboBox)
    
    def _set_ref_point_layer(self, refPointLayer, lastRefPointLayer=True):
        """Sets the reference point layer in the refPointMapLayerComboBox.
        
        Args:
            refPointLayer (QgsVectorLayer): A reference to the reference
                point layer.
            lastRefPointLayer (bool): True to set self.lastRefPointLayer,
                False otherwise.
        
        """
        
        if lastRefPointLayer:
            self.lastRefPointLayer = refPointLayer
        
        self.refPointMapLayerComboBox.setLayer(refPointLayer)
    
    def _set_last_ref_point_layer(self):
        """Sets the lastRefPointLayer.
        
        Sets the lastRefPointLayer according to the current layer
        in the refPointMapLayerComboBox.
        
        """
        
        refPointLayer = self.refPointMapLayerComboBox.currentLayer()
        
        if refPointLayer != self.lastRefPointLayer:
            self.lastRefPointLayer = refPointLayer
    
    def _reset_ref_point_layer(self):
        """Resets the reference point layer."""
        
        layers = self.iface.legendInterface().layers()
        
        if self.lastRefPointLayer not in layers:
            self._set_ref_point_layer(None)
    
    def _rollback_ref_point_layer(self):
        """Rolls the reference point layer back."""
        
        if self.lastRefPointLayer == None:
            self._set_ref_point_layer(self.lastRefPointLayer, False)
        else:
            self.lastRefPointLayer = \
                self.refPointMapLayerComboBox.currentLayer()
    
    def execute(self, layer):
        """Executes the analysis.
        
        Args:
            layer (QgsVectorLayer): A reference to the active layer.
        
        """
        
        try:
            editing = self.dW.check_editing()
            
            refPointLayer = self.refPointMapLayerComboBox.currentLayer()
            
            if refPointLayer == None:
                self.pW.set_text_statusbar.emit(
                    u'Žádná vrstva referenčního bodu.', 10, True)
                return
            
            refPointCount = refPointLayer.featureCount()
            
            refPointLayerCrs = refPointLayer.crs().authid()
            layerCrs = layer.crs().authid()
            
            if refPointLayerCrs != layerCrs:
                self.pW.set_text_statusbar.emit(
                    u'Aktivní vrstva a vrstva referenčního bodu nemají stejný '
                    u'souřadnicový systém.', 10, True)
                return
            
            if refPointCount != 1:
                self.pW.set_text_statusbar.emit(
                    u'Vrstva referenčního bodu neobsahuje právě jeden prvek.',
                    10, True)
                return
            
            layer.removeSelection()
            refPointLayer.removeSelection()
            
            features = self.dW.get_addressed_features(layer)
            
            self.pW.set_text_statusbar.emit(
                u'Provádím analýzu - měření vzdálenosti...', 0, False)
            
            refPointFeatures = refPointLayer.getFeatures()
            
            for feature in refPointFeatures:
                refPoint = feature.geometry().asPoint()
            
            puDistanceColumnName = self.dW.puDistanceColumnName
            
            fieldId = layer.fieldNameIndex(puDistanceColumnName)
            
            layer.startEditing()
            layer.updateFields()
            
            for feature in features:
                geometry = feature.geometry()
                
                if geometry != None:
                    id = feature.id()
                    originalDistance = feature.attribute(puDistanceColumnName)
                    
                    centroid = geometry.centroid().asPoint()
                    distanceDouble = sqrt(refPoint.sqrDist(centroid))
                    distance = int(round(distanceDouble))
                    
                    if distance != originalDistance:
                        layer.changeAttributeValue(id, fieldId, distance)
            
            layer.commitChanges()
            
            if editing:
                self.iface.actionToggleEditing()
            
            self.pW.set_text_statusbar.emit(
                u'Analýza měření vzdálenosti úspěšně dokončena.', 20, False)
        except self.dW.puError:
            QgsApplication.processEvents()
        except:
            QgsApplication.processEvents()
            
            currentCheckAnalysisName = \
                self.pW.checkAnalysisComboBox.currentText()
            
            self.dW.display_error_messages(
                self.pW,
                u'Error executing "{}".'.format(currentCheckAnalysisName),
                u'Chyba při provádění "{}".'.format(currentCheckAnalysisName))
    
    def _set_refPoint_layer(self):
        """Sets current reference point layer.
        
        Sets current reference point layer to None if the last reference point
        layer was None.
        
        """
        
        if self.lastRefPointLayer == None:
            self.refPointMapLayerComboBox.setLayer(self.lastRefPointLayer)
        else:
            self.lastRefPointLayer = \
                self.refPointMapLayerComboBox.currentLayer()
コード例 #20
0
class SvgBubblDialog(QtGui.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(SvgBubblDialog, self).__init__(parent)
        path_prj = QgsProject.instance().readPath("./")
        self.CONF_PATH = os.path.join(path_prj, "svgbubbl.conf.json")
        self.MAX_SPINBOX = 10000000
        #         self._fields_lst=[]
        #         self._color_lst=[]
        self._preset_rows = PresetRows()

        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        #self.setFixedSize(self.size()) #---FIX MAIN WINDOW SIZE
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QtGui.QSizePolicy.Minimum,
                               QtGui.QSizePolicy.Fixed)
        self.lyrCombobox = QgsMapLayerComboBox()
        self.lyrCombobox.layerChanged.connect(
            self.action_lyr_update)  # selected layer from combobox

        self.horizontalLayout.addWidget(self.lyrCombobox)
        self.configBox.currentIndexChanged.connect(self.action_config_set)
        self.configPlus.clicked.connect(self.action_config_add)
        self.configMinus.clicked.connect(self.action_config_remove)

        btnAdd = QtGui.QPushButton('Add expression', self)
        btnAdd.setToolTip('Tooltip <b>QPushButton</b> widget')
        btnAdd.clicked.connect(
            self.action_field_add
        )  # connect btn action 'clicked()' and function add_field
        btnRem = QtGui.QPushButton('Remove expression', self)
        btnRem.clicked.connect(
            self.action_field_pop
        )  # connect btn action 'clicked()' and function add_field
        self.horizontalLayout_2.addWidget(btnAdd, 0)
        self.horizontalLayout_2.addWidget(btnRem, 1)
        self.show_preset_window()
        self.finished.connect(self.config_dump)
        #read config presets
        if os.path.exists(path=self.CONF_PATH):
            self.config_load()
            self.action_config_set()
        QgsMessageLog.logMessage("main window loaded", tag="SvgBubble")

    #===================================================================
    #
    #===================================================================
    def show_preset_window(self):
        self.mygroupbox = QtGui.QGroupBox('this is my groupbox')
        self.configPreset = QtGui.QFormLayout()
        self.mygroupbox.setLayout(self.configPreset)
        self.scroll = QtGui.QScrollArea()
        self.scroll.setWidget(self.mygroupbox)
        self.scroll.setWidgetResizable(True)
        self.verticalLayout.addWidget(self.scroll)

    def clear_preset_window(self):
        self.mygroupbox.deleteLater()
        self.configPreset.deleteLater()
        self.scroll.deleteLater()
        self.mygroupbox = None
        self.configPreset = None
        self.scroll = None

    #===========================================================================
    # load config
    #===========================================================================
    @pyqtSlot()
    def action_config_set(self):
        if self.configBox.count() > 0:
            #self.bar.pushMessage("configBox", "currentIndexChanged", level=QgsMessageBar.INFO)
            presetrows = self.configBox.itemData(self.configBox.currentIndex())
            #self.bar.pushMessage("configBox", str(presetrows), level=QgsMessageBar.INFO)
            #self.bar.pushMessage("configBox", str(self._preset_rows), level=QgsMessageBar.INFO)
            self._preset_rows = presetrows.copy()
            self.redraw_fields()

    #===========================================================================
    # add config preset
    #===========================================================================
    @pyqtSlot()
    def action_config_add(self):
        text, ok = QtGui.QInputDialog.getText(self, 'Input Dialog',
                                              'Enter config name:')
        if ok:
            #if preset exist then remove old
            if self.configBox.findText(text) >= 0:
                #self.configBox.removeItem(self.configBox.findText(text))
                self.configBox.setItemData(self.configBox.findText(text),
                                           self._preset_rows.copy())
            else:
                #store new preset
                self.configBox.addItem(text, self._preset_rows.copy())
            #select current preset as active
            self.configBox.setCurrentIndex(self.configBox.findText(text))

    #===========================================================================
    #
    #===========================================================================
    @pyqtSlot()
    def action_config_remove(self):
        self.configBox.removeItem(self.configBox.currentIndex())
        pass

    #=========================================================================
    #
    #=========================================================================
    def config_dump(self):
        #self.bar.pushMessage("configBox", "config_dump", level=QgsMessageBar.INFO)
        texts = [(self.configBox.itemText(i),
                  self.configBox.itemData(i).dump())
                 for i in range(self.configBox.count())]

        ou_f = open(self.CONF_PATH, mode="w")
        json.dump(texts, ou_f)
        ou_f.flush()
        ou_f.close()

#         texts = [(self.configBox.itemText(i), self.configBox.itemData(i)) for i in range(self.configBox.count())]
#         ou_f=open(self.CONF_PATH,mode="w")
#         #json.dump(texts,ou_f)
#         pickle.dump(texts, ou_f)
#         ou_f.flush()
#         ou_f.close()

#=========================================================================
#
#=========================================================================

    def config_load(self):
        texts = None
        try:
            texts = json.load(open(self.CONF_PATH))
        except:
            self.bar.pushMessage("Trigger",
                                 "Defaul preset not founded",
                                 level=QgsMessageBar.INFO)
            pass
        if texts is not None:
            for name, text in texts:
                #self.bar.pushMessage("Trigger", text, level=QgsMessageBar.INFO)

                preset_rows = PresetRows()
                preset_rows.load(text)
                if self.configBox.findText(name) >= 0:
                    self.configBox.setItemData(self.configBox.findText(name),
                                               preset_rows)
                else:
                    self.configBox.addItem(name, preset_rows)
            self.action_lyr_update()
#         try:
#             dump_texts=pickle.load(file=open(self.CONF_PATH))
#             self.configBox.clear()
#             for name,preset_rows in dump_texts:
#                self.configBox.addItem(name
#                                       ,preset_rows)
#         except:pass

#===========================================================================
#
#===========g================================================================

    @pyqtSlot()
    def action_lyr_update(self):
        self._preset_rows.set_preset_layer(self.lyrCombobox.currentLayer())

    #===============================================================
    #
    #===============================================================
    @pyqtSlot()
    def action_field_add(self):
        #self.bar.pushMessage("Trigger", "signal received", level=QgsMessageBar.INFO)
        field_expression_widget = QgsFieldExpressionWidget()
        field_expression_widget.setLayer(self.lyrCombobox.currentLayer())
        color_btn_widget = QgsColorButton()
        spinbox = QtGui.QSpinBox()
        presetrow = PresetRow(qgsfieldexpressionwidget=field_expression_widget,
                              qgscolorbutton=color_btn_widget,
                              qspinbox=spinbox)
        self._preset_rows.add_preset(presetrow)
        self.redraw_fields()

    #===================================================================
    #
    #===================================================================
    @pyqtSlot()
    def action_field_pop(self):
        self._preset_rows.pop()

    #===========================================================================
    # @param fields:
    #            list of exprression string
    # @param colors:
    #            list of QColor
    #===========================================================================
    def redraw_fields(self):
        #---neeed clear widgets on self.configPreset
        self.clear_preset_window()
        self.show_preset_window()
        for preset in self._preset_rows:
            #self.bar.pushMessage("Trigger", str(preset), level=QgsMessageBar.INFO)
            layout = QtGui.QHBoxLayout()
            layout.addWidget(preset.qgscolorbutton)
            layout.addWidget(preset.qgsfieldexp)
            layout.addWidget(preset.qspinbox)
            self.configPreset.addRow(layout)

    @property
    def preset_rows(self):
        return self._preset_rows

    @property
    def expressions(self):
        return self._preset_rows.qgsfieldexp_lst

    @property
    def colors(self):
        return self._preset_rows.qgscolorbutton_lst
コード例 #21
0
class PotentialSlopeFailure(object):
    """QGIS Plugin Implementation."""
    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
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir, 'i18n',
            'PotentialSlopeFailure_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.dlg = PotentialSlopeFailureDialog(self.iface)
        self.dlg.runButton.clicked.connect(self.start_progress)
        self.dlg.pushButtonHelp.clicked.connect(self.help)
        self.dlg.pushButtonSave.clicked.connect(self.folder_path)
        self.fileDialog = QFileDialog()
        self.fileDialog.setFileMode(QFileDialog.Directory)
        self.fileDialog.setOption(QFileDialog.ShowDirsOnly, True)

        # Declare instance attributes
        #self.actions = []
        #self.menu = self.tr(u'&Potential Slope Failure')
        # TODO: We are going to let the user set this up in a future iteration
        #self.toolbar = self.iface.addToolBar(u'PotentialSlopeFailure')
        #self.toolbar.setObjectName(u'PotentialSlopeFailure')

        # self.layerComboManagerDEM = RasterLayerCombo(self.dlg.comboBoxDem)
        # RasterLayerCombo(self.dlg.comboBoxDem, initLayer="")
        # self.layerComboManagerSOIL = RasterLayerCombo(self.dlg.comboBoxSoil)
        # RasterLayerCombo(self.dlg.comboBoxSoil, initLayer="")
        self.layerComboManagerDEM = QgsMapLayerComboBox(self.dlg.widgetDEM)
        self.layerComboManagerDEM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDEM.setFixedWidth(175)
        self.layerComboManagerSOIL = QgsMapLayerComboBox(self.dlg.widgetSOIL)
        self.layerComboManagerSOIL.setFilters(
            QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerSOIL.setFixedWidth(175)
        self.folderPath = 'None'

    # 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('PotentialSlopeFailure', message)

    # def add_action(
    #     self,
    #     icon_path,
    #     text,
    #     callback,
    #     enabled_flag=True,
    #     add_to_menu=True,
    #     add_to_toolbar=True,
    #     status_tip=None,
    #     whats_this=None,
    #     parent=None):
    #     """Add a toolbar icon to the toolbar.
    #
    #     :param icon_path: Path to the icon for this action. Can be a resource
    #         path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
    #     :type icon_path: str
    #
    #     :param text: Text that should be shown in menu items for this action.
    #     :type text: str
    #
    #     :param callback: Function to be called when the action is triggered.
    #     :type callback: function
    #
    #     :param enabled_flag: A flag indicating if the action should be enabled
    #         by default. Defaults to True.
    #     :type enabled_flag: bool
    #
    #     :param add_to_menu: Flag indicating whether the action should also
    #         be added to the menu. Defaults to True.
    #     :type add_to_menu: bool
    #
    #     :param add_to_toolbar: Flag indicating whether the action should also
    #         be added to the toolbar. Defaults to True.
    #     :type add_to_toolbar: bool
    #
    #     :param status_tip: Optional text to show in a popup when mouse pointer
    #         hovers over the action.
    #     :type status_tip: str
    #
    #     :param parent: Parent widget for the new action. Defaults None.
    #     :type parent: QWidget
    #
    #     :param whats_this: Optional text to show in the status bar when the
    #         mouse pointer hovers over the action.
    #
    #     :returns: The action that was created. Note that the action is also
    #         added to self.actions list.
    #     :rtype: QAction
    #     """
    #
    #     # Create the dialog (after translation) and keep reference
    #     # self.dlg = PotentialSlopeFailureDialog()
    #
    #     icon = QIcon(icon_path)
    #     action = QAction(icon, text, parent)
    #     action.triggered.connect(callback)
    #     action.setEnabled(enabled_flag)
    #
    #     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)
    #
    #     if add_to_menu:
    #         self.iface.addPluginToMenu(self.menu, action)
    #
    #     self.actions.append(action)
    #
    #     return action

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(
            QIcon(':/plugins/PotentialSlopeFailure/slopeicon.png'),
            'Calculates areas prone to slope failures in cohesive soils',
            self.iface.mainWindow())
        # connect the action to the run method
        self.action.triggered.connect(self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(self.tr("&Potential Slope Failure"),
                                   self.action)

        #"""Create the menu entries and toolbar icons inside the QGIS GUI."""
        #
        #icon_path = ':/plugins/PotentialSlopeFailure/icon.png'
        #self.add_action(
        #    icon_path,
        #   text=self.tr(u'Calculates areas prone to slope failures in cohesive soils'),
        #   callback=self.run,
        #   parent=self.iface.mainWindow())

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu("&Potential Slope Failure", self.action)
        self.iface.removeToolBarIcon(self.action)
        # """Removes the plugin menu item and icon from QGIS GUI."""
        # for action in self.actions: self.iface.removePluginMenu(
        #         self.tr(u'&Potential Slope Failure'),
        #         action)
        #     self.iface.removeToolBarIcon(action)
        # remove the toolbar
        # del self.toolbar

    def run(self):
        self.dlg.show()
        self.dlg.exec_()

    def folder_path(self):
        self.fileDialog.open()
        result = self.fileDialog.exec_()
        if result == 1:
            self.folderPath = self.fileDialog.selectedFiles()
            self.dlg.textOutput.setText(self.folderPath[0])

    def start_progress(self):
        if self.folderPath == 'None':
            QMessageBox.critical(None, "Error", "Select a valid output folder")
            return

        # Load DEM
        demlayer = self.layerComboManagerDEM.currentLayer()

        if demlayer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid DEM raster layer is selected")
            return

        provider = demlayer.dataProvider()
        filepath_dem = str(provider.dataSourceUri())

        gdal_dem = gdal.Open(filepath_dem)

        dem = gdal_dem.ReadAsArray().astype(np.float)
        sizex = dem.shape[0]
        sizey = dem.shape[1]

        geotransform = gdal_dem.GetGeoTransform()
        scale = 1 / geotransform[1]

        # Load Soil
        soillayer = self.layerComboManagerSOIL.currentLayer()

        if soillayer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid Soil raster selected")
            return

        # load raster
        gdal.AllRegister()
        provider = soillayer.dataProvider()
        filePathOld = str(provider.dataSourceUri())
        dataSet = gdal.Open(filePathOld)
        soil = dataSet.ReadAsArray().astype(np.float)

        soilsizex = soil.shape[0]
        soilsizey = soil.shape[1]

        if not (soilsizex == sizex) & (soilsizey == sizey):
            QMessageBox.critical(
                None, "Error",
                "The grids must be of same extent and resolution")
            return

        itera = int(360 / self.dlg.spinBoxIter.value())
        alt = self.dlg.spinBoxAlt.value()
        shtot = np.zeros((sizex, sizey))
        index = 0

        # Inverting dem
        dem = dem * (-1.) + np.max(dem)

        self.dlg.progressBar.setRange(0, self.dlg.spinBoxIter.value())

        for i in range(0, self.dlg.spinBoxIter.value()):
            azi = itera * i
            self.dlg.progressBar.setValue(i + 1)
            # self.iface.messageBar().pushMessage("ShadowGenerator", str(azi))
            sh = shadow.shadowingfunctionglobalradiation(
                dem, azi, alt, scale, self.dlg, 1)
            shtot = shtot + sh
            index += 1

        zon1 = shtot / index

        zon1[zon1 == 1] = 2
        zon1[zon1 < 1] = 1
        karta1a = zon1 * soil
        karta1a[karta1a == 0] = 3

        filename = self.folderPath[0] + '/map1a.tif'
        self.saveraster(gdal_dem, filename, karta1a)

        # load result into canvas
        if self.dlg.checkBoxIntoCanvas.isChecked():
            rlayer = self.iface.addRasterLayer(filename)

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

            rlayer.loadNamedStyle(self.plugin_dir + '/misc/map1a.qml')

            if hasattr(rlayer, "setCacheImage"):
                rlayer.setCacheImage(None)
            rlayer.triggerRepaint()

        self.dlg.progressBar.setValue(0)

        QMessageBox.information(
            self.dlg, "Calculation done!",
            "Output (map1a.tif) created in: " + self.folderPath[0] + "/")

    def help(self):
        url = "https://github.com/biglimp/PotentialSlopeFailure/wiki/Potential-Slope-Failure-plugin-for-QGIS"
        webbrowser.open_new_tab(url)

    def saveraster(self, gdal_data, filename, raster):
        rows = gdal_data.RasterYSize
        cols = gdal_data.RasterXSize

        outDs = gdal.GetDriverByName("GTiff").Create(filename, cols, rows,
                                                     int(1), 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())
コード例 #22
0
class EditPuWidget(PuWidget):
    """A widget for editing."""

    set_text_statusbar = pyqtSignal(str, int, bool)

    def _setup_self(self):
        """Sets up self."""

        self.categoryValue = 0
        self.categoryValues = (0, 1, 2, None)
        self.categoryName = self.dW.puCategoryColumnName
        self.shortCategoryName = self.categoryName[:10]
        self.setCategoryValue = 0

        self.setObjectName(u'editFrame')

        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName(u'gridLayout')
        self.gridLayout.setColumnStretch(1, 1)

        self._build_widgets()

    def _build_widgets(self):
        """Builds own widgets."""

        self.set_text_statusbar.connect(self.dW.statusBar.set_text)

        self.lastPerimeterLayer = None

        self.editToolBar = QToolBar(self)
        self.editToolBar.setObjectName(u'editToolBar')
        self._set_icon_size()
        self.iface.initializationCompleted.connect(self._set_icon_size)
        self.gridLayout.addWidget(self.editToolBar, 0, 0, 1, 3)

        for action in self.iface.advancedDigitizeToolBar().actions():
            if action.objectName() == 'mActionUndo':
                self.undoAction = action
            if action.objectName() == 'mActionRedo':
                self.redoAction = action

        self.editToolBar.addAction(self.undoAction)

        self.editToolBar.addAction(self.redoAction)

        self.editToolBar.addSeparator()

        self.toggleEditingAction = self.iface.actionToggleEditing()
        self.toggleEditingAction.setObjectName(u'toggleEditingAction')
        self.editToolBar.addAction(self.toggleEditingAction)

        self.saveActiveLayerEditsAction = \
            self.iface.actionSaveActiveLayerEdits()
        self.saveActiveLayerEditsAction.setObjectName(
            u'saveActiveLayerEditsAction')
        self.editToolBar.addAction(self.saveActiveLayerEditsAction)

        self.cancelEditsAction = self.iface.actionCancelEdits()
        self.cancelEditsAction.setObjectName(u'cancelEditsAction')
        self.editToolBar.addAction(self.cancelEditsAction)

        self.addFeatureAction = self.iface.actionAddFeature()
        self.addFeatureAction.setObjectName(u'addFeatureAction')
        self.editToolBar.addAction(self.addFeatureAction)

        self.nodeToolAction = self.iface.actionNodeTool()
        self.nodeToolAction.setObjectName(u'nodeToolAction')
        self.editToolBar.addAction(self.nodeToolAction)

        self.deleteSelectedAction = self.iface.actionDeleteSelected()
        self.deleteSelectedAction.setObjectName(u'deleteSelectedAction')
        self.editToolBar.addAction(self.deleteSelectedAction)

        self.addPartAction = self.iface.actionAddPart()
        self.addPartAction.setObjectName(u'addPartAction')
        self.editToolBar.addAction(self.addPartAction)

        self.splitFeaturesAction = self.iface.actionSplitFeatures()
        self.splitFeaturesAction.setObjectName(u'splitFeaturesAction')
        self.editToolBar.addAction(self.splitFeaturesAction)

        self.perimeterLabel = QLabel(self)
        self.perimeterLabel.setObjectName(u'perimeterLabel')
        self.perimeterLabel.setText(u'Obvod:')
        self.gridLayout.addWidget(self.perimeterLabel, 1, 0, 1, 1)

        self.perimeterMapLayerComboBox = QgsMapLayerComboBox(self)
        self.perimeterMapLayerComboBox.setObjectName(
            u'perimeterMapLayerComboBox')
        self.perimeterMapLayerComboBox.setFilters(
            QgsMapLayerProxyModel.PolygonLayer)
        self.perimeterMapLayerComboBox.activated.connect(
            self.sync_perimeter_map_layer_combo_box)
        QgsMapLayerRegistry.instance().layersAdded.connect(
            self._rollback_perimeter_layer)
        QgsMapLayerRegistry.instance().layersRemoved.connect(
            self._reset_perimeter_layer)
        self.set_perimeter_layer(self.lastPerimeterLayer)
        self.gridLayout.addWidget(self.perimeterMapLayerComboBox, 1, 1, 1, 1)

        self.createPerimeterPushButton = QPushButton(self)
        self.createPerimeterPushButton.setObjectName(
            u'createPerimeterPushButton')
        self.createPerimeterPushButton.setText(u'Vytvořit')
        self.createPerimeterPushButton.setToolTip(
            u'Vytvořit vrstvu obvodu (.shp) z aktivní vrstvy a načíst')
        self.createPerimeterPushButton.clicked.connect(self._create_perimeter)
        self.gridLayout.addWidget(self.createPerimeterPushButton, 1, 2, 1, 1)

        self.gridLayout.setRowStretch(2, 1)

        self.categoryLabel = QLabel(self)
        self.categoryLabel.setObjectName(u'categoryLabel')
        self.categoryLabel.setText(u'Kategorie parcel:')
        self.gridLayout.addWidget(self.categoryLabel, 3, 0, 1, 1)

        self.categoryComboBox = QComboBox(self)
        self.categoryComboBox.setObjectName(u'categoryComboBox')
        self.categoryComboBox.addItem(u'mimo obvod (0)')
        self.categoryComboBox.addItem(u'v obvodu - neřešené (1)')
        self.categoryComboBox.addItem(u'v obvodu - řešené (2)')
        self.categoryComboBox.addItem(u'bez kategorie')
        self.categoryComboBox.currentIndexChanged.connect(
            self._set_categoryValue)
        self.gridLayout.addWidget(self.categoryComboBox, 3, 1, 1, 1)

        self.selectCategoryPushButton = QPushButton(self)
        self.selectCategoryPushButton.setObjectName(
            u'selectCategoryPushButton')
        self.selectCategoryPushButton.setText(u'Zobrazit')
        self.selectCategoryPushButton.setToolTip(
            u'Zobrazit (vybrat) parcely v kategorii')
        self.selectCategoryPushButton.clicked.connect(self._select_category)
        self.gridLayout.addWidget(self.selectCategoryPushButton, 3, 2, 1, 1)

        self.gridLayout.setRowStretch(4, 1)

        self.setCategoryLabel = QLabel(self)
        self.setCategoryLabel.setObjectName(u'setCategoryLabel')
        self.setCategoryLabel.setText(u'Zařadit:')
        self.gridLayout.addWidget(self.setCategoryLabel, 5, 0, 1, 1)

        self.setCategoryComboBox = QComboBox(self)
        self.setCategoryComboBox.setObjectName(u'setCategoryComboBox')
        self.setCategoryComboBox.addItem(u'vybrané parcely')
        self.setCategoryComboBox.setItemData(
            0, u'Zařadit vybrané parcely do kategorie', Qt.ToolTipRole)
        self.setCategoryComboBox.addItem(u'obvodem')
        self.setCategoryComboBox.setItemData(
            1, u'Zařadit všechny parcely do kategorií na základě obvodu',
            Qt.ToolTipRole)
        self.setCategoryComboBox.currentIndexChanged.connect(
            self._set_setCategoryValue)
        self.gridLayout.addWidget(self.setCategoryComboBox, 5, 1, 1, 1)

        self.setCategoryPushButton = QPushButton(self)
        self.setCategoryPushButton.setObjectName(u'setCategoryPushButton')
        self.setCategoryPushButton.setText(u'Zařadit')
        self.setCategoryPushButton.clicked.connect(
            self._start_setting_pu_category)
        self.gridLayout.addWidget(self.setCategoryPushButton, 5, 2, 1, 1)

    def _set_icon_size(self):
        """Sets editToolBar icon size according to the current QGIS settings."""

        self.editToolBar.setIconSize(self.iface.mainWindow().iconSize())

    def _set_categoryValue(self):
        """Sets categoryValue according to the current index.
        
        categoryValue - description:
            0 - mimo obvod
            1 - v obvodu - neřešené
            2 - v obvodu - řešené
        
        """

        currentIndex = self.categoryComboBox.currentIndex()

        if currentIndex == 3:
            self.categoryValue = None
        else:
            self.categoryValue = currentIndex

    def _set_setCategoryValue(self):
        """Sets setCategoryValue according to the current index.
        
        setCategoryValue - description:
            0 - vybrané parcely
            1 - obvodem
        
        """

        self.setCategoryValue = self.setCategoryComboBox.currentIndex()

    def set_perimeter_layer(self, perimeterLayer, lastPerimeterLayer=True):
        """Sets the perimeter layer in the perimeterMapLayerComboBox.
        
        Args:
            perimeterLayer (QgsVectorLayer): A reference to the perimeter layer.
            lastPerimeterLayer (bool): True to set self.lastPerimeterLayer,
                False otherwise.
        
        """

        if lastPerimeterLayer:
            self.lastPerimeterLayer = perimeterLayer

        self.perimeterMapLayerComboBox.setLayer(perimeterLayer)

    def sync_perimeter_map_layer_combo_box(self):
        """Synchronizes perimeter map layer combo boxes.
        
        Synchronizes with the perimeterMapLayerComboBox in the perimeterWidget.
        
        """

        perimeterLayer = self.perimeterMapLayerComboBox.currentLayer()

        if perimeterLayer != self.lastPerimeterLayer:
            self.lastPerimeterLayer = perimeterLayer

            self.dW.stackedWidget.checkAnalysisPuWidget\
                .perimeterPuCaWidget.set_perimeter_layer(perimeterLayer)

    def _reset_perimeter_layer(self):
        """Resets the perimeter layer."""

        layers = self.iface.legendInterface().layers()

        if self.lastPerimeterLayer not in layers:
            self.set_perimeter_layer(None)

    def _rollback_perimeter_layer(self):
        """Rolls the perimeter layer back."""

        if self.lastPerimeterLayer == None:
            self.set_perimeter_layer(self.lastPerimeterLayer, False)
        else:
            self.lastPerimeterLayer = \
                self.perimeterMapLayerComboBox.currentLayer()

    def _create_perimeter(self):
        """Calls methods for creating and loading perimeter layer."""

        try:
            succes, layer = self.dW.check_layer(self)

            if not succes:
                return

            if layer.featureCount() == 0:
                self.set_text_statusbar.emit(
                    u'Aktivní vrstva neobsahuje žádný prvek.', 10, True)
                return

            editing = self.dW.check_editing()

            title = u'Uložit vrstvu obvodu jako...'
            filters = u'.shp (*.shp)'

            perimeterLayerFilePath = self.dW.open_file_dialog(
                title, filters, False)

            if perimeterLayerFilePath:
                self.set_text_statusbar.emit(u'Vytvářím vrstvu obvodu...', 0,
                                             False)

                fileInfo = QFileInfo(perimeterLayerFilePath)

                if not fileInfo.suffix() == u'shp':
                    perimeterLayerFilePath = \
                        fileInfo.absoluteFilePath() + u'.shp'
                    fileInfo = QFileInfo(perimeterLayerFilePath)

                selectedFeaturesIds = layer.selectedFeaturesIds()

                perimeterLayerName = fileInfo.completeBaseName()

                loadedLayer = self.dW.check_loaded_layers(
                    perimeterLayerFilePath)

                perimeterLayer = self._create_perimeter_layer(
                    layer, perimeterLayerFilePath, self.categoryName,
                    perimeterLayerName, loadedLayer)

                QgsApplication.processEvents()

                loadedLayer = self.dW.check_loaded_layers(
                    perimeterLayerFilePath)

                if loadedLayer:
                    self.iface.actionDraw().trigger()
                    self.set_perimeter_layer(loadedLayer, False)
                    self.sync_perimeter_map_layer_combo_box()
                else:
                    QgsMapLayerRegistry.instance().addMapLayer(perimeterLayer)

                layer.selectByIds(selectedFeaturesIds)

                self.iface.setActiveLayer(layer)

                if editing:
                    self.toggleEditingAction.trigger()

                self.set_text_statusbar.emit(u'Obvod byl úspešně vytvořen.',
                                             15, False)
        except:
            self.dW.display_error_messages(self, u'Error creating perimeter.',
                                           u'Chyba při vytváření obvodu.')

    def _create_perimeter_layer(self, layer, perimeterLayerFilePath,
                                categoryName, perimeterLayerName, loadedLayer):
        """Creates a perimeter layer from the given layer.
        
        Args:
            layer (QgsVectorLayer): A reference to the layer.
            perimeterLayerFilePath (str): A full path to the perimeter layer.
            categoryName (str): A name of the category field the layer is about
                to be dissolved by.
            perimeterLayerName (str): A name of the perimeter layer.
            loadedLayer (bool): A reference to the loaded layer.
                This is relevant only for Windows platform.
        
        Returns:
            QgsVectorLayer: A reference to the perimeter layer.
        
        """

        fileInfo = QFileInfo(perimeterLayerFilePath)

        tempPerimeterLayerName = fileInfo.completeBaseName() + u'.temp'

        layer.removeSelection()

        tempPerimeterLayerPath = processing.runalg('qgis:dissolve', layer,
                                                   False, categoryName,
                                                   None)['OUTPUT']

        tempPerimeterLayer = QgsVectorLayer(tempPerimeterLayerPath,
                                            tempPerimeterLayerName, 'ogr')

        if loadedLayer:
            perimeterLayerName = loadedLayer.name()
            QgsMapLayerRegistry.instance().removeMapLayer(loadedLayer)

        QgsApplication.processEvents()

        processing.runalg('qgis:multiparttosingleparts', tempPerimeterLayer,
                          perimeterLayerFilePath)

        perimeterLayer = QgsVectorLayer(perimeterLayerFilePath,
                                        perimeterLayerName, 'ogr')

        QgsMapLayerRegistry.instance().addMapLayer(perimeterLayer)

        expression = QgsExpression("\"{}\" is null".format(
            self.shortCategoryName))

        self.dW.delete_features_by_expression(perimeterLayer, expression)

        return perimeterLayer

    def set_perimeter_layer_table_config(self, perimeterLayer):
        """Sets perimeter layer table config.
        
        Args:
            layer (QgsVectorLayer): A reference to the perimeter layer.
        
        """

        fields = perimeterLayer.pendingFields()

        tableConfig = perimeterLayer.attributeTableConfig()
        tableConfig.update(fields)

        columns = tableConfig.columns()

        for column in columns:
            if not column.name == self.shortCategoryName:
                column.hidden = True

        tableConfig.setColumns(columns)
        perimeterLayer.setAttributeTableConfig(tableConfig)

    def _start_setting_pu_category(self):
        """Starts setting PU category in a separate thread.."""

        succes, layer = self.dW.check_layer(self)

        if not succes:
            return

        self.executeThread = ExecuteThread(layer)
        self.executeThread.started.connect(self._run_setting_pu_category)
        self.executeThread.start()

    def _run_setting_pu_category(self, layer):
        """Calls methods for setting PU category.
        
        Args:
            layer (QgsVectorLayer): A reference to the layer.
        
        """
        try:
            perimeterLayer = self.perimeterMapLayerComboBox.currentLayer()

            editing = self.dW.check_editing()

            if self.setCategoryValue == 0:
                self._set_category_for_selected(layer, perimeterLayer)

            if self.setCategoryValue == 1:
                self._set_category_by_perimeter(layer, perimeterLayer)

            if editing:
                self.toggleEditingAction.trigger()
        except:
            QgsApplication.processEvents()

            self.dW.display_error_messages(
                self, u'Error setting parcel category.',
                u'Chyba při zařazování do kategorie parcel.')

    def _set_category_for_selected(self, layer, perimeterLayer):
        """Sets a categoryValue to categoryName column for selected features.
        
        Also updates the perimeter layer.
        
        Args:
            layer (QgsVectorLayer): A reference to the layer.
            perimeterLayer (QgsVectorLayer): A reference to the perimeter
                layer.
        
        """

        featureCount = layer.selectedFeatureCount()

        if featureCount == 0:
            self.set_text_statusbar.emit(
                u'V aktivní vrstvě nejsou vybrány žádné prvky.', 10, True)
            return

        currentCategory = self.categoryComboBox.currentText()

        warning = False

        if featureCount == 1:
            self.set_text_statusbar.emit(
                u'Zařazuji vybranou parcelu do kategorie "{}"...'.format(
                    currentCategory), 0, warning)
        else:
            self.set_text_statusbar.emit(
                u'Zařazuji vybrané parcely do kategorie "{}"...'.format(
                    currentCategory), 0, warning)

        selectedFeaturesIds = layer.selectedFeaturesIds()
        selectedFeatures = layer.selectedFeaturesIterator()

        self.dW.set_field_value_for_features(layer, selectedFeatures,
                                             self.categoryName,
                                             self.categoryValue)

        QgsApplication.processEvents()

        self.update_perimeter_layer(layer, perimeterLayer)

        layer.selectByIds(selectedFeaturesIds)

        if featureCount == 1:
            self.set_text_statusbar.emit(
                u'Vybraná parcela byla zařazena do kategorie "{}".'.format(
                    currentCategory), 20, warning)
        else:
            self.set_text_statusbar.emit(
                u'Vybrané parcely byly zařazeny do kategorie "{}".'.format(
                    currentCategory), 20, warning)

    def update_perimeter_layer(self, layer=None, perimeterLayer=None):
        """Updates the perimeter layer.
        
        Args:
            layer (QgsVectorLayer): A reference to the layer.
            perimeterLayer (QgsVectorLayer): A reference to the perimeter
                layer.
        
        """

        if not layer:
            layer = self.iface.activeLayer()

        if not perimeterLayer:
            perimeterLayer = self.perimeterMapLayerComboBox.currentLayer()

        if not self.dW.check_perimeter_layer(perimeterLayer, layer):
            # SpatiaLite fix - start
            perimeterString = u'-obvod.shp'

            if not self.dW.fixedSqliteDriver:
                composedURI = QgsDataSourceURI(layer.source())
                perimeterLayerFilePath = \
                    composedURI.database().split('.sdb')[0] + perimeterString
            else:
                perimeterLayerFilePath = \
                    layer.source().split('.db')[0] + perimeterString
            # SpatiaLite fix - end

            fileInfo = QFileInfo(perimeterLayerFilePath)
            perimeterLayerName = fileInfo.baseName()

            loadedLayer = self.dW.check_loaded_layers(perimeterLayerFilePath)

            perimeterLayer = self._create_perimeter_layer(
                layer, perimeterLayerFilePath, self.categoryName,
                perimeterLayerName, loadedLayer)

            QgsApplication.processEvents()

            loadedLayer = self.dW.check_loaded_layers(perimeterLayerFilePath)

            if loadedLayer:
                self.iface.actionDraw().trigger()
                self.set_perimeter_layer(loadedLayer, False)
                self.sync_perimeter_map_layer_combo_box()
            else:
                QgsMapLayerRegistry.instance().addMapLayer(perimeterLayer)
        else:
            perimeterLayerFilePath = perimeterLayer.source()
            perimeterLayerName = perimeterLayer.name()

            perimeterLayer = self._create_perimeter_layer(
                layer, perimeterLayerFilePath, self.categoryName,
                perimeterLayerName, perimeterLayer)

            self.set_perimeter_layer(perimeterLayer, False)
            self.sync_perimeter_map_layer_combo_box()

        QgsApplication.processEvents()

        self.iface.actionDraw().trigger()

        self.iface.setActiveLayer(layer)

    def _set_category_by_perimeter(self, layer, perimeterLayer):
        """Sets a categoryValue to categoryName column for all features
        according to current layer in perimeterMapLayerComboBox.
        
        Args:
            layer (QgsVectorLayer): A reference to the layer.
            perimeterLayer (QgsVectorLayer): A reference to the perimeter
                layer.
        
        """

        if not self.dW.check_perimeter_layer(perimeterLayer, layer, self):
            return

        if perimeterLayer.featureCount() == 0:
            self.set_text_statusbar.emit(
                u'Vrstva obvodu neobsahuje žádný prvek.', 10, True)
            return

        warning = False

        self.set_text_statusbar.emit(
            u'Zařazuji parcely do kategorií na základě obvodu...', 0, warning)

        selectedFeaturesIds = layer.selectedFeaturesIds()
        perimeterSelectedFeaturesIds = perimeterLayer.selectedFeaturesIds()

        layer.removeSelection()
        perimeterLayer.removeSelection()

        for categoryValue in self.categoryValues:
            if categoryValue == None:
                perimeterLayer.selectAll()
            else:
                self.dW.select_features_by_field_value(perimeterLayer,
                                                       self.shortCategoryName,
                                                       categoryValue)

            if perimeterLayer.selectedFeatureCount() != 0:
                selectedFeaturesLayerFilePath = processing.runalg(
                    'qgis:saveselectedfeatures', perimeterLayer,
                    None)['OUTPUT_LAYER']

                selectedFeaturesLayer = QgsVectorLayer(
                    selectedFeaturesLayerFilePath, 'selectedFeaturesLayer',
                    'ogr')

                processing.runalg('qgis:selectbylocation', layer,
                                  selectedFeaturesLayer, u'within', 0, 0)

                if categoryValue == None:
                    layer.invertSelection()
                    categoryValue = QPyNullVariant

                features = layer.selectedFeaturesIterator()

                self.dW.set_field_value_for_features(layer, features,
                                                     self.categoryName,
                                                     categoryValue)

        layer.selectByIds(selectedFeaturesIds)
        perimeterLayer.selectByIds(perimeterSelectedFeaturesIds)

        self.set_text_statusbar.emit(
            u'Zařazení parcel na základě obvodu úspěšně dokončeno.', 30,
            warning)

    def _select_category(self):
        """Selects features in the current category."""

        try:
            succes, layer = self.dW.check_layer(self)

            if not succes:
                return

            if self.categoryValue == None:
                expression = QgsExpression("\"{}\" is null".format(
                    self.categoryName))
                self.dW.select_features_by_expression(layer, expression)
            else:
                self.dW.select_features_by_field_value(layer,
                                                       self.categoryName,
                                                       self.categoryValue)

            currentCategory = self.categoryComboBox.currentText()

            featureCount = layer.selectedFeatureCount()

            duration = 10
            warning = False

            if featureCount == 0:
                self.set_text_statusbar.emit(
                    u'V kategorii "{}" není žádná parcela.'.format(
                        currentCategory), duration, warning)
            elif featureCount == 1:
                self.set_text_statusbar.emit(
                    u'V kategorii "{}" je {} parcela.'.format(
                        currentCategory, featureCount), duration, warning)
            elif 1 < featureCount < 5:
                self.set_text_statusbar.emit(
                    u'V kategorii "{}" jsou {} parcely.'.format(
                        currentCategory, featureCount), duration, warning)
            elif 5 <= featureCount:
                self.set_text_statusbar.emit(
                    u'V kategorii "{}" je {} parcel.'.format(
                        currentCategory, featureCount), duration, warning)
        except:
            self.dW.display_error_messages(
                self, u'Error selecting parcels in category.',
                u'Chyba při vybírání parcel v kategorii.')

    def check_perimeter_map_layer_combo_box(self):
        """Checks if there is a layer in perimeterMapLayerComboBox.
        
        Returns:
            bool: True when there is a layer in perimeterMapLayerComboBox,
                False otherwise.
        
        """

        if self.perimeterMapLayerComboBox.currentLayer():
            return True
        else:
            return False
コード例 #23
0
ファイル: viewer.py プロジェクト: kant/earthmine-qgis
class Viewer(ViewerBase, ViewerClass):
    trackingChanged = pyqtSignal(bool)
    setLocationTriggered = pyqtSignal()
    updateFeatures = pyqtSignal(bool)
    layerChanged = pyqtSignal(QgsMapLayer)
    clearLine = pyqtSignal()
    closed = pyqtSignal()

    def __init__(self, callbackobject, parent=None):
        """Constructor."""
        super(Viewer, self).__init__(parent)
        self.setupUi(self)
        self.callbackobject = callbackobject
        self.frame = self.webview.page().mainFrame()
        self.actiongroup = QActionGroup(self)
        self.actiongroup.setExclusive(True)
        self.actiongroup.triggered.connect(self.action_triggered)

        self.measuredialog = MeasureDialog(self)

        self.toolbar = QToolBar()
        self.qgisTrackButton = self.toolbar.addAction("QGIS Track")
        self.qgisTrackButton.setIcon(QIcon(":/icons/track"))
        self.qgisTrackButton.setCheckable(True)
        self.qgisTrackButton.setChecked(True)
        self.qgisTrackButton.toggled.connect(self.trackingChanged.emit)

        self.setlocationaction = self.toolbar.addAction("Set location")
        self.setlocationaction.setIcon(QIcon(":/icons/location"))
        self.setlocationaction.triggered.connect(
            self.setLocationTriggered.emit)
        self.setlocationaction.setCheckable(True)

        self.viewfeatures = self.toolbar.addAction("Load QGIS Features")
        self.viewfeatures.setIcon(QIcon(":/icons/features"))
        self.viewfeatures.setCheckable(True)
        self.viewfeatures.setChecked(True)
        self.viewfeatures.toggled.connect(self.updateFeatures.emit)

        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer)

        self.measureaction = self.toolbar.addAction("measure")
        self.measureaction.setObjectName("Measure")
        self.measureaction.setIcon(QIcon(":/icons/measure"))
        self.measureaction.setCheckable(True)

        self.infoaction = self.toolbar.addAction("Info")
        self.infoaction.setObjectName("Info")
        self.infoaction.setIcon(QIcon(":/icons/info"))
        self.infoaction.setCheckable(True)

        self.selectaction = self.toolbar.addAction("Select")
        self.selectaction.setObjectName("Select")
        self.selectaction.setIcon(QIcon(":/icons/select"))
        self.selectaction.setCheckable(True)

        self.toolbar.addSeparator()

        self.deleteaction = self.toolbar.addAction("Delete")
        self.deleteaction.setIcon(QIcon(":/icons/delete"))
        self.deleteaction.triggered.connect(self.delete_selected)
        self.deleteaction.setEnabled(False)

        self.addaction = self.toolbar.addAction("Add")
        self.addaction.setObjectName("Add")
        self.addaction.setIcon(QIcon(":/icons/add"))
        self.addaction.setCheckable(True)

        self.moveaction = self.toolbar.addAction("Move")
        self.moveaction.setObjectName("Move")
        self.moveaction.setIcon(QIcon(":/icons/move"))
        self.moveaction.setCheckable(True)

        self.actiongroup.addAction(self.moveaction)
        self.actiongroup.addAction(self.addaction)
        self.actiongroup.addAction(self.infoaction)
        self.actiongroup.addAction(self.measureaction)
        self.actiongroup.addAction(self.selectaction)

        self.activelayercombo = QgsMapLayerComboBox()
        self.activelayercombo.layerChanged.connect(self.layer_changed)
        self.activelayeraction = self.toolbar.addWidget(self.activelayercombo)
        self.activelayercombo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.activelayercombo.currentIndexChanged.connect(self.index_changed)

        self.zvaluecheck = QCheckBox()
        self.zvaluecheck.setChecked(True)
        self.zvaluecheck.setText("Copy Z value")
        self.zvaluecheck.setToolTip(
            "Copy Z value from viewer to new features in QGIS. Must have a field named Z to enable"
        )
        self.zvalueaction = self.toolbar.addWidget(self.zvaluecheck)

        self.dockWidgetContents.layout().insertWidget(0, self.toolbar)

        self.webview.settings().setAttribute(QWebSettings.PluginsEnabled, True)
        self.webview.settings().setAttribute(QWebSettings.JavascriptEnabled,
                                             True)
        self.webview.settings().setAttribute(
            QWebSettings.DeveloperExtrasEnabled, True)
        self.frame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.frame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
        self.frame.javaScriptWindowObjectCleared.connect(
            self.addcallbackobject)
        self.measuredialog.modeCombo.currentIndexChanged.connect(
            self.action_triggered)
        self.measuredialog.clearButton.clicked.connect(self.clear_line)

        self.earthmine = EarthmineAPI(self.frame)

    def closeEvent(self, event):
        self.closed.emit()
        super(Viewer, self).closeEvent(event)

    def index_changed(self, index):
        if index == -1:
            self.set_button_states(False, False, False, False)

    def clear_line(self):
        self.clearLine.emit()
        self.earthmine.clearLine()

    @property
    def copyZvalue(self):
        layer = self.active_layer
        if not layer:
            return False

        if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType(
        ) == QGis.Point:
            return self.zvaluecheck.isChecked()
        else:
            return False

    @property
    def geom(self):
        return self.measuredialog.geom

    @geom.setter
    def geom(self, value):
        self.measuredialog.geom = value
        self.measuredialog.update_geom_labels()

    @property
    def tracking(self):
        return self.qgisTrackButton.isChecked()

    @property
    def mode(self):
        return self.measuredialog.mode

    @property
    def active_layer(self):
        return self.activelayercombo.currentLayer()

    def layer_changed(self, layer):
        if not layer:
            self.set_button_states(False, False, False, False)
            return

        if layer.type() == QgsMapLayer.VectorLayer:
            enabledselecttools = layer.geometryType() in [
                QGis.Line, QGis.Point
            ]
            enableedittools = layer.isEditable()
            enabledelete = layer.isEditable() and layer.selectedFeatureCount()
            enablemove = layer.geometryType(
            ) == QGis.Point and layer.isEditable()
        else:
            enabledselecttools = False
            enableedittools = False
            enabledelete = False
            enablemove = False

        self.set_button_states(enabledselecttools, enableedittools,
                               enabledelete, enablemove)
        self.action_triggered()
        self.layerChanged.emit(layer)

    def selection_changed(self, layer):
        if layer == self.active_layer:
            enabledelete = layer.isEditable() and layer.selectedFeatureCount()
            self.deleteaction.setEnabled(enabledelete)

    def set_button_states(self, selecttools, edittools, deleteenabled,
                          moveenabled):
        actions = [self.selectaction, self.infoaction]

        for action in actions:
            action.setEnabled(selecttools)

        editactions = [self.deleteaction, self.moveaction, self.addaction]

        for action in editactions:
            action.setEnabled(edittools)

        if edittools:
            self.deleteaction.setEnabled(deleteenabled)
            self.moveaction.setEnabled(moveenabled)

        for action in editactions:
            if action is self.actiongroup.checkedAction(
            ) and not action.isEnabled():
                self.infoaction.toggle()
                break

        layer = self.active_layer
        if not layer:
            enablez = False
        else:
            enablez = layer.type(
            ) == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point
        self.zvalueaction.setEnabled(enablez)

    @property
    def current_action_color(self):
        action = self.actiongroup.checkedAction()
        color = int("0x00ff00", 16)
        if action == self.measureaction:
            if self.mode == "Vertical":
                color = int("0x0000ff", 16)

        return color

    def action_triggered(self, *args):
        action = self.actiongroup.checkedAction()
        layer = self.activelayercombo.currentLayer()

        self.clear_line()
        if not action:
            return

        if not action == self.measureaction and (
                not layer or not layer.type() == QgsMapLayer.VectorLayer):
            return

        color = self.current_action_color
        actiondata = {}

        if action == self.measureaction:
            self.measuredialog.show()
            actiondata['mode'] = self.mode
            geomtype = None
            layerid = None
        else:
            self.measuredialog.hide()
            geomtype = QGis.vectorGeometryType(layer.geometryType())
            layerid = layer.id()

        data = dict(action=action.objectName(),
                    layer=layerid,
                    geom=geomtype,
                    actiondata=actiondata,
                    color=color)

        self.earthmine.updateAction(data)

    def active_tool(self):
        action = self.actiongroup.checkedAction()
        if not action:
            return None
        return action.objectName()

    def update_current_layer(self, layer):
        self.activelayercombo.setLayer(layer)

    def addcallbackobject(self):
        self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject)

    def loadviewer(self, url):
        self.webview.load(url)
        self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject)

    def startViewer(self, settings):
        self.earthmine.startViewer(settings)

    def set_location(self, point):
        # # NOTE Set location takes WGS84 make sure you have transformed it first before sending
        self.earthmine.setLocation(point.x(), point.y())

    def clear_features(self):
        self.earthmine.clearFeatures()

    def clear_layer_features(self, layerid):
        self.earthmine.clearLayerObjects(layerid)

    def remove_feature(self, layerid, featureid):
        """
        :param features: A dict of layerid, id, lat, lng
        :return:
        """
        self.earthmine.removeFeature(layerid, featureid)

    def load_features(self, layerdata, features):
        """
        :param features: A dict of layerid, id, lat, lng
        :return:
        """
        self.earthmine.loadFeatures(layerdata, features)

    def layer_loaded(self, layerid):
        return self.earthmine.layerLoaded(layerid)

    def clear_selection(self, layerid):
        self.earthmine.clearSelection(layerid)

    def set_selection(self, layerid, featureids, clearlast=True):
        self.earthmine.setSelection(layerid, featureids, clearlast)

    def edit_feature(self, layerid, featureid, nodes):
        self.earthmine.editFeature(layerid, featureid, nodes)

    def delete_selected(self):
        layer = self.active_layer
        layer.deleteSelectedFeatures()
コード例 #24
0
class NewProjectDialog(Dialog):
    '''
    dialog to select a layer and a name as inputs for creating a new project
    '''
    def setupUi(self):
        '''
        set up the user interface
        '''
        self.setMinimumWidth(500)
        self.setWindowTitle('Neues Projekt erstellen')

        project_manager = ProjectManager()
        self.project_names = [p.name for p in project_manager.projects]

        layout = QVBoxLayout(self)

        label = QLabel('Name des Projekts')
        self.name_edit = QLineEdit()
        self.name_edit.textChanged.connect(self.validate)
        layout.addWidget(label)
        layout.addWidget(self.name_edit)
        self.path = os.path.join(project_manager.settings.TEMPLATE_PATH,
                                 'projektflaechen')

        hlayout = QHBoxLayout(self)
        label = QLabel('Import der (Teil-)Flächen des Plangebiets')
        self.layer_combo = QgsMapLayerComboBox()
        self.layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer)

        self.source = None

        self.layer_combo.layerChanged.connect(self.set_layer)
        self.layer_combo.layerChanged.connect(self.validate)
        browse_button = QPushButton('...')
        browse_button.clicked.connect(self.browse_path)
        browse_button.setMaximumWidth(30)
        hlayout.addWidget(self.layer_combo)
        hlayout.addWidget(browse_button)
        layout.addWidget(label)
        layout.addLayout(hlayout)

        self.status_label = QLabel()
        layout.addWidget(self.status_label)

        spacer = QSpacerItem(
            20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        layout.addItem(spacer)

        buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
            Qt.Horizontal, self)
        self.ok_button = buttons.button(QDialogButtonBox.Ok)
        self.ok_button.setEnabled(False)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

        if len(self.layer_combo) > 0:
            self.set_layer(self.layer_combo.currentLayer())
        self.layer_combo.setCurrentIndex(0)

    def set_layer(self, layer: QgsVectorLayer = None):
        '''
        set layer as user selection

        Parameters
        ----------
        layer : QgsVectorLayer
            the selected layer
        '''
        if not layer:
            path = self.layer_combo.currentText()
            layer = QgsVectorLayer(path, 'testlayer_shp', 'ogr')
        self.source = layer
        self.validate()

    def browse_path(self):
        '''
        open dialog for user input of path to a shapefile and add it to the
        layer-combo
        '''
        path, sf = QFileDialog.getOpenFileName(
            self, 'Datei wählen', filter="Shapefile(*.shp)",
            directory=self.path)
        if path:
            self.path = os.path.split(path)[0]
            self.layer_combo.setAdditionalItems([str(path)])
            self.layer_combo.setCurrentIndex(self.layer_combo.count()-1)
            self.set_layer()

    def show(self) -> Tuple[bool, str, QgsVectorLayer]:
        '''
        show dialog and return selections made by user
        '''
        confirmed = self.exec_()
        if confirmed:
            return confirmed, self.name_edit.text(), self.source
        return False, None, None

    def validate(self):
        '''
        validate current input of name and layer, set the status label according
        to validation result
        '''
        name = str(self.name_edit.text())
        status_text = ''
        regexp = re.compile('[\\\/\:*?\"\'<>|]')
        error = False
        if name and regexp.search(name):
            status_text = ('Der Projektname darf keines der folgenden Zeichen '
                           'enthalten: \/:*?"\'<>|')
            error = True
        elif name in self.project_names:
            status_text = (
                f'Ein Projekt mit dem Namen {name} existiert bereits!\n'
                'Projektnamen müssen einzigartig sein.')
            error = True

        if self.source:
            if not self.source.isValid():
                status_text = 'Der Layer ist ungültig.'
                error = True
            elif not self.source.geometryType() == QgsWkbTypes.PolygonGeometry:
                status_text = 'Der Layer hat keine Polygongeometrie.'
                error = True

        self.status_label.setText(status_text)

        if not error and (name and self.source):
            self.ok_button.setEnabled(True)
        else:
            self.ok_button.setEnabled(False)
コード例 #25
0
class BpejPuCaWidget(PuCaWidget):
    """A widget for 'BPEJ' analysis."""
    
    def _build_widgets(self):
        """Builds own widgets."""
        
        self.lastBpejLayer = None
        
        self.bpejMapLayerComboBox = QgsMapLayerComboBox(self)
        self.bpejMapLayerComboBox.setObjectName(u'bpejMapLayerComboBox')
        self.bpejMapLayerComboBox.setFilters(
            QgsMapLayerProxyModel.PolygonLayer)
        self.bpejMapLayerComboBox.activated.connect(self._set_last_bpej_layer)
        QgsMapLayerRegistry.instance().layersAdded.connect(
            self._rollback_bpej_layer)
        QgsMapLayerRegistry.instance().layersRemoved.connect(
            self._reset_bpej_layer)
        self.set_bpej_layer(self.lastBpejLayer)
        self.vBoxLayout.addWidget(self.bpejMapLayerComboBox)
        
        self.bpejFieldComboBox = QgsFieldComboBox(self)
        self.bpejFieldComboBox.setObjectName(u'bpejFieldComboBox')
        self.bpejFieldComboBox.setLayer(
            self.bpejMapLayerComboBox.currentLayer())
        self.vBoxLayout.addWidget(self.bpejFieldComboBox)
        
        self.bpejMapLayerComboBox.layerChanged.connect(
            self.bpejFieldComboBox.setLayer)
    
    def set_bpej_layer(self, bpejLayer, lastBpejLayer=True):
        """Sets the BPEJ layer in the bpejMapLayerComboBox.
        
        Args:
            bpejLayer (QgsVectorLayer): A reference to the BPEJ layer.
            lastBpejLayer (bool): True to set self.lastBpejLayer,
                False otherwise.
        
        """
        
        if lastBpejLayer:
            self.lastBpejLayer = bpejLayer
        
        self.bpejMapLayerComboBox.setLayer(bpejLayer)
    
    def _set_last_bpej_layer(self):
        """Sets the lastBpejLayer.
        
        Sets the lastBpejLayer according to the current layer
        in the bpejMapLayerComboBox.
        
        """
        
        bpejLayer = self.bpejMapLayerComboBox.currentLayer()
        
        if bpejLayer != self.lastBpejLayer:
            self.lastBpejLayer = bpejLayer
    
    def _reset_bpej_layer(self):
        """Resets the BPEJ layer."""
        
        layers = self.iface.legendInterface().layers()
        
        if self.lastBpejLayer not in layers:
            self.set_bpej_layer(None)
    
    def _rollback_bpej_layer(self):
        """Rolls the BPEJ layer back."""
        
        if self.lastBpejLayer == None:
            self.set_bpej_layer(self.lastBpejLayer, False)
        else:
            self.lastBpejLayer = self.bpejMapLayerComboBox.currentLayer()
    
    def execute(self, layer):
        """Executes the analysis.
        
        Args:
            layer (QgsVectorLayer): A reference to the active layer.
        
        """
        
        try:
            editing = self.dW.check_editing()
            
            bpejLayer = self.bpejMapLayerComboBox.currentLayer()
            
            if bpejLayer == None:
                self.pW.set_text_statusbar.emit(u'Žádná vrstva BPEJ.', 10, True)
                return
            
            if bpejLayer.featureCount() == 0:
                self.pW.set_text_statusbar.emit(
                    u'Vrstva BPEJ neobsahuje žádný prvek.', 10, True)
                return
            
            bpejLayerCrs = bpejLayer.crs().authid()
            layerCrs = layer.crs().authid()
            
            if bpejLayerCrs != layerCrs:
                self.pW.set_text_statusbar.emit(
                    u'Aktivní vrstva a vrstva BPEJ nemají stejný '
                    u'souřadnicový systém.', 10, True)
                return
            
            bpejField = self.bpejFieldComboBox.currentField()
            
            if bpejField == u'':
                self.pW.set_text_statusbar.emit(
                    u'Není vybrán sloupec ceny.', 10, True)
                return
            
            self.pW.set_text_statusbar.emit(
                u'Provádím analýzu - oceňování podle BPEJ...', 0, False)
            
            layer.removeSelection()
            bpejLayer.removeSelection()
            
            editedBpejField = self._edit_bpej_field(bpejField, layer)
            
            unionFilePath = processing.runalg(
                'qgis:union',
                layer, bpejLayer, None)['OUTPUT']
            
            unionLayer = QgsVectorLayer(unionFilePath, 'unionLayer', 'ogr')
            
            expression = QgsExpression(
                "\"{}\" is null "
                "or "
                "\"{}\" is null "
                "or "
                "\"{}\" is null "
                "or "
                "\"{}\" != 2"
                .format(
                    editedBpejField,
                    self.dW.defaultMajorParNumberColumnName[:10],
                    self.dW.puCategoryColumnName[:10],
                    self.dW.puCategoryColumnName[:10]))
            
            self.dW.delete_features_by_expression(unionLayer, expression)
            
            if unionLayer.featureCount() != 0:
                multiToSingleFilePath = processing.runalg(
                    'qgis:multiparttosingleparts',
                    unionLayer, None)['OUTPUT']
                
                multiToSingleLayer = QgsVectorLayer(
                    multiToSingleFilePath, 'multiToSingleLayer', 'ogr')
                
                bpejCodePrices = self._get_bpej_code_prices()
                
                rowidColumnName = self.dW.rowidColumnName
                
                prices, missingBpejCodes, bpejCodeAreasPrices = \
                    self._calculate_feature_prices(
                        rowidColumnName, multiToSingleLayer,
                        editedBpejField, bpejCodePrices)
                
                priceFieldName = self.dW.puPriceColumnName
                priceFieldId = layer.fieldNameIndex(priceFieldName)
                
                bpejCodeAreaPricesFieldName = \
                    self.dW.puBpejCodeAreaPricesColumnName
                bpejCodeAreaPricesFielId = layer.fieldNameIndex(
                    bpejCodeAreaPricesFieldName)
                
                layer.startEditing()
                layer.updateFields()
                
                features = layer.getFeatures()
                
                for feature in features:
                    rowid = feature.attribute(rowidColumnName)
                    id = feature.id()
                    
                    price = prices[rowid]
                    
                    if price != 0:
                        layer.changeAttributeValue(id, priceFieldId, price)
                        
                        bpejCodeAreaPrices = bpejCodeAreasPrices[rowid]
                        
                        bpejCodeAreaPricesStr = self._get_bpej_string(
                            bpejCodeAreaPrices)
                        
                        layer.changeAttributeValue(
                            id, bpejCodeAreaPricesFielId, bpejCodeAreaPricesStr)
                
                layer.commitChanges()
                
                if editing:
                    self.iface.actionToggleEditing()
                
                if len(missingBpejCodes) != 0:
                    fields = bpejLayer.pendingFields()
                    
                    for field in fields:
                        if field.name() == bpejField:
                            bpejFieldTypeName = field.typeName()
                            break
                    
                    if bpejFieldTypeName.lower() == u'string':
                        missingBpejCodesStr = \
                            '\'' + '\', \''.join(missingBpejCodes) + '\''
                    else:
                        missingBpejCodesStr = ', '.join(missingBpejCodes)
                    
                    expression = QgsExpression(
                        "\"{}\" in ({})".format(bpejField, missingBpejCodesStr))
                    
                    self.dW.select_features_by_expression(bpejLayer, expression)
                    
                    featureCount = bpejLayer.selectedFeatureCount()
                    
                    duration = 15
                    
                    if featureCount == 1:
                        self.iface.messageBar().pushMessage(
                            u'BPEJ kód vybraného prvku ve vrstvě BPEJ '
                            u'nebyl nalezen.', QgsMessageBar.WARNING, duration)
                    elif featureCount > 1:
                        self.iface.messageBar().pushMessage(
                            u'BPEJ kódy vybraných prvků ve vrstvě BPEJ '
                            u'nebyly nalezeny.',
                            QgsMessageBar.WARNING, duration)
            
            self.pW.set_text_statusbar.emit(
                u'Analýza oceňování podle BPEJ úspěšně dokončena.', 20, False)
        except self.dW.puError:
            QgsApplication.processEvents()
        except:
            QgsApplication.processEvents()
            
            currentCheckAnalysisName = \
                self.pW.checkAnalysisComboBox.currentText()
            
            self.dW.display_error_messages(
                self.pW,
                u'Error executing "{}".'.format(currentCheckAnalysisName),
                u'Chyba při provádění "{}".'.format(currentCheckAnalysisName))
    
    def _edit_bpej_field(self, bpejField, layer):
        """Edits BPEJ field name according to the layer fields.
        
        Args:
            bpejField (str): A name of the BPEJ field.
            layer (QgsVectorLayer): A reference to the active layer.
        
        Returns:
            str: An edited BPEJ field name
        
        """
        
        bpejField = bpejField[:10]
        
        parFields = layer.pendingFields()
        
        for field in parFields:
            if bpejField.lower() == field.name().lower():
                if len(bpejField) <= 8:
                    bpejField = bpejField + '_2'
                    break
                elif len(bpejField) == 9:
                    bpejField = bpejField + '_'
                    break
                elif len(bpejField) == 10:
                    bpejField = bpejField[:8] + '_1'
                    break
        
        return bpejField
    
    def _get_bpej_code_prices(self):
        """Returns BPEJ code prices.
        
        Returns:
            dict: A dictionary with BPEJ codes as keys (int)
                and prices as values (float).
        
        """
        
        formatTimeStr = '%d.%m.%Y'
        
        bpejDir = QDir(self.pluginDir.path() + u'/data/bpej')
        
        bpejBaseName = u'SC_BPEJ'
        
        bpejZipFileName = bpejBaseName + u'.zip'
        
        bpejZipFilePath = bpejDir.filePath(bpejZipFileName)
        
        bpejCsvFileName = bpejBaseName + u'.csv'
        
        bpejCsvFilePath = bpejDir.filePath(bpejCsvFileName)
        
        upToDate = self._check_bpej_csv(bpejCsvFilePath, formatTimeStr)
        
        if not upToDate:
            testInternetUrl, bpejZipUrl = self._get_url()
            
            self._download_bpej_csv(
                testInternetUrl, bpejZipUrl, bpejZipFilePath, bpejCsvFileName)
        
        bpejCodePrices = self._read_bpej_csv(bpejCsvFilePath, formatTimeStr)
        
        return bpejCodePrices
    
    def _check_bpej_csv(self, bpejCsvFilePath, formatTimeStr):
        """Checks if the BPEJ CSV file is up-to-date.
        
        Args:
            bpejCsvFilePath (str): A full path to the BPEJ CSV file.
            formatTimeStr (str): A string for time formatting.
        
        Returns:
            bool: True when the BPEJ CSV file is up-to-date, False otherwise.
        
        """
        
        modificationEpochTime = os.path.getmtime(bpejCsvFilePath)
        
        modificationDateTime = datetime.fromtimestamp(modificationEpochTime)
        
        todayDateTime = datetime.now()
        
        bpejTodayDateTime = todayDateTime.replace(
            hour=03, minute=06, second=0, microsecond=0)
        
        if modificationDateTime > bpejTodayDateTime:
            return True
        else:
            return False
    
    def _get_url(self):
        """Returns URL.
        
        Returns an URL for testing the internet connection
        and an URL of the BPEJ ZIP file.
        
        Returns:
            str: An URL for testing the internet connection.
            str: An URL of the BPEJ ZIP file.
        
        """
        
        config = RawConfigParser()
        
        config.read(self.pluginDir.filePath(u'puplugin.cfg'))
        
        testInternetUrl = config.get('BPEJ', 'testinterneturl')
        bpejZipUrl = config.get('BPEJ', 'bpejzipurl')
        
        return testInternetUrl, bpejZipUrl
    
    def _download_bpej_csv(
            self,
            testInternetUrl, bpejZipUrl, bpejZipFilePath, bpejCsvFileName):
        """Downloads BPEJ CSV file and unzips it.
        
        Args:
            testInternetUrl (str): An URL for testing the internet connection.
            bpejZipUrl (str): An URL of the BPEJ ZIP file.
            bpejZipFilePath (str): A full path to the BPEJ ZIP file.
            bpejCsvFileName (str): A name of the BPEJ CSV file.
        
        Raises:
            dw.puError: When a connection to the CUZK website failed.
        
        """
        
        try:
            testInternetConnection = urllib.urlopen(testInternetUrl)
        except:
            return
        else:
            testInternetConnection.close()
        
        try:
            testBpejConnection = urllib.urlopen(bpejZipUrl)
        except:
            raise self.dW.puError(
                self.dW, self.pW,
                u'A Connection to "{}" failed.'.format(bpejZipUrl),
                u'Nepodařilo se připojit k "{}"'.format(bpejZipUrl))
        else:
            testBpejConnection.close()
            
            urllib.urlretrieve(bpejZipUrl, bpejZipFilePath)
            
            self._unzip_bpej_zip(bpejZipFilePath, bpejCsvFileName)
            
            os.remove(bpejZipFilePath)
    
    def _unzip_bpej_zip(self, bpejZipFilePath, bpejCsvFileName):
        """Unzips BPEJ ZIP file into the same directory.
        
        Args:
            bpejZipFilePath (str): A full path to the BPEJ ZIP file.
            bpejCsvFileName (str): A name of the BPEJ CSV file.
        
        """
        
        fileInfo = QFileInfo(bpejZipFilePath)
        
        bpejDir = fileInfo.absolutePath()
        
        bpejZip = zipfile.ZipFile(bpejZipFilePath, 'r')
        
        bpejZipContent = bpejZip.namelist()
        
        if len(bpejZipContent) != 1:
            bpejZip.close()
            
            raise self.dW.puError(
                self.dW, self.pW,
                u'The structure of the BPEJ ZIP file has changed. '
                u'The BPEJ ZIP file contains more than one file.',
                u'Struktura stahovaného BPEJ ZIP souboru se změnila.')
        
        bpejZipFirstMember = bpejZipContent[0]
        
        bpejZip.extract(bpejZipFirstMember, bpejDir)
        bpejZip.close()
        
        if bpejZipFirstMember != bpejCsvFileName:
            bpejDir = QDir(bpejDir)
            
            bpejZipFirstMemberFilePath = bpejDir.filePath(bpejZipFirstMember)
            
            bpejCsvFilePath = bpejDir.filePath(bpejCsvFileName)
            
            os.rename(bpejZipFirstMemberFilePath, bpejCsvFilePath)
    
    def _read_bpej_csv(self, bpejCsvFilePath, formatTimeStr):
        """Reads the BPEJ CSV file.
        
        Args:
            bpejCsvFilePath (str): A full path to the BPEJ CSV file.
            formatTimeStr (str): A string for time formatting.
        
        Returns:
            dict: A dictionary with BPEJ codes as keys (int)
                and prices as values (float).
        
        """
               
        with open(bpejCsvFilePath, 'rb') as bpejCsvFile:
            bpejCsvReader = csv.reader(bpejCsvFile, delimiter=';')
            
            columnNames = bpejCsvReader.next()
            
            codeColumnIndex = columnNames.index('KOD')
            priceColumnIndex = columnNames.index('CENA')
            validFromColumnIndex = columnNames.index('PLATNOST_OD')
            validToColumnIndex = columnNames.index('PLATNOST_DO')
            
            todayDate = datetime.now().date()
            
            bpejCodePrices = {}
            
            for row in bpejCsvReader:
                if len(row) == 0:
                    break
                
                validFromDateStr = row[validFromColumnIndex]
                validFromDate = datetime.strptime(
                    validFromDateStr, formatTimeStr).date()
                
                validToDateStr = row[validToColumnIndex]
                
                if validToDateStr == '':
                    validToDate = todayDate
                else:
                    validToDate = datetime.strptime(
                        validToDateStr, formatTimeStr).date()
                
                if validFromDate <= todayDate <= validToDate:
                    code = int(row[codeColumnIndex])
                    price = row[priceColumnIndex]
                    
                    bpejCodePrices[code] = float(price)
        
        return bpejCodePrices
    
    def _calculate_feature_prices(
            self,
            rowidColumnName, multiToSingleLayer, bpejField, bpejCodePrices):
        """Calculates feature prices.
        
        Args:
            rowidColumnName (str): A name of rowid column.
            multiToSingleLayer (QgsVectorLayer): A reference to the single
                features layer.
            bpejField (str): A name of the BPEJ field.
            bpejCodePrices (dict): A dictionary with BPEJ codes as keys (int)
                and prices as values (float).
        
        Returns:
            defaultdict: A defaultdict with rowids as keys (long)
                and prices as values (float).
            set: A set of BPEJ codes that are not in BPEJ SCV file.
            defaultdict: A defaultdict with rowids as keys (long)
                and defaultdicts as values.
                defaultdict: A defaultdict with BPEJ codes (without dots)
                    as keys (str) and defaultdicts as values.
                    defaultdict: A defaultdict with area and prices
                        as keys (str) and their values as values (float).
                    
        
        """
        
        prices = defaultdict(float)
        
        bpejCodeAreasPrices = defaultdict(
            lambda : defaultdict(lambda : defaultdict(float)))
        
        missingBpejCodes = set()
        
        features = multiToSingleLayer.getFeatures()
        
        for feature in features:
            rowid = feature.attribute(rowidColumnName)
            bpejCode = str(feature.attribute(bpejField))
            geometry = feature.geometry()
            
            editedBpejCode = int(bpejCode.replace('.', ''))
            
            if editedBpejCode in bpejCodePrices:
                bpejPrice = bpejCodePrices[editedBpejCode]
            else:
                bpejPrice = 0.0
                missingBpejCodes.add(bpejCode)
            
            if geometry != None:
                area = geometry.area()
                
                price = bpejPrice*area
                
                bpejCodeAreasPrices[rowid][editedBpejCode]['bpejPrice'] += \
                    bpejPrice
                bpejCodeAreasPrices[rowid][editedBpejCode]['area'] += area
        
        for rowid, bpejCode in bpejCodeAreasPrices.items():
            for editedBpejCode, values in bpejCode.items():
                values['roundedArea'] = round(values['area'])
                values['price'] = values['roundedArea']*values['bpejPrice']
                
                prices[rowid] += values['price']
        
        return (prices, missingBpejCodes, bpejCodeAreasPrices)
    
    def _get_bpej_string(self, bpejCodeAreaPrices):
        """Returns a BPEJ string.
        
        Args:
            bpejCodeAreaPrices (defaultdict): A defaultdict with BPEJ codes
                (without dots) as keys (str) and defaultdicts as values.
                defaultdict: A defaultdict with area and prices
                    as keys (str) and their values as values (float).
        
        Returns:
            str: A string that contains information about BPEJ.
                The string consists of strings
                '<BPEJ code>-<BPEJ price>-<rounded Area>-<price>'
                for each BPEJ code in the input defaultdict separated by ', '.
        
        """
        
        bpejCodeAreaPricesStr = ''
        
        for bpejCode, values in bpejCodeAreaPrices.items():
            bpejCodeAreaPricesStr += str(bpejCode)
            bpejCodeAreaPricesStr += '-'
            bpejCodeAreaPricesStr += str(values['bpejPrice'])
            bpejCodeAreaPricesStr += '-'
            bpejCodeAreaPricesStr += str(int(values['roundedArea']))
            bpejCodeAreaPricesStr += '-'
            bpejCodeAreaPricesStr += str(values['price'])
            bpejCodeAreaPricesStr += ', '
        
        bpejCodeAreaPricesStr = \
            bpejCodeAreaPricesStr.strip(', ')
        
        return bpejCodeAreaPricesStr
コード例 #26
0
ファイル: QpalsQuickLM.py プロジェクト: lwiniwar/qpals
class QpalsQuickLM(object):
    def __init__(self, project, layerlist, iface):
        self.ui = None
        self.project = project
        self.layerlist = layerlist
        self.iface = iface
        self.createUi()

    def createUi(self):
        self.selectedChkBox = QtWidgets.QCheckBox("Use selected lines only")
        self.selectedChkBox.setCheckState(2)
        self.cmbLineLayer = QgsMapLayerComboBox()
        self.cmbLineLayer.setFilters(QgsMapLayerProxyModel.LineLayer)
        self.cmbOdmPath = QpalsDropTextbox.QpalsDropTextbox(
            layerlist=self.layerlist, filterrex=".*\.odm$")
        self.runBtn = QtWidgets.QPushButton("Run")
        self.runBtn.clicked.connect(self.runLM)
        self.ui = QtWidgets.QWidget()
        self.fl = QtWidgets.QFormLayout()
        self.ui.setLayout(self.fl)
        self.fl.addRow(QtWidgets.QLabel("Line layer:"), self.cmbLineLayer)
        self.fl.addRow(QtWidgets.QLabel("Point cloud:"), self.cmbOdmPath)
        self.fl.addRow(self.selectedChkBox)
        self.fl.addRow(self.runBtn)

    def runLM(self):
        params = {}
        layer = self.cmbLineLayer.currentLayer()
        if self.selectedChkBox.checkState() == 2:
            infile = tempfile.NamedTemporaryFile(delete=False)
            params["approxFile"] = infile.name + ".shp"
            infile.close()
            QgsVectorFileWriter.writeAsVectorFormat(layer,
                                                    params["approxFile"],
                                                    "utf-8", layer.crs(),
                                                    "ESRI Shapefile",
                                                    1)  # 1 for selected only
            try:
                os.remove(infile.name + ".prj")
            except:
                pass
        else:
            params["approxFile"] = layer.source()

        outfile = tempfile.NamedTemporaryFile(delete=False)
        params["outFile"] = outfile.name + ".shp"
        outfile.close()

        params["inFile"] = self.cmbOdmPath.text()

        Module = QpalsModuleBase.QpalsModuleBase(execName=os.path.join(
            self.project.opalspath, "opalsLineModeler.exe"),
                                                 QpalsProject=self.project)

        paramlist = []
        for param in params.keys():
            paramlist.append(
                QpalsParameter.QpalsParameter(param, params[param], None, None,
                                              None, None, None))
        Module.params = paramlist
        #print "running module. writing outfile to %s" % params["outFile"]
        moduleOut = Module.run(show=0)
        #print moduleOut
        self.iface.addVectorLayer(params["outFile"],
                                  os.path.basename("Modelled Lines"), "ogr")
コード例 #27
0
class Viewer(ViewerBase, ViewerClass):
    trackingChanged = pyqtSignal(bool)
    setLocationTriggered = pyqtSignal()
    updateFeatures = pyqtSignal(bool)
    layerChanged = pyqtSignal(QgsMapLayer)
    clearLine = pyqtSignal()
    closed = pyqtSignal()

    def __init__(self, callbackobject, parent=None):
        """Constructor."""
        super(Viewer, self).__init__(parent)
        self.setupUi(self)
        self.callbackobject = callbackobject
        self.frame = self.webview.page().mainFrame()
        self.actiongroup = QActionGroup(self)
        self.actiongroup.setExclusive(True)
        self.actiongroup.triggered.connect(self.action_triggered)

        self.measuredialog = MeasureDialog(self)

        self.toolbar = QToolBar()
        self.qgisTrackButton = self.toolbar.addAction("QGIS Track")
        self.qgisTrackButton.setIcon(QIcon(":/icons/track"))
        self.qgisTrackButton.setCheckable(True)
        self.qgisTrackButton.setChecked(True)
        self.qgisTrackButton.toggled.connect(self.trackingChanged.emit)

        self.setlocationaction = self.toolbar.addAction("Set location")
        self.setlocationaction.setIcon(QIcon(":/icons/location"))
        self.setlocationaction.triggered.connect(self.setLocationTriggered.emit)
        self.setlocationaction.setCheckable(True)

        self.viewfeatures = self.toolbar.addAction("Load QGIS Features")
        self.viewfeatures.setIcon(QIcon(":/icons/features"))
        self.viewfeatures.setCheckable(True)
        self.viewfeatures.setChecked(True)
        self.viewfeatures.toggled.connect(self.updateFeatures.emit)

        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer)

        self.measureaction = self.toolbar.addAction("measure")
        self.measureaction.setObjectName("Measure")
        self.measureaction.setIcon(QIcon(":/icons/measure"))
        self.measureaction.setCheckable(True)

        self.infoaction = self.toolbar.addAction("Info")
        self.infoaction.setObjectName("Info")
        self.infoaction.setIcon(QIcon(":/icons/info"))
        self.infoaction.setCheckable(True)

        self.selectaction = self.toolbar.addAction("Select")
        self.selectaction.setObjectName("Select")
        self.selectaction.setIcon(QIcon(":/icons/select"))
        self.selectaction.setCheckable(True)

        self.toolbar.addSeparator()

        self.deleteaction = self.toolbar.addAction("Delete")
        self.deleteaction.setIcon(QIcon(":/icons/delete"))
        self.deleteaction.triggered.connect(self.delete_selected)
        self.deleteaction.setEnabled(False)

        self.addaction = self.toolbar.addAction("Add")
        self.addaction.setObjectName("Add")
        self.addaction.setIcon(QIcon(":/icons/add"))
        self.addaction.setCheckable(True)

        self.moveaction = self.toolbar.addAction("Move")
        self.moveaction.setObjectName("Move")
        self.moveaction.setIcon(QIcon(":/icons/move"))
        self.moveaction.setCheckable(True)

        self.actiongroup.addAction(self.moveaction)
        self.actiongroup.addAction(self.addaction)
        self.actiongroup.addAction(self.infoaction)
        self.actiongroup.addAction(self.measureaction)
        self.actiongroup.addAction(self.selectaction)

        self.activelayercombo = QgsMapLayerComboBox()
        self.activelayercombo.layerChanged.connect(self.layer_changed)
        self.activelayeraction = self.toolbar.addWidget(self.activelayercombo)
        self.activelayercombo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.activelayercombo.currentIndexChanged.connect(self.index_changed)

        self.zvaluecheck = QCheckBox()
        self.zvaluecheck.setChecked(True)
        self.zvaluecheck.setText("Copy Z value")
        self.zvaluecheck.setToolTip("Copy Z value from viewer to new features in QGIS. Must have a field named Z to enable")
        self.zvalueaction = self.toolbar.addWidget(self.zvaluecheck)

        self.dockWidgetContents.layout().insertWidget(0, self.toolbar)

        self.webview.settings().setAttribute(QWebSettings.PluginsEnabled, True)
        self.webview.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
        self.webview.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        self.frame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
        self.frame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
        self.frame.javaScriptWindowObjectCleared.connect(self.addcallbackobject)
        self.measuredialog.modeCombo.currentIndexChanged.connect(self.action_triggered)
        self.measuredialog.clearButton.clicked.connect(self.clear_line)

        self.earthmine = EarthmineAPI(self.frame)

    def closeEvent(self, event):
        self.closed.emit()
        super(Viewer, self).closeEvent(event)

    def index_changed(self, index):
        if index == -1:
            self.set_button_states(False, False, False, False)

    def clear_line(self):
        self.clearLine.emit()
        self.earthmine.clearLine()

    @property
    def copyZvalue(self):
        layer = self.active_layer
        if not layer:
            return False

        if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point:
            return self.zvaluecheck.isChecked()
        else:
            return False

    @property
    def geom(self):
        return self.measuredialog.geom

    @geom.setter
    def geom(self, value):
        self.measuredialog.geom = value
        self.measuredialog.update_geom_labels()

    @property
    def tracking(self):
        return self.qgisTrackButton.isChecked()

    @property
    def mode(self):
        return self.measuredialog.mode

    @property
    def active_layer(self):
        return self.activelayercombo.currentLayer()

    def layer_changed(self, layer):
        if not layer:
            self.set_button_states(False, False, False, False)
            return

        if layer.type() == QgsMapLayer.VectorLayer:
            enabledselecttools = layer.geometryType() in [QGis.Line, QGis.Point]
            enableedittools = layer.isEditable()
            enabledelete = layer.isEditable() and layer.selectedFeatureCount()
            enablemove = layer.geometryType() == QGis.Point and layer.isEditable()
        else:
            enabledselecttools = False
            enableedittools = False
            enabledelete = False
            enablemove = False

        self.set_button_states(enabledselecttools, enableedittools, enabledelete, enablemove)
        self.action_triggered()
        self.layerChanged.emit(layer)

    def selection_changed(self, layer):
        if layer == self.active_layer:
            enabledelete = layer.isEditable() and layer.selectedFeatureCount()
            self.deleteaction.setEnabled(enabledelete)

    def set_button_states(self, selecttools, edittools, deleteenabled, moveenabled):
        actions = [self.selectaction, self.infoaction]

        for action in actions:
            action.setEnabled(selecttools)

        editactions = [self.deleteaction, self.moveaction, self.addaction]

        for action in editactions:
            action.setEnabled(edittools)

        if edittools:
            self.deleteaction.setEnabled(deleteenabled)
            self.moveaction.setEnabled(moveenabled)

        for action in editactions:
            if action is self.actiongroup.checkedAction() and not action.isEnabled():
                self.infoaction.toggle()
                break

        layer = self.active_layer
        if not layer:
            enablez = False
        else:
            enablez = layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point
        self.zvalueaction.setEnabled(enablez)

    @property
    def current_action_color(self):
        action = self.actiongroup.checkedAction()
        color = int("0x00ff00", 16)
        if action == self.measureaction:
            if self.mode == "Vertical":
                color = int("0x0000ff", 16)

        return color

    def action_triggered(self, *args):
        action = self.actiongroup.checkedAction()
        layer = self.activelayercombo.currentLayer()

        self.clear_line()
        if not action:
            return

        if not action == self.measureaction and (not layer or not layer.type() == QgsMapLayer.VectorLayer):
            return

        color = self.current_action_color
        actiondata = {}

        if action == self.measureaction:
            self.measuredialog.show()
            actiondata['mode'] = self.mode
            geomtype = None
            layerid = None
        else:
            self.measuredialog.hide()
            geomtype = QGis.vectorGeometryType(layer.geometryType())
            layerid = layer.id()

        data = dict(action=action.objectName(),
                    layer=layerid,
                    geom=geomtype,
                    actiondata=actiondata,
                    color=color)

        self.earthmine.updateAction(data)

    def active_tool(self):
        action = self.actiongroup.checkedAction()
        if not action:
            return None
        return action.objectName()

    def update_current_layer(self, layer):
        self.activelayercombo.setLayer(layer)

    def addcallbackobject(self):
        self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject)

    def loadviewer(self, url):
        self.webview.load(url)
        self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject)

    def startViewer(self, settings):
        self.earthmine.startViewer(settings)

    def set_location(self, point):
        # # NOTE Set location takes WGS84 make sure you have transformed it first before sending
        self.earthmine.setLocation(point.x(), point.y())

    def clear_features(self):
        self.earthmine.clearFeatures()

    def clear_layer_features(self, layerid):
        self.earthmine.clearLayerObjects(layerid)

    def remove_feature(self, layerid, featureid):
        """
        :param features: A dict of layerid, id, lat, lng
        :return:
        """
        self.earthmine.removeFeature(layerid, featureid)

    def load_features(self, layerdata, features):
        """
        :param features: A dict of layerid, id, lat, lng
        :return:
        """
        self.earthmine.loadFeatures(layerdata, features)

    def layer_loaded(self, layerid):
        return self.earthmine.layerLoaded(layerid)

    def clear_selection(self, layerid):
        self.earthmine.clearSelection(layerid)

    def set_selection(self, layerid, featureids, clearlast=True):
        self.earthmine.setSelection(layerid, featureids, clearlast)

    def edit_feature(self, layerid, featureid, nodes):
        self.earthmine.editFeature(layerid, featureid, nodes)

    def delete_selected(self):
        layer = self.active_layer
        layer.deleteSelectedFeatures()
コード例 #28
0
ファイル: uav_preparer.py プロジェクト: biglimp/UAVPreparer
class UAVPreparer:
    """QGIS Plugin Implementation."""
    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
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'UAVPreparer_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&UAV Preparer')

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None

        # Declare variables
        self.outputfile = None

    # 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('UAVPreparer', message)

    def add_action(self,
                   icon_path,
                   text,
                   callback,
                   enabled_flag=True,
                   add_to_menu=True,
                   add_to_toolbar=True,
                   status_tip=None,
                   whats_this=None,
                   parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

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

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

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            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/uav_preparer/icon.png'
        self.add_action(icon_path,
                        text=self.tr(u'UAV Preparer'),
                        callback=self.run,
                        parent=self.iface.mainWindow())

        # will be set False in run()
        self.first_start = True

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&UAV Preparer'), action)
            self.iface.removeToolBarIcon(action)

    def run(self):
        """Run method that performs all the real work"""
        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start == True:
            self.first_start = False
            self.dlg = UAVPreparerDialog()

        # Access the raster layer
        self.layerComboManagerDSM = QgsMapLayerComboBox(self.dlg.widgetDSM)
        self.layerComboManagerDSM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDSM.setFixedWidth(175)
        self.layerComboManagerDSM.setCurrentIndex(-1)

        # Access the vector layer and an attribute field
        self.layerComboManagerPoint = QgsMapLayerComboBox(
            self.dlg.widgetPointLayer)
        self.layerComboManagerPoint.setCurrentIndex(-1)
        self.layerComboManagerPoint.setFilters(
            QgsMapLayerProxyModel.PointLayer)
        self.layerComboManagerPoint.setFixedWidth(175)
        self.layerComboManagerPointField = QgsFieldComboBox(
            self.dlg.widgetField)
        self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(
            self.layerComboManagerPointField.setLayer)

        # Set up of file save dialog
        self.fileDialog = QFileDialog()
        self.dlg.pushButtonSave.clicked.connect(self.savefile)

        # Set up for the Help button
        self.dlg.helpButton.clicked.connect(self.help)

        # Set up for the Run button
        self.dlg.runButton.clicked.connect(self.start_progress)

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass

    def savefile(self):
        self.outputfile = self.fileDialog.getSaveFileName(
            None, "Save File As:", None, "Text Files (*.txt)")
        self.dlg.textOutput.setText(self.outputfile[0])

    def help(self):
        url = "https://github.com/biglimp/UAVPreparer"
        webbrowser.open_new_tab(url)

    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(), "polygon", "ogr")

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

        ### main code ###

        #  set radius
        r = 100  # half picture size

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

        # load big raster
        bigraster = gdal.Open(filepath_dsm)
        filepath_tempdsm = self.plugin_dir + '/clipdsm.tif'

        self.dlg.progressBar.setRange(0, numfeat)
        i = 0
        for f in vlayer.getFeatures():
            self.dlg.progressBar.setValue(i + 1)
            # get the coordinate for the point
            y = f.geometry().centroid().asPoint().y()
            x = f.geometry().centroid().asPoint().x()

            bbox = (x - r, y + r, x + r, y - r)
            gdal.Translate(filepath_tempdsm, bigraster, projWin=bbox)
            data = gdal.Open(filepath_tempdsm)
            mat = np.array(data.ReadAsArray())

            result[i, 0] = int(f.attributes()[idx])
            result[i, 1] = np.mean(mat)
            result[i, 2] = np.max(mat)
            result[i, 3] = np.min(mat)

            i = i + 1

        # Saving to file
        numformat = '%d ' + '%6.2f ' * 3
        headertext = 'id mean max min'
        np.savetxt(self.outputfile[0],
                   result,
                   fmt=numformat,
                   delimiter=' ',
                   header=headertext)

        self.iface.messageBar().pushMessage(
            'UAV Preparer. Operation successful!',
            level=Qgis.Success,
            duration=5)