コード例 #1
0
class ToolBar(QObject):
    def __init__(self, iface, qgis_utils):
        QObject.__init__(self)
        self.iface = iface
        self.qgis_utils = qgis_utils
        self.logger = Logger()
        self.geometry = GeometryUtils()

    def build_boundary(self, db):
        QgsProject.instance().setAutoTransaction(False)
        layer = self.qgis_utils.get_layer_from_layer_tree(
            db, db.names.OP_BOUNDARY_T)
        use_selection = True

        if layer is None:
            self.logger.message_with_button_load_layer_emitted.emit(
                QCoreApplication.translate(
                    "ToolBar", "First load the layer {} into QGIS!").format(
                        db.names.OP_BOUNDARY_T),
                QCoreApplication.translate("ToolBar",
                                           "Load layer {} now").format(
                                               db.names.OP_BOUNDARY_T),
                db.names.OP_BOUNDARY_T, Qgis.Warning)
            return
        else:
            if layer.selectedFeatureCount() == 0:

                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are no selected boundaries. Do you want to use all the {} boundaries in the database?"
                    ).format(layer.featureCount()),
                    QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    self.logger.warning_msg(
                        __name__,
                        QCoreApplication.translate(
                            "ToolBar", "First select at least one boundary!"))
                    return

        if use_selection:
            new_boundary_geoms, boundaries_to_del_ids = self.geometry.fix_selected_boundaries(
                db.names, layer, db.names.T_ID_F)
            num_boundaries = layer.selectedFeatureCount()
        else:
            new_boundary_geoms, boundaries_to_del_ids = self.geometry.fix_boundaries(
                layer, db.names.T_ID_F)
            num_boundaries = layer.featureCount()

        if len(new_boundary_geoms) > 0:
            layer.startEditing(
            )  # Safe, even if layer is already on editing state

            # the boundaries that are to be replaced are removed
            layer.deleteFeatures(boundaries_to_del_ids)

            # Create features based on segment geometries
            new_fix_boundary_features = list()
            for boundary_geom in new_boundary_geoms:
                feature = QgsVectorLayerUtils().createFeature(
                    layer, boundary_geom)

                # TODO: Remove when local id and working space are defined
                feature.setAttribute(db.names.OID_T_LOCAL_ID_F, 1)
                feature.setAttribute(db.names.OID_T_NAMESPACE_F,
                                     db.names.OP_BOUNDARY_T)

                new_fix_boundary_features.append(feature)

            layer.addFeatures(new_fix_boundary_features)
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} feature(s) was(were) analyzed generating {} boundary(ies)!"
                ).format(num_boundaries, len(new_fix_boundary_features)))
            self.iface.mapCanvas().refresh()
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar", "There are no boundaries to build."))

    def fill_topology_table_pointbfs(self, db, use_selection=True):
        layers = {
            db.names.OP_BOUNDARY_T: {
                'name': db.names.OP_BOUNDARY_T,
                'geometry': None,
                LAYER: None
            },
            db.names.POINT_BFS_T: {
                'name': db.names.POINT_BFS_T,
                'geometry': None,
                LAYER: None
            },
            db.names.OP_BOUNDARY_POINT_T: {
                'name': db.names.OP_BOUNDARY_POINT_T,
                'geometry': None,
                LAYER: None
            }
        }

        self.qgis_utils.get_layers(db, layers, load=True)
        if not layers:
            return None

        if use_selection:
            if layers[
                    db.names.OP_BOUNDARY_T][LAYER].selectedFeatureCount() == 0:
                if self.qgis_utils.get_layer_from_layer_tree(
                        db, db.names.OP_BOUNDARY_T) is None:
                    self.logger.message_with_button_load_layer_emitted.emit(
                        QCoreApplication.translate(
                            "ToolBar",
                            "First load the layer {} into QGIS and select at least one boundary!"
                        ).format(db.names.OP_BOUNDARY_T),
                        QCoreApplication.translate("ToolBar",
                                                   "Load layer {} now").format(
                                                       db.names.OP_BOUNDARY_T),
                        db.names.OP_BOUNDARY_T, Qgis.Warning)
                else:
                    reply = QMessageBox.question(
                        None,
                        QCoreApplication.translate("ToolBar", "Continue?"),
                        QCoreApplication.translate(
                            "ToolBar",
                            "There are no selected boundaries. Do you want to fill the '{}' table for all the {} boundaries in the database?"
                        ).format(
                            db.names.POINT_BFS_T, layers[
                                db.names.OP_BOUNDARY_T][LAYER].featureCount()),
                        QMessageBox.Yes | QMessageBox.Cancel,
                        QMessageBox.Cancel)
                    if reply == QMessageBox.Yes:
                        use_selection = False
                    elif reply == QMessageBox.Cancel:
                        self.logger.warning_msg(
                            __name__,
                            QCoreApplication.translate(
                                "ToolBar",
                                "First select at least one boundary!"))
                        return
            else:
                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are {selected} boundaries selected. Do you want to fill the '{table}' table just for the selected boundaries?\n\nIf you say 'No', the '{table}' table will be filled for all boundaries in the database."
                    ).format(selected=layers[db.names.OP_BOUNDARY_T]
                             [LAYER].selectedFeatureCount(),
                             table=db.names.POINT_BFS_T),
                    QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = True
                elif reply == QMessageBox.No:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    return

        bfs_features = layers[db.names.POINT_BFS_T][LAYER].getFeatures()

        # Get unique pairs id_boundary-id_boundary_point
        existing_pairs = [
            (bfs_feature[db.names.POINT_BFS_T_OP_BOUNDARY_F],
             bfs_feature[db.names.POINT_BFS_T_OP_BOUNDARY_POINT_F])
            for bfs_feature in bfs_features
        ]
        existing_pairs = set(existing_pairs)

        id_pairs = self.geometry.get_pair_boundary_boundary_point(
            layers[db.names.OP_BOUNDARY_T][LAYER],
            layers[db.names.OP_BOUNDARY_POINT_T][LAYER],
            db.names.T_ID_F,
            use_selection=use_selection)

        if id_pairs:
            layers[db.names.POINT_BFS_T][LAYER].startEditing()
            features = list()
            for id_pair in id_pairs:
                if not id_pair in existing_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.POINT_BFS_T][LAYER])
                    feature.setAttribute(db.names.POINT_BFS_T_OP_BOUNDARY_F,
                                         id_pair[0])
                    feature.setAttribute(
                        db.names.POINT_BFS_T_OP_BOUNDARY_POINT_F, id_pair[1])
                    features.append(feature)
            layers[db.names.POINT_BFS_T][LAYER].addFeatures(features)
            layers[db.names.POINT_BFS_T][LAYER].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into {}! {} out of {} records already existed in the database."
                ).format(len(features), len(id_pairs), db.names.POINT_BFS_T,
                         len(id_pairs) - len(features), len(id_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_boundary_point found."))

    def fill_topology_tables_morebfs_less(self, db, use_selection=True):
        layers = {
            db.names.OP_PLOT_T: {
                'name': db.names.OP_PLOT_T,
                'geometry': QgsWkbTypes.PolygonGeometry,
                LAYER: None
            },
            db.names.MORE_BFS_T: {
                'name': db.names.MORE_BFS_T,
                'geometry': None,
                LAYER: None
            },
            db.names.LESS_BFS_T: {
                'name': db.names.LESS_BFS_T,
                'geometry': None,
                LAYER: None
            },
            db.names.OP_BOUNDARY_T: {
                'name': db.names.OP_BOUNDARY_T,
                'geometry': None,
                LAYER: None
            }
        }

        self.qgis_utils.get_layers(db, layers, load=True)
        if not layers:
            return None

        if use_selection:
            if layers[db.names.OP_PLOT_T][LAYER].selectedFeatureCount() == 0:
                if self.qgis_utils.get_layer_from_layer_tree(
                        db,
                        db.names.OP_PLOT_T,
                        geometry_type=QgsWkbTypes.PolygonGeometry) is None:
                    self.logger.message_with_button_load_layer_emitted.emit(
                        QCoreApplication.translate(
                            "ToolBar",
                            "First load the layer {} into QGIS and select at least one plot!"
                        ).format(db.names.OP_PLOT_T),
                        QCoreApplication.translate("ToolBar",
                                                   "Load layer {} now").format(
                                                       db.names.OP_PLOT_T),
                        db.names.OP_PLOT_T, Qgis.Warning)
                else:
                    reply = QMessageBox.question(
                        None,
                        QCoreApplication.translate("ToolBar", "Continue?"),
                        QCoreApplication.translate(
                            "ToolBar",
                            "There are no selected plots. Do you want to fill the '{more}' and '{less}' tables for all the {all} plots in the database?"
                        ).format(more=db.names.MORE_BFS_T,
                                 less=db.names.LESS_BFS_T,
                                 all=layers[db.names.OP_PLOT_T]
                                 [LAYER].featureCount()),
                        QMessageBox.Yes | QMessageBox.Cancel,
                        QMessageBox.Cancel)
                    if reply == QMessageBox.Yes:
                        use_selection = False
                    elif reply == QMessageBox.Cancel:
                        self.logger.warning_msg(
                            __name__,
                            QCoreApplication.translate(
                                "ToolBar", "First select at least one plot!"))
                        return
            else:
                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are {selected} plots selected. Do you want to fill the '{more}' and '{less}' tables just for the selected plots?\n\nIf you say 'No', the '{more}' and '{less}' tables will be filled for all plots in the database."
                    ).format(selected=layers[db.names.OP_PLOT_T]
                             [LAYER].selectedFeatureCount(),
                             more=db.names.MORE_BFS_T,
                             less=db.names.LESS_BFS_T),
                    QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = True
                elif reply == QMessageBox.No:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    return

        more_bfs_features = layers[db.names.MORE_BFS_T][LAYER].getFeatures()
        less_features = layers[db.names.LESS_BFS_T][LAYER].getFeatures()

        # Get unique pairs id_boundary-id_plot in both tables
        existing_more_pairs = [
            (more_bfs_feature[db.names.MORE_BFS_T_OP_PLOT_F],
             more_bfs_feature[db.names.MORE_BFS_T_OP_BOUNDARY_F])
            for more_bfs_feature in more_bfs_features
        ]
        existing_more_pairs = set(existing_more_pairs)
        # Todo: Update when ili2db issue is solved.
        # Todo: When an abstract class only implements a concrete class, the name of the attribute is different if two or more classes are implemented.
        existing_less_pairs = [
            (less_feature[db.names.LESS_BFS_T_OP_PLOT_F],
             less_feature[db.names.LESS_BFS_T_OP_BOUNDARY_F])
            for less_feature in less_features
        ]
        existing_less_pairs = set(existing_less_pairs)

        id_more_pairs, id_less_pairs = self.geometry.get_pair_boundary_plot(
            layers[db.names.OP_BOUNDARY_T][LAYER],
            layers[db.names.OP_PLOT_T][LAYER],
            db.names.T_ID_F,
            use_selection=use_selection)
        if id_less_pairs:
            layers[db.names.LESS_BFS_T][LAYER].startEditing()
            features = list()
            for id_pair in id_less_pairs:
                if not id_pair in existing_less_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.LESS_BFS_T][LAYER])
                    feature.setAttribute(db.names.LESS_BFS_T_OP_PLOT_F,
                                         id_pair[0])
                    # Todo: Update LESS_BFS_T_OP_BOUNDARY_F by LESS_BFS_T_OP_BOUNDARY_F.
                    # Todo: When an abstract class only implements a concrete class, the name of the attribute is different if two or more classes are implemented.
                    feature.setAttribute(db.names.LESS_BFS_T_OP_BOUNDARY_F,
                                         id_pair[1])
                    features.append(feature)
            layers[db.names.LESS_BFS_T][LAYER].addFeatures(features)
            layers[db.names.LESS_BFS_T][LAYER].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into '{}'! {} out of {} records already existed in the database."
                ).format(len(features), len(id_less_pairs),
                         db.names.LESS_BFS_T,
                         len(id_less_pairs) - len(features),
                         len(id_less_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_plot found for '{}' table.").
                format(db.names.LESS_BFS_T))

        if id_more_pairs:
            layers[db.names.MORE_BFS_T][LAYER].startEditing()
            features = list()
            for id_pair in id_more_pairs:
                if not id_pair in existing_more_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.MORE_BFS_T][LAYER])
                    feature.setAttribute(db.names.MORE_BFS_T_OP_PLOT_F,
                                         id_pair[0])
                    feature.setAttribute(db.names.MORE_BFS_T_OP_BOUNDARY_F,
                                         id_pair[1])
                    features.append(feature)
            layers[db.names.MORE_BFS_T][LAYER].addFeatures(features)
            layers[db.names.MORE_BFS_T][LAYER].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into '{}'! {} out of {} records already existed in the database."
                ).format(len(features), len(id_more_pairs),
                         db.names.MORE_BFS_T,
                         len(id_more_pairs) - len(features),
                         len(id_more_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_plot found for '{}' table.").
                format(db.names.MORE_BFS_T))
コード例 #2
0
class ToolBar(QObject):
    def __init__(self, iface):
        QObject.__init__(self)
        self.iface = iface
        self.logger = Logger()
        self.app = AppInterface()
        self.geometry = GeometryUtils()

    def build_boundary(self, db):
        QgsProject.instance().setAutoTransaction(False)
        layer = self.app.core.get_ladm_layer_from_qgis(
            db, db.names.LC_BOUNDARY_T, EnumLayerRegistryType.IN_LAYER_TREE)
        use_selection = True

        if layer is None:
            self.logger.message_with_button_load_layer_emitted.emit(
                QCoreApplication.translate(
                    "ToolBar", "First load the layer {} into QGIS!").format(
                        db.names.LC_BOUNDARY_T),
                QCoreApplication.translate("ToolBar",
                                           "Load layer {} now").format(
                                               db.names.LC_BOUNDARY_T),
                db.names.LC_BOUNDARY_T, Qgis.Warning)
            return
        else:
            if layer.selectedFeatureCount() == 0:

                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are no selected boundaries. Do you want to use all the {} boundaries in the database?"
                    ).format(layer.featureCount()),
                    QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    self.logger.warning_msg(
                        __name__,
                        QCoreApplication.translate(
                            "ToolBar", "First select at least one boundary!"))
                    return

        if use_selection:
            new_boundary_geoms, boundaries_to_del_ids = self.geometry.fix_selected_boundaries(
                db.names, layer, db.names.T_ID_F)
            num_boundaries = layer.selectedFeatureCount()
        else:
            new_boundary_geoms, boundaries_to_del_ids = self.geometry.fix_boundaries(
                layer, db.names.T_ID_F)
            num_boundaries = layer.featureCount()

        if len(new_boundary_geoms) > 0:
            layer.startEditing(
            )  # Safe, even if layer is already on editing state

            # the boundaries that are to be replaced are removed
            layer.deleteFeatures(boundaries_to_del_ids)

            # Create features based on segment geometries
            new_fix_boundary_features = list()
            for boundary_geom in new_boundary_geoms:
                feature = QgsVectorLayerUtils().createFeature(
                    layer, boundary_geom)

                # TODO: Remove when local id and namespace are defined
                feature.setAttribute(db.names.OID_T_LOCAL_ID_F, 1)
                feature.setAttribute(db.names.OID_T_NAMESPACE_F,
                                     db.names.LC_BOUNDARY_T)

                new_fix_boundary_features.append(feature)

            layer.addFeatures(new_fix_boundary_features)
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} feature(s) was(were) analyzed generating {} boundary(ies)!"
                ).format(num_boundaries, len(new_fix_boundary_features)))
            self.iface.mapCanvas().refresh()
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar", "There are no boundaries to build."))

    def fill_topology_table_pointbfs(self, db, use_selection=True):
        layers = {
            db.names.LC_BOUNDARY_T: None,
            db.names.POINT_BFS_T: None,
            db.names.LC_BOUNDARY_POINT_T: None
        }

        self.app.core.get_layers(db, layers, load=True)
        if not layers:
            return None

        if use_selection:
            if layers[db.names.LC_BOUNDARY_T].selectedFeatureCount() == 0:
                if self.app.core.get_ladm_layer_from_qgis(
                        db, db.names.LC_BOUNDARY_T,
                        EnumLayerRegistryType.IN_LAYER_TREE) is None:
                    self.logger.message_with_button_load_layer_emitted.emit(
                        QCoreApplication.translate(
                            "ToolBar",
                            "First load the layer {} into QGIS and select at least one boundary!"
                        ).format(db.names.LC_BOUNDARY_T),
                        QCoreApplication.translate("ToolBar",
                                                   "Load layer {} now").format(
                                                       db.names.LC_BOUNDARY_T),
                        db.names.LC_BOUNDARY_T, Qgis.Warning)
                else:
                    reply = QMessageBox.question(
                        None,
                        QCoreApplication.translate("ToolBar", "Continue?"),
                        QCoreApplication.translate(
                            "ToolBar",
                            "There are no selected boundaries. Do you want to fill the '{}' table for all the {} boundaries in the database?"
                        ).format(
                            db.names.POINT_BFS_T,
                            layers[db.names.LC_BOUNDARY_T].featureCount()),
                        QMessageBox.Yes | QMessageBox.Cancel,
                        QMessageBox.Cancel)
                    if reply == QMessageBox.Yes:
                        use_selection = False
                    elif reply == QMessageBox.Cancel:
                        self.logger.warning_msg(
                            __name__,
                            QCoreApplication.translate(
                                "ToolBar",
                                "First select at least one boundary!"))
                        return
            else:
                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are {selected} boundaries selected. Do you want to fill the '{table}' table just for the selected boundaries?\n\nIf you say 'No', the '{table}' table will be filled for all boundaries in the database."
                    ).format(selected=layers[
                        db.names.LC_BOUNDARY_T].selectedFeatureCount(),
                             table=db.names.POINT_BFS_T),
                    QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = True
                elif reply == QMessageBox.No:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    return

        bfs_features = layers[db.names.POINT_BFS_T].getFeatures()

        # Get unique pairs id_boundary-id_boundary_point
        existing_pairs = [
            (bfs_feature[db.names.POINT_BFS_T_LC_BOUNDARY_F],
             bfs_feature[db.names.POINT_BFS_T_LC_BOUNDARY_POINT_F])
            for bfs_feature in bfs_features
        ]
        existing_pairs = set(existing_pairs)

        tolerance = self.app.settings.tolerance
        id_pairs = self.geometry.get_pair_boundary_boundary_point(
            layers[db.names.LC_BOUNDARY_T],
            layers[db.names.LC_BOUNDARY_POINT_T],
            db.names.T_ID_F,
            use_selection=use_selection,
            tolerance=tolerance)

        if id_pairs:
            layers[db.names.POINT_BFS_T].startEditing()
            features = list()
            for id_pair in id_pairs:
                if not id_pair in existing_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.POINT_BFS_T])
                    feature.setAttribute(db.names.POINT_BFS_T_LC_BOUNDARY_F,
                                         id_pair[0])
                    feature.setAttribute(
                        db.names.POINT_BFS_T_LC_BOUNDARY_POINT_F, id_pair[1])
                    features.append(feature)
            layers[db.names.POINT_BFS_T].addFeatures(features)
            layers[db.names.POINT_BFS_T].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into {}! {} out of {} records already existed in the database."
                ).format(len(features), len(id_pairs), db.names.POINT_BFS_T,
                         len(id_pairs) - len(features), len(id_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_boundary_point found."))

    def fill_topology_tables_morebfs_less(self, db, use_selection=True):
        layers = {
            db.names.LC_PLOT_T: None,
            db.names.MORE_BFS_T: None,
            db.names.LESS_BFS_T: None,
            db.names.LC_BOUNDARY_T: None
        }

        self.app.core.get_layers(db, layers, load=True)
        if not layers:
            return None

        if use_selection:
            if layers[db.names.LC_PLOT_T].selectedFeatureCount() == 0:
                if self.app.core.get_ladm_layer_from_qgis(
                        db, db.names.LC_PLOT_T,
                        EnumLayerRegistryType.IN_LAYER_TREE) is None:
                    self.logger.message_with_button_load_layer_emitted.emit(
                        QCoreApplication.translate(
                            "ToolBar",
                            "First load the layer {} into QGIS and select at least one plot!"
                        ).format(db.names.LC_PLOT_T),
                        QCoreApplication.translate("ToolBar",
                                                   "Load layer {} now").format(
                                                       db.names.LC_PLOT_T),
                        db.names.LC_PLOT_T, Qgis.Warning)
                else:
                    reply = QMessageBox.question(
                        None,
                        QCoreApplication.translate("ToolBar", "Continue?"),
                        QCoreApplication.translate(
                            "ToolBar",
                            "There are no selected plots. Do you want to fill the '{more}' and '{less}' tables for all the {all} plots in the database?"
                        ).format(
                            more=db.names.MORE_BFS_T,
                            less=db.names.LESS_BFS_T,
                            all=layers[db.names.LC_PLOT_T].featureCount()),
                        QMessageBox.Yes | QMessageBox.Cancel,
                        QMessageBox.Cancel)
                    if reply == QMessageBox.Yes:
                        use_selection = False
                    elif reply == QMessageBox.Cancel:
                        self.logger.warning_msg(
                            __name__,
                            QCoreApplication.translate(
                                "ToolBar", "First select at least one plot!"))
                        return
            else:
                reply = QMessageBox.question(
                    None, QCoreApplication.translate("ToolBar", "Continue?"),
                    QCoreApplication.translate(
                        "ToolBar",
                        "There are {selected} plots selected. Do you want to fill the '{more}' and '{less}' tables just for the selected plots?\n\nIf you say 'No', the '{more}' and '{less}' tables will be filled for all plots in the database."
                    ).format(selected=layers[
                        db.names.LC_PLOT_T].selectedFeatureCount(),
                             more=db.names.MORE_BFS_T,
                             less=db.names.LESS_BFS_T),
                    QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    use_selection = True
                elif reply == QMessageBox.No:
                    use_selection = False
                elif reply == QMessageBox.Cancel:
                    return

        tolerance = self.app.settings.tolerance
        if tolerance:
            # We need to adjust input layers to take tolerance into account
            # Use the same configuration we use in quality rule 3004 (Plots should be covered by boundaries).
            layers[db.names.LC_PLOT_T] = self.app.core.adjust_layer(
                layers[db.names.LC_PLOT_T], layers[db.names.LC_PLOT_T],
                tolerance, True, use_selection)
            layers[db.names.LC_BOUNDARY_T] = self.app.core.adjust_layer(
                layers[db.names.LC_BOUNDARY_T], layers[db.names.LC_PLOT_T],
                tolerance, True)
            if use_selection:
                layers[db.names.LC_PLOT_T].selectAll(
                )  # Because this layer is already filtered by selected features

        # Get unique pairs id_boundary-id_plot in both tables
        existing_more_pairs = set([
            (more_bfs_feature[db.names.MORE_BFS_T_LC_PLOT_F],
             more_bfs_feature[db.names.MORE_BFS_T_LC_BOUNDARY_F])
            for more_bfs_feature in layers[db.names.MORE_BFS_T].getFeatures()
        ])
        existing_less_pairs = set([
            (less_feature[db.names.LESS_BFS_T_LC_PLOT_F],
             less_feature[db.names.LESS_BFS_T_LC_BOUNDARY_F])
            for less_feature in layers[db.names.LESS_BFS_T].getFeatures()
        ])

        id_more_pairs, id_less_pairs = self.geometry.get_pair_boundary_plot(
            layers[db.names.LC_BOUNDARY_T],
            layers[db.names.LC_PLOT_T],
            db.names.T_ID_F,
            use_selection=use_selection)
        if id_less_pairs:
            layers[db.names.LESS_BFS_T].startEditing()
            features = list()
            for id_pair in id_less_pairs:
                if not id_pair in existing_less_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.LESS_BFS_T])
                    feature.setAttribute(db.names.LESS_BFS_T_LC_PLOT_F,
                                         id_pair[0])
                    feature.setAttribute(db.names.LESS_BFS_T_LC_BOUNDARY_F,
                                         id_pair[1])
                    features.append(feature)
            layers[db.names.LESS_BFS_T].addFeatures(features)
            layers[db.names.LESS_BFS_T].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into '{}'! {} out of {} records already existed in the database."
                ).format(len(features), len(id_less_pairs),
                         db.names.LESS_BFS_T,
                         len(id_less_pairs) - len(features),
                         len(id_less_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_plot found for '{}' table.").
                format(db.names.LESS_BFS_T))

        if id_more_pairs:
            layers[db.names.MORE_BFS_T].startEditing()
            features = list()
            for id_pair in id_more_pairs:
                if not id_pair in existing_more_pairs:  # Avoid duplicated pairs in the DB
                    # Create feature
                    feature = QgsVectorLayerUtils().createFeature(
                        layers[db.names.MORE_BFS_T])
                    feature.setAttribute(db.names.MORE_BFS_T_LC_PLOT_F,
                                         id_pair[0])
                    feature.setAttribute(db.names.MORE_BFS_T_LC_BOUNDARY_F,
                                         id_pair[1])
                    features.append(feature)
            layers[db.names.MORE_BFS_T].addFeatures(features)
            layers[db.names.MORE_BFS_T].commitChanges()
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "{} out of {} records were saved into '{}'! {} out of {} records already existed in the database."
                ).format(len(features), len(id_more_pairs),
                         db.names.MORE_BFS_T,
                         len(id_more_pairs) - len(features),
                         len(id_more_pairs)))
        else:
            self.logger.info_msg(
                __name__,
                QCoreApplication.translate(
                    "ToolBar",
                    "No pairs id_boundary-id_plot found for '{}' table.").
                format(db.names.MORE_BFS_T))