Пример #1
0
def open_file(dialog=None,
              osm_file=None,
              output_geom_types=None,
              white_list_column=None,
              layer_name="OsmFile",
              config_outputs=None,
              output_dir=None,
              final_query=None,
              prefix_file=None):
    """
    Open an osm file.

    Memory layer if no output directory is set, or Geojson in the output
    directory.

    :param final_query: The query where the file comes from. Might be empty if
    it's a local OSM file.
    :type final_query: basestring
    """
    outputs = {}
    if output_dir:
        for layer in ['points', 'lines', 'multilinestrings', 'multipolygons']:
            if not prefix_file:
                prefix_file = layer_name

            outputs[layer] = join(output_dir,
                                  prefix_file + "_" + layer + ".geojson")

            if isfile(outputs[layer]):
                raise FileOutPutException(suffix='(' + outputs[layer] + ')')

    # Legacy, waiting to remove the OsmParser for QGIS >= 3.6
    # Change in osm_file_dialog.py L131 too
    output_geom_legacy = [geom.value.lower() for geom in output_geom_types]
    if not white_list_column:
        white_list_column = {}
    white_list_legacy = ({
        cols.value.lower(): csv
        for cols, csv in white_list_column.items()
    })

    LOGGER.info('The OSM file is: {}'.format(osm_file))

    # Parsing the file
    osm_parser = OsmParser(osm_file=osm_file,
                           layers=output_geom_legacy,
                           white_list_column=white_list_legacy)

    osm_parser.signalText.connect(dialog.set_progress_text)
    osm_parser.signalPercentage.connect(dialog.set_progress_percentage)

    start_time = time.time()
    layers = osm_parser.parse()
    elapsed_time = time.time() - start_time
    parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time))
    LOGGER.info('The OSM parser took: {}'.format(parser_time))

    # Finishing the process with geojson or memory layer
    num_layers = 0

    for i, (layer, item) in enumerate(layers.items()):
        dialog.set_progress_percentage(i / len(layers) * 100)
        QApplication.processEvents()
        if item['featureCount'] and (LayerType(layer.capitalize())
                                     in output_geom_types):

            final_layer_name = layer_name
            # If configOutputs is not None (from My Queries)
            if config_outputs:
                if config_outputs[layer]['namelayer']:
                    final_layer_name = config_outputs[layer]['namelayer']

            if output_dir:
                dialog.set_progress_text(
                    tr('From memory layer to GeoJSON: ' + layer))
                # Transforming the vector file
                osm_geometries = {
                    'points': QgsWkbTypes.Point,
                    'lines': QgsWkbTypes.LineString,
                    'multilinestrings': QgsWkbTypes.MultiLineString,
                    'multipolygons': QgsWkbTypes.MultiPolygon
                }
                memory_layer = item['vector_layer']

                encoding = get_default_encoding()
                writer = QgsVectorFileWriter(outputs[layer], encoding,
                                             memory_layer.fields(),
                                             osm_geometries[layer],
                                             memory_layer.crs(), "GeoJSON")

                for f in memory_layer.getFeatures():
                    writer.addFeature(f)

                del writer

                # Loading the final vector file
                new_layer = QgsVectorLayer(outputs[layer], final_layer_name,
                                           "ogr")
            else:
                new_layer = item['vector_layer']
                new_layer.setName(final_layer_name)

            # Try to set styling if defined
            if config_outputs and config_outputs[layer]['style']:
                new_layer.loadNamedStyle(config_outputs[layer]['style'])
            else:
                # Loading default styles
                if layer == "multilinestrings" or layer == "lines":
                    if "colour" in item['tags']:
                        new_layer.loadNamedStyle(
                            join(dirname(dirname(abspath(__file__))), "styles",
                                 layer + "_colour.qml"))

            # Add action about OpenStreetMap
            add_actions(new_layer, item['tags'])

            if final_query:
                QgsExpressionContextUtils.setLayerVariable(
                    new_layer, 'quickosm_query', final_query)

            QgsProject.instance().addMapLayer(new_layer)
            num_layers += 1

    return num_layers
Пример #2
0
class MultiType(Enum):
    """Type of combination of two queries"""
    AND = tr('And')
    OR = tr('Or')
Пример #3
0
    def update_personal_preset_view(self):
        """Update the presets displayed."""
        preset_folder = query_preset()
        files = filter(
            lambda folder: os.path.isdir(join(preset_folder, folder)),
            os.listdir(preset_folder))

        self.dialog.list_personal_preset_mp.clear()

        for file in files:
            file_path = join(preset_folder, file, file + '.json')
            with open(file_path, encoding='utf8') as json_file:
                data = json.load(json_file, object_hook=as_enum)
            name = data['file_name']

            item = QListWidgetItem(self.dialog.list_personal_preset_mp)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
                          | Qt.ItemIsEnabled)
            self.dialog.list_personal_preset_mp.addItem(item)

            preset = QFrame()
            preset.setObjectName('FramePreset')
            preset.setFrameStyle(QFrame.StyledPanel)
            preset.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            hbox = QHBoxLayout()
            vbox = QVBoxLayout()
            label_name = QLabel(name)
            label_name.setStyleSheet('font-weight: bold;')
            label_name.setWordWrap(True)
            vbox.addWidget(label_name)
            for label in data['description']:
                if not label:
                    label = tr('No description')
                real_label = QLabel(label)
                real_label.setWordWrap(True)
                vbox.addWidget(real_label)
            hbox.addItem(vbox)
            button_edit = QPushButton()
            button_remove = QPushButton()
            button_edit.setIcon(
                QIcon(QgsApplication.iconPath("mActionToggleEditing.svg")))
            button_remove.setIcon(
                QIcon(QgsApplication.iconPath('symbologyRemove.svg')))
            button_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_remove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_edit.setToolTip(tr('Edit the preset'))
            button_remove.setToolTip(tr('Delete the preset'))
            hbox.addWidget(button_edit)
            hbox.addWidget(button_remove)
            if data['advanced']:
                self.listAdvanced.append(True)
                preset.setStyleSheet('#FramePreset { margin: 3px;'
                                     ' border: 3px solid ' +
                                     self.advanced_selected + ';'
                                     ' border-width: 1px 1px 1px 4px;}')
            else:
                self.listAdvanced.append(False)
                preset.setStyleSheet('#FramePreset { margin: 3px;'
                                     ' border: 3px solid ' +
                                     self.basic_selected + ';'
                                     ' border-width: 1px 1px 1px 4px;}')
            preset.setLayout(hbox)

            # Actions on click
            remove = partial(self.verification_remove_preset, item, name)
            button_remove.clicked.connect(remove)
            edit = partial(self.edit_preset, data)
            button_edit.clicked.connect(edit)

            item.setSizeHint(preset.minimumSizeHint())
            self.dialog.list_personal_preset_mp.setItemWidget(item, preset)

        self.listAdvanced.append(False)
Пример #4
0
def process_query(dialog: QDialog = None,
                  query: str = None,
                  description: str = None,
                  area: Union[str, List[str]] = None,
                  key: Union[str, List[str]] = None,
                  value: Union[str, List[str]] = None,
                  type_multi_request: list = None,
                  bbox: QgsRectangle = None,
                  output_dir: str = None,
                  output_format: Format = None,
                  prefix_file: str = None,
                  output_geometry_types: list = None,
                  layer_name: str = "OsmQuery",
                  white_list_values: dict = None,
                  config_outputs: dict = None) -> int:
    """execute a query and send the result file to open_file."""
    # Save the query in the historic
    q_manage = QueryManagement(query=query,
                               name=prefix_file if prefix_file else layer_name,
                               description=description,
                               advanced=value is None,
                               type_multi_request=type_multi_request,
                               keys=key,
                               values=value,
                               area=area,
                               bbox=bbox,
                               output_geometry_types=output_geometry_types,
                               white_list_column=white_list_values)
    q_manage.write_query_historic()

    if dialog.feedback_process.isCanceled():
        return None

    # Prepare outputs
    dialog.set_progress_text(tr('Prepare outputs'))

    # Getting the default overpass api and running the query
    server = get_setting('defaultOAPI', OVERPASS_SERVERS[0]) + 'interpreter'
    dialog.set_progress_text(
        tr('Downloading data from Overpass {server_name}'.format(
            server_name=server)))
    # Replace Nominatim or BBOX
    query = QueryPreparation(query, bbox, area, server)
    QApplication.processEvents()
    final_query = query.prepare_query()
    url = query.prepare_url()
    connexion_overpass_api = ConnexionOAPI(url)
    LOGGER.debug('Encoded URL: {}'.format(url))
    osm_file = connexion_overpass_api.run()

    return open_file(dialog=dialog,
                     osm_file=osm_file,
                     output_geom_types=output_geometry_types,
                     white_list_column=white_list_values,
                     key=key,
                     layer_name=layer_name,
                     output_dir=output_dir,
                     output_format=output_format,
                     prefix_file=prefix_file,
                     final_query=final_query,
                     config_outputs=config_outputs,
                     feedback=dialog.feedback_process)
Пример #5
0
def open_file(dialog: QDialog = None,
              osm_file: str = None,
              output_geom_types: list = None,
              white_list_column: dict = None,
              key: Union[str, List[str]] = None,
              layer_name: str = "OsmFile",
              config_outputs: dict = None,
              output_dir: str = None,
              output_format: Format = None,
              final_query: str = None,
              prefix_file: str = None,
              subset: bool = False,
              subset_query: str = None,
              feedback: QgsFeedback = None) -> int:
    """
    Open an osm file.

    Memory layer if no output directory is set, or Geojson in the output
    directory.

    :param final_query: The query where the file comes from. Might be empty if
    it's a local OSM file.
    :type final_query: basestring
    """

    if output_geom_types is None:
        output_geom_types = OSM_LAYERS
    # Legacy, waiting to remove the OsmParser for QGIS >= 3.6
    # Change in osm_file_dialog.py L131 too
    output_geom_legacy = [geom.value.lower() for geom in output_geom_types]
    if not white_list_column:
        white_list_column = None

    LOGGER.info('The OSM file is: {}'.format(osm_file))
    if feedback:
        if feedback.isCanceled():
            return None

    # Parsing the file
    osm_parser = OsmParser(osm_file=osm_file,
                           layers=output_geom_legacy,
                           output_format=output_format,
                           output_dir=output_dir,
                           prefix_file=prefix_file,
                           layer_name=layer_name,
                           key=key,
                           white_list_column=white_list_column,
                           subset=subset,
                           subset_query=subset_query,
                           feedback=feedback)

    if dialog:
        osm_parser.signalText.connect(dialog.set_progress_text)
        osm_parser.signalPercentage.connect(dialog.set_progress_percentage)

    start_time = time.time()
    layers = osm_parser.processing_parse()
    elapsed_time = time.time() - start_time
    parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time))
    LOGGER.info('The OSM parser took: {}'.format(parser_time))

    if feedback:
        if feedback.isCanceled():
            return None

    # Finishing the process with an output format or memory layer
    num_layers = 0

    for i, (layer, item) in enumerate(layers.items()):
        if dialog:
            dialog.set_progress_percentage(i / len(layers) * 100)
        QApplication.processEvents()
        if item['featureCount'] and (LayerType(layer.capitalize())
                                     in output_geom_types):

            final_layer_name = layer_name
            # If configOutputs is not None (from My Queries)
            if config_outputs:
                if config_outputs[layer]['namelayer']:
                    final_layer_name = config_outputs[layer]['namelayer']

            new_layer = item['vector_layer']
            new_layer.setName(final_layer_name)

            # Try to set styling if defined
            if config_outputs and config_outputs[layer]['style']:
                new_layer.loadNamedStyle(config_outputs[layer]['style'])
            else:
                if "colour" in item['tags']:
                    index = item['tags'].index('colour')
                    colors = new_layer.uniqueValues(index)
                    categories = []
                    for value in colors:
                        if str(value) == 'None':
                            value = ''
                        if layer in ['lines', 'multilinestrings']:
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.LineGeometry)
                        elif layer == "points":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PointGeometry)
                        elif layer == "multipolygons":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PolygonGeometry)
                        symbol.setColor(QColor(value))
                        category = QgsRendererCategory(str(value), symbol,
                                                       str(value))
                        categories.append(category)

                    renderer = QgsCategorizedSymbolRenderer(
                        "colour", categories)
                    new_layer.setRenderer(renderer)

            # Add action about OpenStreetMap
            actions.add_actions(new_layer, item['tags'])

            QgsProject.instance().addMapLayer(new_layer)

            if final_query:
                QgsExpressionContextUtils.setLayerVariable(
                    new_layer, 'quickosm_query', final_query)
                actions.add_relaunch_action(new_layer, final_layer_name)
                if dialog:
                    dialog.iface.addCustomActionForLayer(
                        dialog.reload_action, new_layer)

            metadata = QgsLayerMetadata()
            metadata.setRights([tr("© OpenStreetMap contributors")])
            metadata.setLicenses(['https://openstreetmap.org/copyright'])
            new_layer.setMetadata(metadata)
            num_layers += 1

    return num_layers
Пример #6
0
 def save_add_existing(self):
     """Verify and ask the save destination."""
     self.existing_preset = True
     self.dialog.button_save_query.setText(tr('Save and add query to an existing preset'))
Пример #7
0
    def setup_panel(self):
        super().setup_panel()
        """Setup the UI for the QuickQuery."""

        # Setup presets and keys auto completion
        self.setup_preset()

        # Table Keys/Values
        self.setup_table()

        # Query type
        self.dialog.combo_query_type_qq.addItem(tr('In'), 'in')
        self.dialog.combo_query_type_qq.addItem(tr('Around'), 'around')
        self.dialog.combo_query_type_qq.addItem(tr('Canvas Extent'), 'canvas')
        self.dialog.combo_query_type_qq.addItem(tr('Layer Extent'), 'layer')
        self.dialog.combo_query_type_qq.addItem(tr('Not Spatial'), 'attributes')

        # self.cb_query_type_qq.setItemIcon(
        #   0, QIcon(resources_path('in.svg')))
        # self.cb_query_type_qq.setItemIcon(
        #   1, QIcon(resources_path('around.svg')))
        # self.cb_query_type_qq.setItemIcon(
        #   2, QIcon(resources_path('map_canvas.svg')))
        # self.cb_query_type_qq.setItemIcon(
        #   3, QIcon(resources_path('extent.svg')))
        # self.cb_query_type_qq.setItemIcon(
        #   4, QIcon(resources_path('mIconTableLayer.svg')))

        self.dialog.combo_query_type_qq.currentIndexChanged.connect(
            self.query_type_updated)

        self.dialog.button_save_query.setMenu(QMenu())

        self.action_new = QAction(SaveType.New.value)
        self.action_new.triggered.connect(self.save_new)
        self.action_existing = QAction(SaveType.Existing.value)
        self.action_existing.triggered.connect(self.save_add_existing)
        self.dialog.button_save_query.menu().addAction(self.action_new)
        self.dialog.button_save_query.menu().addAction(self.action_existing)

        self.dialog.button_save_query.clicked.connect(self.save_query)

        self.dialog.button_show_query.setMenu(QMenu())

        self.dialog.action_oql_qq.triggered.connect(self.query_language_oql)
        self.dialog.action_xml_qq.triggered.connect(self.query_language_xml)
        self.dialog.button_show_query.menu().addAction(self.dialog.action_oql_qq)
        self.dialog.button_show_query.menu().addAction(self.dialog.action_xml_qq)

        query_oql = partial(self.show_query, QueryLanguage.OQL)
        self.dialog.button_show_query.clicked.connect(query_oql)

        self.dialog.button_run_query_qq.clicked.connect(self.run)
        self.dialog.button_map_features.clicked.connect(open_plugin_documentation)
        self.dialog.button_box_qq.button(QDialogButtonBox.Reset).clicked.connect(
            self.dialog.reset_form)

        # setup callbacks for friendly-label-update only
        self.dialog.line_place_qq.textChanged.connect(self.update_friendly)
        self.dialog.spin_place_qq.valueChanged.connect(self.update_friendly)
        self.dialog.combo_extent_layer_qq.layerChanged.connect(self.query_type_updated)

        self.query_type_updated()
        self.init_nominatim_autofill()
        self.update_friendly()

        self.update_history_view()
Пример #8
0
 def save_new(self):
     """Verify the save destination."""
     self.existing_preset = False
     self.dialog.button_save_query.setText(tr('Save query in a new preset'))
Пример #9
0
 def add_outputs(self):
     """Set up the outputs of the algorithm."""
     output = QgsProcessingOutputVectorLayer(
         self.OUTPUT_LAYER, tr('Output layer')
     )
     self.addOutput(output)
Пример #10
0
 def shortHelpString(self) -> str:
     """Return an helper for the algorithm."""
     return tr('Decorate the layer as an QuickOSM output.')
Пример #11
0
 def group() -> str:
     """Return the group of the algorithm."""
     return tr('Advanced')
Пример #12
0
 def displayName() -> str:
     """Return the display name of the algorithm."""
     return tr('Decorate a layer from OSM')