コード例 #1
0
class SetPointMapTool(QgsMapToolEmitPoint):
    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(Qt.red)
        self.vertexMarker.setCursor(Qt.CrossCursor)
        self.reset()

    def reset(self):
        self.centerPoint = None
        self.vertexMarker.hide()
        #self.isEmittingPoint = False
        #self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        self.centerPoint = self.toMapCoordinates(e.pos())
        self.vertexMarker.setCenter(self.centerPoint)
        if not self.vertexMarker.isVisible():
            self.vertexMarker.show()
        #self.endPoint = self.startPoint
        #self.isEmittingPoint = True
        #self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        return
        #self.isEmittingPoint = False
        # r = self.rectangle()
        #if r is not None:
        #   print "Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()

    def canvasMoveEvent(self, e):
        return
        #if not self.isEmittingPoint:
        #return
        #self.endPoint = self.toMapCoordinates(e.pos())
        #self.showRect(self.startPoint, self.endPoint)

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y(
        ) == self.endPoint.y():
            return None
        return QgsRectangle(self.startPoint, self.endPoint)

    def deactivate(self):
        super(SetPointMapTool, self).deactivate()
        #self.emit(SIGNAL("deactivated()"))
        self.deactivated.emit()
コード例 #2
0
class StartEndMarker(object):

    def __init__(self, canvas, waypoints, color):

        self.canvas = canvas
        self.color = color
        self.start_vertex_marker = QgsVertexMarker(self.canvas)
        self.end_vertex_marker = QgsVertexMarker(self.canvas)

        self.update_markers(waypoints)

    def update_markers(self, steps):
        """
        Update start and end vertex markers on canvas.
        :param steps: waypoints in the mission
        :type: list
        """

        if len(steps) > 1:
            self.start_vertex_marker.setCenter(QgsPointXY(steps[0].x(), steps[0].y()))
            self.start_vertex_marker.setColor(self.color)
            self.start_vertex_marker.setIconSize(14)
            self.start_vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)  # ICON_BOX, ICON_CROSS, ICON_X
            self.start_vertex_marker.setPenWidth(2)

            self.start_vertex_marker.show()

            self.end_vertex_marker.setCenter(QgsPointXY(steps[-1].x(), steps[-1].y()))
            self.end_vertex_marker.setColor(self.color)
            self.end_vertex_marker.setIconSize(14)
            self.end_vertex_marker.setIconType(QgsVertexMarker.ICON_BOX)  # ICON_BOX, ICON_CROSS, ICON_X
            self.end_vertex_marker.setPenWidth(2)
            self.end_vertex_marker.show()

        else:

            self.start_vertex_marker.hide()
            self.end_vertex_marker.hide()

    def hide_markers(self):
        """ hide vertex markers. """
        self.start_vertex_marker.hide()
        self.end_vertex_marker.hide()

    def close_markers(self):
        """ Remove vertex markers from canvas."""
        self.hide_markers()
        self.canvas.scene().removeItem(self.start_vertex_marker)
        self.canvas.scene().removeItem(self.end_vertex_marker)
        self.start_vertex_marker = None
        self.end_vertex_marker = None
コード例 #3
0
class ParentManage(ParentAction, object):

    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to keep common functions of classes
        'ManageDocument', 'ManageElement' and 'ManageVisit' of toolbar 'edit' """

        super(ParentManage, self).__init__(iface, settings, controller, plugin_dir)

        self.x = ""
        self.y = ""
        self.canvas = self.iface.mapCanvas()
        self.plan_om = None
        self.previous_map_tool = None
        self.autocommit = True
        self.lazy_widget = None
        self.workcat_id_end = None
        self.xyCoordinates_conected = False
        self.remove_ids = True
        self.snapper_manager = None


    def reset_lists(self):
        """ Reset list of selected records """

        self.ids = []
        self.list_ids = {}
        self.list_ids['arc'] = []
        self.list_ids['node'] = []
        self.list_ids['connec'] = []
        self.list_ids['gully'] = []
        self.list_ids['element'] = []


    def reset_layers(self):
        """ Reset list of layers """

        self.layers = {}
        self.layers['arc'] = []
        self.layers['node'] = []
        self.layers['connec'] = []
        self.layers['gully'] = []
        self.layers['element'] = []


    def reset_model(self, dialog, table_object, geom_type):
        """ Reset model of the widget """ 

        table_relation = table_object + "_x_" + geom_type
        widget_name = "tbl_" + table_relation
        widget = utils_giswater.getWidget(dialog, widget_name)
        if widget:              
            widget.setModel(None)


    def remove_selection(self, remove_groups=True):
        """ Remove all previous selections """

        layer = self.controller.get_layer_by_tablename("v_edit_arc")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_node")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_connec")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_element")
        if layer:
            layer.removeSelection()
            
        if self.project_type == 'ud':
            layer = self.controller.get_layer_by_tablename("v_edit_gully")
            if layer:
                layer.removeSelection()

        try:
            if remove_groups:
                for layer in self.layers['arc']:
                    layer.removeSelection()
                for layer in self.layers['node']:
                    layer.removeSelection()
                for layer in self.layers['connec']:
                    layer.removeSelection()
                for layer in self.layers['gully']:
                    layer.removeSelection()
                for layer in self.layers['element']:
                    layer.removeSelection()
        except:
            pass

        self.canvas.refresh()
    
    
    def reset_widgets(self, dialog, table_object):
        """ Clear contents of input widgets """
        
        if table_object == "doc":
            utils_giswater.setWidgetText(dialog, "doc_type", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
        elif table_object == "element":
            utils_giswater.setWidgetText(dialog, "elementcat_id", "")
            utils_giswater.setWidgetText(dialog, "state", "")
            utils_giswater.setWidgetText(dialog, "expl_id","")
            utils_giswater.setWidgetText(dialog, "ownercat_id", "")
            utils_giswater.setWidgetText(dialog, "location_type", "")
            utils_giswater.setWidgetText(dialog, "buildercat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id_end", "")
            utils_giswater.setWidgetText(dialog, "comment", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
            utils_giswater.setWidgetText(dialog, "rotation", "")
            utils_giswater.setWidgetText(dialog, "verified", "")
            utils_giswater.setWidgetText(dialog, dialog.num_elements, "")
                    
    
    def fill_widgets(self, dialog, table_object, row):
        """ Fill input widgets with data int he @row """
        
        if table_object == "doc":
            
            utils_giswater.setWidgetText(dialog, "doc_type", row["doc_type"])
            utils_giswater.setWidgetText(dialog, "observ",  row["observ"])
            utils_giswater.setWidgetText(dialog, "path",  row["path"])
             
        elif table_object == "element":
                    
            state = ""  
            if row['state']:          
                sql = (f"SELECT name FROM value_state"
                       f" WHERE id = '{row['state']}'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    state = row_aux[0]
    
            expl_id = ""
            if row['expl_id']:
                sql = (f"SELECT name FROM exploitation"
                       f" WHERE expl_id = '{row['expl_id']}'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    expl_id = row_aux[0]

            utils_giswater.setWidgetText(dialog, "code", row['code'])
            sql = (f"SELECT elementtype_id FROM cat_element"
                   f" WHERE id = '{row['elementcat_id']}'")
            row_type = self.controller.get_row(sql)
            if row_type:
                utils_giswater.setWidgetText(dialog, "element_type", row_type[0])

            utils_giswater.setWidgetText(dialog, "elementcat_id", row['elementcat_id'])
            utils_giswater.setWidgetText(dialog, "num_elements", row['num_elements'])
            utils_giswater.setWidgetText(dialog, "state", state)
            utils_giswater.setWidgetText(dialog, "expl_id", expl_id)
            utils_giswater.setWidgetText(dialog, "ownercat_id", row['ownercat_id'])
            utils_giswater.setWidgetText(dialog, "location_type", row['location_type'])
            utils_giswater.setWidgetText(dialog, "buildercat_id", row['buildercat_id'])
            utils_giswater.setWidgetText(dialog, "builtdate", row['builtdate'])
            utils_giswater.setWidgetText(dialog, "workcat_id", row['workcat_id'])
            utils_giswater.setWidgetText(dialog, "workcat_id_end", row['workcat_id_end'])
            utils_giswater.setWidgetText(dialog, "comment", row['comment'])
            utils_giswater.setWidgetText(dialog, "observ", row['observ'])
            utils_giswater.setWidgetText(dialog, "link", row['link'])
            utils_giswater.setWidgetText(dialog, "verified", row['verified'])
            utils_giswater.setWidgetText(dialog, "rotation", row['rotation'])
            if str(row['undelete']) == 'True':
                dialog.undelete.setChecked(True)
            
              
    def get_records_geom_type(self, dialog, table_object, geom_type):
        """ Get records of @geom_type associated to selected @table_object """
        
        object_id = utils_giswater.getWidgetText(dialog, table_object + "_id")
        table_relation = table_object + "_x_" + geom_type
        widget_name = "tbl_" + table_relation           
        
        exists = self.controller.check_table(table_relation)
        if not exists:
            self.controller.log_info(f"Not found: {table_relation}")
            return
              
        sql = (f"SELECT {geom_type}_id "
               f"FROM {table_relation} "
               f"WHERE {table_object}_id = '{object_id}'")
        rows = self.controller.get_rows(sql, commit=True, log_info=False)
        if rows:
            for row in rows:
                self.list_ids[geom_type].append(str(row[0]))
                self.ids.append(str(row[0]))

            expr_filter = self.get_expr_filter(geom_type)
            self.set_table_model(dialog, widget_name, geom_type, expr_filter)
    
    
    def exist_object(self, dialog, table_object):
        """ Check if selected object (document or element) already exists """
        
        # Reset list of selected records
        self.reset_lists()
        
        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"           
        object_id = utils_giswater.getWidgetText(dialog, table_object + "_id")

        # Check if we already have data with selected object_id
        sql = (f"SELECT * "
               f" FROM {table_object}"
               f" WHERE {field_object_id} = '{object_id}'")
        row = self.controller.get_row(sql, log_info=False)

        # If object_id not found: Clear data
        if not row:    
            self.reset_widgets(dialog, table_object)
            if table_object == 'element':
                self.set_combo(dialog, 'state', 'value_state', 'state_vdefault', field_name='name')
                self.set_combo(dialog, 'expl_id', 'exploitation', 'exploitation_vdefault', field_id='expl_id',field_name='name')
                self.set_calendars(dialog, 'builtdate', 'config_param_user', 'value', 'builtdate_vdefault')
                self.set_combo(dialog, 'workcat_id', 'cat_work', 'workcat_vdefault', field_id='id', field_name='id')
            if hasattr(self, 'single_tool_mode'):
                # some tools can work differently if standalone or integrated in
                # another tool
                if self.single_tool_mode:
                    self.remove_selection(True)
            else:
                self.remove_selection(True)
            self.reset_model(dialog, table_object, "arc")
            self.reset_model(dialog, table_object, "node")
            self.reset_model(dialog, table_object, "connec")
            self.reset_model(dialog, table_object, "element")
            if self.project_type == 'ud':
                self.reset_model(dialog, table_object, "gully")

            return

        # Fill input widgets with data of the @row
        self.fill_widgets(dialog, table_object, row)

        # Check related 'arcs'
        self.get_records_geom_type(dialog, table_object, "arc")
        
        # Check related 'nodes'
        self.get_records_geom_type(dialog, table_object, "node")
        
        # Check related 'connecs'
        self.get_records_geom_type(dialog, table_object, "connec")

        # Check related 'elements'
        self.get_records_geom_type(dialog, table_object, "element")

        # Check related 'gullys'
        if self.project_type == 'ud':        
            self.get_records_geom_type(dialog, table_object, "gully")


    def populate_combo(self, dialog, widget, table_name, field_name="id"):
        """ Executes query and fill combo box """

        sql = (f"SELECT {field_name}"
               f" FROM {table_name}"
               f" ORDER BY {field_name}")
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        utils_giswater.fillComboBox(dialog, widget, rows)
        if rows:
            utils_giswater.setCurrentIndex(dialog, widget, 0)


    def set_combo(self, dialog, widget, table_name, parameter, field_id='id', field_name='id'):
        """ Executes query and set combo box """
        
        sql = (f"SELECT t1.{field_name} FROM {table_name} as t1"
               f" INNER JOIN config_param_user as t2 ON t1.{field_id}::text = t2.value::text"
               f" WHERE parameter = '{parameter}' AND cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.setWidgetText(dialog, widget, row[0])


    def set_calendars(self, dialog, widget, table_name, value, parameter):
        """ Executes query and set QDateEdit """
        
        sql = (f"SELECT {value} FROM {table_name}"
               f" WHERE parameter = '{parameter}' AND cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            date = QDate.fromString(row[0], 'yyyy-MM-dd')
        else:
            date = QDate.currentDate()
        utils_giswater.setCalendarDate(dialog, widget, date)


    def add_point(self):
        """ Create the appropriate map tool and connect to the corresponding signal """

        active_layer = self.iface.activeLayer()
        if active_layer is None:
            active_layer = self.controller.get_layer_by_tablename('version')
            self.iface.setActiveLayer(active_layer)

        # Vertex marker
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setColor(QColor(255, 100, 255))
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.vertex_marker.setPenWidth(3)

        # Snapper
        if self.snapper_manager is None:
            self.snapper_manager = SnappingConfigManager(self.iface)
            self.snapper = self.snapper_manager.get_snapper()
            if self.snapper_manager.controller is None:
                self.snapper_manager.set_controller(self.controller)

        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.previous_map_tool = self.canvas.mapTool()
        self.canvas.setMapTool(self.emit_point)
        self.canvas.xyCoordinates.connect(self.mouse_move)
        self.xyCoordinates_conected = True
        self.emit_point.canvasClicked.connect(partial(self.get_xy))


    def mouse_move(self, point):

        # Hide marker and get coordinates
        self.snapped_point = None
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(point=point)

        # Snapping
        result = self.snapper_manager.snap_to_background_layers(event_point)
        if self.snapper_manager.result_is_valid():
            self.snapper_manager.add_marker(result, self.vertex_marker)
        else:
            self.vertex_marker.hide()


    def get_xy(self, point):
        """ Get coordinates of selected point """

        if self.snapped_point:
            self.x = self.snapped_point.x()
            self.y = self.snapped_point.y()
        else:
            self.x = point.x()
            self.y = point.y()

        message = "Geometry has been added!"
        self.controller.show_info(message)
        self.emit_point.canvasClicked.disconnect()
        self.canvas.xyCoordinates.disconnect()
        self.xyCoordinates_conected = False
        self.iface.mapCanvas().refreshAllLayers()
        self.vertex_marker.hide()


    def get_values_from_form(self, dialog):

        self.enddate = utils_giswater.getCalendarDate(dialog, "enddate")
        self.workcat_id_end = utils_giswater.getWidgetText(dialog, "workcat_id_end")
        self.description = utils_giswater.getWidgetText(dialog, "descript")


    def tab_feature_changed(self, dialog, table_object):
        """ Set geom_type and layer depending selected tab
            @table_object = ['doc' | 'element' | 'cat_work']
        """

        self.get_values_from_form(dialog)
        tab_position = dialog.tab_feature.currentIndex()
        if tab_position == 0:
            self.geom_type = "arc"   
        elif tab_position == 1:
            self.geom_type = "node"
        elif tab_position == 2:
            self.geom_type = "connec"
        elif tab_position == 3:
            self.geom_type = "element"
        elif tab_position == 4:
            self.geom_type = "gully"

        self.hide_generic_layers()                  
        widget_name = f"tbl_{table_object}_x_{self.geom_type}"
        viewname = f"v_edit_{self.geom_type}"
        self.widget = utils_giswater.getWidget(dialog, widget_name)
            
        # Adding auto-completion to a QLineEdit
        self.set_completer_feature_id(dialog.feature_id, self.geom_type, viewname)
        
        self.iface.actionPan().trigger()    
        

    def set_completer_object(self, dialog, table_object):
        """ Set autocomplete of widget @table_object + "_id" 
            getting id's from selected @table_object 
        """
                     
        widget = utils_giswater.getWidget(dialog, table_object + "_id")
        if not widget:
            return
        
        # Set SQL
        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        sql = (f"SELECT DISTINCT({field_object_id})"
               f" FROM {table_object}")
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        if rows is None:
            return

        for i in range(0, len(rows)):
            aux = rows[i]
            rows[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(rows)
        self.completer.setModel(model)
        
        
    def set_completer_widget(self, tablename, widget, field_id):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        # Set SQL
        sql = (f"SELECT DISTINCT({field_id})"
               f" FROM {tablename}"
               f" ORDER BY {field_id}")
        row = self.controller.get_rows(sql, commit=True)
        for i in range(0, len(row)):
            aux = row[i]
            row[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(row)
        self.completer.setModel(model)
                

    def set_completer_feature_id(self, widget, geom_type, viewname):
        """ Set autocomplete of widget 'feature_id' 
            getting id's from selected @viewname 
        """
             
        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = (f"SELECT {geom_type}_id"
               f" FROM {viewname}")
        row = self.controller.get_rows(sql, commit=self.autocommit)
        if row:
            for i in range(0, len(row)):
                aux = row[i]
                row[i] = str(aux[0])

            model.setStringList(row)
            self.completer.setModel(model)


    def get_expr_filter(self, geom_type):
        """ Set an expression filter with the contents of the list.
            Set a model with selected filter. Attach that model to selected table 
        """

        list_ids = self.list_ids[geom_type]
        field_id = geom_type + "_id"
        if len(list_ids) == 0:
            return None

        # Set expression filter with features in the list        
        expr_filter = field_id + " IN ("
        for i in range(len(list_ids)):
            expr_filter += f"'{list_ids[i]}', "
        expr_filter = expr_filter[:-2] + ")"

        # Check expression
        (is_valid, expr) = self.check_expression(expr_filter)
        if not is_valid:
            return None

        # Select features of layers applying @expr
        self.select_features_by_ids(geom_type, expr)
        
        return expr_filter


    def reload_table(self, dialog, table_object, geom_type, expr_filter):
        """ Reload @widget with contents of @tablename applying selected @expr_filter """

        if type(table_object) is str:
            widget_name = f"tbl_{table_object}_x_{geom_type}"
            widget = utils_giswater.getWidget(dialog, widget_name)

            if not widget:
                message = "Widget not found"
                self.controller.log_info(message, parameter=widget_name)
                return None

        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return None

        expr = self.set_table_model(dialog, widget, geom_type, expr_filter)
        return expr


    def set_table_model(self, dialog, table_object, geom_type, expr_filter):
        """ Sets a TableModel to @widget_name attached to
            @table_name and filter @expr_filter 
        """

        expr = None
        if expr_filter:
            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter)    #@UnusedVariable
            if not is_valid:
                return expr

        # Set a model with selected filter expression
        table_name = "v_edit_" + geom_type
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set the model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.select()
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
            return expr

        # Attach model to selected widget
        if type(table_object) is str:
            widget = utils_giswater.getWidget(dialog, table_object)
            if not widget:
                message = "Widget not found"
                self.controller.log_info(message, parameter=table_object)
                return expr
        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return expr

        if expr_filter:
            widget.setModel(model)
            widget.model().setFilter(expr_filter)
            widget.model().select()
        else:
            widget.setModel(None)

        return expr


    def apply_lazy_init(self, widget):
        """Apply the init function related to the model. It's necessary
        a lazy init because model is changed everytime is loaded."""

        if self.lazy_widget is None:
            return
        if widget != self.lazy_widget:
            return
        self.lazy_init_function(self.lazy_widget)


    def lazy_configuration(self, widget, init_function):
        """set the init_function where all necessary events are set.
        This is necessary to allow a lazy setup of the events because set_table_events
        can create a table with a None model loosing any event connection."""

        # TODO: create a dictionary with key:widged.objectName value:initFuction
        # to allow multiple lazy initialization
        self.lazy_widget = widget
        self.lazy_init_function = init_function


    def select_features_by_ids(self, geom_type, expr):
        """ Select features of layers of group @geom_type applying @expr """

        # Build a list of feature id's and select them
        for layer in self.layers[geom_type]:
            if expr is None:
                layer.removeSelection()  
            else:                
                it = layer.getFeatures(QgsFeatureRequest(expr))
                id_list = [i.id() for i in it]
                if len(id_list) > 0:
                    layer.selectByIds(id_list)   
                else:
                    layer.removeSelection()             
        
             
    def delete_records(self, dialog, table_object, query=False):
        """ Delete selected elements of the table """

        self.disconnect_signal_selection_changed()

        if type(table_object) is str:
            widget_name = f"tbl_{table_object}_x_{self.geom_type}"
            widget = utils_giswater.getWidget(dialog, widget_name)
            if not widget:
                message = "Widget not found"
                self.controller.show_warning(message, parameter=widget_name)
                return
        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return

        # Control when QTableView is void or has no model
        try:
            # Get selected rows
            selected_list = widget.selectionModel().selectedRows()
        except AttributeError as e:
            selected_list = []


        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        if query:
            full_list = widget.model()
            for x in range(0, full_list.rowCount()):
                self.ids.append(widget.model().record(x).value(f"{self.geom_type}_id"))
        else:
            self.ids = self.list_ids[self.geom_type]

        field_id = self.geom_type + "_id"
        
        del_id = []
        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_feature = widget.model().record(row).value(field_id)
            inf_text += f"{id_feature}, "
            list_id += f"'{id_feature}', "
            del_id.append(id_feature)
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            for el in del_id:
                self.ids.remove(el)
        else:
            return

        expr_filter = None
        expr = None
        if len(self.ids) > 0:

            # Set expression filter with features in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter) #@UnusedVariable
            if not is_valid:
                return

        # Update model of the widget with selected expr_filter
        if query:
            self.delete_feature_at_plan(dialog, self.geom_type, list_id)
            self.reload_qtable(dialog, self.geom_type, self.plan_om)
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)

        # Select features with previous filter
        # Build a list of feature id's and select them
        self.select_features_by_ids(self.geom_type, expr)

        if query:
            self.remove_selection()
        # Update list
        self.list_ids[self.geom_type] = self.ids
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def manage_close(self, dialog, table_object, cur_active_layer=None):
        """ Close dialog and disconnect snapping """

        if cur_active_layer:
            self.iface.setActiveLayer(cur_active_layer)
        if hasattr(self, 'single_tool_mode'):
            # some tools can work differently if standalone or integrated in
            # another tool
            if self.single_tool_mode:
                self.remove_selection(True)
        else:
            self.remove_selection(True)
        self.reset_model(dialog, table_object, "arc")
        self.reset_model(dialog, table_object, "node")
        self.reset_model(dialog, table_object, "connec")
        self.reset_model(dialog, table_object, "element")
        if self.project_type == 'ud':
            self.reset_model(dialog, table_object, "gully")
        self.close_dialog(dialog)
        self.hide_generic_layers()
        self.disconnect_snapping()   
        self.disconnect_signal_selection_changed()


    def selection_init(self, dialog, table_object, query=False):
        """ Set canvas map tool to an instance of class 'MultipleSelection' """

        multiple_selection = MultipleSelection(self.iface, self.controller, self.layers[self.geom_type], 
            parent_manage=self, table_object=table_object, dialog=dialog)
        self.disconnect_signal_selection_changed()
        self.previous_map_tool = self.canvas.mapTool()        
        self.canvas.setMapTool(multiple_selection)              
        self.connect_signal_selection_changed(dialog, table_object, query)
        cursor = self.get_cursor_multiple_selection()
        self.canvas.setCursor(cursor)


    def selection_changed(self, dialog, table_object, geom_type, query=False):
        """ Slot function for signal 'canvas.selectionChanged' """
        self.disconnect_signal_selection_changed()
        field_id = geom_type + "_id"

        if self.remove_ids:
            self.ids = []

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount() > 0:
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    if selected_id not in self.ids:
                        self.ids.append(selected_id)

        if geom_type == 'arc':
            self.list_ids['arc'] = self.ids
        elif geom_type == 'node':
            self.list_ids['node'] = self.ids
        elif geom_type == 'connec':
            self.list_ids['connec'] = self.ids
        elif geom_type == 'gully':
            self.list_ids['gully'] = self.ids
        elif geom_type == 'element':
            self.list_ids['element'] = self.ids

        expr_filter = None
        if len(self.ids) > 0:
            # Set 'expr_filter' with features that are in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter)   #@UnusedVariable
            if not is_valid:
                return                                           
                          
            self.select_features_by_ids(geom_type, expr)
                        
        # Reload contents of table 'tbl_@table_object_x_@geom_type'
        if query:
            self.insert_feature_to_plan(dialog, self.geom_type)
            if self.plan_om == 'plan':
                self.remove_selection()
            self.reload_qtable(dialog, geom_type, self.plan_om)
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)

        # Remove selection in generic 'v_edit' layers
        if self.plan_om == 'plan':
            self.remove_selection(False)
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def delete_feature_at_plan(self, dialog, geom_type, list_id):
        """ Delete features_id to table plan_@geom_type_x_psector"""

        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        sql = (f"DELETE FROM {self.plan_om}_psector_x_{geom_type} "
               f"WHERE {geom_type}_id IN ({list_id}) AND psector_id = '{value}'")
        self.controller.execute_sql(sql)


    def enable_feature_type(self, dialog):

        feature_type = dialog.findChild(QComboBox, 'feature_type')
        table = dialog.findChild(QTableView, 'tbl_relation')
        if feature_type is not None and table is not None:
            if len(self.ids) > 0:
                feature_type.setEnabled(False)
            else:
                feature_type.setEnabled(True)


    def insert_feature(self, dialog, table_object, query=False, remove_ids=True):
        """ Select feature with entered id. Set a model with selected filter.
            Attach that model to selected table
        """

        self.disconnect_signal_selection_changed()

        # Clear list of ids
        if remove_ids:
            self.ids = []
        field_id = self.geom_type + "_id"

        feature_id = utils_giswater.getWidgetText(dialog, "feature_id")
        if feature_id == 'null':
            message = "You need to enter a feature id"
            self.controller.show_info_box(message)
            return

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount() > 0:
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    if selected_id not in self.ids:
                        self.ids.append(selected_id)
            if feature_id not in self.ids:
                # If feature id doesn't exist in list -> add
                self.ids.append(str(feature_id))

        # Set expression filter with features in the list
        expr_filter = f'"{field_id}" IN ('
        for i in range(len(self.ids)):
            expr_filter += f"'{self.ids[i]}', "
        expr_filter = expr_filter[:-2] + ")"

        # Check expression
        (is_valid, expr) = self.check_expression(expr_filter)
        if not is_valid:
            return

        # Select features with previous filter
        # Build a list of feature id's and select them
        for layer in self.layers[self.geom_type]:
            it = layer.getFeatures(QgsFeatureRequest(expr))
            id_list = [i.id() for i in it]
            if len(id_list) > 0:
                layer.selectByIds(id_list)

        # Reload contents of table 'tbl_???_x_@geom_type'
        if query:
            self.insert_feature_to_plan(dialog, self.geom_type)
            self.remove_selection()
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)            

        # Update list
        self.list_ids[self.geom_type] = self.ids
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def insert_feature_to_plan(self, dialog, geom_type):
        """ Insert features_id to table plan_@geom_type_x_psector """

        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        for i in range(len(self.ids)):
            sql = (f"SELECT {geom_type}_id "
                   f"FROM {self.plan_om}_psector_x_{geom_type} "
                   f"WHERE {geom_type}_id = '{self.ids[i]}' AND psector_id = '{value}'")
            row = self.controller.get_row(sql)
            if not row:
                sql = (f"INSERT INTO {self.plan_om}_psector_x_{geom_type}"
                       f"({geom_type}_id, psector_id) VALUES('{self.ids[i]}', '{value}')")
                self.controller.execute_sql(sql)
            self.reload_qtable(dialog, geom_type, self.plan_om)


    def reload_qtable(self, dialog, geom_type, plan_om):
        """ Reload QtableView """
        
        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        expr = f"psector_id = '{value}'"
        qtable = utils_giswater.getWidget(dialog, f'tbl_psector_x_{geom_type}')
        self.fill_table_by_expr(qtable, f"{plan_om}_psector_x_{geom_type}", expr)
        self.set_table_columns(dialog, qtable, f"{plan_om}_psector_x_{geom_type}")
        self.refresh_map_canvas()


    def fill_table_by_expr(self, qtable, table_name, expr):
        """
        :param qtable: QTableView to show
        :param expr: expression to set model
        """
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name
            
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setFilter(expr)
        model.setEditStrategy(QSqlTableModel.OnFieldChange)
        qtable.setEditTriggers(QTableView.DoubleClicked)
        model.select()
        qtable.setModel(model)
        qtable.show()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

    def disconnect_snapping(self):
        """ Select 'Pan' as current map tool and disconnect snapping """

        try:
            self.iface.actionPan().trigger()
            self.canvas.xyCoordinates.disconnect()
            if self.emit_point:       
                self.emit_point.canvasClicked.disconnect()
        except:
            pass


    def fill_table_object(self, widget, table_name, expr_filter=None):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.sort(0, 1)
        if expr_filter:
            model.setFilter(expr_filter)            
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)


    def filter_by_id(self, dialog, widget_table, widget_txt, table_object, field_object_id='id'):

        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        object_id = utils_giswater.getWidgetText(dialog, widget_txt)
        if object_id != 'null':
            expr = f"{field_object_id}::text ILIKE '%{object_id}%'"
            # Refresh model with selected filter
            widget_table.model().setFilter(expr)
            widget_table.model().select()
        else:
            self.fill_table_object(widget_table, self.schema_name + "." + table_object)


    def delete_selected_object(self, widget, table_object):
        """ Delete selected objects of the table (by object_id) """

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        inf_text = ""
        list_id = ""
        field_object_id = "id"

        if table_object == "element":
            field_object_id = table_object + "_id"
        elif "v_ui_om_visitman_x_" in table_object:
            field_object_id = "visit_id"

        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = widget.model().record(row).value(str(field_object_id))
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            sql = (f"DELETE FROM {table_object} "
                   f"WHERE {field_object_id} IN ({list_id})")
            self.controller.execute_sql(sql, commit=self.autocommit)
            widget.model().select()

    
    def open_selected_object(self, dialog, widget, table_object):
        """ Open object form with selected record of the table """

        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        row = selected_list[0].row()

        # Get object_id from selected row
        field_object_id = "id"
        widget_id = table_object + "_id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        if table_object == "v_ui_om_visit":
            widget_id = "visit_id"
        elif "v_ui_om_visitman_x_" in table_object:
            field_object_id = "visit_id"
        selected_object_id = widget.model().record(row).value(field_object_id)

        # Close this dialog and open selected object
        dialog.close()

        if table_object == "doc":
            self.manage_document()
            utils_giswater.setWidgetText(self.dlg_add_doc, widget_id, selected_object_id)
        elif table_object == "element":
            self.manage_element(new_element_id=False)
            utils_giswater.setWidgetText(self.dlg_add_element, widget_id, selected_object_id)
        elif table_object == "v_ui_om_visit":
            self.manage_visit(visit_id=selected_object_id)
        elif "v_ui_om_visitman_x_" in table_object:
            self.manage_visit(visit_id=selected_object_id)


    def set_selectionbehavior(self, dialog):
        
        # Get objects of type: QTableView
        widget_list = dialog.findChildren(QTableView)
        for widget in widget_list:
            widget.setSelectionBehavior(QAbstractItemView.SelectRows) 
        
        
    def hide_generic_layers(self, visible=False):       
        """ Hide generic layers """
        
        layer = self.controller.get_layer_by_tablename("v_edit_arc")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_node")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_connec")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_element")
        if layer:
            self.controller.set_layer_visible(layer)
            
        if self.project_type == 'ud':
            layer = self.controller.get_layer_by_tablename("v_edit_gully")
            if layer:
                self.controller.set_layer_visible(layer)
        
    
    def connect_signal_selection_changed(self, dialog, table_object, query=False):
        """ Connect signal selectionChanged """
        
        try:
            self.canvas.selectionChanged.connect(partial(self.selection_changed, dialog,  table_object, self.geom_type, query))
        except Exception:    
            pass
    
    
    def disconnect_signal_selection_changed(self):
        """ Disconnect signal selectionChanged """
        
        try:
            self.canvas.selectionChanged.disconnect()  
            self.iface.actionPan().trigger()
        except Exception:   
            pass
        

    def fill_widget_with_fields(self, dialog, data_object, field_names):
        """Fill the Widget with value get from data_object limited to 
        the list of field_names."""
        
        for field_name in field_names:
            value = getattr(data_object, field_name)
            if not hasattr(dialog, field_name):
                continue

            widget = getattr(dialog, field_name)
            if type(widget) == QDateEdit:
                widget.setDate(value if value else QDate.currentDate())
            elif type(widget) == QDateTimeEdit:
                widget.setDateTime(value if value else QDateTime.currentDateTime())


            if type(widget) in [QLineEdit, QTextEdit]:
                if value:
                    widget.setText(value)
                else:
                    widget.clear()
            if type(widget) in [QComboBox]:
                if not value:
                    widget.setCurrentIndex(0)
                    continue
                # look the value in item text
                index = widget.findText(str(value))
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue
                # look the value in itemData
                index = widget.findData(value)
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue


    def set_model_to_table(self, widget, table_name, expr_filter):
        """ Set a model with selected filter.
        Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel();
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setFilter(expr_filter)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        if widget:
            widget.setModel(model)
        else:
            self.controller.log_info("set_model_to_table: widget not found")
コード例 #4
0
class gazetteerSearch:
    def __init__(self, iface):
        self.dock = None
        self.results = []
        # Save reference to the QGIS interface
        self.iface = iface
        self.iface.newProjectCreated.connect(self._hideMarker)
        self.iface.projectRead.connect(self._hideMarker)
        self.canvas = self.iface.mapCanvas()
        self.marker = QgsVertexMarker(self.iface.mapCanvas())
        self.marker.setIconSize(20)
        self.marker.setPenWidth(3)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.marker.hide()

        # Create the dialog and keep reference
        self.widget = gazetteerSearchDialog()
        self.widget.runSearch.connect(self.runSearch)
        self.widget.ui.clearButton.pressed.connect(self.clearResults)
        self.widget.zoomRequested.connect(self.zoomTo)
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + "/python/plugins/gazetteersearch"
        # initialize locale

        localePath = ""
        if QGis.QGIS_VERSION_INT < 10900:
            locale = QSettings().value("locale/userLocale").toString()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]
        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/gazetteersearch_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)

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

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/gazetteersearch/icon.png"), \
            u"Gazetteer Search", 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(u"&Gazetteer Search", self.action)

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(u"&Gazetteer Search",self.action)
        self.iface.removeToolBarIcon(self.action)
        self.iface.mapCanvas().scene().removeItem(self.marker)
        self.marker = None

    def _hideMarker(self):
        self.marker.hide()

    # run method that performs all the real work
    def run(self):
        if not self.dock:
            self.dock = QDockWidget("Gazetteer Search", self.iface.mainWindow())
            self.dock.setWidget(self.widget)
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock)
            self.gazetteers = common.getGazetteers()
            for gazetter in self.gazetteers.iterkeys():
                self.widget.addGazetter(gazetter)

            if len(self.gazetteers) == 1:
                self.widget.hideGazetteers()
        else:
            self.dock.show()

    def runSearch(self, searchString, selectedGazetteer):
        searchString = searchString.encode('utf-8')
        gazetteer_config = self.gazetteers[str(selectedGazetteer)]
        gazetteer = self.getGazetteerModule(gazetteer_config)
        url = common.prepareURL(gazetteer.url, gazetteer.params, searchString)

        def callback(data):
            try:
                self.results = list(gazetteer.parseRequestResults(data, self.iface))
            except:
                self.results = []

            if len(self.results) == 0:
                self.widget.addError('No results found for "%s"' % searchString)

            for res in self.results:
                self.widget.addResult(res.description)

        common.search(url, callback)

    def clearResults(self):
        self.widget.clearResults()
        self.marker.hide()

    def getGazetteerModule(self, config):
        gazetteer_module = config['gazetteer']
        imported_gazetteer = import_module('gazetteersearch.gazetteers.%s' % gazetteer_module)
        return imported_gazetteer

    def zoomTo(self, name):
        for res in self.results:
            if unicode(res.description) == unicode(name):
                dest_crs = self.canvas.mapRenderer().destinationCrs()
                if QGis.QGIS_VERSION_INT < 10900:
                    src_crs = QgsCoordinateReferenceSystem()
                    src_crs.createFromEpsg(res.epsg)
                else:
                    src_crs = QgsCoordinateReferenceSystem(res.epsg, QgsCoordinateReferenceSystem.EpsgCrsId)
                transform = QgsCoordinateTransform(src_crs, dest_crs)
                new_point = transform.transform(res.x, res.y)
                x = new_point.x()
                y = new_point.y()
                self.canvas.setExtent(QgsRectangle(x,y,x,y))
                self.canvas.zoomScale(res.zoom)
                self.canvas.refresh()
                self.marker.setCenter(new_point)
                self.marker.show()
                return
コード例 #5
0
ファイル: add_tank_tool.py プロジェクト: mcgoldba/XPSS
class AddTankTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.snapper = None
        self.snapped_feat_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = None

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = False

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        if not self.mouse_clicked:

            # Mouse not clicked: snapping to closest vertex
            # (retval, result) = self.snapper.snapMapPoint(self.toMapCoordinates(event.pos()))
            # if len(result) > 0:
            # It's a vertex on an existing pipe

            match = self.snapper.snapToMap(self.mouse_pt)

            if match.isValid():

                # self.snapped_feat_id = result[0].snappedAtGeometry
                # snapped_vertex = result[0].snappedVertex
                # self.snapped_vertex_nr = result[0].snappedVertexNr
                # self.snapped_vertex = QgsPoint(snapped_vertex.x(), snapped_vertex.y())

                self.snapped_feat_id = match.featureId()
                self.snapped_vertex = match.point()
                self.snapped_vertex_nr = match.vertexIndex()

                self.vertex_marker.setCenter(self.snapped_vertex)
                self.vertex_marker.setColor(QColor(255, 0, 0))
                self.vertex_marker.setIconSize(10)
                self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                self.vertex_marker.setPenWidth(3)
                self.vertex_marker.show()

            else:

                # It's a new, isolated vertex
                self.snapped_feat_id = None
                self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return

        if event.button() == Qt.LeftButton:

            self.mouse_clicked = False

            # Find first available ID for Tanks
            tank_eid = NetworkUtils.find_next_id(self.params.tanks_vlay,
                                                 Tank.prefix)  # TODO: softcode

            curve = self.data_dock.cbo_tank_curve.itemData(
                self.data_dock.cbo_tank_curve.currentIndex())
            if curve is not None:
                tank_curve_id = curve.id
            else:
                tank_curve_id = None

            elev = 0
            if self.elev is None and self.params.dem_rlay is not None:
                self.iface.messageBar().pushMessage(
                    Parameters.plug_in_name,
                    'Elevation value not available: element elevation set to 0.',
                    Qgis.Warning, 5)  # TODO: softcode
            else:
                elev = self.elev

            diameter = float(self.data_dock.txt_tank_diameter.text())
            deltaz = float(self.data_dock.txt_tank_deltaz.text())
            level_init = float(self.data_dock.txt_tank_level_init.text())
            level_min = float(self.data_dock.txt_tank_level_min.text())
            level_max = float(self.data_dock.txt_tank_level_max.text())
            vol_min = float(self.data_dock.txt_tank_vol_min.text())
            tank_desc = self.data_dock.txt_tank_desc.text()
            tank_tag = self.data_dock.cbo_tank_tag.currentText()

            # No links snapped: create a new stand-alone tank
            if self.snapped_feat_id is None:

                NodeHandler.create_new_tank(self.params, self.mouse_pt,
                                            tank_eid, tank_curve_id, diameter,
                                            elev, deltaz, level_init,
                                            level_min, level_max, vol_min,
                                            tank_desc, tank_tag)

            # A link has been snapped
            else:

                # Get the snapped pipe and split it
                request = QgsFeatureRequest().setFilterFid(
                    self.snapped_feat_id)
                feats = list(self.params.pipes_vlay.getFeatures(request))
                if len(feats) > 0:

                    snapped_pipe = QgsFeature(feats[0])
                    (start_node_ft,
                     end_node_ft) = NetworkUtils.find_start_end_nodes(
                         self.params, snapped_pipe.geometry())

                    if start_node_ft is None or end_node_ft is None:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'The pipe is missing the start or end nodes. Cannot add a new tank along the pipe.',
                            Qgis.Warning, 5)  # TODO: softcode
                        return

                    # Check that the snapped point on line is distant enough from start/end nodes
                    if start_node_ft.geometry().distance(QgsGeometry.fromPointXY(self.snapped_vertex)) > self.params.min_dist and\
                        end_node_ft.geometry().distance(QgsGeometry.fromPointXY(self.snapped_vertex)) > self.params.min_dist:

                        LinkHandler.split_pipe(self.params, snapped_pipe,
                                               self.snapped_vertex)

                        # New node on existing line
                        NodeHandler.create_new_tank(
                            self.params, self.snapped_vertex, tank_eid,
                            tank_curve_id, diameter, self.elev, deltaz,
                            level_init, level_min, level_max, vol_min,
                            tank_desc, tank_tag)

                    # Replace pipe start node with new tank
                    elif start_node_ft.geometry().distance(
                            QgsGeometry.fromPointXY(self.snapped_vertex)) <= 0:

                        # Delete junction
                        NodeHandler.delete_node(self.params,
                                                self.params.junctions_vlay,
                                                start_node_ft, False)

                        # New node on existing line
                        NodeHandler.create_new_tank(
                            self.params, self.snapped_vertex, tank_eid,
                            tank_curve_id, diameter, self.elev, deltaz,
                            level_init, level_min, level_max, vol_min,
                            tank_desc, tank_tag)

                    # Replace pipe end node with new tank
                    elif end_node_ft.geometry().distance(
                            QgsGeometry.fromPointXY(self.snapped_vertex)) <= 0:

                        # Delete junction
                        NodeHandler.delete_node(self.params,
                                                self.params.junctions_vlay,
                                                end_node_ft, False)

                        # New node on existing line
                        NodeHandler.create_new_tank(
                            self.params, self.snapped_vertex, tank_eid,
                            tank_curve_id, diameter, self.elev, deltaz,
                            level_init, level_min, level_max, vol_min,
                            tank_desc, tank_tag)

                    else:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'The selected position is too close to a junction: cannon create the tank.',
                            Qgis.Warning, 5)  # TODO: softcode

            self.iface.mapCanvas().refresh()

    def activate(self):

        self.update_snapper()

        # Editing
        if not self.params.tanks_vlay.isEditable():
            self.params.tanks_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()

    def deactivate(self):

        # QgsProject.instance().setSnapSettingsForLayer(self.params.pipes_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToSegment,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)

        self.data_dock.btn_add_tank.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def update_snapper(self):
        layers = {self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment}
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)
        self.snapper.toggleEnabled()

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
コード例 #6
0
class QGISRedEditLinksGeometryTool(QgsMapTool):
    ownMainLayers = ["Pipes", "Valves", "Pumps", "ServiceConnections"]

    def __init__(self, button, iface, projectDirectory, netwName):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.ProjectDirectory = projectDirectory
        self.NetworkName = netwName
        self.toolbarButton = button

        self.snapper = None
        self.vertexMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.vertexMarker.setColor(QColor(255, 87, 51))
        self.vertexMarker.setIconSize(15)
        self.vertexMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(3)
        self.vertexMarker.hide()

        self.pipeSnapper = None
        self.pipeMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.pipeMarker.setColor(QColor(143, 0, 255))
        self.pipeMarker.setIconSize(10)
        try:
            self.pipeMarker.setIconType(
                QgsVertexMarker.ICON_DOUBLE_TRIANGLE)  # or ICON_CROSS, ICON_X
        except:
            self.pipeMarker.setIconType(
                QgsVertexMarker.ICON_X)  # or ICON_CROSS, ICON_X
        self.pipeMarker.setPenWidth(3)
        self.pipeMarker.hide()

        self.mouseClicked = False
        self.clickedPoint = None
        self.objectSnapped = None
        self.pipeSnapped = None
        self.selectedFeature = None
        self.selectedLayer = None
        self.newPositionVector = QgsVector(0, 0)
        self.rubberBand = None
        self.newVertexMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.newVertexMarker.setColor(QColor(55, 198, 5))
        self.newVertexMarker.setIconSize(15)
        self.newVertexMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.newVertexMarker.setPenWidth(3)
        self.newVertexMarker.hide()

    def activate(self):
        cursor = QCursor()
        cursor.setShape(Qt.ArrowCursor)
        self.iface.mapCanvas().setCursor(cursor)

        myLayers = []
        # Editing
        layers = self.getLayers()
        for layer in layers:
            openedLayerPath = self.getLayerPath(layer)
            for name in self.ownMainLayers:
                layerPath = self.generatePath(
                    self.ProjectDirectory,
                    self.NetworkName + "_" + name + ".shp")
                if openedLayerPath == layerPath:
                    myLayers.append(layer)
                    if not layer.isEditable():
                        layer.startEditing()
        # Snapping
        self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())
        self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings())
        config = QgsSnappingConfig(QgsProject.instance())
        config.setType(2)  # Vertex
        config.setMode(2)  # All layers
        config.setTolerance(10)
        config.setUnits(1)  # Pixels
        config.setEnabled(True)
        self.snapper.setConfig(config)

        self.pipeSnapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())
        self.pipeSnapper.setMapSettings(self.iface.mapCanvas().mapSettings())
        config = QgsSnappingConfig(QgsProject.instance())
        config.setType(2)  # Vertex
        config.setMode(2)  # All layers
        config.setTolerance(10)
        config.setUnits(1)  # Pixels
        config.setEnabled(True)
        self.pipeSnapper.setConfig(config)

    def deactivate(self):
        self.toolbarButton.setChecked(False)
        # End Editing
        layers = self.getLayers()
        for layer in layers:
            openedLayerPath = self.getLayerPath(layer)
            for name in self.ownMainLayers:
                layerPath = self.generatePath(
                    self.ProjectDirectory,
                    self.NetworkName + "_" + name + ".shp")
                if openedLayerPath == layerPath:
                    if layer.isModified():
                        layer.commitChanges()
                    else:
                        layer.rollBack()

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    """Methods"""

    def getUniformedPath(self, path):
        return QGISRedUtils().getUniformedPath(path)

    def getLayerPath(self, layer):
        return QGISRedUtils().getLayerPath(layer)

    def generatePath(self, folder, fileName):
        return QGISRedUtils().generatePath(folder, fileName)

    def getLayers(self):
        return QGISRedUtils().getLayers()

    def areOverlapedPoints(self, point1, point2):
        tolerance = 0.1
        if point1.distance(point2) < tolerance:
            return True
        else:
            return False

    def isInPath(self, point1, point2, myPoint):
        width = point2.x() - point1.x()
        height = point2.y() - point1.y()
        widthM = myPoint.x() - point1.x()
        heightM = myPoint.y() - point1.y()
        if abs(width) >= abs(height):
            yEst = widthM * height / width + point1.y()
            if abs(yEst - myPoint.y()) < 1E-9:
                return True
        else:
            xEst = heightM * width / height + point1.x()
            if abs(xEst - myPoint.x()) < 1E-9:
                return True
        return False

    def createRubberBand(self, points):
        myPoints = points
        if isinstance(points[0], QgsPointXY):
            myPoints = []
            for p in points:
                myPoints.append(QgsPoint(p.x(), p.y()))
        self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand.setToGeometry(QgsGeometry.fromPolyline(myPoints), None)
        self.rubberBand.setColor(QColor(55, 198, 5))
        self.rubberBand.setWidth(1)
        self.rubberBand.setLineStyle(Qt.DashLine)
        self.newVertexMarker.setCenter(QgsPointXY(points[0].x(),
                                                  points[0].y()))
        self.newVertexMarker.show()

    def updateRubberBand(self):
        newX = self.clickedPoint.x() + self.newPositionVector.x()
        newY = self.clickedPoint.y() + self.newPositionVector.y()
        self.rubberBand.movePoint(1, QgsPointXY(newX, newY))
        self.newVertexMarker.setCenter(QgsPointXY(newX, newY))

    def moveVertexLink(self, layer, feature, newPosition, vertexIndex):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.moveVertex(newPosition.x(), newPosition.y(),
                                      feature.id(), vertexIndex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    def deleteVertexLink(self, layer, feature, vertexIndex):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.deleteVertex(feature.id(), vertexIndex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    def insertVertexLink(self, layer, feature, newPoint):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            vertex = -1
            if layer.geometryType() == 1:  # Line
                featureGeometry = self.selectedFeature.geometry()
                if featureGeometry.isMultipart():
                    parts = featureGeometry.get()
                    for part in parts:  # only one part
                        for i in range(len(part) - 1):
                            if self.isInPath(
                                    QgsPointXY(part[i].x(), part[i].y()),
                                    QgsPointXY(part[i + 1].x(),
                                               part[i + 1].y()), newPoint):
                                vertex = i + 1
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.insertVertex(newPoint.x(), newPoint.y(),
                                        feature.id(), vertex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    """Events"""

    def canvasPressEvent(self, event):
        if self.objectSnapped is None:
            self.clickedPoint = None
            return

        if event.button() == Qt.RightButton:
            self.mouseClicked = False
            self.clickedPoint = None

        if event.button() == Qt.LeftButton:
            self.clickedPoint = self.objectSnapped.point()
            if self.vertexIndex == -1:
                return
            self.mouseClicked = True
            self.createRubberBand(
                [self.objectSnapped.point(),
                 self.objectSnapped.point()])

    def canvasMoveEvent(self, event):
        mousePoint = self.toMapCoordinates(event.pos())
        # Mouse not clicked
        if not self.mouseClicked:
            self.pipeSnappedOn = False
            matchSnapper = self.snapper.snapToMap(mousePoint)
            if matchSnapper.isValid():
                valid = False
                layer = matchSnapper.layer()
                snapLayerPath = self.getLayerPath(layer)
                for name in self.ownMainLayers:
                    layerPath = self.generatePath(
                        self.ProjectDirectory,
                        self.NetworkName + "_" + name + ".shp")
                    if snapLayerPath == layerPath:
                        valid = True
                if valid:
                    self.objectSnapped = matchSnapper
                    self.selectedLayer = layer

                    vertex = matchSnapper.point()
                    featureId = matchSnapper.featureId()
                    request = QgsFeatureRequest().setFilterFid(featureId)
                    nodes = list(layer.getFeatures(request))
                    self.selectedFeature = QgsFeature(nodes[0])
                    # #Ver aquí si es el nudo inicial y final
                    middleNode = False
                    self.vertexIndex = -1
                    if layer.geometryType() == 1:  # Line
                        featureGeometry = self.selectedFeature.geometry()
                        if featureGeometry.isMultipart():
                            parts = featureGeometry.get()
                            for part in parts:  # only one part
                                if middleNode:
                                    break
                                i = -1
                                for v in part:
                                    i = i + 1
                                    if (
                                            i == 0 or i == len(part) - 1
                                    ) and "ServiceConnections" not in snapLayerPath:
                                        continue

                                    matchedPoint = QgsPointXY(
                                        vertex.x(), vertex.y())
                                    if self.areOverlapedPoints(
                                            QgsGeometry.fromPointXY(
                                                matchedPoint),
                                            QgsGeometry.fromPointXY(
                                                QgsPointXY(v.x(), v.y()))):
                                        middleNode = True
                                        self.vertexIndex = i
                                        if (
                                                i == 0 or i == len(part) - 1
                                        ) and "ServiceConnections" in snapLayerPath:
                                            self.pipeSnappedOn = True
                                        break
                    if middleNode:
                        self.vertexMarker.setCenter(
                            QgsPointXY(vertex.x(), vertex.y()))
                        self.vertexMarker.show()
                    else:
                        self.vertexMarker.hide()
                else:
                    self.objectSnapped = None
                    self.selectedFeature = None
                    self.selectedLayer = None
                    self.vertexMarker.hide()
            else:
                self.objectSnapped = None
                self.selectedFeature = None
                self.selectedLayer = None
                self.vertexMarker.hide()
        # Mouse clicked
        else:
            # Snap pipe layer
            if self.pipeSnappedOn:
                matchSnapper = self.pipeSnapper.snapToMap(mousePoint)
                if matchSnapper.isValid():
                    valid = False
                    layer = matchSnapper.layer()
                    snapLayerPath = self.getLayerPath(layer)
                    for name in self.ownMainLayers:
                        layerPath = self.generatePath(
                            self.ProjectDirectory,
                            self.NetworkName + "_Pipes.shp")
                        if snapLayerPath == layerPath:
                            valid = True
                    if valid:
                        self.pipeSnapped = matchSnapper
                        self.pipeMarker.setCenter(matchSnapper.point())
                        self.pipeMarker.show()
                    else:
                        self.pipeMarker.hide()
                else:
                    self.pipeMarker.hide()
                    self.pipeSnapped = None

            # # Update rubber band
            if self.objectSnapped is not None and self.rubberBand is not None:
                snappedPoint = self.objectSnapped.point()
                self.newPositionVector = QgsVector(
                    mousePoint.x() - snappedPoint.x(),
                    mousePoint.y() - snappedPoint.y())
                self.updateRubberBand()

    def canvasReleaseEvent(self, event):
        if self.mouseClicked:
            if event.button() == 1:
                mousePoint = self.toMapCoordinates(event.pos())
                if (self.pipeSnapped is not None):
                    mousePoint = self.pipeSnapped.point()
                self.mouseClicked = False
                if self.objectSnapped is not None:
                    self.moveVertexLink(self.selectedLayer,
                                        self.selectedFeature, mousePoint,
                                        self.vertexIndex)
        elif event.button() == 2:
            if self.objectSnapped is not None:
                self.deleteVertexLink(self.selectedLayer, self.selectedFeature,
                                      self.vertexIndex)
        elif event.button() == 1:
            if self.objectSnapped is not None:
                self.insertVertexLink(self.selectedLayer, self.selectedFeature,
                                      self.objectSnapped.point())
        self.objectSnapped = None
        self.pipeSnapped = None
        self.selectedFeature = None
        self.selectedLayer = None
        self.vertexIndex = -1
        self.iface.mapCanvas().refresh()
        # Remove vertex marker and rubber band
        self.vertexMarker.hide()
        self.iface.mapCanvas().scene().removeItem(self.rubberBand)
        self.newVertexMarker.hide()
        self.pipeMarker.hide()
コード例 #7
0
class MincutConnec(QgsMapTool):

    canvasClicked = pyqtSignal()

    def __init__(self, iface, controller):
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.controller = controller
        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)

        self.dragging = False

        # Vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

        # Rubber band
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Line)
        self.rubber_band.setColor(color)
        self.rubber_band.setWidth(1)

        # Select rectangle
        self.select_rect = QRect()

        # TODO: Parametrize
        self.connec_group = ["Wjoin", "Tap", "Fountain", "Greentap"]
        #self.snapperManager = SnappingConfigManager(self.iface)
        self.snapper = QgsMapCanvasSnapper(self.canvas)

    def activate(self):
        pass

    def canvasPressEvent(self, event):  #@UnusedVariable
        self.select_rect.setRect(0, 0, 0, 0)
        self.rubber_band.reset()

    def canvasMoveEvent(self, event):
        """ With left click the digitizing is finished """

        if event.buttons() == Qt.LeftButton:
            if not self.dragging:
                self.dragging = True
                self.select_rect.setTopLeft(event.pos())
            self.select_rect.setBottomRight(event.pos())
            self.set_rubber_band()

        else:
            # Hide highlight
            self.vertex_marker.hide()

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)

            # Snapping
            (retval, result) = self.snapper.snapToBackgroundLayers(
                event_point)  # @UnusedVariable

            # That's the snapped point
            if result:
                # Check feature
                for snap_point in result:
                    element_type = snap_point.layer.name()
                    if element_type in self.connec_group:
                        # Get the point
                        point = QgsPoint(snap_point.snappedVertex)
                        # Add marker
                        self.vertex_marker.setCenter(point)
                        self.vertex_marker.show()
                        break

    def canvasReleaseEvent(self, event):
        """ With left click the digitizing is finished """

        if event.button() == Qt.LeftButton:

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)

            # Not dragging, just simple selection
            if not self.dragging:

                # Snap to node
                (retval, result) = self.snapper.snapToBackgroundLayers(
                    event_point)  # @UnusedVariable

                # That's the snapped point
                if result:
                    # Check feature
                    for snapped_point in result:
                        element_type = snapped_point.layer.name()
                        if element_type in self.connec_group:
                            feat_type = 'connec'
                        else:
                            continue

                        point = QgsPoint(
                            snapped_point.snappedVertex)  # @UnusedVariable
                        # layer.removeSelection()
                        # layer.select([result[0].snappedAtGeometry])

                        #snapped_point.layer.removeSelection()
                        snapped_point.layer.select(
                            [snapped_point.snappedAtGeometry])

            else:

                # Set valid values for rectangle's width and height
                if self.select_rect.width() == 1:
                    self.select_rect.setLeft(self.select_rect.left() + 1)

                if self.select_rect.height() == 1:
                    self.select_rect.setBottom(self.select_rect.bottom() + 1)

                self.set_rubber_band()
                self.select_multiple_features(self.selected_rectangle)
                self.dragging = False

            # Refresh map canvas
            self.rubber_band.reset()
            self.refresh_map_canvas()

    def set_rubber_band(self):

        # Coordinates transform
        transform = self.canvas.getCoordinateTransform()

        # Coordinates
        ll = transform.toMapCoordinates(self.select_rect.left(),
                                        self.select_rect.bottom())
        lr = transform.toMapCoordinates(self.select_rect.right(),
                                        self.select_rect.bottom())
        ul = transform.toMapCoordinates(self.select_rect.left(),
                                        self.select_rect.top())
        ur = transform.toMapCoordinates(self.select_rect.right(),
                                        self.select_rect.top())

        # Rubber band
        self.rubber_band.reset()
        self.rubber_band.addPoint(ll, False)
        self.rubber_band.addPoint(lr, False)
        self.rubber_band.addPoint(ur, False)
        self.rubber_band.addPoint(ul, False)
        self.rubber_band.addPoint(ll, True)

        self.selected_rectangle = QgsRectangle(ll, ur)

    def select_multiple_features(self, rectangle):

        if self.connec_group is None:
            return

        if QGis.QGIS_VERSION_INT >= 21600:

            # Selection for all connec group layers
            for layer_name in self.connec_group:
                # Get layer by his name
                layer = self.controller.get_layer_by_layername(layer_name,
                                                               log_info=True)
                if layer:
                    self.group_pointers_connec.append(layer)
                    layer.selectByRect(rectangle)

        else:
            for layer_name in self.connec_group:
                self.iface.setActiveLayer(layer)
                layer.removeSelection()
                layer.select(rectangle, True)
コード例 #8
0
ファイル: add_pipe_tool.py プロジェクト: mcgoldba/XPSS
class AddPipeTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.first_click = False
        self.rubber_band = QgsRubberBand(self.canvas(), False)
        self.rubber_band.setColor(QColor(255, 128, 128))
        self.rubber_band.setWidth(1)
        self.rubber_band.setBrushStyle(Qt.Dense4Pattern)
        self.rubber_band.reset()

        self.snapper = None
        self.snapped_feat_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = None

        self.diameter_dialog = None

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = False

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        last_ix = self.rubber_band.numberOfVertices()

        self.rubber_band.movePoint(last_ix - 1,
                                   (self.snapped_vertex if self.snapped_vertex
                                    is not None else self.mouse_pt))

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        # Mouse not clicked: snapping to closest vertex
        match = self.snapper.snapToMap(self.mouse_pt)

        if match.isValid():
            # Pipe starts from an existing vertex
            self.snapped_feat_id = match.featureId()
            self.snapped_vertex = match.point()
            self.snapped_vertex_nr = match.vertexIndex()

            self.vertex_marker.setCenter(self.snapped_vertex)
            self.vertex_marker.setColor(QColor(255, 0, 0))
            self.vertex_marker.setIconSize(10)
            self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            self.vertex_marker.setPenWidth(3)
            self.vertex_marker.show()
        #
        else:

            # It's a new, isolated pipe
            self.snapped_vertex = None
            self.snapped_feat_id = None
            self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        # if not self.mouse_clicked:
        #     return
        if event.button() == Qt.LeftButton:

            # Update rubber bands
            self.rubber_band.addPoint(
                (self.snapped_vertex
                 if self.snapped_vertex is not None else self.mouse_pt), True)
            if self.first_click:
                self.rubber_band.addPoint(
                    (self.snapped_vertex if self.snapped_vertex is not None
                     else self.mouse_pt), True)

            self.first_click = not self.first_click

        elif event.button() == Qt.RightButton:

            # try:

            pipe_band_geom = self.rubber_band.asGeometry()

            # No rubber band geometry and feature snapped: pop the context menu
            if self.rubber_band.size(
            ) == 0 and self.snapped_feat_id is not None:
                menu = QMenu()
                section_action = menu.addAction('Section...')  # TODO: softcode
                diameter_action = menu.addAction(
                    'Change diameter...')  # TODO: softcode
                action = menu.exec_(self.iface.mapCanvas().mapToGlobal(
                    QPoint(event.pos().x(),
                           event.pos().y())))

                pipe_ft = vector_utils.get_feats_by_id(self.params.pipes_vlay,
                                                       self.snapped_feat_id)[0]
                if action == section_action:
                    if self.params.dem_rlay is None:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'No DEM selected. Cannot edit section.',
                            Qgis.Warning, 5)  # TODO: softcode
                    else:
                        # Check whether the pipe is all inside the DEM
                        pipe_pts = pipe_ft.geometry().asPolyline()

                        for pt in pipe_pts:
                            if not self.params.dem_rlay.extent().contains(pt):
                                self.iface.messageBar().pushMessage(
                                    Parameters.plug_in_name,
                                    'Some pipe vertices fall outside of the DEM. Cannot edit section.',
                                    Qgis.Warning, 5)  # TODO: softcode
                                return

                        # Check whether the start/end nodes have an elevation value
                        (start_node_ft,
                         end_node_ft) = NetworkUtils.find_start_end_nodes(
                             self.params, pipe_ft.geometry())
                        start_node_elev = start_node_ft.attribute(
                            Junction.field_name_elev)
                        end_node_elev = end_node_ft.attribute(
                            Junction.field_name_elev)
                        if start_node_elev == NULL or end_node_elev == NULL:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Missing elevation value in start or end node attributes. Cannot edit section.',
                                Qgis.Warning, 5)  # TODO: softcode
                            return

                        pipe_dialog = PipeSectionDialog(
                            self.iface.mainWindow(), self.iface, self.params,
                            pipe_ft)
                        pipe_dialog.exec_()

                elif action == diameter_action:

                    old_diam = pipe_ft.attribute(Pipe.field_name_diameter)
                    self.diameter_dialog = DiameterDialog(
                        self.iface.mainWindow(), self.params, old_diam)
                    self.diameter_dialog.exec_()  # Exec creates modal dialog
                    new_diameter = self.diameter_dialog.get_diameter()
                    if new_diameter is None:
                        return

                    # Update pipe diameter
                    vector_utils.update_attribute(self.params.pipes_vlay,
                                                  pipe_ft,
                                                  Pipe.field_name_diameter,
                                                  new_diameter)

                    # Check if a valve is present
                    adj_valves = NetworkUtils.find_links_adjacent_to_link(
                        self.params, self.params.pipes_vlay, pipe_ft, True,
                        True, False)

                    if adj_valves['valves']:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'Valves detected on the pipe: need to update their diameters too.',
                            Qgis.Warning, 5)  # TODO: softcode

                return

            # There's a rubber band: create new pipe
            if pipe_band_geom is not None:

                #XPSS ADDED - transform rubber band CRS
                canvas_crs = self.canvas().mapSettings().destinationCrs()
                #pipes_vlay = Parameters().pipes_vlay()
                #print(pipes_vlay)
                qepanet_crs = self.params.pipes_vlay.sourceCrs()
                crs_transform = QgsCoordinateTransform(canvas_crs, qepanet_crs,
                                                       QgsProject.instance())
                pipe_band_geom.transform(crs_transform)

                # Finalize line
                rubberband_pts = pipe_band_geom.asPolyline()[:-1]

                if len(rubberband_pts) == 0:
                    self.iface.mapCanvas().refresh()
                    return

                rubberband_pts = self.remove_duplicated_point(rubberband_pts)

                if len(rubberband_pts) < 2:
                    self.rubber_band.reset()
                    return

                # Check whether the pipe points are located on existing nodes
                junct_nrs = [0]
                for p in range(1, len(rubberband_pts) - 1):
                    overlapping_nodes = NetworkUtils.find_overlapping_nodes(
                        self.params, rubberband_pts[p])
                    if overlapping_nodes['junctions'] or overlapping_nodes[
                            'reservoirs'] or overlapping_nodes['tanks']:
                        junct_nrs.append(p)

                junct_nrs.append(len(rubberband_pts) - 1)

                new_pipes_nr = len(junct_nrs) - 1

                new_pipes_fts = []
                new_pipes_eids = []

                for np in range(new_pipes_nr):

                    pipe_eid = NetworkUtils.find_next_id(
                        self.params.pipes_vlay, Pipe.prefix)  # TODO: softcode
                    #demand = float(self.data_dock.txt_pipe_demand.text())
                    length_units = 'm'  #TODO soft code
                    diameter = float(self.data_dock.cbo_pipe_dia.\
                                     currentText())
                    diameter_units = self.data_dock.cbo_pipe_dia_units.\
                        currentText()
                    #loss = float(self.data_dock.txt_pipe_loss.text())
                    #status = self.data_dock.cbo_pipe_status.currentText()
                    material = self.data_dock.cbo_pipe_mtl.currentText()
                    roughness = float(self.data_dock.txt_roughness.text())
                    #pipe_desc = self.data_dock.txt_pipe_desc.text()
                    #pipe_tag = self.data_dock.cbo_pipe_tag.currentText()
                    num_edu = 1
                    zone_id = 0
                    velocity = 0
                    velocity_units = 'm/s'
                    frictionloss = 0
                    frictionloss_units = 'm'

                    pipe_ft = LinkHandler.create_new_pipe(
                        self.params, pipe_eid, length_units, diameter,
                        diameter_units, 0, roughness, " ", material,
                        rubberband_pts[junct_nrs[np]:junct_nrs[np + 1] + 1],
                        True, " ", " ", num_edu, zone_id, velocity,
                        velocity_units, frictionloss, frictionloss_units)
                    self.rubber_band.reset()

                    new_pipes_fts.append(pipe_ft)
                    new_pipes_eids.append(pipe_eid)

                # emitter_coeff_s = self.data_dock.txt_junction_emit_coeff.text()
                #
                # if emitter_coeff_s is None or emitter_coeff_s == '':
                #     emitter_coeff = float(0)
                # else:
                #     emitter_coeff = float(self.data_dock.txt_junction_emit_coeff.text())

                # # Description
                # junction_desc = self.data_dock.txt_junction_desc.text()
                #
                # # Tag
                # junction_tag = self.data_dock.cbo_junction_tag.currentText()

                zone_end = 0
                pressure = 0
                pressure_units = self.data_dock.cbo_rpt_units_pressure.currentText(
                )

                # Create start and end node, if they don't exist
                (start_junction,
                 end_junction) = NetworkUtils.find_start_end_nodes(
                     self.params, new_pipes_fts[0].geometry())
                new_start_junction = None
                if not start_junction:
                    new_start_junction = rubberband_pts[0]
                    junction_eid = NetworkUtils.find_next_id(
                        self.params.junctions_vlay, Junction.prefix)
                    elev = raster_utils.read_layer_val_from_coord(
                        self.params.dem_rlay, new_start_junction, 1)
                    if elev is None:
                        elev = 0
                        # If elev is none, and the DEM is selected, it's better to inform the user
                        if self.params.dem_rlay is not None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Elevation value not available: element elevation set to 0.',
                                Qgis.Warning, 5)  # TODO: softcode
                    deltaz = float(0)
                    #j_demand = float(self.data_dock.txt_junction_demand.text())

                    # pattern = self.data_dock.cbo_junction_pattern.itemData(
                    #     self.data_dock.cbo_junction_pattern.currentIndex())
                    # if pattern is not None:
                    #     pattern_id = pattern.id
                    # else:
                    #     pattern_id = None
                    NodeHandler.create_new_junction(self.params,
                                                    new_start_junction,
                                                    junction_eid, elev, 0,
                                                    deltaz, None, 0, " ", " ",
                                                    zone_end, pressure,
                                                    pressure_units)

                (start_junction,
                 end_junction) = NetworkUtils.find_start_end_nodes(
                     self.params,
                     new_pipes_fts[len(new_pipes_fts) - 1].geometry())
                new_end_junction = None
                if not end_junction:
                    new_end_junction = rubberband_pts[len(rubberband_pts) - 1]
                    junction_eid = NetworkUtils.find_next_id(
                        self.params.junctions_vlay, Junction.prefix)
                    elev = raster_utils.read_layer_val_from_coord(
                        self.params.dem_rlay, new_end_junction, 1)
                    if elev is None:
                        elev = 0
                        # If elev is none, and the DEM is selected, it's better to inform the user
                        if self.params.dem_rlay is not None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Elevation value not available: element elevation set to 0.',
                                Qgis.Warning, 5)  # TODO: softcode
                    deltaz = float(0)

                    # pattern = self.data_dock.cbo_junction_pattern.itemData(
                    #     self.data_dock.cbo_junction_pattern.currentIndex())
                    # if pattern is not None:
                    #     pattern_id = pattern.id
                    # else:
                    #     pattern_id = None
                    NodeHandler.create_new_junction(self.params,
                                                    new_end_junction,
                                                    junction_eid, elev, 0,
                                                    deltaz, None, 0, " ", " ",
                                                    zone_end, pressure,
                                                    pressure_units)

                # If end or start node intersects a pipe, split it
                if new_start_junction:
                    for pipe_ft in self.params.pipes_vlay.getFeatures():
                        if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[0] and\
                                        pipe_ft.geometry().distance(QgsGeometry.fromPointXY(new_start_junction)) < self.params.tolerance:
                            LinkHandler.split_pipe(self.params, pipe_ft,
                                                   new_start_junction)

                if new_end_junction:
                    for pipe_ft in self.params.pipes_vlay.getFeatures():
                        if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[-1] and\
                                        pipe_ft.geometry().distance(QgsGeometry.fromPointXY(new_end_junction)) < self.params.tolerance:
                            LinkHandler.split_pipe(self.params, pipe_ft,
                                                   new_end_junction)

            self.iface.mapCanvas().refresh()

        # except Exception as e:
        #     self.rubber_band.reset()
        #     self.iface.messageBar().pushWarning('Cannot add new pipe to ' + self.params.pipes_vlay.name() + ' layer', repr(e))
        #     traceback.print_exc(file=sys.stdout)

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.rubber_band.reset()

    def activate(self):

        self.update_snapper()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()

    def deactivate(self):

        # QgsProject.instance().setSnapSettingsForLayer(self.params.junctions_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToVertex,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)
        #
        # QgsProject.instance().setSnapSettingsForLayer(self.params.reservoirs_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToVertex,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)
        # QgsProject.instance().setSnapSettingsForLayer(self.params.tanks_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToVertex,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)
        # QgsProject.instance().setSnapSettingsForLayer(self.params.pipes_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToSegment,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)

        # self.rubber_band.reset()
        self.data_dock.btn_add_pipe.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def remove_duplicated_point(self, pts):

        # This is needed because the rubber band sometimes returns duplicated points
        purged_pts = [pts[0]]
        for p in enumerate(list(range(len(pts) - 1)), 1):
            if pts[p[0]] == pts[p[0] - 1]:
                continue
            else:
                purged_pts.append(pts[p[0]])

        return purged_pts

    def update_snapper(self):
        layers = {
            self.params.junctions_vlay: QgsSnappingConfig.Vertex,
            self.params.reservoirs_vlay: QgsSnappingConfig.Vertex,
            self.params.tanks_vlay: QgsSnappingConfig.Vertex,
            self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment
        }

        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)
        self.snapper.toggleEnabled()

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
コード例 #9
0
class GwParentMapTool(QgsMapTool):
	def __init__(self, icon_path, text, toolbar, action_group, iface, settings, controller, plugin_dir):
		
		self.iface = iface
		self.settings = settings
		self.controller = controller
		self.plugin_dir = plugin_dir
		
		self.show_help = bool(int(self.settings.value('status/show_help', 1)))
		self.layer_arc = None
		self.layer_connec = None
		self.layer_gully = None
		self.layer_node = None
		self.snapper_manager = SnappingConfigManager(self.iface)
		self.snapper_manager.controller = controller
		
		self.canvas = iface.mapCanvas()
		super().__init__(self.canvas)
		
		
		icon = None
		if os.path.exists(icon_path):
			icon = QIcon(icon_path)
		
		self.action = None
		if icon is None:
			self.action = QAction(text, action_group)
		else:
			self.action = QAction(icon, text, action_group)
			
		self.action.setObjectName(text)
		self.action.setCheckable(True)
		self.action.triggered.connect(self.clicked_event)
		
		# Change map tool cursor
		self.cursor = QCursor()
		self.cursor.setShape(Qt.CrossCursor)
		
		# Get default cursor
		# noinspection PyCallingNonCallable
		self.std_cursor = self.parent().cursor()
		
		# Set default vertex marker
		color = QColor(255, 100, 255)
		self.vertex_marker = QgsVertexMarker(self.canvas)
		self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
		self.vertex_marker.setColor(color)
		self.vertex_marker.setIconSize(15)
		self.vertex_marker.setPenWidth(3)
		
		# Set default rubber band
		color_selection = QColor(254, 178, 76, 63)
		self.rubber_band = QgsRubberBand(self.canvas, 2)
		self.rubber_band.setColor(color)
		self.rubber_band.setFillColor(color_selection)
		self.rubber_band.setWidth(1)
		self.reset()
		
		self.force_active_layer = True
		
		toolbar.addAction(self.action)
		self.setAction(self.action)
	
	
	def clicked_event(self):
		self.controller.prev_maptool = self.iface.mapCanvas().mapTool()
		if not (self == self.iface.mapCanvas().mapTool()):
			self.iface.mapCanvas().setMapTool(self)
		else:
			self.iface.mapCanvas().unsetMapTool(self)
			
	
	def deactivate(self):
	
		# Uncheck button
		self.action.setChecked(False)
		
		# Restore previous snapping
		self.snapper_manager.recover_snapping_options()
		
		# Enable snapping
		self.snapper_manager.enable_snapping(True)
		
		# Recover cursor
		self.canvas.setCursor(self.std_cursor)
		
		# Remove highlight
		self.vertex_marker.hide()
	
	
	def canvasMoveEvent(self, event):
	
		# Make sure active layer is always 'v_edit_node'
		cur_layer = self.iface.activeLayer()
		if cur_layer != self.layer_node and self.force_active_layer:
			self.iface.setActiveLayer(self.layer_node)
		
		# Hide highlight and get coordinates
		self.vertex_marker.hide()
		event_point = self.snapper_manager.get_event_point(event)
		
		# Snapping
		result = self.snapper_manager.snap_to_current_layer(event_point)
		if self.snapper_manager.result_is_valid():
			self.snapper_manager.add_marker(result, self.vertex_marker)
	
	
	def recover_previus_maptool(self):
		if self.controller.prev_maptool:
			self.iface.mapCanvas().setMapTool(self.controller.prev_maptool)
			self.controller.prev_maptool = None
	
	
	def remove_vertex(self):
		""" Remove vertex_marker from canvas"""
		vertex_items = [i for i in self.iface.mapCanvas().scene().items() if issubclass(type(i), QgsVertexMarker)]
		
		for ver in vertex_items:
			if ver in self.iface.mapCanvas().scene().items():
				if self.vertex_marker == ver:
					self.iface.mapCanvas().scene().removeItem(ver)
	
	
	def set_action_pan(self):
		""" Set action 'Pan' """
		try:
			self.iface.actionPan().trigger()
		except Exception:
			pass
	
	
	def reset_rubber_band(self, geom_type="polygon"):
		
		try:
			if geom_type == "polygon":
				geom_type = QgsWkbTypes.PolygonGeometry
			elif geom_type == "line":
				geom_type = QgsWkbTypes.LineString
			self.rubber_band.reset(geom_type)
		except:
			pass
	
	
	def reset(self):
	
		self.reset_rubber_band()
		self.snapped_feat = None
	
	
	def cancel_map_tool(self):
		""" Executed if user press right button or escape key """
		
		# Reset rubber band
		self.reset()
		
		# Deactivate map tool
		self.deactivate()
		self.set_action_pan()
	
	
	def remove_markers(self):
		""" Remove previous markers """
		
		vertex_items = [i for i in list(self.canvas.scene().items()) if issubclass(type(i), QgsVertexMarker)]
		for ver in vertex_items:
			if ver in list(self.canvas.scene().items()):
				self.canvas.scene().removeItem(ver)
	
	
	def refresh_map_canvas(self):
		""" Refresh all layers present in map canvas """
		
		self.canvas.refreshAllLayers()
		for layer_refresh in self.canvas.layers():
			layer_refresh.triggerRepaint()
コード例 #10
0
class Result(object):
    def __init__(self,iface,description=None,x=None,y=None,zoom=None,epsg=None):
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.description = unicode(description)
        self.x = float(x)
        self.y = float(y)
        self.zoom = int(zoom)
        self.epsg = int(epsg)
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.setIconSize(20)
        self.marker.setPenWidth(3)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.marker.setColor(QColor('green'))
        self._active = False
        self._visible = False
        self._xtrans = None
        self._ytrans = None

    @property
    def active(self):
        return self._active

    @active.setter
    def active(self,value):
        if value == True:
            self._active = True
            self.marker.setColor(QColor('red'))
            self.marker.updateCanvas()
        else:
            self._active = False
            self.marker.setColor(QColor('green'))
            self.marker.updateCanvas()

    @property
    def visible(self):
        return self._visible

    @visible.setter
    def visible(self,value):
        if value == True:
            if self.x is not None and self.y is not None:
                self._visible = True
                dest_crs = self.canvas.mapRenderer().destinationCrs()
                src_crs = QgsCoordinateReferenceSystem()
                src_crs.createFromEpsg(self.epsg)
                transform = QgsCoordinateTransform(src_crs, dest_crs)
                new_point = transform.transform(self.x, self.y)
                self._xtrans = new_point.x()
                self._ytrans = new_point.y()
                self.marker.setCenter(new_point)
                self.marker.show()
            else:
                self._visible = False
                raise ValueError("Can't show marker without x and y coordinates.")
        else:
            self._visible = False
            self.marker.hide()

    def unload(self):
        self.canvas.scene().removeItem(self.marker)
        self.marker = None

    def zoomTo(self):
        if self._xtrans is not None and self._ytrans is not None:
            r = QgsRectangle(self._xtrans,self._ytrans,self._xtrans,self._ytrans)
            self.canvas.setExtent(r)
            self.canvas.zoomScale(self.zoom)
            self.canvas.refresh()
        else:
            raise ValueError("Point does not have x and y coordinates")
コード例 #11
0
ファイル: line.py プロジェクト: Giswater/giswater_qgis_plugin
class LineMapTool(QgsMapTool):

    def __init__(self, iface, settings, action, index_action):  
        ''' Class constructor '''
        
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.index_action = index_action
        self.elem_type_type = self.settings.value('insert_values/'+str(index_action)+'_elem_type_type')           
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Set rubber band features
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)
        mFillColor = QColor(255, 0, 0);
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(2)
        self.reset()        
        
        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(0, 255, 0))
        self.vertexMarker.setIconSize(9)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)

        # Snapper
        self.snapper = QgsMapCanvasSnapper(self.canvas)

        # Control button state
        self.mCtrl = False
        self.started = False
        
        # Tracing options
        self.firstTimeOnSegment = True
        self.lastPointMustStay = False
        self.lastPoint = None
        
        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)
        self.parent().setCursor(self.cursor)                                             
 
 
    def keyPressEvent(self,  event):
        ''' We need to know, if ctrl-key is pressed '''
        if event.key() == Qt.Key_Control:
            self.mCtrl = True


    def keyReleaseEvent(self,  event):
        ''' Ctrl-key is released '''
        if event.key() == Qt.Key_Control:
            self.mCtrl = False
        
        # Remove the last added point when the delete key is pressed
        if event.key() == Qt.Key_Backspace:
            self.rubberBand.removeLastPoint()
       

    def reset(self):
        self.start_point = self.end_point = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Line)
                       
    
    
    ''' QgsMapTools inherited event functions '''
        
    def canvasPressEvent(self, event):
        ''' On left click, we add a point '''
        
        if event.button()  ==  1:
            # layer = self.canvas.currentLayer()
            layer = self.iface.activeLayer() 
    
            # Declare, that are we going to work
            self.started = True
            
            if layer <> None:
                x = event.pos().x()
                y = event.pos().y()
                selPoint = QPoint(x,y)
    
                # Check something snapped
                (retval,result) = self.snapper.snapToBackgroundLayers(selPoint) #@UnusedVariable
              
                # The point we want to have, is either from snapping result
                if result <> []:
                    point = result[0].snappedVertex
    
                    # If we snapped something, it's either a vertex
                    if result[0].snappedVertexNr <> -1:
                        self.firstTimeOnSegment = True
                
                    # Or a point on a segment, so we have to declare, that a point on segment is found
                    else:
                        self.firstTimeOnSegment = False
    
                # Or its some point from out in the wild
                else:
                    point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), x, y)
                    self.firstTimeOnSegment = True
    
                # Bring the rubberband to the cursor i.e. the clicked point
                self.rubberBand.movePoint(point)
    
                # Set a new point to go on with
                self.appendPoint(point)
              
                # Try to remember that this point was on purpose i.e. clicked by the user
                self.lastPointMustStay = True
                self.firstTimeOnSegment = True    
                       
    
    def canvasMoveEvent(self, event):
        
        # Hide highlight
        self.vertexMarker.hide()
            
        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        eventPoint = QPoint(x,y)

        # Snapping        
        (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable

        # That's the snapped point
        if result <> []:
            point = QgsPoint(result[0].snappedVertex)

            # Add marker    
            self.vertexMarker.setCenter(point)
            self.vertexMarker.show()
            
        # Check tracing 
        if self.started:
                        
            # Only if the ctrl key is pressed
            if self.mCtrl == True:
                 
                # So if we have found a snapping
                if result <> []:

                    # If it is a vertex, not a point on a segment
                    if result[0].snappedVertexNr <> -1: 
                        self.rubberBand.movePoint(point) 
                        self.appendPoint(point)
                        self.lastPointMustStay = True
                    
                        # The next point found, may  be on a segment
                        self.firstTimeOnSegment = True
                                          
                    # We are on a segment
                    else:
                        self.rubberBand.movePoint(point)
                    
                        # If we are on a new segment, we add the point in any case
                        if self.firstTimeOnSegment:
                            self.appendPoint(point)
                            self.lastPointMustStay = True
                            self.firstTimeOnSegment = False
                    
                        # if we are not on a new segment, we have to test, if this point is really needed
                        else:
                            # but only if we have already enough points
                            if self.rubberBand.numberOfVertices() >=3:
                                num_vertexs = self.rubberBand.numberOfVertices()    
                                lastRbP = self.rubberBand.getPoint(0, num_vertexs-2)
                                nextToLastRbP = self.rubberBand.getPoint(0, num_vertexs-3)                          
                                if not self.pointOnLine(lastRbP, nextToLastRbP, QgsPoint(point)):
                                    self.appendPoint(point)
                                    self.lastPointMustStay = False
                                else:
                                    if not self.lastPointMustStay:
                                        self.rubberBand.removeLastPoint()
                                        self.rubberBand.movePoint(point)
                            else:
                                self.appendPoint(point)
                                self.lastPointMustStay = False
                                self.firstTimeOnSegment = False
          
                else:
                    #if nothing specials happens, just update the rubberband to the cursor position
                    point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform (), x, y)
                    self.rubberBand.movePoint(point)
          
            else:
                ''' In "not-tracing" state, just update the rubberband to the cursor position
                 but we have still to snap to act like the "normal" digitize tool '''
                if result <> []:
                    point = QgsPoint(result[0].snappedVertex)
                
                    # Add marker    
                    self.vertexMarker.setCenter(point)
                    self.vertexMarker.show()

                else:
                    point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(),  x, y)
                
                self.rubberBand.movePoint(point)            
        
        
    def canvasReleaseEvent(self, event):
        ''' With right click the digitizing is finished '''
        
        if event.button() == 2:
      
            # layer = self.canvas.currentLayer()
            layer = self.iface.activeLayer()
            
            x = event.pos().x()
            y = event.pos().y()
            
            if layer <> None and self.started == True: 
                selPoint = QPoint(x,y)
                (retval,result) = self.snapper.snapToBackgroundLayers(selPoint) #@UnusedVariable
        
            if result <> []:
                point = result[0].snappedVertex #@UnusedVariable
            else:
                point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), x, y)  #@UnusedVariable
        
            self.sendGeometry()
 
        
    def appendPoint(self, point):
        ''' Don't add the point if it is identical to the last point we added '''
        
        if not (self.lastPoint == point) :      
            self.rubberBand.addPoint(point)
            self.lastPoint = QgsPoint(point)
        else:
            pass
          
    
    def sendGeometry(self):
        
        #layer = self.canvas.currentLayer()
        layer = self.iface.activeLayer()        
        
        coords = []
        self.rubberBand.removeLastPoint()
        
        if QGis.QGIS_VERSION_INT >= 10700:
            [coords.append(self.rubberBand.getPoint(0, i)) for i in range(self.rubberBand.numberOfVertices())]
        else:
            [coords.append(self.rubberBand.getPoint(0,i)) for i in range(1,self.rubberBand.numberOfVertices())]
        
        # On the Fly reprojection, not necessary any more, mapToLayerCoordinates is clever enough on its own
        #layerEPSG = layer.srs().epsg()
        #projectEPSG = self.canvas.mapRenderer().destinationSrs().epsg()
        #if layerEPSG != projectEPSG:
        coords_tmp = coords[:]
        coords = []
        for point in coords_tmp:
            transformedPoint = self.canvas.mapRenderer().mapToLayerCoordinates( layer, point );
            coords.append(transformedPoint)

        # Filter duplicated points
        coords_tmp = coords[:]
        coords = []
        lastPt = None
        for pt in coords_tmp:
            if (lastPt <> pt) :
                coords.append(pt)
                lastPt = pt
                 
        # Add geometry to feature.
        g = QgsGeometry().fromPolyline(coords)

        self.rubberBand.reset(QGis.Line)
        self.started = False
        
        # Write the feature
        self.createFeature(g)
        
        
    def createFeature(self, geom):

        # layer = self.canvas.currentLayer()
        layer = self.iface.activeLayer()        
        provider = layer.dataProvider()
        f = QgsFeature()
    	
        if (geom.isGeosValid()):
            f.setGeometry(geom)
        else:
            reply = QMessageBox.question(self.iface.mainWindow(), 'Feature not valid',
                "The geometry of the feature you just added isn't valid. Do you want to use it anyway?",
            QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.Yes:
                f.setGeometry(geom)
            else:
                return False
				
      
        # Add attribute fields to feature.
        fields = layer.pendingFields()
        
        try: #API-Break 1.8 vs. 2.0 handling
            attr = f.initAttributes(len(fields))    #@UnusedVariable
            for i in range(len(fields)):
                f.setAttribute(i, provider.defaultValue(i))
              
        except AttributeError: #<=1.8
            # Add attributefields to feature.
            for i in fields:
                f.addAttribute(i, provider.defaultValue(i))
        
        idx = layer.fieldNameIndex('epa_type')
        f[idx] = self.elem_type_type
        
        # Upload changes
        layer.startEditing()
        layer.addFeature(f)
        
        # Control PostgreSQL exceptions
        boolOk = layer.commitChanges()

        # Update canvas        
        self.canvas.refresh()
 
        # Capture edit exception
        if boolOk:
                        
            # Spatial query to retrieve last added line, start searchingcandidates
            cands = layer.getFeatures(QgsFeatureRequest().setFilterRect(f.geometry().boundingBox()))

            # Iterate on candidates
            for line_feature in cands:
                if line_feature.geometry().equals(f.geometry()):

                    # Highlight
                    layer.setSelectedFeatures([line_feature.id()])

                    # Open form
                    self.iface.openFeatureForm(layer, line_feature)
                    break
        
        else:
            
            # Delete
            layer.rollBack()
            
            # User error
            msg = "Error adding PIPE: Typically this occurs if\n the first point is not located in a existing\n node or feature is out of the defined sectors."
            QMessageBox.information(None, "PostgreSQL error:", msg)

                
    def activate(self):
        self.canvas.setCursor(self.cursor)
  
  
    def deactivate(self):
        try:
            self.rubberBand.reset(QGis.Line)
        except AttributeError:
            pass
コード例 #12
0
class ExtractRasterValue(ParentMapTool):
    """ Button 18. User select nodes and assign raster elevation or value """

    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        # Call ParentMapTool constructor
        super(ExtractRasterValue, self).__init__(iface, settings, action, index_action)

        self.dragging = False

        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(255, 25, 25))
        self.vertexMarker.setIconSize(11)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)

        # Rubber band
        self.rubberBand = QgsRubberBand(self.canvas, True)
        mFillColor = QColor(100, 0, 0)
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(3)
        mBorderColor = QColor(254, 58, 29)
        self.rubberBand.setBorderColor(mBorderColor)

        # Select rectangle
        self.selectRect = QRect()

        # Init
        self.vectorLayer = None
        self.rasterLayer = None

    def reset(self):
        """ Clear selected features """

        layer = self.vectorLayer
        if layer is not None:
            layer.removeSelection()

        # Graphic elements
        self.rubberBand.reset()

    def set_config_action(self, action_99):
        """ Get the config form action"""
        self.configAction = action_99

    """ QgsMapTools inherited event functions """

    def canvasMoveEvent(self, event):
        """ With left click the digitizing is finished """

        if self.vectorLayer is None:
            return

        if event.buttons() == Qt.LeftButton:

            if not self.dragging:
                self.dragging = True
                self.selectRect.setTopLeft(event.pos())

            self.selectRect.setBottomRight(event.pos())
            self.set_rubber_band()

        else:

            # Hide highlight
            self.vertexMarker.hide()

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)

            # Snapping
            (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

            # That's the snapped point
            if result <> []:

                # Check Arc or Node
                for snapPoint in result:

                    if snapPoint.layer == self.vectorLayer:

                        # Get the point
                        point = QgsPoint(result[0].snappedVertex)

                        # Add marker
                        self.vertexMarker.setCenter(point)
                        self.vertexMarker.show()

                        break

    def canvasPressEvent(self, event):

        self.selectRect.setRect(0, 0, 0, 0)
        self.rubberBand.reset()

    def canvasReleaseEvent(self, event):
        """ With left click the digitizing is finished """

        if event.button() == Qt.LeftButton:

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)

            # Node layer
            layer = self.vectorLayer

            # Not dragging, just simple selection
            if not self.dragging:

                # Snap to node
                (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

                # That's the snapped point
                if result <> [] and (result[0].layer.name() == self.vectorLayer.name()):

                    point = QgsPoint(result[0].snappedVertex)  # @UnusedVariable
                    layer.removeSelection()
                    layer.select([result[0].snappedAtGeometry])

                    # Interpolate values
                    self.raster_interpolate()

                    # Hide highlight
                    self.vertexMarker.hide()

            else:

                # Set valid values for rectangle's width and height
                if self.selectRect.width() == 1:
                    self.selectRect.setLeft(self.selectRect.left() + 1)

                if self.selectRect.height() == 1:
                    self.selectRect.setBottom(self.selectRect.bottom() + 1)

                self.set_rubber_band()
                selectGeom = self.rubberBand.asGeometry()  # @UnusedVariable
                self.select_multiple_features(self.selectRectMapCoord)
                self.dragging = False

                # Interpolate values
                self.raster_interpolate()

        elif event.button() == Qt.RightButton:

            # Interpolate values
            self.raster_interpolate()

    def activate(self):

        # Check button
        self.action().setChecked(True)

        # Rubber band
        self.rubberBand.reset()

        # Store user snapping configuration
        self.snapperManager.storeSnappingOptions()

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Get layers
        res = self.find_raster_layers()
        #        if res == 0:
        #            self.controller.show_warning("Raster configuration tool not properly configured.")
        #            return

        # Change cursor
        self.canvas.setCursor(self.cursor)

        # Show help message when action is activated
        if self.show_help:
            message = (
                "Right click to use current selection, select connec points by clicking or dragging (selection box)"
            )
            self.controller.show_info(message, context_name="ui_message")

        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_arc)
        except:
            self.canvas.setCurrentLayer(self.layer_arc)

    def deactivate(self):

        # Check button
        self.action().setChecked(False)

        # Rubber band
        self.rubberBand.reset()

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

        # Recover cursor
        self.canvas.setCursor(self.stdCursor)

    def nearestNeighbor(self, thePoint):

        ident = self.dataProv.identify(thePoint, QgsRaster.IdentifyFormatValue)
        value = None
        if ident is not None:  # and ident.has_key(choosenBand+1):
            try:
                value = float(ident.results()[int(self.band)])
            except TypeError:
                value = None
        if value == self.noDataValue:
            return None
        return value

    def writeInterpolation(self, f, fieldIdx):

        thePoint = f.geometry().asPoint()
        value = self.nearestNeighbor(thePoint)
        self.vectorLayer.changeAttributeValue(f.id(), fieldIdx, value)

    def raster_interpolate(self):
        """ Interpolate features value from raster """

        # Interpolate values
        if self.vectorLayer is None and self.rasterLayer is None:
            return

        # Get data provider
        layer = self.vectorLayer
        self.dataProv = self.rasterLayer.dataProvider()
        if self.dataProv.srcNoDataValue(int(self.band)):
            self.noDataValue = self.dataProv.srcNoDataValue(int(self.band))
        else:
            self.noDataValue = None

        self.continueProcess = True

        self.fieldIdx = ""
        self.fieldIdx = layer.fieldNameIndex(self.fieldName)

        if self.band == 0:
            self.controller.show_warning("You must choose a band for the raster layer.")
            return
        if self.fieldName == "":
            self.controller.show_warning("You must choose a field to write values.")
            return
        if self.fieldIdx < 0:
            self.controller.show_warning("Selected field does not exist in feature layer.")
            return

        k = 0
        c = 0
        f = QgsFeature()

        # Check features selected
        if layer.selectedFeatureCount() == 0:
            message = "You have to select at least one feature!"
            self.controller.show_warning(message, context_name="ui_message")

            return

        # Check editable
        if not layer.isEditable():
            layer.startEditing()

        # Get selected id's
        ids = self.vectorLayer.selectedFeaturesIds()

        for fid in ids:

            k += 1
            layer.getFeatures(QgsFeatureRequest(fid)).nextFeature(f)
            c += 1
            self.writeInterpolation(f, self.fieldIdx)
            QCoreApplication.processEvents()

        self.controller.show_info(
            "%u values have been updated in layer %s.%s over %u points using %s raster"
            % (c, self.vectorLayer.name(), self.fieldName, k, self.table_raster)
        )

        # Check editable
        if layer.isEditable():
            layer.commitChanges()

        # Refresh map canvas
        self.rubberBand.reset()
        self.iface.mapCanvas().refresh()

    def set_rubber_band(self):

        # Coordinates transform
        transform = self.canvas.getCoordinateTransform()

        # Coordinates
        ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom())
        lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom())
        ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top())
        ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top())

        # Rubber band
        self.rubberBand.reset()
        self.rubberBand.addPoint(ll, False)
        self.rubberBand.addPoint(lr, False)
        self.rubberBand.addPoint(ur, False)
        self.rubberBand.addPoint(ul, False)
        self.rubberBand.addPoint(ll, True)

        self.selectRectMapCoord = QgsRectangle(ll, ur)

    def select_multiple_features(self, selectGeometry):

        # Default choice
        behaviour = QgsVectorLayer.SetSelection

        # Modifiers
        modifiers = QApplication.keyboardModifiers()

        if modifiers == Qt.ControlModifier:
            behaviour = QgsVectorLayer.AddToSelection
        elif modifiers == Qt.ShiftModifier:
            behaviour = QgsVectorLayer.RemoveFromSelection

        if self.vectorLayer is None:
            return

        # Change cursor
        QApplication.setOverrideCursor(Qt.WaitCursor)

        # Selection
        self.vectorLayer.selectByRect(selectGeometry, behaviour)

        # Old cursor
        QApplication.restoreOverrideCursor()

    def find_raster_layers(self):

        # Query database (form data)
        sql = "SELECT *"
        sql += " FROM " + self.schema_name + ".config_extract_raster_value"

        rows = self.controller.get_rows(sql)

        if not rows:
            self.controller.show_warning("Any data found in table config_extract_raster_value")
            self.configAction.activate(QAction.Trigger)
            return 0

        # Layers
        row = rows[0]
        self.table_raster = row[1]
        self.band = row[2]
        self.table_vector = row[3]
        self.fieldName = row[4]

        # Check if we have any layer loaded
        layers = self.iface.legendInterface().layers()
        if len(layers) == 0:
            return

        # Init layers
        self.rasterLayer = None
        self.vectorLayer = None

        # Iterate over all layers to get the ones specified in 'db' config section
        for cur_layer in layers:

            if cur_layer.name() == self.table_raster:
                self.rasterLayer = cur_layer

            (uri_schema, uri_table) = self.controller.get_layer_source(cur_layer)  # @UnusedVariable
            if uri_table is not None:
                if self.table_vector in uri_table:
                    self.vectorLayer = cur_layer

        # Check config
        if self.vectorLayer is None or self.rasterLayer is None:
            self.configAction.activate(QAction.Trigger)

        # Set snapping
        if self.vectorLayer <> None:
            self.snapperManager.snapToLayer(self.vectorLayer)
        else:
            self.controller.show_warning("Check vector_layer in config form, layer does not exist or is not defined.")
            return 0

        if self.rasterLayer == None:
            self.controller.show_warning("Check raster_layer in config form, layer does not exist or is not defined.")
            return 0

        return 1
コード例 #13
0
class ApisMapToolEmitPolygonAndPoint(QgsMapTool, ApisMapToolMixin):

    mappingFinished = pyqtSignal(QgsGeometry, QgsGeometry, QgsCoordinateReferenceSystem)

    def __init__(self, canvas):
        QgsMapTool.__init__(self, canvas)

        self.canvas = canvas
        self.rubberBand = None
        self.tempRubberBand = None
        self.vertexMarker = None
        self.capturedPoints = []
        self.derivedPoint = None
        self.capturing = False
        self.setCursor(Qt.CrossCursor)

    def canvasReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if not self.capturing:
                self.startCapturing()
            self.addVertex(event.pos())
        elif event.button() == Qt.RightButton:
            point = self.getDerivedPoint()
            polygon = self.getCapturedPolygon()
            self.stopCapturing()
            if point != None and polygon != None:
                pointGeom = self.getPointGeometry(point)
                polygonGeom = self.getPolygonGeometry(polygon)
                if pointGeom != None and polygonGeom != None:
                    self.mappingFinished.emit(pointGeom, polygonGeom, self.canvas.mapSettings().destinationCrs())
                else:
                    self.clearScene()
            else:
                self.clearScene()

    def canvasMoveEvent(self, event):
        if self.tempRubberBand != None and self.capturing:
            mapPt = self.transformCoordinates(event.pos())
            self.tempRubberBand.movePoint(mapPt)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete:
            self.removeLastVertex()
            event.ignore()
        if event.key() == Qt.Key_Escape:
            self.stopCapturing()
            self.clearScene()
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
            point = self.getDerivedPoint()
            polygon = self.getCapturedPolygon()
            self.stopCapturing()
            if point != None and polygon != None:
                pointGeom = self.getPointGeometry(point)
                polygonGeom = self.getPolygonGeometry(polygon)
                if pointGeom != None and polygonGeom != None:
                    self.mappingFinished.emit(pointGeom, polygonGeom, self.canvas.mapSettings().destinationCrs())
                else:
                    self.clearScene()
            else:
                self.clearScene()

    def startCapturing(self):
        self.clearScene()

        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubberBand.setWidth(2)
        self.rubberBand.setFillColor(QColor(220, 0, 0, 120))
        self.rubberBand.setBorderColor(QColor(220, 0, 0))
        self.rubberBand.setLineStyle(Qt.DotLine)
        self.rubberBand.show()

        self.tempRubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.tempRubberBand.setWidth(2)
        self.tempRubberBand.setFillColor(QColor(0, 0, 0, 0))
        self.tempRubberBand.setBorderColor(QColor(220, 0, 0))
        self.tempRubberBand.setLineStyle(Qt.DotLine)
        self.tempRubberBand.show()

        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setIconType(1)
        self.vertexMarker.setColor(QColor(220, 0, 0))
        self.vertexMarker.setIconSize(16)
        self.vertexMarker.setPenWidth(3)
        self.vertexMarker.show()

        self.capturing = True

    def clearScene(self):
        if self.vertexMarker:
            self.canvas.scene().removeItem(self.vertexMarker)
            self.vertexMarker = None
        if self.rubberBand:
            self.canvas.scene().removeItem(self.rubberBand)
            self.rubberBand = None
        if self.tempRubberBand:
            self.canvas.scene().removeItem(self.tempRubberBand)
            self.tempRubberBand = None

    def stopCapturing(self):
        if self.vertexMarker and self.rubberBand and self.rubberBand.numberOfVertices() < 3:
            self.canvas.scene().removeItem(self.vertexMarker)
            self.vertexMarker = None
        if self.rubberBand and self.rubberBand.numberOfVertices() < 3:
            self.canvas.scene().removeItem(self.rubberBand)
            self.rubberBand = None
        if self.tempRubberBand:
            self.canvas.scene().removeItem(self.tempRubberBand)
            self.tempRubberBand = None
        self.capturing = False
        self.capturedPoints = []
        self.derivedPoint = None
        self.canvas.refresh()

    def addVertex(self, canvasPoint):
        mapPt = self.transformCoordinates(canvasPoint)

        self.rubberBand.addPoint(mapPt)
        self.capturedPoints.append(mapPt)

        bandSize = self.rubberBand.numberOfVertices()
        if bandSize > 2:

            rubGeom = self.rubberBand.asGeometry()
            cpGeom = rubGeom.centroid()
            if not rubGeom.contains(cpGeom):
                cpGeom = rubGeom.pointOnSurface()
            #nearestCp = rubGeom.nearestPoint(cpGeom)
            self.vertexMarker.setCenter(cpGeom.asPoint())
            self.derivedPoint = cpGeom.asPoint()
            self.vertexMarker.show()



        self.tempRubberBand.reset(QGis.Polygon)
        firstPoint = self.rubberBand.getPoint(0, 0)
        self.tempRubberBand.addPoint(firstPoint)
        self.tempRubberBand.movePoint(mapPt)
        self.tempRubberBand.addPoint(mapPt)

    def removeLastVertex(self):
        if not self.capturing:
            return

        bandSize = self.rubberBand.numberOfVertices()
        tempBandSize = self.tempRubberBand.numberOfVertices()
        numPoints = len(self.capturedPoints)

        if bandSize < 1 or numPoints < 1:
            return

        self.rubberBand.removePoint(-1)

        if bandSize > 1:
            if tempBandSize > 1:
                point = self.rubberBand.getPoint(0, bandSize - 2)
                self.tempRubberBand.movePoint(tempBandSize - 2, point)
        else:
            self.tempRubberBand.reset(QGis.Polygon)

        bandSize = self.rubberBand.numberOfVertices()
        if bandSize < 3:
            self.vertexMarker.hide()
        else:
            rubGeom = self.rubberBand.asGeometry()
            cpGeom = rubGeom.centroid()
            if not rubGeom.contains(cpGeom):
                cpGeom = rubGeom.pointOnSurface()
            #nearestCp = rubGeom.nearestPoint(cpGeom)
            self.vertexMarker.setCenter(cpGeom.asPoint())
            self.derivedPoint = cpGeom.asPoint()
            self.vertexMarker.show()


        del self.capturedPoints[-1]

    def getCapturedPolygon(self):
        polygon = self.capturedPoints

        if len(polygon) < 3:
            return None
        else:
            return polygon

    def getDerivedPoint(self):
        point = self.derivedPoint

        if point == None:
            return None
        else:
            return point

    def getPointGeometry(self, geom):
        p = QgsGeometry.fromPoint(geom)
        if p.isGeosValid() and not p.isGeosEmpty():
            return p
        else:
            return None

    def getPolygonGeometry(self, geom):
        p = QgsGeometry.fromPolygon([geom])
        if p.isGeosValid() and not p.isGeosEmpty():
            return p
        else:
            return None
コード例 #14
0
class ZoomToPostcode:
    """QGIS Plugin Implementation."""

    METADATA_URL = "http://qgis.locationcentre.co.uk/ZoomToPostcode_medata.xml"
    POSTCODE_URL = "http://qgis.locationcentre.co.uk/UK_Postcodes.zip"

    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
        self.canvas = iface.mapCanvas()

        # initialize plugin directory
        self.plugin_dir = path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = path.join(
            self.plugin_dir,
            'i18n',
            'ZoomToPostcode_{}.qm'.format(locale))

        if 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 = ZoomToPostcodeDialog()

        # Create licence dlg
        self.licence_dlg = LicenceDialog()

        # Create various class references
        self.marker = None
        self.completer = None

        self.previous_searches = []

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Zoom To Postcode')
        self.toolbar = self.iface.addToolBar(u'ZoomToPostcode')
        self.toolbar.setObjectName(u'ZoomToPostcode')

    # 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('ZoomToPostcode', 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."""

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

        # Configure toolbar widget
        self.toolbar = self.iface.addToolBar("Zoom To Postcode Toolbar")
        self.toolbar.setObjectName("Zoom To Postcode Toolbar")
        self.toolbar_search = QLineEdit()
        self.toolbar_search.setMaximumWidth(100)
        self.toolbar_search.setAlignment(Qt.AlignLeft)
        self.toolbar_search.setPlaceholderText("Enter postcode...")
        self.toolbar.addWidget(self.toolbar_search)
        self.toolbar_search.returnPressed.connect(self.check_pkl)

        self.search_btn = QAction(QIcon(":/plugins/zoomtopostcode/zoomicon.png"), "Search", self.iface.mainWindow())
        self.search_btn.triggered.connect(self.check_pkl)
        self.toolbar.addActions([self.search_btn])

        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/zoomtopostcode/zoomicon.png"), u"Zoom to Postcode",
                              self.iface.mainWindow())
        self.action.triggered.connect(self.toolbar.show)

        self.licence = QAction(u"OS Licence", self.iface.mainWindow())
        self.licence.triggered.connect(self.licence_dlg.show)

        # Add toolbar button and menu item
        self.iface.addPluginToMenu(u"&Zoom to Postcode", self.action)
        self.iface.addPluginToMenu(u"&Zoom to Postcode", self.licence)

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

        # remove the toolbar
        del self.toolbar

    def run(self):
        """Show the toolbar dialog."""
        self.dlg.show()

    def search_completer(self):
        self.completer = QCompleter(self.previous_searches, self.iface.mainWindow())
        self.completer.setCompletionMode(QCompleter.PopupCompletion)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)

    def check_crs(self):
        """Check if a transformation needs to take place.

        :return: None
        """
        srs = self.canvas.mapSettings().destinationCrs()
        current_crs = srs.authid()
        return current_crs

    def transform(self, cor):
        """Transforms point from british nation grid to map crs.

        :param cor: Coords
        :return: Point
        """
        srs = self.canvas.mapSettings().destinationCrs()
        crs_src = QgsCoordinateReferenceSystem(27700)
        crs_dest = QgsCoordinateReferenceSystem(srs)
        xform = QgsCoordinateTransform(crs_src, crs_dest, QgsProject.instance())
        x, y = cor
        t_point = xform.transform(float(x), float(y))
        return t_point

    def check_pkl(self):
        """Check the Pickle postcode dir exists.

        :return: None
        """
        checkpkl = path.isdir(path.join(self.plugin_dir, 'UK_Postcodes'))
        if checkpkl:
            xml_path = path.join(self.plugin_dir, r'UK_Postcodes/metadata.xml')
            check_xml = path.isfile(xml_path)
            if check_xml:
                check_currency = self.check_pcode_date(xml_path)
                if check_currency:
                    self.postcode_dict()
                else:
                    self.update_pcode_option()
            else:
                self.update_pcode_option()
        else:
            msg = "Postcode files must be downloaded to use this plugin, do you wish to continue?"
            goahead = QMessageBox.question(self.iface.mainWindow(), "Download Message", msg, QMessageBox.Yes,
                                           QMessageBox.No)
            if goahead == QMessageBox.Yes:
                self.download_pkl()
            else:
                pass

    def check_pcode_date(self, xml_path):
        """Parses metadata xml to check currency of pcodes.

        :param xml_path: Full path to xml file.
        :return: True for up-to-date postcodes, False requires download to update
        """
        try:

            http = urllib3.PoolManager()
            r = http.request('GET', self.METADATA_URL, retries=3)

            xml_as_string = ET.fromstring(r.data.decode('utf-8'))
            tree_web = ET.ElementTree(xml_as_string)
            root_web = tree_web.getroot()
            current_version = ""
            for child in root_web:
                if child.tag == "pcode_date":
                    current_version = child.text
            tree_plugin = ET.parse(xml_path)
            root_plugin = tree_plugin.getroot()
            last_update = ""
            for child in root_plugin:
                if child.tag == "pcode_date":
                    last_update = child.text
            last_up_datetime = datetime.strptime(last_update, '%Y-%m-%d')
            curr_ver_datetime = datetime.strptime(current_version, '%Y-%m-%d')
            if last_up_datetime.date() >= curr_ver_datetime.date():
                return True
            else:
                return False

        except urllib3.exceptions.MaxRetryError:
            QMessageBox.information(self.iface.mainWindow(),
                                    "HTTP Error",
                                    "Unable to download file")

    def update_pcode_option(self):
        """Provide option to update postcodes.

        :return: None
        """
        msg = "Updated postcode files are available, do you wish to download?"
        goahead = QMessageBox.question(self.iface.mainWindow(), "Download Message", msg, QMessageBox.Yes,
                                       QMessageBox.No)
        if goahead == QMessageBox.Yes:
            self.download_pkl()
        if goahead == QMessageBox.No:
            self.postcode_dict()

    def download_pkl(self):
        """Download the Pickle postcode file to the plugin dir.

        :return: None
        """
        pcode_path = path.join(path.dirname(__file__), 'UK_Postcodes')
        if not path.exists(pcode_path):
            makedirs(pcode_path)

        try:
            http = urllib3.PoolManager()
            response = http.request('GET', self.POSTCODE_URL, preload_content=False, retries=3)
            content_length = response.headers['Content-Length']
            total_size = int(content_length)
            downloaded = 0
            CHUNK = 256 * 10240
            dlbar = QProgressBar()
            dlbar.setMinimum(0)
            dlbar.setMaximum(total_size)
            zip_temp = tempfile.NamedTemporaryFile(mode='w+b', suffix='.zip', delete=False)
            zip_temp_n = zip_temp.name
            zip_temp.seek(0)

            with open(zip_temp_n, 'wb') as fp:
                while True:
                    dlbar.show()
                    chunk = response.read(CHUNK)
                    downloaded += len(chunk)
                    dlbar.setValue(downloaded)
                    if not chunk:
                        break
                    fp.write(chunk)
            response.release_conn()

            pcode_zip = ZipFile(zip_temp)
            pcode_zip.extractall(pcode_path)
            zip_temp.close()
            self.check_pkl()

        except urllib3.exceptions.MaxRetryError:
            QMessageBox.information(self.iface.mainWindow(),
                                    "HTTP Error",
                                    "Unable to download file")

    def postcode_dict(self):
        """Create dictionary of postcodes from correct Pickle file.

        :return: None
        """
        try:
            input_pcode = self.toolbar_search.text().replace(' ', '')
            if input_pcode[1].isdigit():
                find_pkl = str(r"UK_Postcodes/" + input_pcode[:1] + ".pkl")
            else:
                find_pkl = str(r"UK_Postcodes/" + input_pcode[:2] + ".pkl")
            pklfile = open(path.join(path.dirname(__file__), find_pkl), 'rb')
            pcode_dict = pickle.load(pklfile)
            pklfile.close()
            if input_pcode.upper() not in self.previous_searches:
                self.previous_searches.append(input_pcode.upper())
                self.search_completer()
                self.toolbar_search.setCompleter(self.completer)
            self.zoomto(pcode_dict)
        except (KeyError, IOError):
            QMessageBox.information(self.iface.mainWindow(),
                                    "Invalid postcode",
                                    "The postcode you entered was not found")
        except IndexError:
            pass

    def zoomto(self, pcode_dict):
        """Find the coordinates for postcode in the dictionary.

        :param pcode_dict:
        :return: None
        """
        current_crs = self.check_crs()
        input_pc = self.toolbar_search.text()
        input_pc_fmt = str(input_pc).replace(' ', '').upper()
        coords = pcode_dict[input_pc_fmt]
        x, y = coords
        if current_crs != "EPSG:27700":
            cor = (x, y)
            point = self.transform(cor)
            self.update_canvas(point)
        else:
            point = (x, y)
            self.update_canvas(point)

    def update_canvas(self, point):
        """Update the canvas and add vertex marker.

        :param point:
        :return: None
        """
        x, y = point
        scale = 120
        rect = QgsRectangle(float(x) - scale, float(y) - scale, float(x) + scale, float(y) + scale)
        self.canvas.setExtent(rect)
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.setIconSize(15)
        self.marker.setPenWidth(2)
        self.marker.setCenter(QgsPointXY(int(x), int(y)))
        self.canvas.refresh()
        self.canvas.extentsChanged.connect(self.remove_marker)

    def remove_marker(self):
        """Remove vertex marker.

        :return: None
        """
        self.marker.hide()
        self.canvas.scene().removeItem(self.marker)
        self.canvas.extentsChanged.disconnect(self.remove_marker)
コード例 #15
0
# coding: utf-8
from PyQt4.QtGui import QColor
from qgis.utils import iface
from qgis.core import QgsPoint
from qgis.gui import QgsVertexMarker

canvas = iface.mapCanvas()
m = QgsVertexMarker(canvas)
m.setCenter(QgsPoint(0, 0))

m.setColor(QColor(0, 0, 255))
m.setIconSize(7)
m.setIconType(QgsVertexMarker.ICON_BOX)  # See the enum IconType from http://www.qgis.org/api/classQgsVertexMarker.html
m.setPenWidth(3)

m.hide()
m.show()

# Remove the element
# canvas.scene().removeItem(m)
コード例 #16
0
class mapillary_cursor():
    def transformToWGS84(self, pPoint):
        # transformation from the current SRS to WGS84
        crcMappaCorrente = self.iface.mapCanvas().mapSettings().destinationCrs(
        )  # get current crs
        crsSrc = crcMappaCorrente
        crsDest = QgsCoordinateReferenceSystem(4326)  # WGS 84
        xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
        return xform.transform(pPoint)  # forward transformation: src -> dest

    def transformToCurrentSRS(self, pPoint):
        # transformation from the current SRS to WGS84
        crcMappaCorrente = self.iface.mapCanvas().mapSettings().destinationCrs(
        )  # get current crs
        crsDest = crcMappaCorrente
        crsSrc = QgsCoordinateReferenceSystem(4326)  # WGS 84
        xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
        return xform.transform(pPoint)  # forward transformation: src -> dest

    def __init__(self, parentInstance):
        self.parentInstance = parentInstance
        self.iface = parentInstance.iface
        self.mapCanvas = self.iface.mapCanvas()
        self.lineOfSight = QgsRubberBand(self.mapCanvas,
                                         QgsWkbTypes.LineGeometry)
        self.sightDirection = QgsRubberBand(self.mapCanvas,
                                            QgsWkbTypes.LineGeometry)
        self.pointOfView = QgsVertexMarker(self.mapCanvas)
        self.cursor = QgsVertexMarker(self.mapCanvas)
        self.sightDirection.setColor(QColor(CURSOR_COLOR))
        self.lineOfSight.setColor(QColor(CURSOR_COLOR))
        self.pointOfView.setColor(QColor(CURSOR_COLOR))
        self.cursor.setColor(QColor(CURSOR_COLOR))
        self.lineOfSight.setWidth(2)
        self.sightDirection.setWidth(1)
        self.sightDirection.setLineStyle(Qt.DashLine)
        self.pointOfView.setIconType(QgsRubberBand.ICON_CIRCLE)
        self.cursor.setIconType(QgsRubberBand.ICON_CIRCLE)
        self.pointOfView.setIconSize(20)
        self.cursor.setIconSize(20)
        self.cursor.setPenWidth(2)
        self.pointOfView.setPenWidth(2)
        self.samples_datasource = ''
        self.delete()
        #self.update_ds(self.parentInstance.sample_settings.settings['sample_source'])

    def getSamplesLayer(self, samples_datasource):
        if samples_datasource != 'memory':
            if not os.path.exists(samples_datasource):
                self.create_datasource_from_template(samples_datasource)
            samples_lyr = QgsVectorLayer(samples_datasource,
                                         SAMPLES_LAYER_NAME, 'ogr')
        else:
            samples_lyr = QgsVectorLayer("Point?crs=epsg:4326&index=yes",
                                         SAMPLES_LAYER_NAME, 'memory')
        self.checkForTemplateFields(samples_lyr)
        return samples_lyr

    def getFieldFromDefinition(self, field_type):
        type_pack = field_type[1].split("|")
        if field_type[2]:
            comment = field_type[2]
        else:
            comment = field_type[0]
        return QgsField(name=field_type[0],
                        type=int(type_pack[0]),
                        len=int(type_pack[1]),
                        prec=int(type_pack[2]),
                        comment=comment)

    def checkForTemplateFields(self, layer):

        layerFieldNamesList = []
        for field in layer.fields().toList():
            layerFieldNamesList.append(field.name())

        for fieldDef in FIELDS_TEMPLATE:
            if not fieldDef[0] in layerFieldNamesList:
                layer.startEditing()
                layer.addAttribute(self.getFieldFromDefinition(fieldDef))
                layer.commitChanges()

    def update_ds(self, ds):
        if self.samples_datasource != ds:
            self.samples_datasource = ds
            self.samplesLayer = self.getSamplesLayer(ds)
            self.samplesLayer.triggerRepaint()
        self.samplesLayer.loadNamedStyle(
            os.path.join(os.path.dirname(__file__), "res",
                         "mapillary_samples.qml"))
        self.samplesLayer.featureAdded.connect(self.newAddedFeat)

    def create_datasource_from_template(self, datasource):
        fieldSet = QgsFields()
        for fieldDef in FIELDS_TEMPLATE:
            fieldSet.append(self.getFieldFromDefinition(fieldDef))
        writer = QgsVectorFileWriter(datasource, 'UTF-8', fieldSet,
                                     QgsWkbTypes.Point,
                                     QgsCoordinateReferenceSystem(4326),
                                     "ESRI Shapefile")
        if writer.hasError():
            print("error", writer.errorMessage())
        del writer

    def draw(self, pointOfView_coords, orig_pointOfView_coords, cursor_coords,
             endOfSight_coords):
        if pointOfView_coords[0]:
            self.cursor.show()
            self.pointOfView.show()
            self.lineOfSight.reset()
            self.sightDirection.reset()
            pointOfView = self.transformToCurrentSRS(
                QgsPointXY(pointOfView_coords[1], pointOfView_coords[0]))
            cursor = self.transformToCurrentSRS(
                QgsPointXY(cursor_coords[1], cursor_coords[0]))
            endOfSight = self.transformToCurrentSRS(
                QgsPointXY(endOfSight_coords[1], endOfSight_coords[0]))
            self.pointOfView.setCenter(pointOfView)
            self.cursor.setCenter(cursor)
            self.lineOfSight.addPoint(pointOfView)
            self.lineOfSight.addPoint(cursor)
            self.sightDirection.addPoint(pointOfView)
            self.sightDirection.addPoint(endOfSight)
            self.cursor.updatePosition()
        else:
            self.delete()

    def delete(self):
        self.cursor.hide()
        self.pointOfView.hide()
        self.lineOfSight.reset()
        self.sightDirection.reset()

    def addSampleLayerToCanvas(self):
        if not QgsProject.instance().mapLayer(self.samplesLayer.id()):
            QgsProject.instance().addMapLayer(self.samplesLayer)
            self.restoreMarkers()

    def sample(self, type, id, key, sample_coords, img_coords=None):
        self.samplesLayer.startEditing()
        samplePoint = QgsPointXY(sample_coords[1], sample_coords[0])
        #sampleDevicePoint = self.iface.mapCanvas().getCoordinateTransform().transform(samplePoint.x(),samplePoint.y())
        self.addSampleLayerToCanvas()
        sampleFeat = QgsFeature(self.samplesLayer.fields())
        sampleFeat['type'] = type
        sampleFeat['id'] = id
        sampleFeat['key'] = key
        if img_coords:
            sampleFeat['img_coords'] = img_coords
        sampleFeat.setGeometry(QgsGeometry.fromPointXY(samplePoint))
        #self.samplesLayer.dataProvider().addFeatures([sampleFeat])
        print('', self.samplesLayer.addFeature(sampleFeat))
        self.samplesLayer.commitChanges()

    def newAddedFeat(self, featId):
        if featId < 0:
            return
        self.samplesLayer.triggerRepaint()
        if self.parentInstance.sample_settings.settings['auto_open_form']:
            newFeat = self.samplesLayer.getFeature(featId)
            self.parentInstance.samples_form.open(newFeat)

    def getSamplesList(self):
        samples = []
        id = 1
        for feat in self.samplesLayer.getFeatures():
            samples.append({
                "id": id,
                "latLon": {
                    'lat': feat.geometry().asPoint().y(),
                    'lon': feat.geometry().asPoint().x(),
                }
            })

    def restoreTags(self, key):
        exp = QgsExpression('"type" = \'tag\' and "key" = \'%s\'' % key)
        tags = []
        for feat in self.samplesLayer.getFeatures(QgsFeatureRequest(exp)):
            if feat['cat']:
                color = self.parentInstance.sample_settings.settings[
                    'categories'][str(feat['cat'])]
            else:
                color = '#ffffff'

            tags.append({
                'id': str(feat['id']),
                'key': str(feat['key']),
                'note': str(feat['note']),
                'cat': str(feat['cat']),
                'color': color,
                'geometry': json.loads(feat['img_coords'])
            })
        return tags

    def editSample(self, type, key, id):
        exp = QgsExpression(
            '"type" = \'%s\' and "key" = \'%s\' and "id" = \'%s\'' %
            (type, key, id))
        for feat in self.samplesLayer.getFeatures(QgsFeatureRequest(exp)):
            self.parentInstance.samples_form.open(feat)

    def moveMarker(self, key, id, sample_coords):
        exp = QgsExpression(
            '"type" = \'marker\' and "key" = \'%s\' and "id" = \'%s\'' %
            (key, id))
        for feat in self.samplesLayer.getFeatures(QgsFeatureRequest(exp)):
            samplePoint = QgsPointXY(sample_coords[1], sample_coords[0])
            self.samplesLayer.startEditing()
            self.samplesLayer.changeGeometry(
                feat.id(), QgsGeometry.fromPointXY(samplePoint))
            self.samplesLayer.commitChanges()
            self.samplesLayer.triggerRepaint()

    def restoreMarkers(self):
        if self.parentInstance.sample_settings.settings[
                'sample_source'] != 'memory':
            exp = QgsExpression('"type" = \'marker\'')
            markersDef = []
            for feat in self.samplesLayer.getFeatures(QgsFeatureRequest(exp)):
                if feat['cat']:
                    color = self.parentInstance.sample_settings.settings[
                        'categories'][str(feat['cat'])]
                else:
                    color = '#ffffff'
                markersDef.append({
                    'key': str(feat['key']),
                    'id': str(feat['id']),
                    'color': color,
                    'loc': {
                        'lon': feat.geometry().asPoint().x(),
                        'lat': feat.geometry().asPoint().y()
                    }
                })

            self.parentInstance.viewer.addMarkers(markersDef)
コード例 #17
0
ファイル: add_junction_tool.py プロジェクト: aecforge/QEPANET
class AddJunctionTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.snapper = None
        self.snapped_feat_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = None

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = False

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        if not self.mouse_clicked:

            # Mouse not clicked: snapping to closest vertex
            # (retval, result) = self.snapper.snapMapPoint(self.toMapCoordinates(event.pos()))

            match = self.snapper.snapToMap(self.mouse_pt)

            if match.isValid():

                # if len(result) > 0:

                self.snapped_feat_id = match.featureId()
                self.snapped_vertex = match.point()
                self.snapped_vertex_nr = match.vertexIndex()

                # It's a vertex on an existing pipe
                # self.snapped_feat_id = result[0].snappedAtGeometry
                #
                # snapped_vertex = result[0].snappedVertex
                # self.snapped_vertex_nr = result[0].snappedVertexNr

                # self.snapped_vertex = QgsPoint(snapped_vertex.x(), snapped_vertex.y())
                self.vertex_marker.setCenter(self.snapped_vertex)
                self.vertex_marker.setColor(QColor(255, 0, 0))
                self.vertex_marker.setIconSize(10)
                self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                self.vertex_marker.setPenWidth(3)
                self.vertex_marker.show()

            else:

                # It's a new, isolated vertex
                self.snapped_feat_id = None
                self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return

        if event.button() == Qt.LeftButton:

            self.mouse_clicked = False

            # Find first available ID for Junctions
            node_eid = NetworkUtils.find_next_id(
                self.params.junctions_vlay, Junction.prefix)  # TODO: softcode

            elev = 0
            if self.elev is None and self.params.dem_rlay is not None:
                self.iface.messageBar().pushMessage(
                    Parameters.plug_in_name,
                    'Elevation value not available: element elevation set to 0.',
                    QgsMessageBar.WARNING, 5)  # TODO: softcode
            else:
                elev = self.elev

            j_demand = float(self.data_dock.txt_junction_demand.text())
            deltaz = float(self.data_dock.txt_junction_deltaz.text())

            pattern = self.data_dock.cbo_junction_pattern.itemData(
                self.data_dock.cbo_junction_pattern.currentIndex())
            if pattern is not None:
                pattern_id = pattern.id
            else:
                pattern_id = None

            emitter_coeff_s = self.data_dock.txt_junction_emit_coeff.text()
            if emitter_coeff_s is None or emitter_coeff_s == '':
                emitter_coeff = float(0)
            else:
                emitter_coeff = float(
                    self.data_dock.txt_junction_emit_coeff.text())

            junction_desc = self.data_dock.txt_junction_desc.text()
            junction_tag = self.data_dock.cbo_junction_tag.currentText()

            # No links snapped: create a new stand-alone node
            if self.snapped_feat_id is None:

                NodeHandler.create_new_junction(self.params, self.mouse_pt,
                                                node_eid, elev, j_demand,
                                                deltaz, pattern_id,
                                                emitter_coeff, junction_desc,
                                                junction_tag)

            # A link has been snapped
            else:

                # Get the snapped pipe
                request = QgsFeatureRequest().setFilterFid(
                    self.snapped_feat_id)
                feats = list(self.params.pipes_vlay.getFeatures(request))
                if len(feats) > 0:
                    snapped_pipe = QgsFeature(feats[0])

                    snapped_ft_pts = QgsGeometry.asPolyline(
                        snapped_pipe.geometry())

                    # The new junction is on the start or end node of the pipe
                    if NetworkUtils.points_overlap(QgsGeometry.fromPoint(self.snapped_vertex), QgsGeometry.fromPoint(snapped_ft_pts[0]), self.params.tolerance) or\
                        NetworkUtils.points_overlap(QgsGeometry.fromPoint(self.snapped_vertex), QgsGeometry.fromPoint(snapped_ft_pts[len(snapped_ft_pts) - 1]), self.params.tolerance):

                        NodeHandler.create_new_junction(
                            self.params, self.snapped_vertex, node_eid,
                            self.elev, j_demand, deltaz, pattern_id,
                            emitter_coeff, junction_desc, junction_tag)

                    else:

                        # Split the pipe
                        (start_node_ft,
                         end_node_ft) = NetworkUtils.find_start_end_nodes(
                             self.params, snapped_pipe.geometry())

                        if start_node_ft is None or end_node_ft is None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'The pipe is missing the start or end nodes. Cannot add a new junction along the pipe.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                            return

                        # Check that the snapped point on line is distant enough from start/end nodes
                        if start_node_ft.geometry().distance(QgsGeometry.fromPoint(self.snapped_vertex)) > self.params.min_dist and\
                            end_node_ft.geometry().distance(QgsGeometry.fromPoint(self.snapped_vertex)) > self.params.min_dist:

                            NodeHandler.create_new_junction(
                                self.params, self.snapped_vertex, node_eid,
                                self.elev, j_demand, deltaz, pattern_id,
                                emitter_coeff, junction_desc, junction_tag)

                            LinkHandler.split_pipe(self.params, snapped_pipe,
                                                   self.snapped_vertex)
                        else:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'The new junction is too close to either the pipe end or start nodes. Cannot add a new junction along the pipe.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode

    def activate(self):

        # Snapping
        self.update_snapper()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()

    def deactivate(self):

        if self.params.pipes_vlay is not None:
            QgsProject.instance().setSnapSettingsForLayer(
                self.params.pipes_vlay.id(), True, QgsSnapper.SnapToSegment, 0,
                self.params.snap_tolerance, True)

        self.data_dock.btn_add_junction.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def update_snapper(self):
        layers = {
            self.params.junctions_vlay: QgsPointLocator.Vertex,
            self.params.pipes_vlay: QgsPointLocator.All
        }
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
コード例 #18
0
class AddValveTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.snapper = None
        self.snapped_pipe_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = -1

        self.diameter_dialog = None

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = True

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        if not self.mouse_clicked:

            # Mouse not clicked: snapping to closest vertex
            # (retval, result) = self.snapper.snapMapPoint(self.toMapCoordinates(event.pos()))
            # if len(result) > 0:

            match = self.snapper.snapToMap(self.mouse_pt)
            if match.isValid():

                # It's a vertex on an existing pipe
                # self.snapped_pipe_id = result[0].snappedAtGeometry
                # snapped_vertex = result[0].snappedVertex
                # self.snapped_vertex_nr = result[0].snappedVertexNr
                # self.snapped_vertex = QgsPoint(snapped_vertex.x(), snapped_vertex.y())

                self.snapped_pipe_id = match.featureId()
                self.snapped_vertex = match.point()
                self.snapped_vertex_nr = match.vertexIndex()

                self.vertex_marker.setCenter(self.snapped_vertex)
                self.vertex_marker.setColor(QColor(255, 0, 0))
                self.vertex_marker.setIconSize(10)
                self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                self.vertex_marker.setPenWidth(3)
                self.vertex_marker.show()

            else:

                # It's a new, isolated vertex
                self.snapped_pipe_id = None
                self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return

        if event.button() == Qt.LeftButton:

            self.mouse_clicked = False

            # No pipe snapped: notify user
            if self.snapped_pipe_id is None:

                self.iface.messageBar().pushMessage(
                    Parameters.plug_in_name,
                    'You need to snap the cursor to a pipe to add a valve.',
                    QgsMessageBar.INFO, 5)

            # A pipe has been snapped
            else:

                request = QgsFeatureRequest().setFilterFid(
                    self.snapped_pipe_id)
                feats = self.params.pipes_vlay.getFeatures(request)
                features = [feat for feat in feats]
                if len(features) == 1:

                    # Check whether the pipe has a start and an end node
                    (start_node, end_node) = NetworkUtils.find_start_end_nodes(
                        self.params, features[0].geometry())

                    if not start_node or not end_node:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'The pipe is missing the start or end nodes.',
                            QgsMessageBar.WARNING, 5)  # TODO: softcode
                        return

                    # Find endnode closest to valve position
                    dist_1 = start_node.geometry().distance(
                        QgsGeometry.fromPoint(self.snapped_vertex))
                    dist_2 = end_node.geometry().distance(
                        QgsGeometry.fromPoint(self.snapped_vertex))

                    # Get the attributes of the closest junction
                    (start_node, end_node) = NetworkUtils.find_start_end_nodes(
                        self.params, features[0].geometry(), False, True, True)
                    if dist_1 < dist_2:
                        closest_junction_ft = start_node
                    else:
                        closest_junction_ft = end_node

                    # Create the valve
                    diameter = features[0].attribute(Pipe.field_name_diameter)
                    # diameter = self.data_dock.txt_valve_diameter.text()
                    minor_loss = self.data_dock.txt_valve_minor_loss.text()
                    selected_type = self.data_dock.cbo_valve_type.itemData(
                        self.data_dock.cbo_valve_type.currentIndex())
                    if selected_type != Valve.type_gpv:
                        setting = self.data_dock.txt_valve_setting.text()
                    else:
                        valve_curve = self.data_dock.cbo_valve_curve.itemData(
                            self.data_dock.cbo_valve_curve.currentIndex())
                        if valve_curve is not None:
                            setting = valve_curve.id
                        else:
                            setting = None

                    # Pump status
                    valve_status = self.data_dock.cbo_valve_status.itemData(
                        self.data_dock.cbo_valve_status.currentIndex())

                    # Valve description
                    valve_desc = self.data_dock.txt_valve_desc.text()

                    # Valve tag
                    valve_tag = self.data_dock.cbo_valve_tag.currentText()

                    try:
                        LinkHandler.create_new_pumpvalve(
                            self.params, self.data_dock, features[0],
                            closest_junction_ft, self.snapped_vertex,
                            self.params.valves_vlay, {
                                Valve.field_name_diameter: diameter,
                                Valve.field_name_minor_loss: minor_loss,
                                Valve.field_name_setting: setting,
                                Valve.field_name_type: selected_type,
                                Valve.field_name_status: valve_status,
                                Valve.field_name_description: valve_desc,
                                Valve.field_name_tag: valve_tag
                            })

                    except PumpValveCreationException as ex:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name, ex.message,
                            QgsMessageBar.INFO, 5)

        elif event.button() == Qt.RightButton:

            self.mouse_clicked = False

            # Check whether it clicked on a valve vertex
            if len(
                    NetworkUtils.find_adjacent_links(
                        self.params, self.snapped_vertex)['valves']) == 0:
                return

            menu = QMenu()
            diameter_action = menu.addAction(
                'Change diameter...')  # TODO: softcode
            invert_action = menu.addAction(
                'Flip orientation')  # TODO: softcode
            action = menu.exec_(self.iface.mapCanvas().mapToGlobal(
                QPoint(event.pos().x(),
                       event.pos().y())))

            request = QgsFeatureRequest().setFilterFid(self.snapped_pipe_id)
            feats = self.params.pipes_vlay.getFeatures(request)
            features = [feat for feat in feats]
            if len(features) == 1:
                adj_links = NetworkUtils.find_links_adjacent_to_link(
                    self.params, self.params.pipes_vlay, features[0], True,
                    True, False)

                for valve_ft in adj_links['valves']:

                    if action == diameter_action:
                        old_diam = valve_ft.attribute(
                            Valve.field_name_diameter)
                        self.diameter_dialog = DiameterDialog(
                            self.iface.mainWindow(), self.params, old_diam)
                        self.diameter_dialog.exec_(
                        )  # Exec creates modal dialog
                        new_diameter = self.diameter_dialog.get_diameter()
                        if new_diameter is None:
                            return

                        # Update valve diameter
                        vector_utils.update_attribute(
                            self.params.valves_vlay, valve_ft,
                            Valve.field_name_diameter, new_diameter)

                        # Modify pipes diameters
                        adj_pipes_fts = NetworkUtils.find_links_adjacent_to_link(
                            self.params, self.params.valves_vlay, valve_ft,
                            False, True, True)

                        if adj_pipes_fts:

                            for adj_pipe_ft in adj_pipes_fts['pipes']:

                                vector_utils.update_attribute(
                                    self.params.pipes_vlay, adj_pipe_ft,
                                    Pipe.field_name_diameter, new_diameter)

                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Diameters of pipes adjacent to valve updated.',
                                QgsMessageBar.INFO, 5)  # TODO: softcode

                    elif action == invert_action:

                        request = QgsFeatureRequest().setFilterFid(
                            self.snapped_pipe_id)
                        feats = self.params.pipes_vlay.getFeatures(request)
                        features = [feat for feat in feats]
                        if len(features) == 1:
                            adj_links = NetworkUtils.find_links_adjacent_to_link(
                                self.params, self.params.pipes_vlay,
                                features[0], True, True, False)

                            for adj_link in adj_links['valves']:
                                adj_link_pts = adj_link.geometry().asPolyline()
                                for adj_link_pt in adj_link_pts:
                                    if NetworkUtils.points_overlap(
                                            adj_link_pt, self.snapped_vertex,
                                            self.params.tolerance):

                                        geom = adj_link.geometry()

                                        if geom.wkbType(
                                        ) == QGis.WKBMultiLineString:
                                            nodes = geom.asMultiPolyline()
                                            for line in nodes:
                                                line.reverse()
                                            newgeom = QgsGeometry.fromMultiPolyline(
                                                nodes)
                                            self.params.valves_vlay.changeGeometry(
                                                adj_link.id(), newgeom)

                                        if geom.wkbType(
                                        ) == QGis.WKBLineString:
                                            nodes = geom.asPolyline()
                                            nodes.reverse()
                                            newgeom = QgsGeometry.fromPolyline(
                                                nodes)
                                            self.params.valves_vlay.changeGeometry(
                                                adj_link.id(), newgeom)

                                        self.iface.mapCanvas().refresh()

                                        break

    def activate(self):

        snap_layer_pipes = NetworkUtils.set_up_snap_layer(
            self.params.pipes_vlay, None, QgsSnapper.SnapToVertexAndSegment)

        self.update_snapper()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()
        if not self.params.valves_vlay.isEditable():
            self.params.valves_vlay.startEditing()

    def deactivate(self):

        QgsProject.instance().setSnapSettingsForLayer(
            self.params.pipes_vlay.id(), True, QgsSnapper.SnapToSegment,
            QgsTolerance.MapUnits, 0, True)

        self.data_dock.btn_add_valve.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def update_snapper(self):
        layers = {self.params.pipes_vlay: QgsPointLocator.All}
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
コード例 #19
0
class BeoordelingstoolDockWidget(QtGui.QDockWidget, FORM_CLASS):

    closingPlugin = pyqtSignal()

    def __init__(self,
                 parent=None,
                 manhole_layer=None,
                 pipe_layer=None,
                 measuring_point_layer=None):
        """Constructor."""
        super(BeoordelingstoolDockWidget, self).__init__(parent)
        # 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.add_herstelmaatregelen()
        self.tabWidget.currentChanged.connect(self.tab_changed)

        self.manholes = manhole_layer
        self.pipes = pipe_layer
        self.measuring_points = measuring_point_layer

        self.manholes.selectionChanged.connect(self.get_selected_manhole)
        self.pipes.selectionChanged.connect(self.get_selected_pipe)
        self.measuring_points.selectionChanged.connect(
            self.get_selected_measuring_point)

        # Enable the 'Select Feature` tool by default.
        iface.actionSelect().trigger()

        # General tab
        self.set_project_properties()
        self.pushbutton_upload_voortgang_json.clicked.connect(
            self.show_login_dialog_voortgang)
        self.pushbutton_upload_zip_json.clicked.connect(
            self.show_login_dialog_final)

        # Manholes tab
        self.selected_manhole_id = 0
        self.pushbutton_save_attribute_manholes.clicked.connect(
            self.save_beoordeling_putten)

        # Pipes tab
        self.selected_pipe_id = 0
        self.pushbutton_save_attribute_pipes.clicked.connect(
            self.save_beoordeling_leidingen)
        self.pushbutton_pipe_to_measuring_point.clicked.connect(
            self.show_measuring_point)

        # Measuring points tab
        self.selected_measuring_point_id = 0
        self.pushbutton_save_attribute_measuring_points.clicked.connect(
            self.save_beoordeling_measuring_points)
        self.pushbutton_measuring_points_previous.clicked.connect(
            self.show_previous_measuring_point)
        self.pushbutton_measuring_point_to_pipe.clicked.connect(self.show_pipe)
        self.pushbutton_measuring_points_next.clicked.connect(
            self.show_next_measuring_point)

        self.selected_measuring_points_ids = []
        self.measure_point_marker = QgsVertexMarker(iface.mapCanvas())
        self.measure_point_marker.setColor(Qt.blue)
        self.disable_next_measuring_point_button()
        self.disable_previous_measuring_point_button()

    def closeEvent(self, event):
        self.measure_point_marker.hide()
        self.closingPlugin.emit()
        event.accept()

    def add_herstelmaatregelen(self):
        """Add the herstelmaatregelen to the comboboxes"""
        self.field_combobox_manholes.addItems(HERSTELMAATREGELEN)
        self.field_combobox_pipes.addItems(HERSTELMAATREGELEN)
        self.field_combobox_measuring_points.addItems(HERSTELMAATREGELEN)

    def tab_changed(self):
        """Change the active layer upon selecting another tab."""
        if self.tabWidget.currentIndex() == 1:
            # Set manholes as active layer
            manholes_layer = QgsMapLayerRegistry.instance().mapLayersByName(
                SHP_NAME_MANHOLES)[0]
            iface.setActiveLayer(manholes_layer)
        elif self.tabWidget.currentIndex() == 2:
            # Set pipes as active layer
            pipes_layer = QgsMapLayerRegistry.instance().mapLayersByName(
                SHP_NAME_PIPES)[0]
            iface.setActiveLayer(pipes_layer)
        elif self.tabWidget.currentIndex() == 3:
            # Set measuring_points as active layer
            measuring_points_layer = QgsMapLayerRegistry.instance(
            ).mapLayersByName(SHP_NAME_MEASURING_POINTS)[0]
            iface.setActiveLayer(measuring_points_layer)

    def set_project_properties(self):
        """
        Set the project name on the General tab of the dockwidget.
        The name of the project name property of the review.json in the same
        folder as the layer is used as the project name.
        """
        # Check if the manholes, pipes and measuring_points layers exist
        if self.manholes and self.pipes and self.measuring_points:
            # Get project name from the json saved in the same folder as the "manholes" layer
            layer_dir = get_layer_dir(self.manholes)
            json_path = os.path.join(layer_dir, JSON_NAME)
            try:
                data = json.load(open(json_path))
                if data[JSON_KEY_PROJ][JSON_KEY_NAME]:
                    self.label_project_name.setText(
                        data[JSON_KEY_PROJ][JSON_KEY_NAME])
                else:
                    iface.messageBar().pushMessage("Warning",
                                                   "No project name defined.",
                                                   level=QgsMessageBar.WARNING,
                                                   duration=0)
                if data[JSON_KEY_PROJ][JSON_KEY_URL]:
                    self.textedit_project_url.setText(
                        "<a href=google.com>{}</a>".format(
                            data[JSON_KEY_PROJ][JSON_KEY_URL]))
                    # .clicked(QDesktopServices.openUrl(QUrl(data[JSON_KEY_PROJ][JSON_KEY_URL], QUrl.TolerantMode)))
                    # self.label_project_url.setText("<a href={}>{}</a>".format(data[JSON_KEY_PROJ][JSON_KEY_URL]))
                else:
                    iface.messageBar().pushMessage("Warning",
                                                   "No project url defined.",
                                                   level=QgsMessageBar.WARNING,
                                                   duration=0)
            except:
                # TODO: bare except. Also fails when there's a json if it is without project url.
                iface.messageBar().pushMessage(
                    "Error",
                    "No {} found.".format(JSON_NAME),
                    level=QgsMessageBar.CRITICAL,
                    duration=0)

    def show_login_dialog_voortgang(self):
        """
        Show the login dialog.

        If the user data typed in the login dialog is correct, a json
        is created from the shapefiles and uploaded to the server.
        """
        # Check if the manholes, pipes and measuring_points layers exist
        self.login_dialog = BeoordelingstoolLoginDialog()
        self.login_dialog.show()
        self.login_dialog.output.connect(self.upload_voortgang)

    def show_login_dialog_final(self):
        """
        Show the login dialog.

        If the user data typed in the login dialog is correct, a json
        is created from the shapefiles and uploaded to the server.
        A zip is also created from these shapefiles and json and uploaded
        to the server.
        """
        self.login_dialog = BeoordelingstoolLoginDialog()
        self.login_dialog.show()
        self.login_dialog.output.connect(self.upload_final)

    def upload_voortgang(self, user_data):
        """Upload the voortgang (json)."""
        print "voortgang"
        review_json = self.convert_shps_to_json()
        # upload json to server (get url from json)
        save_json_to_server(review_json, user_data)
        iface.messageBar().pushMessage("Info",
                                       "JSON uploaded.",
                                       level=QgsMessageBar.INFO,
                                       duration=0)

    def upload_final(self, user_data):
        """Upload the final version (json + zip with shapefiles and qmls)."""
        review_json = self.convert_shps_to_json()
        # Upload JSON
        save_json_to_server(review_json, user_data)
        # Upload zip
        # Check if the manholes, pipes and measuring_points layers exist
        manholes_layerList = QgsMapLayerRegistry.instance().mapLayersByName(
            SHP_NAME_MANHOLES)
        pipes_layerList = QgsMapLayerRegistry.instance().mapLayersByName(
            SHP_NAME_PIPES)
        measuring_points_layerList = QgsMapLayerRegistry.instance(
        ).mapLayersByName(SHP_NAME_MEASURING_POINTS)
        if manholes_layerList and pipes_layerList and measuring_points_layerList:
            # Get project name from the json saved in the same folder as the "manholes" layer
            layer_dir = get_layer_dir(manholes_layerList[0])
            temp_dir = tempfile.mkdtemp(prefix="beoordelingstool")
            project_name = review_json[JSON_KEY_PROJ][JSON_KEY_NAME]
            zip_url = review_json[JSON_KEY_PROJ][JSON_KEY_URL]
            create_zip(project_name, layer_dir, temp_dir)
            save_zip_to_server(project_name, temp_dir, zip_url, user_data)
            iface.messageBar().pushMessage("Info",
                                           "JSON and ZIP uploaded.",
                                           level=QgsMessageBar.INFO,
                                           duration=0)

    def convert_shps_to_json(self):
        """
        Convert the manholes, pipes and measuring points shapefiles to a json.

        Args:
            (dict) user_data: A dict containing the username and password.

        Returns:
            (dict) json_: A dict containing the information about the project and the shapefiles.
        """
        # Check if the manholes, pipes and measuring_points layers exist
        manholes_layerList = QgsMapLayerRegistry.instance().mapLayersByName(
            SHP_NAME_MANHOLES)
        pipes_layerList = QgsMapLayerRegistry.instance().mapLayersByName(
            SHP_NAME_PIPES)
        measuring_points_layerList = QgsMapLayerRegistry.instance(
        ).mapLayersByName(SHP_NAME_MEASURING_POINTS)
        if manholes_layerList and pipes_layerList and measuring_points_layerList:
            # Get directory to save json in
            layer_dir = get_layer_dir(manholes_layerList[0])
            json_path = os.path.join(layer_dir, JSON_NAME)
            # Pipes
            pipes = create_pipes_json(pipes_layerList[0],
                                      measuring_points_layerList[0])
            # Manholes
            manholes = create_manholes_json(manholes_layerList[0])
            json_ = {}
            json_project = {}
            if json_path:
                data = json.load(open(json_path))
                if data[JSON_KEY_PROJ][JSON_KEY_NAME]:
                    json_project[JSON_KEY_NAME] = data[JSON_KEY_PROJ][
                        JSON_KEY_NAME]
                else:
                    iface.messageBar().pushMessage(
                        "Error",
                        "No project name found.",
                        level=QgsMessageBar.CRITICAL,
                        duration=0)
                    return json_
                if data[JSON_KEY_PROJ][JSON_KEY_URL]:
                    json_project[JSON_KEY_URL] = data[JSON_KEY_PROJ][
                        JSON_KEY_URL]
                else:
                    iface.messageBar().pushMessage(
                        "Error",
                        "No project url found.",
                        level=QgsMessageBar.CRITICAL,
                        duration=0)
                    return json_
                if data[JSON_KEY_PROJ][JSON_KEY_SLUG]:
                    json_project[JSON_KEY_SLUG] = data[JSON_KEY_PROJ][
                        JSON_KEY_SLUG]
                else:
                    iface.messageBar().pushMessage(
                        "Error",
                        "No project slug found.",
                        level=QgsMessageBar.CRITICAL,
                        duration=0)
                    return json_
            else:
                iface.messageBar().pushMessage("Error",
                                               "No json found.",
                                               level=QgsMessageBar.CRITICAL,
                                               duration=0)
                return
            json_[JSON_KEY_PROJ] = json_project
            json_["pipes"] = pipes
            json_["manholes"] = manholes
            with open("{}".format(json_path), 'w') as outfile:
                json.dump(json_, outfile, indent=2)
            return json_
        else:
            iface.messageBar().pushMessage(
                "Warning",
                "You don't have a manholes, pipes and measuring_points layer.",
                level=QgsMessageBar.WARNING,
                duration=0)
            json_ = {}
            return json_

    def get_selected_manhole(self):
        layer = iface.activeLayer()
        for f in layer.selectedFeatures():
            self.field_combobox_manholes.setCurrentIndex(self.field_combobox_manholes.findText(str(f["Herstelmaa"]))) \
                if self.field_combobox_manholes.findText(str(f["Herstelmaa"])) else self.field_combobox_manholes.setCurrentIndex(0)
            self.value_plaintextedit_manholes.setPlainText(
                f["Opmerking"] if type(f["Opmerking"]
                                       ) is not QPyNullVariant else "")

            for index, field in enumerate(MANHOLE_FIELDS):
                value = f[field] if type(
                    f[field]) is not QPyNullVariant else ""
                self.tablewidget_manholes.setItem(0, index,
                                                  QTableWidgetItem(value))

            self.mark_feature(f)
            self.selected_manhole_id = f.id()

    def save_beoordeling_putten(self):
        """Save herstelmaatregel and opmerking in the shapefile."""
        layer = iface.activeLayer()
        manhole_id = self.selected_manhole_id
        if manhole_id is None:
            return
        herstelmaatregel = str(self.field_combobox_manholes.currentText())
        opmerking = str(self.value_plaintextedit_manholes.toPlainText())
        layer.startEditing()
        layer.changeAttributeValue(manhole_id, 55,
                                   herstelmaatregel)  # Herstelmaatregel
        layer.changeAttributeValue(manhole_id, 56, opmerking)  # Opmerking
        layer.commitChanges()
        layer.triggerRepaint()
        iface.messageBar().pushMessage("Info",
                                       "Manhole saved",
                                       level=QgsMessageBar.INFO,
                                       duration=5)

    def show_pipe(self):
        """Show the pipe to which a measuring point belongs."""
        measure_point = self.measuring_points.getFeatures(
            QgsFeatureRequest().setFilterFid(
                self.selected_measuring_point_id)).next()
        pipe_id = int(measure_point.attribute('PIPE_ID'))
        self.pipes.setSelectedFeatures([pipe_id])

    def get_selected_pipe(self):
        selected_pipes = self.pipes.selectedFeatures()
        if len(selected_pipes) > 1:
            # Set the pipe selection to the first pipe. This will cause a
            # selectionChanged-signal which will call this method again.
            self.pipes.setSelectedFeatures([selected_pipes[0].id()])
            return
        if len(selected_pipes) == 1:
            # always show the first pipe
            self.display_pipe(selected_pipes[0].id())

    def display_pipe(self, pipe_id):
        """Show the pipe_id attributes on the pipe-tab"""
        pipe = self.pipes.getFeatures(QgsFeatureRequest(pipe_id)).next()

        hestelmaatregel = self.field_combobox_pipes.findText(
            str(pipe["Herstelmaa"]))
        if hestelmaatregel:
            self.field_combobox_pipes.setCurrentIndex(hestelmaatregel)
        else:
            self.field_combobox_pipes.setCurrentIndex(0)

        opmerking = pipe['Opmerking']
        if opmerking:
            self.value_plaintextedit_pipes.setPlainText(opmerking)
        else:
            self.value_plaintextedit_pipes.setPlainText("")

        for index, field in enumerate(PIPE_FIELDS):
            value = pipe[field] if type(
                pipe[field]) is not QPyNullVariant else ""
            self.tablewidget_pipes.setItem(0, index, QTableWidgetItem(value))

        iface.setActiveLayer(self.pipes)
        self.pipes.triggerRepaint()
        # Go to the pipe tab
        self.tabWidget.setCurrentIndex(2)
        self.selected_pipe_id = pipe.id()

    def save_beoordeling_leidingen(self):
        """Save herstelmaatregel and opmerking in the shapefile."""
        layer = iface.activeLayer()
        pipe_id = self.selected_pipe_id
        if pipe_id is None:
            return
        herstelmaatregel = str(self.field_combobox_pipes.currentText())
        opmerking = str(self.value_plaintextedit_pipes.toPlainText())
        layer.startEditing()
        layer.changeAttributeValue(pipe_id, 68,
                                   herstelmaatregel)  # Herstelmaatregel
        layer.changeAttributeValue(pipe_id, 69, opmerking)  # Opmerking
        layer.commitChanges()
        layer.triggerRepaint()
        iface.messageBar().pushMessage("Info",
                                       "Pipe saved",
                                       level=QgsMessageBar.INFO,
                                       duration=5)

    def show_measuring_point(self):
        """Show the measuring point that belongs to a certain pipe."""
        if not self.measuring_points:
            iface.messageBar().pushMessage(
                "Error",
                "There is no measuring points layer.",
                level=QgsMessageBar.CRITICAL,
                duration=0)
            return

        expr = QgsExpression("\"PIPE_ID\" IS '{}'".format(
            self.selected_pipe_id))
        measuring_points = self.measuring_points.getFeatures(
            QgsFeatureRequest(expr))
        ids = [measuring_point.id() for measuring_point in measuring_points]
        if len(ids) == 0:
            iface.messageBar().pushMessage(
                "Warning",
                "There are no measuring points connected to this pipe.",
                level=QgsMessageBar.WARNING,
                duration=0)
            return

        # Setting the selected measure points causes the measure_points onchange to trigger
        # which calls get_selected_measuring_point() to display the measure point.
        self.measuring_points.setSelectedFeatures(ids)

        iface.setActiveLayer(self.measuring_points)
        self.measuring_points.triggerRepaint()
        # Go to measuring points tab
        self.tabWidget.setCurrentIndex(3)

    def _display_measuring_point_attributes(self, feature):
        self.mark_feature(feature)
        # Trigger
        trigger = feature.attribute('Trigger') or ''
        self.value_measpoint_trigger.setText(trigger)

        # Herstelmaatregel:
        hmr = 0 or self.field_combobox_measuring_points.findText(
            str(feature["Herstelmaa"]))
        self.field_combobox_measuring_points.setCurrentIndex(hmr)

        # Opmerking:
        self.value_plaintextedit_measuring_points.setPlainText(
            str(feature["Opmerking"]) if type(feature["Opmerking"]
                                              ) is not QPyNullVariant else "")

        # Pipe ID
        self.tablewidget_measuring_points.setItem(
            0, 0, QTableWidgetItem(feature["PIPE_ID"]))

        # Other attributes:
        field_names = set(field.name() for field in feature.fields())
        for idx, code in enumerate(list('ABCDEFGIJKLMNO'), start=1):
            if code == 'A':
                # Translate feature A into its description
                text_to_display = RIBX_CODE_DESCRIPTION_MAPPING.get(
                    feature["A"], feature["A"])
                self.tablewidget_measuring_points.setItem(
                    0, idx, QTableWidgetItem(text_to_display))
                continue

            input_text = ''
            if code in field_names:
                input_text = str(feature[code])

            self.tablewidget_measuring_points.setItem(
                0, idx, QTableWidgetItem(QTableWidgetItem(input_text, 1)))

    def mark_feature(self, feature):
        """Set the marker to feature"""
        self.measure_point_marker.setCenter(feature.geometry().asPoint())
        self.measure_point_marker.setVisible(True)

    def get_selected_measuring_point(self):
        layer = self.measuring_points
        measuring_point_ids = [
            feature.id() for feature in layer.selectedFeatures()
        ]
        if len(measuring_point_ids) > 0:
            # We have some measuring points in our selection
            # Display the first one:
            self.selected_measuring_points_ids = measuring_point_ids
            feature = layer.selectedFeatures()[0]
            self.selected_measuring_point_id = feature.id()
            self._display_measuring_point_attributes(feature)
            self.display_measuring_points_count()

    def show_previous_measuring_point(self):
        """Show the next measuring point."""
        current_index = self.selected_measuring_points_ids.index(
            self.selected_measuring_point_id)
        self.selected_measuring_point_id = self.selected_measuring_points_ids[
            current_index - 1]
        new_measuring_points = self.measuring_points.getFeatures(
            QgsFeatureRequest().setFilterFid(self.selected_measuring_point_id))
        new_measuring_point = list(new_measuring_points)[0]
        self._display_measuring_point_attributes(new_measuring_point)
        self.display_measuring_points_count()

    def show_next_measuring_point(self):
        """Show the next measuring point."""
        current_index = self.selected_measuring_points_ids.index(
            self.selected_measuring_point_id)
        self.selected_measuring_point_id = self.selected_measuring_points_ids[
            current_index + 1]
        new_measuring_points = self.measuring_points.getFeatures(
            QgsFeatureRequest().setFilterFid(self.selected_measuring_point_id))
        new_measuring_point = list(new_measuring_points)[0]
        self._display_measuring_point_attributes(new_measuring_point)
        self.display_measuring_points_count()

    def display_measuring_points_count(self):
        current = self.selected_measuring_points_ids.index(
            self.selected_measuring_point_id)
        total = len(self.selected_measuring_points_ids)
        self.Nr_measuring_points.setText('{} / {}'.format(current + 1, total))

        if current == 0:
            self.disable_previous_measuring_point_button()
        else:
            self.enable_previous_measuring_point_button()

        if current + 1 >= total:
            self.disable_next_measuring_point_button()
        elif current + 1 < total:
            self.enable_next_measuring_point_button()

    def disable_previous_measuring_point_button(self):
        self.pushbutton_measuring_points_previous.setDisabled(True)

    def enable_previous_measuring_point_button(self):
        self.pushbutton_measuring_points_previous.setEnabled(True)

    def disable_next_measuring_point_button(self):
        self.pushbutton_measuring_points_next.setDisabled(True)

    def enable_next_measuring_point_button(self):
        self.pushbutton_measuring_points_next.setEnabled(True)

    def save_beoordeling_measuring_points(self):
        """Save herstelmaatregel and opmerking in the shapefile."""
        layer = iface.activeLayer()
        measuring_point_id = self.selected_measuring_point_id
        if measuring_point_id is None:
            return
        herstelmaatregel = str(
            self.field_combobox_measuring_points.currentText())
        opmerking = str(
            self.value_plaintextedit_measuring_points.toPlainText())
        layer.startEditing()
        layer.changeAttributeValue(measuring_point_id, 16,
                                   herstelmaatregel)  # Herstelmaatregel
        layer.changeAttributeValue(measuring_point_id, 17,
                                   opmerking)  # Opmerking
        layer.commitChanges()
        layer.triggerRepaint()
        iface.messageBar().pushMessage("Info",
                                       "Measuring point saved",
                                       level=QgsMessageBar.INFO,
                                       duration=5)
コード例 #20
0
class gazetteerSearch:
    def __init__(self, iface):
        self.dock = None
        self.results = []
        # Save reference to the QGIS interface
        self.iface = iface
        self.iface.newProjectCreated.connect(self._hideMarker)
        self.iface.projectRead.connect(self._hideMarker)
        self.canvas = self.iface.mapCanvas()
        self.marker = QgsVertexMarker(self.iface.mapCanvas())
        self.marker.setIconSize(20)
        self.marker.setPenWidth(3)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.marker.hide()

        # Create the dialog and keep reference
        self.widget = gazetteerSearchDialog()
        self.widget.runSearch.connect(self.runSearch)
        self.widget.ui.clearButton.pressed.connect(self.clearResults)
        self.widget.zoomRequested.connect(self.zoomTo)
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDbFilePath()).path(
        ) + "/python/plugins/gazetteersearch"
        # initialize locale
        localePath = ""
        locale = QSettings().value("locale/userLocale").toString()[0:2]

        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/gazetteersearch_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)

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

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/gazetteersearch/icon.png"), \
            u"Gazetteer Search", 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(u"&Gazetteer Search", self.action)

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(u"&Gazetteer Search", self.action)
        self.iface.removeToolBarIcon(self.action)
        self.iface.mapCanvas().scene().removeItem(self.marker)
        self.marker = None

    def _hideMarker(self):
        self.marker.hide()

    # run method that performs all the real work
    def run(self):
        if not self.dock:
            self.dock = QDockWidget("Gazetteer Search",
                                    self.iface.mainWindow())
            self.dock.setWidget(self.widget)
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock)
            self.gazetteers = common.getGazetteers()
            for gazetter in self.gazetteers.iterkeys():
                self.widget.addGazetter(gazetter)

            if len(self.gazetteers) == 1:
                self.widget.hideGazetteers()
        else:
            self.dock.show()

    def runSearch(self, searchString, selectedGazetteer):
        gazetteer_config = self.gazetteers[str(selectedGazetteer)]
        gazetteer = self.getGazetteerModule(gazetteer_config)
        url = common.prepareURL(gazetteer.url, gazetteer.params, searchString)
        data = common.search(url)

        try:
            self.results = list(gazetteer.parseRequestResults(data))
        except ValueError:
            self.results = []

        if len(self.results) == 0:
            self.widget.addError('No results found for "%s"' % searchString)

        for res in self.results:
            self.widget.addResult(res.description)

    def clearResults(self):
        self.widget.clearResults()
        self.marker.hide()

    def getGazetteerModule(self, config):
        gazetteer_module = config['gazetteer']
        imported_gazetteer = import_module('gazetteers.%s' % gazetteer_module)
        return imported_gazetteer

    def zoomTo(self, name):
        for res in self.results:
            if unicode(res.description) == unicode(name):
                dest_crs = self.canvas.mapRenderer().destinationCrs()
                src_crs = QgsCoordinateReferenceSystem()
                src_crs.createFromEpsg(res.epsg)
                transform = QgsCoordinateTransform(src_crs, dest_crs)
                new_point = transform.transform(res.x, res.y)
                x = new_point.x()
                y = new_point.y()
                self.canvas.setExtent(QgsRectangle(x, y, x, y))
                self.canvas.zoomScale(res.zoom)
                self.canvas.refresh()
                self.marker.setCenter(new_point)
                self.marker.show()
                return
コード例 #21
0
class ProfileDockWidget(QDockWidget):
    """
    DockWidget class to display the profile
    """

    closeSignal = pyqtSignal()

    def __init__(self, iface, geometry, mntButton=False, zerosButton=False):
        """
        Constructor
        :param iface: interface
        :param width: dock widget geometry
        """
        QDockWidget.__init__(self)
        self.setWindowTitle(QCoreApplication.translate("VDLTools", "Profile Tool"))
        self.__iface = iface
        self.__geom = geometry
        self.__canvas = self.__iface.mapCanvas()
        self.__types = ['PDF', 'PNG']  # ], 'SVG', 'PS']
        self.__libs = []
        if Qwt5_loaded:
            self.__lib = 'Qwt5'
            self.__libs.append('Qwt5')
            if matplotlib_loaded:
                self.__libs.append('Matplotlib')
        elif matplotlib_loaded:
            self.__lib = 'Matplotlib'
            self.__libs.append('Matplotlib')
        else:
            self.__lib = None
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "No graph lib available (qwt5 or matplotlib)"),
                level=QgsMessageBar.CRITICAL, duration=0)

        self.__doTracking = False
        self.__vline = None

        self.__profiles = None
        self.__numLines = None
        self.__mntPoints = None

        self.__marker = None
        self.__tabmouseevent = None

        if self.__geom is not None:
            self.setGeometry(self.__geom)

        self.__contentWidget = QWidget()
        self.setWidget(self.__contentWidget)

        self.__boxLayout = QHBoxLayout()
        self.__contentWidget.setLayout(self.__boxLayout)

        self.__plotFrame = QFrame()
        self.__frameLayout = QHBoxLayout()
        self.__plotFrame.setLayout(self.__frameLayout)

        self.__printLayout = QHBoxLayout()
        self.__printLayout.addWidget(self.__plotFrame)

        self.__legendLayout = QVBoxLayout()
        self.__printLayout.addLayout(self.__legendLayout)

        self.__printWdg = QWidget()
        self.__printWdg.setLayout(self.__printLayout)

        self.__plotWdg = None
        self.__changePlotWidget()

        size = QSize(150, 20)

        self.__boxLayout.addWidget(self.__printWdg)

        self.__vertLayout = QVBoxLayout()

        self.__libCombo = QComboBox()
        self.__libCombo.setFixedSize(size)
        self.__libCombo.addItems(self.__libs)
        self.__vertLayout.addWidget(self.__libCombo)
        self.__libCombo.currentIndexChanged.connect(self.__setLib)

        if mntButton:
            self.__displayMnt = False
            self.__mntButton = QPushButton(QCoreApplication.translate("VDLTools", "Display MNT"))
            self.__mntButton.setFixedSize(size)
            self.__mntButton.clicked.connect(self.__mnt)
            self.__vertLayout.addWidget(self.__mntButton)

        if zerosButton:
            self.__displayZeros = False
            self.__zerosButton = QPushButton(QCoreApplication.translate("VDLTools", "Display Zeros"))
            self.__zerosButton.setFixedSize(size)
            self.__zerosButton.clicked.connect(self.__zeros)
            self.__vertLayout.addWidget(self.__zerosButton)
        else:
            self.__displayZeros = True

        self.__maxLabel = QLabel("y max")
        self.__maxLabel.setFixedSize(size)
        self.__vertLayout.addWidget(self.__maxLabel)
        self.__maxSpin = QSpinBox()
        self.__maxSpin.setFixedSize(size)
        self.__maxSpin.setRange(-10000, 10000)
        self.__maxSpin.valueChanged.connect(self.__reScalePlot)
        self.__vertLayout.addWidget(self.__maxSpin)
        self.__vertLayout.insertSpacing(10, 20)

        self.__minLabel = QLabel("y min")
        self.__minLabel.setFixedSize(size)
        self.__vertLayout.addWidget(self.__minLabel)
        self.__minSpin = QSpinBox()
        self.__minSpin.setFixedSize(size)
        self.__minSpin.setRange(-10000, 10000)
        self.__minSpin.valueChanged.connect(self.__reScalePlot)
        self.__vertLayout.addWidget(self.__minSpin)
        self.__vertLayout.insertSpacing(10, 40)

        self.__typeCombo = QComboBox()
        self.__typeCombo.setFixedSize(size)
        self.__typeCombo.addItems(self.__types)
        self.__vertLayout.addWidget(self.__typeCombo)
        self.__saveButton = QPushButton(QCoreApplication.translate("VDLTools", "Save"))
        self.__saveButton.setFixedSize(size)
        self.__saveButton.clicked.connect(self.__save)
        self.__vertLayout.addWidget(self.__saveButton)

        self.__boxLayout.addLayout(self.__vertLayout)

        self.__maxSpin.setEnabled(False)
        self.__minSpin.setEnabled(False)

        self.__colors = []
        for cn in QColor.colorNames():
            qc = QColor(cn)
            val = qc.red() + qc.green() + qc.blue()
            if 0 < val < 450:
                self.__colors.append(cn)

    def mntButton(self):
        """
        To get the mnt button instance
        :return: mnt button instance
        """
        return self.__mntButton

    def zerosButton(self):
        """
        To get the zeros button instance
        :return: zeros button instance
        """
        return self.__zerosButton

    def displayMnt(self):
        """
        To get if we want to display mnt
        :return: true or false
        """
        return self.__displayMnt

    def __mnt(self):
        """
        To toggle mnt display choice
        """
        if self.__displayMnt:
            self.__displayMnt = False
            self.__mntButton.setText(QCoreApplication.translate("VDLTools", "Display MNT"))
        else:
            self.__displayMnt = True
            self.__mntButton.setText(QCoreApplication.translate("VDLTools", "Remove MNT"))

    def __zeros(self):
        """
        To toggle if we want to display zero elevations or not
        """
        if self.__displayZeros:
            self.__displayZeros = False
            self.__zerosButton.setText(QCoreApplication.translate("VDLTools", "Display Zeros"))
        else:
            self.__displayZeros = True
            self.__zerosButton.setText(QCoreApplication.translate("VDLTools", "Remove Zeros"))

    def __changePlotWidget(self):
        """
        When plot widget is change (qwt <-> matplotlib)
        """
        self.__activateMouseTracking(False)
        while self.__frameLayout.count():
            child = self.__frameLayout.takeAt(0)
            child.widget().deleteLater()
        self.__plotWdg = None

        if self.__lib == 'Qwt5':
            self.__plotWdg = QwtPlot(self.__plotFrame)
            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            sizePolicy.setHorizontalStretch(10)
            sizePolicy.setVerticalStretch(0)
            self.__plotWdg.setSizePolicy(sizePolicy)
            self.__plotWdg.setAutoFillBackground(False)
            # Decoration
            self.__plotWdg.setCanvasBackground(Qt.white)
            self.__plotWdg.plotLayout().setAlignCanvasToScales(False)
            self.__plotWdg.plotLayout().setSpacing(100)
            self.__plotWdg.plotLayout().setCanvasMargin(10, QwtPlot.xBottom)
            self.__plotWdg.plotLayout().setCanvasMargin(10, QwtPlot.yLeft)
            title = QwtText(QCoreApplication.translate("VDLTools", "Distance [m]"))
            title.setFont(QFont("Helvetica", 10))
            self.__plotWdg.setAxisTitle(QwtPlot.xBottom, title)
            title.setText(QCoreApplication.translate("VDLTools", "Elevation [m]"))
            title.setFont(QFont("Helvetica", 10))
            self.__plotWdg.setAxisTitle(QwtPlot.yLeft, title)
            self.__zoomer = QwtPlotZoomer(QwtPlot.xBottom, QwtPlot.yLeft, QwtPicker.DragSelection, QwtPicker.AlwaysOff,
                                          self.__plotWdg.canvas())
            self.__zoomer.setRubberBandPen(QPen(Qt.blue))
            grid = QwtPlotGrid()
            grid.setPen(QPen(QColor('grey'), 0, Qt.DotLine))
            grid.attach(self.__plotWdg)
            self.__frameLayout.addWidget(self.__plotWdg)

        elif self.__lib == 'Matplotlib':
            fig = Figure((1.0, 1.0), linewidth=0.0, subplotpars=SubplotParams(left=0, bottom=0, right=1, top=1,
                                                                              wspace=0, hspace=0))

            font = {'family': 'arial', 'weight': 'normal', 'size': 12}
            rc('font', **font)

            rect = fig.patch
            rect.set_facecolor((0.9, 0.9, 0.9))

            self.__axes = fig.add_axes((0.07, 0.16, 0.92, 0.82))
            self.__axes.set_xbound(0, 1000)
            self.__axes.set_ybound(0, 1000)
            self.__manageMatplotlibAxe(self.__axes)
            self.__plotWdg = FigureCanvasQTAgg(fig)
            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            self.__plotWdg.setSizePolicy(sizePolicy)
            self.__frameLayout.addWidget(self.__plotWdg)

    def setProfiles(self, profiles, numLines):
        """
        To set the profiles
        :param profiles: profiles : positions with elevations (for line and points)
        :param numLines: number of selected connected lines
        """
        self.__numLines = numLines
        self.__profiles = profiles
        if self.__lib == 'Matplotlib':
            self.__prepare_points()

    def __getLinearPoints(self):
        """
        To extract the linear points of the profile
        """
        profileLen = 0
        self.__profiles[0]['l'] = profileLen
        for i in range(0, len(self.__profiles)-1):
            x1 = float(self.__profiles[i]['x'])
            y1 = float(self.__profiles[i]['y'])
            x2 = float(self.__profiles[i+1]['x'])
            y2 = float(self.__profiles[i+1]['y'])
            profileLen += sqrt(((x2-x1)*(x2-x1)) + ((y2-y1)*(y2-y1)))
            self.__profiles[i+1]['l'] = profileLen

    def __getMnt(self, settings):
        """
        To get the MN data for the profile
        :param settings: settings containing MN url
        """
        if settings is None or settings.mntUrl is None or settings.mntUrl == "None":
            url = 'https://map.lausanne.ch/prod/wsgi/profile.json'
        elif settings.mntUrl == "":
            return
        else:
            url = settings.mntUrl
        names = ['MNT', 'MNS', 'Rocher (approx.)']
        data = "layers=MNT%2CMNS%2CRocher%20(approx.)&geom=%7B%22type%22%3A%22LineString%22%2C%22coordinates%22%3A%5B"

        pos = 0
        for i in range(len(self.__profiles)):
            if pos > 0:
                data += "%2C"
            pos += 1
            data += "%5B" + str(self.__profiles[i]['x']) + "%2C" + str(self.__profiles[i]['y']) + "%5D"
        data += "%5D%7D&nbPoints=" + str(int(self.__profiles[len(self.__profiles)-1]['l']+1))
        try:
            response = requests.post(url, data=data)
            j = response.text
            j_obj = json.loads(j)
            profile = j_obj['profile']
            self.__mntPoints = []
            self.__mntPoints.append(names)
            mnt_l = []
            mnt_z = []
            for p in range(len(names)):
                z = []
                mnt_z.append(z)
            for pt in profile:
                mnt_l.append(float(pt['dist']))
                values = pt['values']
                for p in range(len(names)):
                    if names[p] in values:
                        mnt_z[p].append(float(values[names[p]]))
                    else:
                        mnt_z[p].append(None)
            self.__mntPoints.append(mnt_l)
            self.__mntPoints.append(mnt_z)
        except HTTPError as e:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "HTTP Error"),
                QCoreApplication.translate("VDLTools", "status error") + "[" + str(e.code) + "] : " + e.reason,
                level=QgsMessageBar.CRITICAL, duration=0)
        except URLError as e:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "URL Error"),
                e.reason, level=QgsMessageBar.CRITICAL, duration=0)
        except ValueError as e:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "No MNT values here"),
                level=QgsMessageBar.CRITICAL, duration=0)


    def attachCurves(self, names, settings, usedMnts):
        """
        To attach the curves for the layers to the profile
        :param names: layers names
        """
        if (self.__profiles is None) or (self.__profiles == 0):
            return

        self.__getLinearPoints()
        if usedMnts is not None and (usedMnts[0] or usedMnts[1] or usedMnts[2]):
            self.__getMnt(settings)

        c = 0

        if self.__mntPoints is not None:
                for p in range(len(self.__mntPoints[0])):
                    if usedMnts[p]:
                        legend = QLabel("<font color='" + self.__colors[c] + "'>" + self.__mntPoints[0][p]
                                        + "</font>")
                        self.__legendLayout.addWidget(legend)

                        if self.__lib == 'Qwt5':

                            xx = [list(g) for k, g in itertools.groupby(self.__mntPoints[1],
                                                                        lambda x: x is None) if not k]
                            yy = [list(g) for k, g in itertools.groupby(self.__mntPoints[2][p], lambda x: x is None)
                                  if not k]

                            for j in range(len(xx)):
                                curve = QwtPlotCurve(self.__mntPoints[0][p])
                                curve.setData(xx[j], yy[j])
                                curve.setPen(QPen(QColor(self.__colors[c]), 3))
                                curve.attach(self.__plotWdg)

                        elif self.__lib == 'Matplotlib':
                            qcol = QColor(self.__colors[c])
                            self.__plotWdg.figure.get_axes()[0].plot(self.__mntPoints[1], self.__mntPoints[2][p],
                                                                     gid=self.__mntPoints[0][p], linewidth=3)
                            tmp = self.__plotWdg.figure.get_axes()[0].get_lines()
                            for t in range(len(tmp)):
                                if self.__mntPoints[0][p] == tmp[t].get_gid():
                                    tmp[c].set_color((old_div(qcol.red(), 255.0), old_div(qcol.green(), 255.0),
                                                      old_div(qcol.blue(), 255.0), old_div(qcol.alpha(), 255.0)))
                                    self.__plotWdg.draw()
                                    break
                        c += 1

        if 'z' in self.__profiles[0]:
            for i in range(len(self.__profiles[0]['z'])):
                if i < self.__numLines:
                    v = 0
                else:
                    v = i - self.__numLines + 1
                name = names[v]
                xx = []
                yy = []
                for prof in self.__profiles:
                    xx.append(prof['l'])
                    yy.append(prof['z'][i])

                for j in range(len(yy)):
                    if yy[j] is None:
                        xx[j] = None

                if i == 0 or i > (self.__numLines-1):
                    legend = QLabel("<font color='" + self.__colors[c] + "'>" + name + "</font>")
                    self.__legendLayout.addWidget(legend)

                if self.__lib == 'Qwt5':

                    # Split xx and yy into single lines at None values
                    xx = [list(g) for k, g in itertools.groupby(xx, lambda x: x is None) if not k]
                    yy = [list(g) for k, g in itertools.groupby(yy, lambda x: x is None) if not k]

                    # Create & attach one QwtPlotCurve per one single line
                    for j in range(len(xx)):
                        curve = QwtPlotCurve(name)
                        curve.setData(xx[j], yy[j])
                        curve.setPen(QPen(QColor(self.__colors[c]), 3))
                        if i > (self.__numLines-1):
                            curve.setStyle(QwtPlotCurve.Dots)
                            pen = QPen(QColor(self.__colors[c]), 8)
                            pen.setCapStyle(Qt.RoundCap)
                            curve.setPen(pen)
                        curve.attach(self.__plotWdg)

                elif self.__lib == 'Matplotlib':
                    qcol = QColor(self.__colors[c])
                    if i < self.__numLines:
                        self.__plotWdg.figure.get_axes()[0].plot(xx, yy, gid=name, linewidth=3)
                    else:
                        self.__plotWdg.figure.get_axes()[0].plot(xx, yy, gid=name, linewidth=5, marker='o',
                                                                 linestyle='None')
                    tmp = self.__plotWdg.figure.get_axes()[0].get_lines()
                    for t in range(len(tmp)):
                        if name == tmp[t].get_gid():
                            tmp[c].set_color((old_div(qcol.red(), 255.0), old_div(qcol.green(), 255.0),
                                              old_div(qcol.blue(), 255.0), old_div(qcol.alpha(), 255.0)))
                            self.__plotWdg.draw()
                            break
                c += 1

        # scaling this
        try:
            self.__reScalePlot(None, True)
        except:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Rescale problem... (trace printed)"),
                level=QgsMessageBar.CRITICAL, duration=0)
            print(sys.exc_info()[0], traceback.format_exc())
        if self.__lib == 'Qwt5':
            self.__plotWdg.replot()
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].redraw_in_frame()
            self.__plotWdg.draw()
            self.__activateMouseTracking(True)
            self.__marker.show()

    def __reScalePlot(self, value=None, auto=False):
        """
        To rescale the profile plot depending to the bounds
        :param value: juste because connections give value
        :param auto: if automatic ranges calcul is wanted
        """
        if (self.__profiles is None) or (self.__profiles == 0):
            self.__plotWdg.replot()
            return

        maxi = 0
        for i in range(len(self.__profiles)):
            if (ceil(self.__profiles[i]['l'])) > maxi:
                maxi = ceil(self.__profiles[i]['l'])
        if self.__lib == 'Qwt5':
            self.__plotWdg.setAxisScale(2, 0, maxi, 0)
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].set_xbound(0, maxi)

        minimumValue = self.__minSpin.value()
        maximumValue = self.__maxSpin.value()

        # to set max y and min y displayed
        if auto:
            minimumValue = 1000000000
            maximumValue = -1000000000
            for i in range(len(self.__profiles)):
                if 'z' in self.__profiles[i]:
                    mini = self.__minTab(self.__profiles[i]['z'])
                    if (mini > 0 or self.__displayZeros) and mini < minimumValue:
                        minimumValue = ceil(mini) - 1
                    maxi = self.__maxTab(self.__profiles[i]['z'])
                    if maxi > maximumValue:
                        maximumValue = floor(maxi) + 1
                if self.__mntPoints is not None:
                    for pts in self.__mntPoints[2]:
                        miniMnt = self.__minTab(pts)
                        if (miniMnt > 0 or self.__displayZeros) and miniMnt < minimumValue:
                            minimumValue = ceil(miniMnt) - 1
                        maxiMnt = self.__maxTab(pts)
                        if maxiMnt > maximumValue:
                            maximumValue = floor(maxiMnt) + 1
        self.__maxSpin.setValue(maximumValue)
        self.__minSpin.setValue(minimumValue)
        self.__maxSpin.setEnabled(True)
        self.__minSpin.setEnabled(True)

        if self.__lib == 'Qwt5':
            rect = QRectF(0, minimumValue, maxi, maximumValue-minimumValue)
            self.__zoomer.setZoomBase(rect)

        # to draw vertical lines
        for i in range(len(self.__profiles)):
            zz = []
            for j in range(self.__numLines):
                if self.__profiles[i]['z'][j] is not None:
                    zz.append(j)
            color = None
            if len(zz) == 2:
                width = 3
                color = QColor('red')
            else:
                width = 1

            if self.__lib == 'Qwt5':
                vertLine = QwtPlotMarker()
                vertLine.setLineStyle(QwtPlotMarker.VLine)
                pen = vertLine.linePen()
                pen.setWidth(width)
                if color is not None:
                    pen.setColor(color)
                vertLine.setLinePen(pen)
                vertLine.setXValue(self.__profiles[i]['l'])
                label = vertLine.label()
                label.setText(str(i))
                vertLine.setLabel(label)
                vertLine.setLabelAlignment(Qt.AlignLeft)
                vertLine.attach(self.__plotWdg)
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.get_axes()[0].vlines(self.__profiles[i]['l'], minimumValue, maximumValue,
                                                           linewidth=width)

        if minimumValue < maximumValue:
            if self.__lib == 'Qwt5':
                self.__plotWdg.setAxisScale(0, minimumValue, maximumValue, 0)
                self.__plotWdg.replot()
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.get_axes()[0].set_ybound(minimumValue, maximumValue)
                self.__plotWdg.figure.get_axes()[0].redraw_in_frame()
                self.__plotWdg.draw()

    @staticmethod
    def __minTab(tab):
        """
        To get the minimum value in a table
        :param tab: table to scan
        :return: minimum value
        """
        mini = 1000000000
        for t in tab:
            if t is None:
                continue
            if t < mini:
                mini = t
        return mini

    @staticmethod
    def __maxTab(tab):
        """
        To get the maximum value in a table
        :param tab: table to scan
        :return: maximum value
        """
        maxi = -1000000000
        for t in tab:
            if t is None:
                continue
            if t > maxi:
                maxi = t
        return maxi

    def __setLib(self):
        """
        To set the new widget library (qwt <-> matplotlib)
        """
        self.__lib = self.__libs[self.__libCombo.currentIndex()]
        self.__changePlotWidget()

    def __save(self):
        """
        To save the profile in a file, on selected format
        """
        idx = self.__typeCombo.currentIndex()
        if idx == 0:
            self.__outPDF()
        elif idx == 1:
            self.__outPNG()
        else:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Invalid index ") + str(idx),
                level=QgsMessageBar.CRITICAL, duration=0)

    def __outPDF(self):
        """
        To save the profile as pdf file
        """
        fileName = QFileDialog.getSaveFileName(
            self.__iface.mainWindow(), QCoreApplication.translate("VDLTools", "Save As"),
            QCoreApplication.translate("VDLTools", "Profile.pdf"),"Portable Document Format (*.pdf)")
        if fileName is not None:
            if self.__lib == 'Qwt5':
                printer = QPrinter()
                printer.setCreator(QCoreApplication.translate("VDLTools", "QGIS Profile Plugin"))
                printer.setOutputFileName(fileName)
                printer.setOutputFormat(QPrinter.PdfFormat)
                printer.setOrientation(QPrinter.Landscape)
                self.__plotWdg.print_(printer)
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.savefig(str(fileName))

    def __outPNG(self):
        """
        To save the profile as png file
        """
        fileName = QFileDialog.getSaveFileName(
            self.__iface.mainWindow(), QCoreApplication.translate("VDLTools", "Save As"),
            QCoreApplication.translate("VDLTools", "Profile.png"),"Portable Network Graphics (*.png)")
        if fileName is not None:
            QPixmap.grabWidget(self.__printWdg).save(fileName, "PNG")

    def clearData(self):
        """
        To clear the displayed data
        """
        if self.__profiles is None:
            return
        if self.__lib == 'Qwt5':
            self.__plotWdg.clear()
            self.__profiles = None
            temp1 = self.__plotWdg.itemList()
            for j in range(len(temp1)):
                if temp1[j].rtti() == QwtPlotItem.Rtti_PlotCurve:
                    temp1[j].detach()
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].cla()
            self.__manageMatplotlibAxe(self.__plotWdg.figure.get_axes()[0])
        self.__maxSpin.setEnabled(False)
        self.__minSpin.setEnabled(False)
        self.__maxSpin.setValue(0)
        self.__minSpin.setValue(0)

        # clear legend
        while self.__legendLayout.count():
            child = self.__legendLayout.takeAt(0)
            child.widget().deleteLater()

    def __manageMatplotlibAxe(self, axe):
        """
        To manage the axes for matplotlib library
        :param axe: the axes element
        """
        axe.grid()
        axe.tick_params(axis="both", which="major", direction="out", length=10, width=1, bottom=True, top=False,
                        left=True, right=False)
        axe.minorticks_on()
        axe.tick_params(axis="both", which="minor", direction="out", length=5, width=1, bottom=True, top=False,
                        left=True, right=False)
        axe.set_xlabel(QCoreApplication.translate("VDLTools", "Distance [m]"))
        axe.set_ylabel(QCoreApplication.translate("VDLTools", "Elevation [m]"))

    def __activateMouseTracking(self, activate):
        """
        To (de)activate the mouse tracking on the profile for matplotlib library
        :param activate: true to activate, false to deactivate
        """
        if activate:
            self.__doTracking = True
            self.__loadRubber()
            self.cid = self.__plotWdg.mpl_connect('motion_notify_event', self.__mouseevent_mpl)
        elif self.__doTracking:
            self.__doTracking = False
            self.__plotWdg.mpl_disconnect(self.cid)
            if self.__marker is not None:
                self.__canvas.scene().removeItem(self.__marker)
            try:
                if self.__vline is not None:
                    self.__plotWdg.figure.get_axes()[0].lines.remove(self.__vline)
                    self.__plotWdg.draw()
            except Exception as e:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools", "Tracking exception : ") + str(e),
                    level=QgsMessageBar.CRITICAL, duration=0)

    def __mouseevent_mpl(self, event):
        """
        To manage matplotlib mouse tracking event
        :param event: mouse tracking event
        """
        if event.xdata is not None:
            try:
                if self.__vline is not None:
                    self.__plotWdg.figure.get_axes()[0].lines.remove(self.__vline)
            except Exception as e:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools", "Mouse event exception : ") + str(e),
                    level=QgsMessageBar.CRITICAL, duration=0)
            xdata = float(event.xdata)
            self.__vline = self.__plotWdg.figure.get_axes()[0].axvline(xdata, linewidth=2, color='k')
            self.__plotWdg.draw()
            i = 1
            while i < len(self.__tabmouseevent)-1 and xdata > self.__tabmouseevent[i][0]:
                i += 1
            i -= 1

            x = self.__tabmouseevent[i][1] + (self.__tabmouseevent[i + 1][1] - self.__tabmouseevent[i][1]) / (
            self.__tabmouseevent[i + 1][0] - self.__tabmouseevent[i][0]) * (xdata - self.__tabmouseevent[i][0])
            y = self.__tabmouseevent[i][2] + (self.__tabmouseevent[i + 1][2] - self.__tabmouseevent[i][2]) / (
            self.__tabmouseevent[i + 1][0] - self.__tabmouseevent[i][0]) * (xdata - self.__tabmouseevent[i][0])
            self.__marker.show()
            self.__marker.setCenter(QgsPoint(x, y))

    def __loadRubber(self):
        """
        To load te rubber band for mouse tracking on map
        """
        self.__marker = QgsVertexMarker(self.__canvas)
        self.__marker.setIconSize(5)
        self.__marker.setIconType(QgsVertexMarker.ICON_BOX)
        self.__marker.setPenWidth(3)

    def __prepare_points(self):
        """
        To prepare the points on map for mouse tracking on profile
        """
        self.__tabmouseevent = []
        length = 0
        for i, point in enumerate(self.__profiles):
            if i == 0:
                self.__tabmouseevent.append([0, point['x'], point['y']])
            else:
                length += ((self.__profiles[i]['x'] - self.__profiles[i-1]['x']) ** 2 +
                           (self.__profiles[i]['y'] - self.__profiles[i-1]['y']) ** 2) ** 0.5
                self.__tabmouseevent.append([float(length), float(point['x']), float(point['y'])])

    def closeEvent(self, event):
        """
        When the dock widget is closed
        :param event: close event
        """
        if self.__maxSpin is not None:
            Signal.safelyDisconnect(self.__maxSpin.valueChanged, self.__reScalePlot)
            self.__maxSpin = None
        if self.__minSpin is not None:
            Signal.safelyDisconnect(self.__minSpin.valueChanged, self.__reScalePlot)
            self.__minSpin = None
        if self.__saveButton is not None:
            Signal.safelyDisconnect(self.__saveButton.clicked, self.__save)
            self.__saveButton = None
        if self.__libCombo is not None:
            Signal.safelyDisconnect(self.__libCombo.currentIndexChanged, self.__setLib)
            self.__libCombo = None
        self.closeSignal.emit()
        if self.__marker is not None:
            self.__marker.hide()
        QDockWidget.closeEvent(self, event)
コード例 #22
0
class StartDrawing(QgsMapToolEmitPoint):
    def __init__(self, canvas, iface):
        QgsMapToolEmitPoint.__init__(self, canvas)

        # qgis interface
        self.canvas = canvas
        self.iface = iface

        # snap marker
        self.snap_mark = QgsVertexMarker(self.canvas)
        self.snap_mark.setColor(QColor(0, 0, 255))
        self.snap_mark.setPenWidth(2)
        self.snap_mark.setIconType(QgsVertexMarker.ICON_BOX)
        self.snap_mark.setIconSize(10)

        # rectangle
        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.GeometryType(3))
        self.rubberBand.setWidth(3)
        self.rubberBand.setStrokeColor(QColor(254, 0, 0))

        # initialize variable
        self.rubberBand_width = 0
        self.rubberBand_height = 0
        self.rubberBand_angle = 0

        self.reset()

    def setConfiguration(self, width, height, angle):
        self.rubberBand_width = width
        self.rubberBand_height = height
        self.rubberBand_angle = angle

    def reset(self):
        self.rubberBand.reset(QgsWkbTypes.GeometryType(3))
        self.isEmittingPoint = False

    def canvasMoveEvent(self, e):
        self.snap_mark.hide()
        self.snapPoint = False
        self.rubberBand.reset(QgsWkbTypes.GeometryType(3))

        self.snapPoint = self.checkSnapToPoint(e.pos())

        if self.snapPoint[0]:
            self.snap_mark.setCenter(self.snapPoint[1])
            self.snap_mark.show()
            self.rectangle = self.getRectangle(self.snapPoint[1])
            self.rubberBand.setToGeometry(self.rectangle, None)
            self.rubberBand.show()

        else:
            self.rectangle = self.getRectangle(self.toMapCoordinates(e.pos()))
            self.rubberBand.setToGeometry(self.rectangle, None)
            self.rubberBand.show()

    def checkSnapToPoint(self, point):
        snapped = False
        snap_point = self.toMapCoordinates(point)
        snapper = self.canvas.snappingUtils()
        snapMatch = snapper.snapToMap(point)
        if snapMatch.hasVertex():
            snap_point = snapMatch.point()
            snapped = True
        return snapped, snap_point

    def canvasPressEvent(self, e):
        if self.snapPoint == False:
            point = self.toMapCoordinates(self.canvas.mouseLastXY())
        else:
            point = self.snapPoint[1]

        layer = self.iface.activeLayer()

        layer_crs = layer.crs().authid()
        layer_crs = QgsCoordinateReferenceSystem(layer_crs)
        canvas_crs = self.canvas.mapSettings().destinationCrs().authid()
        canvas_crs = QgsCoordinateReferenceSystem(canvas_crs)
        crs2crs = QgsCoordinateTransform(canvas_crs, layer_crs,
                                         QgsProject.instance())

        feature = QgsFeature()
        fields = layer.fields()
        feature.setFields(fields)

        if layer.wkbType() == QgsWkbTypes.Polygon or layer.wkbType(
        ) == QgsWkbTypes.MultiPolygon:
            if layer_crs == canvas_crs:
                feature.setGeometry(self.rectangle)
            else:
                geom = self.rectangle
                geom.transform(crs2crs)
                feature.setGeometry(geom)

            layer.startEditing()
            layer.addFeature(feature)
            layer.commitChanges()
            layer.reload()
        else:
            self.iface.messageBar().pushCritical(
                'QRectangle Creator: ',
                'The current layer is not of Polygon or MultiPolygon type. The object has not been added'
            )

    def getRectangle(self, point):
        polygon = QgsWkbTypes.GeometryType(3)

        x = point.x()
        y = point.y()

        points = [[
            QgsPointXY(  # Left Top corner
                x - (self.rubberBand_width / 2),
                y + (self.rubberBand_height / 2)),
            QgsPointXY(  # Right Top corner
                x + (self.rubberBand_width / 2),
                y + (self.rubberBand_height / 2)),
            QgsPointXY(  # Right Down corner
                x + (self.rubberBand_width / 2),
                y - (self.rubberBand_height / 2)),
            QgsPointXY(  # Left Down corner
                x - (self.rubberBand_width / 2),
                y - (self.rubberBand_height / 2))
        ]]
        polygon = QgsGeometry.fromPolygonXY(points)
        polygon.rotate(self.rubberBand_angle, point)
        return polygon
コード例 #23
0
class ParentMapTool(QgsMapTool):
    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.show_help = bool(int(self.settings.value('status/show_help', 1)))
        self.index_action = index_action
        self.layer_arc = None
        self.layer_connec = None
        self.layer_node = None

        self.layer_arc_man = None
        self.layer_connec_man = None
        self.layer_node_man = None
        self.layer_gully_man = None

        self.schema_name = None
        self.controller = None
        self.dao = None

        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Snapper
        self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper = QgsMapCanvasSnapper(self.canvas)

        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)

        # Get default cursor
        self.std_cursor = self.parent().cursor()

        # Set default vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

        # Set default rubber band
        color_selection = QColor(254, 178, 76, 63)
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubber_band.setColor(color)
        self.rubber_band.setFillColor(color_selection)
        self.rubber_band.setWidth(1)
        self.reset()

        self.force_active_layer = True

        # Set default encoding
        reload(sys)
        sys.setdefaultencoding('utf-8')  #@UndefinedVariable

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def set_layers(self,
                   layer_arc_man,
                   layer_connec_man,
                   layer_node_man,
                   layer_gully_man=None):
        """ Sets layers involved in Map Tools functions
            Sets Snapper Manager """
        self.layer_arc_man = layer_arc_man
        self.layer_connec_man = layer_connec_man
        self.layer_node_man = layer_node_man
        self.layer_gully_man = layer_gully_man
        self.snapper_manager.set_layers(layer_arc_man, layer_connec_man,
                                        layer_node_man, layer_gully_man)

    def set_controller(self, controller):
        self.controller = controller
        self.schema_name = controller.schema_name
        self.plugin_dir = self.controller.plugin_dir
        self.snapper_manager.controller = controller

    def deactivate(self):

        # Uncheck button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapper_manager.recover_snapping_options()

        # Recover cursor
        self.canvas.setCursor(self.std_cursor)

        # Remove highlight
        self.vertex_marker.hide()

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def set_action_pan(self):
        """ Set action 'Pan' """
        try:
            self.iface.actionPan().trigger()
        except Exception:
            pass

    def reset(self):

        # Graphic elements
        self.rubber_band.reset(QGis.Polygon)

        # Selection
        self.snapped_feat = None

    def cancel_map_tool(self):
        """ Executed if user press right button or escape key """

        # Reset rubber band
        self.reset()

        # Deactivate map tool
        self.deactivate()
        self.set_action_pan()

    def remove_markers(self):
        """ Remove previous markers """

        vertex_items = [
            i for i in self.canvas.scene().items()
            if issubclass(type(i), QgsVertexMarker)
        ]
        for ver in vertex_items:
            if ver in self.canvas.scene().items():
                self.canvas.scene().removeItem(ver)

    def refresh_map_canvas(self):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top and maximize button
        if maximize_button and stay_on_top:
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint
                               | Qt.WindowMaximizeButtonHint
                               | Qt.WindowStaysOnTopHint)
        elif not maximize_button and stay_on_top:
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint
                               | Qt.WindowStaysOnTopHint)
        elif maximize_button and not stay_on_top:
            dlg.setWindowFlags(Qt.WindowMaximizeButtonHint)

        # Open dialog
        dlg.open()

    def close_dialog(self, dlg=None, set_action_pan=True):
        """ Close dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
        try:
            self.save_settings(dlg)
            dlg.close()
            if set_action_pan:
                map_tool = self.canvas.mapTool()
                # If selected map tool is from the plugin, set 'Pan' as current one
                if map_tool.toolName() == '':
                    self.set_action_pan()
        except AttributeError:
            pass

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.width())
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.height())
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_width", dialog.width())
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_height", dialog.height())
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_x",
                dialog.pos().x())
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_y",
                dialog.pos().y())
        except:
            pass

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return (False, expr)
        return (True, expr)

    def canvasMoveEvent(self, event):

        # Make sure active layer is always 'v_edit_node'
        cur_layer = self.iface.activeLayer()
        if cur_layer != self.layer_node and self.force_active_layer:
            self.iface.setActiveLayer(self.layer_node)

        # Hide highlight
        self.vertex_marker.hide()

        try:
            # Get current mouse coordinates
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)
        except (TypeError, KeyError):
            self.iface.actionPan().trigger()
            return

        # Snapping
        (retval,
         result) = self.snapper.snapToCurrentLayer(event_point,
                                                   2)  # @UnusedVariable

        # That's the snapped features
        if result:
            # Get the point and add marker on it
            point = QgsPoint(result[0].snappedVertex)
            self.vertex_marker.setCenter(point)
            self.vertex_marker.show()
コード例 #24
0
ファイル: delete_tool.py プロジェクト: mcgoldba/XPSS
class DeleteTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.elev = -1
        self.vertex_marker = QgsVertexMarker(self.canvas())

        # Stroke
        self.rubber_band = QgsRubberBand(self.data_dock.iface.mapCanvas())
        self.rubber_band.setColor(QColor(255, 0, 0, 255))
        self.rubber_band.setWidth(2)

        self.mouse_clicked = False
        self.snapper = None

        self.clicked_pt = None

        self.snap_results = None
        self.adj_links_fts = None

        self.selected_node_ft = None
        self.selected_node_ft_lay = None
        self.mouse_pt = None
        self.pump_valve_selected = False
        self.pump_or_valve = None
        self.pump_valve_ft = None
        self.adj_junctions = None
        self.delta_vec = None

        self.adj_pipes_fts_d = {}

    def canvasPressEvent(self, event):

        # if self.snap_results is None:
        #     return

        if event.button() == Qt.RightButton:
            self.mouse_clicked = False
            self.clicked_pt = None

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True
            self.clicked_pt = self.toMapCoordinates(event.pos())

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        if elev is not None:
            self.elev = elev
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))

        # Mouse not clicked
        if not self.mouse_clicked:

            match = self.snapper.snapToMap(self.mouse_pt)
            if match.isValid():

                self.snap_results = match
                # snapped_pt = self.snap_results[0].snappedVertex

                self.snapped_pipe_id = match.featureId()
                snapped_vertex = match.point()
                self.snapped_vertex_nr = match.vertexIndex()

                self.vertex_marker.setCenter(
                    QgsPointXY(snapped_vertex.x(), snapped_vertex.y()))
                self.vertex_marker.setColor(QColor(255, 0, 0))
                self.vertex_marker.setIconSize(10)
                self.vertex_marker.setIconType(
                    QgsVertexMarker.ICON_CIRCLE)  # or ICON_CROSS, ICON_X
                self.vertex_marker.setPenWidth(3)
                self.vertex_marker.show()
            else:
                self.snap_results = None
                self.selected_node_ft = None
                self.vertex_marker.hide()

        # Mouse clicked: draw rectangle
        else:
            if self.snap_results is None:
                end_point = self.toMapCoordinates(event.pos())
                self.show_rect(self.clicked_pt, end_point)

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return
        if event.button() == Qt.LeftButton:
            self.mouse_clicked = False

            # Snapped: one element selected
            if self.snap_results is not None:

                selected_node_ft_lay, selected_node_ft = vector_utils.findSnappedNode(
                    self.snapper, self.snap_results, self.params)

                # A node ha been snapped
                if selected_node_ft_lay is not None:
                    self.delete_element(selected_node_ft_lay, selected_node_ft)

                # A link has been snapped
                else:
                    snapped_ft = vector_utils.get_feats_by_id(
                        self.snap_results.layer(),
                        self.snap_results.featureId())
                    snapped_layer = self.snap_results.layer()
                    self.delete_element(snapped_layer, snapped_ft[0])

            # Not snapped: rectangle
            else:
                rubber_band_rect = self.rubber_band.asGeometry().boundingBox()

                self.rubber_band.reset()

                self.delete_elements(self.params.valves_vlay, rubber_band_rect)
                self.delete_elements(self.params.pumps_vlay, rubber_band_rect)
                self.delete_elements(self.params.pipes_vlay, rubber_band_rect)
                self.delete_elements(self.params.tanks_vlay, rubber_band_rect)
                self.delete_elements(self.params.reservoirs_vlay,
                                     rubber_band_rect)
                self.delete_elements(self.params.junctions_vlay,
                                     rubber_band_rect)

            # Refresh
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.junctions_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.reservoirs_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.tanks_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.pipes_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.pumps_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.valves_vlay)

    def activate(self):

        cursor = QCursor()
        cursor.setShape(Qt.ArrowCursor)
        self.iface.mapCanvas().setCursor(cursor)

        layers = {
            self.params.junctions_vlay: QgsSnappingConfig.Vertex,
            self.params.reservoirs_vlay: QgsSnappingConfig.Vertex,
            self.params.tanks_vlay: QgsSnappingConfig.Vertex,
            self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment
        }
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)
        self.snapper.toggleEnabled()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.reservoirs_vlay.isEditable():
            self.params.reservoirs_vlay.startEditing()
        if not self.params.tanks_vlay.isEditable():
            self.params.tanks_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()
        if not self.params.pumps_vlay.isEditable():
            self.params.pumps_vlay.startEditing()
        if not self.params.valves_vlay.isEditable():
            self.params.valves_vlay.startEditing()

    def deactivate(self):
        self.data_dock.btn_delete_element.setChecked(False)
        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def show_rect(self, start_point, end_point):

        self.rubber_band.reset()
        if start_point.x() == end_point.x() or start_point.y() == end_point.y(
        ):
            return

        point1 = QgsPointXY(start_point.x(), start_point.y())
        point2 = QgsPointXY(start_point.x(), end_point.y())
        point3 = QgsPointXY(end_point.x(), end_point.y())
        point4 = QgsPointXY(end_point.x(), start_point.y())
        point5 = QgsPointXY(start_point.x(), start_point.y())

        self.rubber_band.addPoint(point1, False)
        self.rubber_band.addPoint(point2, False)
        self.rubber_band.addPoint(point3, False)
        self.rubber_band.addPoint(point4, False)
        self.rubber_band.closePoints(True)  # true to update canvas
        self.rubber_band.show()

    def delete_elements(self, layer, rectangle):

        try:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            feats = layer.getFeatures()
            for feat in feats:
                if rectangle.contains(feat.geometry().boundingBox()):
                    self.delete_element(layer, feat)

        finally:
            QApplication.restoreOverrideCursor()

    def delete_element(self, layer, feature):

        # If node
        if layer == self.params.junctions_vlay or \
                        layer == self.params.reservoirs_vlay or \
                        layer == self.params.tanks_vlay:

            # The node is a junction
            if layer == self.params.junctions_vlay:

                adj_links_fts = NetworkUtils.find_adjacent_links(
                    self.params, feature.geometry())

                # Only pipes adjacent to node: it's a simple junction
                if not adj_links_fts['pumps'] and not adj_links_fts['valves']:

                    # Delete node
                    NodeHandler.delete_node(self.params, layer, feature)

                    # Delete adjacent pipes
                    adj_pipes = NetworkUtils.find_adjacent_links(
                        self.params, feature.geometry())
                    for adj_pipe in adj_pipes['pipes']:
                        LinkHandler.delete_link(self.params.pipes_vlay,
                                                adj_pipe)

                # The node is part of a pump or valve
                else:

                    if adj_links_fts['pumps']:
                        LinkHandler.delete_link(self.params,
                                                self.params.pumps_vlay,
                                                feature)

                    elif adj_links_fts['valves']:
                        LinkHandler.delete_link(self.params,
                                                self.params.valves_vlay,
                                                feature)

            # The node is a reservoir or a tank
            elif layer == self.params.reservoirs_vlay or \
                            layer == self.params.tanks_vlay:

                adj_pipes = NetworkUtils.find_adjacent_links(
                    self.params, feature.geometry())['pipes']

                NodeHandler._delete_feature(self.params, layer, feature)

                for adj_pipe in adj_pipes:
                    LinkHandler.delete_link(self.params,
                                            self.params.pipes_vlay, adj_pipe)

        # If pipe
        elif layer == self.params.pipes_vlay:

            if self.snap_results is not None:
                vertex = feature.geometry().closestVertexWithContext(
                    self.snap_results.point())
                vertex_dist = vertex[0]
                if vertex_dist < self.params.min_dist:
                    # Delete vertex
                    LinkHandler.delete_vertex(self.params,
                                              self.params.pipes_vlay, feature,
                                              vertex[1])
                else:
                    # Delete whole feature
                    LinkHandler.delete_link(self.params, layer, feature)
            else:
                LinkHandler.delete_link(self.params, layer, feature)
コード例 #25
0
class ParentMapTool(QgsMapTool):
    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.show_help = bool(int(self.settings.value('status/show_help', 1)))
        self.index_action = index_action
        self.layer_arc = None
        self.layer_connec = None
        self.layer_gully = None
        self.layer_node = None
        self.schema_name = None
        self.controller = None
        self.dao = None
        self.snapper_manager = None

        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)

        # Get default cursor
        # noinspection PyCallingNonCallable
        self.std_cursor = self.parent().cursor()

        # Set default vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

        # Set default rubber band
        color_selection = QColor(254, 178, 76, 63)
        self.rubber_band = QgsRubberBand(self.canvas, 2)
        self.rubber_band.setColor(color)
        self.rubber_band.setFillColor(color_selection)
        self.rubber_band.setWidth(1)
        self.reset()

        self.force_active_layer = True

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def set_controller(self, controller):

        self.controller = controller
        self.schema_name = controller.schema_name
        self.plugin_dir = self.controller.plugin_dir
        if self.snapper_manager is None:
            self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper_manager.controller = controller

    def deactivate(self):

        # Uncheck button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapper_manager.recover_snapping_options()

        # Enable snapping
        self.snapper_manager.enable_snapping(True)

        # Recover cursor
        self.canvas.setCursor(self.std_cursor)

        # Remove highlight
        self.vertex_marker.hide()

    def recover_previus_maptool(self):
        if self.controller.prev_maptool:
            self.iface.mapCanvas().setMapTool(self.controller.prev_maptool)
            self.controller.prev_maptool = None

    def remove_vertex(self):
        """ Remove vertex_marker from canvas"""
        vertex_items = [
            i for i in self.iface.mapCanvas().scene().items()
            if issubclass(type(i), QgsVertexMarker)
        ]

        for ver in vertex_items:
            if ver in self.iface.mapCanvas().scene().items():
                if self.vertex_marker == ver:
                    self.iface.mapCanvas().scene().removeItem(ver)

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def set_action_pan(self):
        """ Set action 'Pan' """
        try:
            self.iface.actionPan().trigger()
        except Exception:
            pass

    def reset_rubber_band(self, geom_type="polygon"):

        try:
            if geom_type == "polygon":
                geom_type = QgsWkbTypes.PolygonGeometry
            elif geom_type == "line":
                geom_type = QgsWkbTypes.LineString
            self.rubber_band.reset(geom_type)
        except:
            pass

    def reset(self):

        self.reset_rubber_band()
        self.snapped_feat = None

    def cancel_map_tool(self):
        """ Executed if user press right button or escape key """

        # Reset rubber band
        self.reset()

        # Deactivate map tool
        self.deactivate()
        self.set_action_pan()

    def remove_markers(self):
        """ Remove previous markers """

        vertex_items = [
            i for i in list(self.canvas.scene().items())
            if issubclass(type(i), QgsVertexMarker)
        ]
        for ver in vertex_items:
            if ver in list(self.canvas.scene().items()):
                self.canvas.scene().removeItem(ver)

    def refresh_map_canvas(self):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    info=True,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        # Check database connection before opening dialog
        if not self.controller.check_db_connection():
            return

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top, maximize/minimize button and information button
        # if info is True maximize flag will be ignored
        # To enable maximize button you must set info to False
        flags = Qt.WindowCloseButtonHint
        if info:
            flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint
        else:
            if maximize_button:
                flags |= Qt.WindowMinMaxButtonsHint

        if stay_on_top:
            flags |= Qt.WindowStaysOnTopHint

        dlg.setWindowFlags(flags)

        # Open dialog
        if issubclass(type(dlg), GwDialog):
            dlg.open()
        elif issubclass(type(dlg), GwMainWindow):
            dlg.show()
        else:
            dlg.show()

    def close_dialog(self, dlg=None, set_action_pan=True):
        """ Close dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
        try:
            self.save_settings(dlg)
            dlg.close()
            if set_action_pan:
                map_tool = self.canvas.mapTool()
                # If selected map tool is from the plugin, set 'Pan' as current one
                if map_tool.toolName() == '':
                    self.set_action_pan()
        except AttributeError:
            pass

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                screens = ctypes.windll.user32
                screen_x = screens.GetSystemMetrics(78)
                screen_y = screens.GetSystemMetrics(79)
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_width", dialog.property('width'))
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_height", dialog.property('height'))
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_x",
                dialog.pos().x())
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_y",
                dialog.pos().y())
        except:
            pass

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return False, expr

        return True, expr

    def get_composers_list(self):

        layour_manager = QgsProject.instance().layoutManager().layouts()
        active_composers = [layout for layout in layour_manager]

        return active_composers

    def get_composer_index(self, name):

        index = 0
        composers = self.get_composers_list()
        for comp_view in composers:
            composer_name = comp_view.name()
            if composer_name == name:
                break
            index += 1

        return index

    def canvasMoveEvent(self, event):

        # Make sure active layer is always 'v_edit_node'
        cur_layer = self.iface.activeLayer()
        if cur_layer != self.layer_node and self.force_active_layer:
            self.iface.setActiveLayer(self.layer_node)

        # Hide highlight and get coordinates
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(event)

        # Snapping
        result = self.snapper_manager.snap_to_current_layer(event_point)
        if self.snapper_manager.result_is_valid():
            self.snapper_manager.add_marker(result, self.vertex_marker)

    def create_body(self, form='', feature='', filter_fields='', extras=None):
        """ Create and return parameters as body to functions"""

        client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, '
        form = f'"form":{{{form}}}, '
        feature = '"feature":{' + feature + '}, '
        filter_fields = '"filterFields":{' + filter_fields + '}'
        page_info = '"pageInfo":{}'
        data = '"data":{' + filter_fields + ', ' + page_info
        if extras:
            data += ', ' + extras
        data += f'}}}}$$'
        body = "" + client + form + feature + data

        return body

    def refresh_legend(self):
        """ This function solves the bug generated by changing the type of feature.
        Mysteriously this bug is solved by checking and unchecking the categorization of the tables.
        # TODO solve this bug
        """
        layers = [
            self.controller.get_layer_by_tablename('v_edit_node'),
            self.controller.get_layer_by_tablename('v_edit_connec'),
            self.controller.get_layer_by_tablename('v_edit_gully')
        ]

        for layer in layers:
            if layer:
                ltl = QgsProject.instance().layerTreeRoot().findLayer(
                    layer.id())
                ltm = self.iface.layerTreeView().model()
                legendNodes = ltm.layerLegendNodes(ltl)
                for ln in legendNodes:
                    current_state = ln.data(Qt.CheckStateRole)
                    ln.setData(Qt.Unchecked, Qt.CheckStateRole)
                    ln.setData(Qt.Checked, Qt.CheckStateRole)
                    ln.setData(current_state, Qt.CheckStateRole)

    def put_layer_into_toc(self,
                           tablename=None,
                           the_geom="the_geom",
                           field_id="id",
                           group='GW Layers'):
        """ Put layer from postgres DB into TOC"""
        schema_name = self.controller.credentials['schema'].replace('"', '')
        uri = QgsDataSourceUri()
        uri.setConnection(self.controller.credentials['host'],
                          self.controller.credentials['port'],
                          self.controller.credentials['db'],
                          self.controller.credentials['user'],
                          self.controller.credentials['password'])
        if not field_id:
            field_id = self.controller.get_pk(tablename)
            if not field_id:
                field_id = "id"
        uri.setDataSource(schema_name, f'{tablename}', the_geom, None,
                          field_id)
        layer = QgsVectorLayer(uri.uri(), f'{tablename}', "postgres")

        root = QgsProject.instance().layerTreeRoot()
        my_group = root.findGroup(group)
        if my_group is None:
            my_group = root.insertGroup(0, group)

        my_group.insertLayer(0, layer)
        self.iface.mapCanvas().refresh()
        return layer

    def populate_info_text(self,
                           dialog,
                           data,
                           force_tab=True,
                           reset_text=True,
                           tab_idx=1):

        change_tab = False
        text = qt_tools.getWidgetText(dialog,
                                      'txt_infolog',
                                      return_string_null=False)
        if reset_text:
            text = ""
        for item in data['info']['values']:
            if 'message' in item:
                if item['message'] is not None:
                    text += str(item['message']) + "\n"
                    if force_tab:
                        change_tab = True
                else:
                    text += "\n"

        qt_tools.setWidgetText(dialog, 'txt_infolog', text + "\n")
        qtabwidget = dialog.findChild(QTabWidget, 'mainTab')
        if change_tab and qtabwidget is not None:
            qtabwidget.setCurrentIndex(tab_idx)

        return change_tab
コード例 #26
0
class MincutMapTool(ParentMapTool):
    ''' Button 26. User select one node or arc.
    Execute SQL function: 'gw_fct_mincut'
    This function fills 3 temporary tables with id's: node_id, arc_id and valve_id
    Returns and integer: error code
    Get these id's and select them in its corresponding layers '''    

    def __init__(self, iface, settings, action, index_action):  
        ''' Class constructor '''
        
        # Call ParentMapTool constructor     
        super(MincutMapTool, self).__init__(iface, settings, action, index_action)  

        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(255, 25, 25))
        self.vertexMarker.setIconSize(11)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)



    ''' QgsMapTools inherited event functions '''

    def canvasMoveEvent(self, event):

        # Hide highlight
        self.vertexMarker.hide()

        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        eventPoint = QPoint(x,y)

        # Snapping        
        (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable   
        self.current_layer = None

        # That's the snapped point
        if result <> []:

            # Check Arc or Node
            for snapPoint in result:

                if snapPoint.layer.name() == self.layer_node.name() or snapPoint.layer.name() == self.layer_arc.name():
                    
                    # Get the point
                    point = QgsPoint(result[0].snappedVertex)

                    # Add marker
                    self.vertexMarker.setCenter(point)
                    self.vertexMarker.show()

                    # Data for function
                    self.current_layer = result[0].layer
                    self.snappFeat = next(result[0].layer.getFeatures(QgsFeatureRequest().setFilterFid(result[0].snappedAtGeometry)))

                    # Change symbol
                    if snapPoint.layer.name() == self.layer_node.name():
                        self.vertexMarker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                    else:
                        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX)

                    break


    def canvasReleaseEvent(self, event):
        ''' With left click the digitizing is finished '''
        
        if event.button() == Qt.LeftButton and self.current_layer is not None:

            # Get selected layer type: 'arc' or 'node'
            if self.current_layer.name() == self.layer_arc.name():
                elem_type = 'arc'
            elif self.current_layer.name() == self.layer_node.name():
                elem_type = 'node'
            else:
                message = "Current layer not valid"
                self.controller.show_warning(message, context_name='ui_message')
                return

            feature = self.snappFeat
            elem_id = feature.attribute(elem_type+'_id')

            # Execute SQL function
            function_name = "gw_fct_mincut"
            sql = "SELECT "+self.schema_name+"."+function_name+"('"+str(elem_id)+"', '"+elem_type+"');"
            result = self.controller.execute_sql(sql)
            print sql
            if result:
                # Get 'arc' and 'node' list and select them
                self.mg_flow_trace_select_features(self.layer_arc, 'arc')
                self.mg_flow_trace_select_features(self.layer_node, 'node')

            # Refresh map canvas
            self.iface.mapCanvas().refresh()


    def mg_flow_trace_select_features(self, layer, elem_type):

        sql = "SELECT * FROM "+self.schema_name+".anl_mincut_"+elem_type+" ORDER BY "+elem_type+"_id"
        rows = self.controller.get_rows(sql)
        if rows:
    
            # Build an expression to select them
            aux = "\""+elem_type+"_id\" IN ("
            for elem in rows:
                aux += elem[0] + ", "
            aux = aux[:-2] + ")"
    
            # Get a featureIterator from this expression:
            expr = QgsExpression(aux)
            if expr.hasParserError():
                message = "Expression Error: " + str(expr.parserErrorString())
                self.controller.show_warning(message, context_name='ui_message')
                return
            it = layer.getFeatures(QgsFeatureRequest(expr))
    
            # Build a list of feature id's from the previous result
            id_list = [i.id() for i in it]
    
            # Select features with these id's
            layer.setSelectedFeatures(id_list)


    def activate(self):

        # Check button
        self.action().setChecked(True)

        # Store user snapping configuration
        self.snapperManager.storeSnappingOptions()

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to arc and node
        self.snapperManager.snapToArc()
        self.snapperManager.snapToNode()

        # Change cursor
        self.canvas.setCursor(self.cursor)

        # Show help message when action is activated
        if self.show_help:
            message = "Select a node or pipe and click on it, the valves minimum cut polygon is computed"
            self.controller.show_info(message, context_name='ui_message' )  
        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_arc)
        except:
            self.canvas.setCurrentLayer(self.layer_arc)


    def deactivate(self):

        # Check button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

        # Recover cursor
        self.canvas.setCursor(self.stdCursor)

        # Remove highlight
        self.h = None
        
        
コード例 #27
0
class MyBoton2(dialog.GwAction):
    def __init__(self, icon_path, action_name, text, toolbar, action_group):
        super().__init__(icon_path, action_name, text, toolbar, action_group)

    def clicked_event(self):

        self.selection_type = SelectionType.ACTIVE
        self.dlg_btn2 = DlgBoton2()
        tools_gw.load_settings(self.dlg_btn2)

        # Secció: selecció de capes
        self.dlg_btn2.rdb_layers_active.clicked.connect(
            partial(self.selection_type_changed, SelectionType.ACTIVE))
        self.dlg_btn2.rdb_layers_all.clicked.connect(
            partial(self.selection_type_changed, SelectionType.ALL))

        # Secció: activar l'estat de "seleccionant al mapa"
        self.dlg_btn2.btn_select.clicked.connect(self.selection_start)
        self.dlg_btn2.btn_cancel.clicked.connect(self.deactivate_signals)
        self.dlg_btn2.btn_cancel.clicked.connect(
            lambda: self.dlg_btn2.rdb_layers_active.setEnabled(True))
        self.dlg_btn2.btn_cancel.clicked.connect(
            lambda: self.dlg_btn2.rdb_layers_all.setEnabled(True))
        # Secció: sortida
        self.dlg_btn2.btn_close.clicked.connect(self.dlg_btn2.close)
        self.dlg_btn2.rejected.connect(
            partial(tools_gw.save_settings, self.dlg_btn2))
        self.dlg_btn2.rejected.connect(partial(self.deactivate_signals))

        self.refresh_selection_type()

        tools_gw.open_dialog(self.dlg_btn2)

    def selection_type_changed(self, new_type):

        self.selection_type = SelectionType(new_type)
        print(f"Selection type changed to { SelectionType(new_type) }")

        self.refresh_selection_type()

    def refresh_selection_type(self):

        if self.selection_type == SelectionType.ACTIVE:
            self.dlg_btn2.chk_layer_arc.setEnabled(False)
            self.dlg_btn2.chk_layer_connec.setEnabled(False)
            self.dlg_btn2.chk_layer_node.setEnabled(False)
        else:
            self.dlg_btn2.chk_layer_arc.setEnabled(True)
            self.dlg_btn2.chk_layer_connec.setEnabled(True)
            self.dlg_btn2.chk_layer_node.setEnabled(True)

    def selection_start(self):

        print(f"Selection state started")

        self.is_selecting = True

        self.dlg_btn2.rdb_layers_active.setEnabled(False)
        self.dlg_btn2.rdb_layers_all.setEnabled(False)
        # self.dlg_btn2.btn_select.setEnabled(False)
        #

        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.canvas.setMapTool(self.emit_point)
        # Snapper
        self.snapper_manager = snap_manager.GwSnapManager(self.iface)
        self.snapper = self.snapper_manager.get_snapper()
        # Vertex marker
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setColor(QColor(255, 100, 255))
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.vertex_marker.setPenWidth(3)
        # Store user snapping configuration
        self.previous_snapping = self.snapper_manager.get_snapping_options()

        if self.selection_type == SelectionType.ACTIVE:
            print("single selector")
            self.activate_snapping(self.emit_point)
        elif self.selection_type == SelectionType.ALL:
            print("all selector")
            # Store user snapping configuration
            if tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_arc) or \
                    tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_connec) or \
                    tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_node):
                self.set_user_config()
            self.activate_snapping(self.emit_point)

    def set_user_config(self):

        print(f"set_user_config")
        # Disable snapping
        self.snapper_manager.set_snapping_status()

        # Set snapping to 'arc', 'node', 'connec' and 'gully'
        self.snapper_manager.set_snapping_layers()

        if tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_arc):
            print("Set snap to arc")
            self.snapper_manager.config_snap_to_arc()

        if tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_connec):
            print("Set snap to connec")
            self.snapper_manager.config_snap_to_connec()

        if tools_qt.is_checked(self.dlg_btn2, self.dlg_btn2.chk_layer_node):
            print("Set snap to node")
            self.snapper_manager.config_snap_to_node()

        self.snapper_manager.set_snap_mode()

    def activate_snapping(self, emit_point):

        # Set signals
        self.canvas.xyCoordinates.connect(self.canvas_move_event)
        emit_point.canvasClicked.connect(
            partial(self.canvas_release_event, emit_point))

    def canvas_move_event(self, point):

        # Get clicked point
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(point=point)
        if self.selection_type == SelectionType.ACTIVE:
            result = self.snapper_manager.snap_to_current_layer(event_point)
        elif self.selection_type == SelectionType.ALL:
            result = self.snapper_manager.snap_to_project_config_layers(
                event_point)
        if self.snapper_manager.result_is_valid():
            self.snapper_manager.add_marker(result, self.vertex_marker)

    def canvas_release_event(self, emit_point, point, btn):

        if btn == Qt.RightButton:
            if btn == Qt.RightButton:
                tools_qgis.disconnect_snapping(False, emit_point,
                                               self.vertex_marker)
                return

        # Get coordinates
        event_point = self.snapper_manager.get_event_point(point=point)
        if self.selection_type == SelectionType.ACTIVE:
            result = self.snapper_manager.snap_to_current_layer(event_point)
        elif self.selection_type == SelectionType.ALL:
            result = self.snapper_manager.snap_to_project_config_layers(
                event_point)
        if not result.isValid():
            return

        layer = self.snapper_manager.get_snapped_layer(result)
        # Get the point. Leave selection
        snapped_feat = self.snapper_manager.get_snapped_feature(result)
        feature_id = self.snapper_manager.get_snapped_feature_id(result)
        snapped_point = self.snapper_manager.get_snapped_point(result)
        layer.select([feature_id])
        self.snapper_manager.restore_snap_options(self.previous_snapping)
        self.deactivate_signals()

    def deactivate_signals(self):

        self.vertex_marker.hide()
        try:
            self.canvas.xyCoordinates.disconnect()
        except TypeError:
            pass

        try:
            self.emit_point.canvasClicked.disconnect()
        except TypeError:
            pass
コード例 #28
0
class GwDimensioning:
    def __init__(self):
        """ Class constructor """

        self.iface = global_vars.iface
        self.settings = global_vars.settings
        self.controller = global_vars.controller
        self.plugin_dir = global_vars.plugin_dir
        self.canvas = global_vars.canvas

        self.vertex_marker = QgsVertexMarker(self.canvas)

    def open_dimensioning_form(self,
                               qgis_feature=None,
                               layer=None,
                               db_return=None,
                               fid=None,
                               rubber_band=None):
        self.dlg_dim = DimensioningUi()
        load_settings(self.dlg_dim)

        self.user_current_layer = self.iface.activeLayer()
        # Set layers dimensions, node and connec
        self.layer_dimensions = self.controller.get_layer_by_tablename(
            "v_edit_dimensions")
        self.layer_node = self.controller.get_layer_by_tablename("v_edit_node")
        self.layer_connec = self.controller.get_layer_by_tablename(
            "v_edit_connec")

        feature = None
        if qgis_feature is None:
            features = self.layer_dimensions.getFeatures()
            for feature in features:
                if feature['id'] == fid:
                    return feature
            qgis_feature = feature

        #qgis_feature = self.get_feature_by_id(self.layer_dimensions, fid, 'id')

        # when funcion is called from new feature
        if db_return is None:
            rubber_band = QgsRubberBand(self.canvas, 0)
            body = create_body()
            function_name = 'gw_fct_getdimensioning'
            json_result = self.controller.get_json(function_name, body)
            if json_result is None:
                return False
            db_return = [json_result]

        # get id from db response
        self.fid = db_return[0]['body']['feature']['id']

        # ACTION SIGNALS
        actionSnapping = self.dlg_dim.findChild(QAction, "actionSnapping")
        actionSnapping.triggered.connect(partial(self.snapping,
                                                 actionSnapping))
        set_icon(actionSnapping, "103")

        actionOrientation = self.dlg_dim.findChild(QAction,
                                                   "actionOrientation")
        actionOrientation.triggered.connect(
            partial(self.orientation, actionOrientation))
        set_icon(actionOrientation, "133")

        # LAYER SIGNALS
        self.layer_dimensions.editingStarted.connect(
            lambda: actionSnapping.setEnabled(True))
        self.layer_dimensions.editingStopped.connect(
            lambda: actionSnapping.setEnabled(False))
        self.layer_dimensions.editingStarted.connect(
            lambda: actionOrientation.setEnabled(True))
        self.layer_dimensions.editingStopped.connect(
            lambda: actionOrientation.setEnabled(False))
        self.layer_dimensions.editingStarted.connect(
            partial(enable_all, self.dlg_dim, db_return[0]['body']['data']))
        self.layer_dimensions.editingStopped.connect(
            partial(disable_all, self.dlg_dim, db_return[0]['body']['data'],
                    False))

        # WIDGETS SIGNALS
        self.dlg_dim.btn_accept.clicked.connect(
            partial(self.save_dimensioning, qgis_feature, layer))
        self.dlg_dim.btn_cancel.clicked.connect(
            partial(self.cancel_dimensioning))
        self.dlg_dim.dlg_closed.connect(partial(self.cancel_dimensioning))
        self.dlg_dim.dlg_closed.connect(partial(save_settings, self.dlg_dim))
        self.dlg_dim.dlg_closed.connect(rubber_band.reset)

        self.create_map_tips()

        layout_list = []
        for field in db_return[0]['body']['data']['fields']:
            if 'hidden' in field and field['hidden']:
                continue

            label, widget = self.set_widgets(self.dlg_dim, db_return, field)

            if widget.objectName() == 'id':
                qt_tools.setWidgetText(self.dlg_dim, widget, self.fid)
            layout = self.dlg_dim.findChild(QGridLayout, field['layoutname'])

            # Profilactic issue to prevent missed layouts againts db response and form
            if layout is not None:
                # Take the QGridLayout with the intention of adding a QSpacerItem later
                if layout not in layout_list and layout.objectName() not in (
                        'lyt_top_1', 'lyt_bot_1', 'lyt_bot_2'):
                    layout_list.append(layout)
                    # Add widgets into layout
                    layout.addWidget(label, 0, field['layoutorder'])
                    layout.addWidget(widget, 1, field['layoutorder'])

                # If field is on top or bottom layout the position is horitzontal no vertical
                if field['layoutname'] in ('lyt_top_1', 'lyt_bot_1',
                                           'lyt_bot_2'):
                    layout.addWidget(label, 0, field['layoutorder'])
                    layout.addWidget(widget, 1, field['layoutorder'])
                else:
                    put_widgets(self.dlg_dim, field, label, widget)

        # Add a QSpacerItem into each QGridLayout of the list
        for layout in layout_list:
            vertical_spacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum,
                                           QSizePolicy.Expanding)
            layout.addItem(vertical_spacer1)

        if self.layer_dimensions:
            self.iface.setActiveLayer(self.layer_dimensions)
            if self.layer_dimensions.isEditable():
                actionSnapping.setEnabled(True)
                actionOrientation.setEnabled(True)
                enable_all(self.dlg_dim, db_return[0]['body']['data'])
            else:
                actionSnapping.setEnabled(False)
                actionOrientation.setEnabled(False)
                disable_all(self.dlg_dim, db_return[0]['body']['data'], False)

        title = f"DIMENSIONING - {self.fid}"
        open_dialog(self.dlg_dim, dlg_name='dimensioning', title=title)
        return False, False

    def cancel_dimensioning(self):

        self.iface.actionRollbackEdits().trigger()
        close_dialog(self.dlg_dim)
        restore_user_layer(self.user_current_layer)

    def save_dimensioning(self, qgis_feature, layer):

        # Upsert feature into db
        layer.updateFeature(qgis_feature)
        layer.commitChanges()

        # Create body
        fields = ''
        list_widgets = self.dlg_dim.findChildren(QLineEdit)
        for widget in list_widgets:
            widget_name = widget.property('columnname')
            widget_value = qt_tools.getWidgetText(self.dlg_dim, widget)
            if widget_value == 'null':
                continue
            fields += f'"{widget_name}":"{widget_value}", '

        list_widgets = self.dlg_dim.findChildren(QCheckBox)
        for widget in list_widgets:
            widget_name = widget.property('columnname')
            widget_value = f'"{qt_tools.isChecked(self.dlg_dim, widget)}"'
            if widget_value == 'null':
                continue
            fields += f'"{widget_name}":{widget_value},'

        list_widgets = self.dlg_dim.findChildren(QComboBox)
        for widget in list_widgets:
            widget_name = widget.property('columnname')
            widget_value = f'"{qt_tools.get_item_data(self.dlg_dim, widget)}"'
            if widget_value == 'null':
                continue
            fields += f'"{widget_name}":{widget_value},'

        # remove last character (,) from fields
        fields = fields[:-1]

        feature = '"tableName":"v_edit_dimensions", '
        feature += f'"id":"{self.fid}"'
        extras = f'"fields":{{{fields}}}'
        body = create_body(feature=feature, extras=extras)
        result = self.controller.get_json('gw_fct_setdimensioning', body)

        # Close dialog
        close_dialog(self.dlg_dim)

    def deactivate_signals(self, action, emit_point=None):
        self.vertex_marker.hide()
        try:
            self.canvas.xyCoordinates.disconnect()
        except TypeError:
            pass

        try:
            emit_point.canvasClicked.disconnect()
        except TypeError:
            pass

        if not action.isChecked():
            action.setChecked(False)
            return True

        return False

    def snapping(self, action):

        # Set active layer and set signals
        emit_point = QgsMapToolEmitPoint(self.canvas)
        self.canvas.setMapTool(emit_point)
        if self.deactivate_signals(action, emit_point):
            return

        remove_marker(self.vertex_marker)
        self.previous_snapping = get_snapping_options()
        enable_snapping()
        snap_to_node()
        snap_to_connec_gully()
        set_snapping_mode()

        self.dlg_dim.actionOrientation.setChecked(False)
        self.iface.setActiveLayer(self.layer_node)
        self.canvas.xyCoordinates.connect(self.mouse_move)
        emit_point.canvasClicked.connect(
            partial(self.click_button_snapping, action, emit_point))

    def mouse_move(self, point):

        # Hide marker and get coordinates
        self.vertex_marker.hide()
        event_point = get_event_point(point=point)

        # Snapping
        result = snap_to_background_layers(event_point)
        if result.isValid():
            layer = get_snapped_layer(result)
            # Check feature
            if layer == self.layer_node or layer == self.layer_connec:
                add_marker(result, self.vertex_marker)

    def click_button_snapping(self, action, emit_point, point, btn):

        if not self.layer_dimensions:
            return

        if btn == Qt.RightButton:
            if btn == Qt.RightButton:
                action.setChecked(False)
                self.deactivate_signals(action, emit_point)
                return

        layer = self.layer_dimensions
        self.iface.setActiveLayer(layer)

        # Get coordinates
        event_point = get_event_point(point=point)

        # Snapping
        result = snap_to_background_layers(event_point)
        if result.isValid():

            layer = get_snapped_layer(result)
            # Check feature
            if layer == self.layer_node:
                feat_type = 'node'
            elif layer == self.layer_connec:
                feat_type = 'connec'
            else:
                return

            # Get the point
            snapped_feat = get_snapped_feature(result)
            feature_id = get_snapped_feature_id(result)
            element_id = snapped_feat.attribute(feat_type + '_id')

            # Leave selection
            layer.select([feature_id])

            # Get depth of the feature
            fieldname = None
            self.project_type = self.controller.get_project_type()
            if self.project_type == 'ws':
                fieldname = "depth"
            elif self.project_type == 'ud' and feat_type == 'node':
                fieldname = "ymax"
            elif self.project_type == 'ud' and feat_type == 'connec':
                fieldname = "connec_depth"

            if fieldname is None:
                return

            depth = snapped_feat.attribute(fieldname)
            if depth in ('', None, 0, '0', 'NULL'):
                qt_tools.setText(self.dlg_dim, "depth", None)
            else:
                qt_tools.setText(self.dlg_dim, "depth", depth)
            qt_tools.setText(self.dlg_dim, "feature_id", element_id)
            qt_tools.setText(self.dlg_dim, "feature_type", feat_type.upper())

            apply_snapping_options(self.previous_snapping)
            self.deactivate_signals(action, emit_point)
            action.setChecked(False)

    def orientation(self, action):

        emit_point = QgsMapToolEmitPoint(self.canvas)
        self.canvas.setMapTool(emit_point)
        if self.deactivate_signals(action, emit_point):
            return

        remove_marker(self.vertex_marker)
        self.previous_snapping = get_snapping_options()
        enable_snapping()
        snap_to_node()
        snap_to_connec_gully()
        set_snapping_mode()

        self.dlg_dim.actionSnapping.setChecked(False)
        emit_point.canvasClicked.connect(
            partial(self.click_button_orientation, action, emit_point))

    def click_button_orientation(self, action, emit_point, point, btn):

        if not self.layer_dimensions:
            return

        if btn == Qt.RightButton:
            action.setChecked(False)
            self.deactivate_signals(action, emit_point)
            return

        self.x_symbol = self.dlg_dim.findChild(QLineEdit, "x_symbol")

        self.x_symbol.setText(str(int(point.x())))

        self.y_symbol = self.dlg_dim.findChild(QLineEdit, "y_symbol")
        self.y_symbol.setText(str(int(point.y())))

        apply_snapping_options(self.previous_snapping)
        self.deactivate_signals(action, emit_point)
        action.setChecked(False)

    def create_map_tips(self):
        """ Create MapTips on the map """

        row = self.controller.get_config('qgis_dim_tooltip')
        if not row or row[0].lower() != 'true':
            return

        self.timer_map_tips = QTimer(self.canvas)
        self.map_tip_node = QgsMapTip()
        self.map_tip_connec = QgsMapTip()

        self.canvas.xyCoordinates.connect(self.map_tip_changed)
        self.timer_map_tips.timeout.connect(self.show_map_tip)
        self.timer_map_tips_clear = QTimer(self.canvas)
        self.timer_map_tips_clear.timeout.connect(self.clear_map_tip)

    def map_tip_changed(self, point):
        """ SLOT. Initialize the Timer to show MapTips on the map """

        if self.canvas.underMouse():
            self.last_map_position = QgsPointXY(point.x(), point.y())
            self.map_tip_node.clear(self.canvas)
            self.map_tip_connec.clear(self.canvas)
            self.timer_map_tips.start(100)

    def show_map_tip(self):
        """ Show MapTips on the map """

        self.timer_map_tips.stop()
        if self.canvas.underMouse():
            point_qgs = self.last_map_position
            point_qt = self.canvas.mouseLastXY()
            if self.layer_node:
                self.map_tip_node.showMapTip(self.layer_node, point_qgs,
                                             point_qt, self.canvas)
            if self.layer_connec:
                self.map_tip_connec.showMapTip(self.layer_connec, point_qgs,
                                               point_qt, self.canvas)
            self.timer_map_tips_clear.start(1000)

    def clear_map_tip(self):
        """ Clear MapTips """

        self.timer_map_tips_clear.stop()
        self.map_tip_node.clear(self.canvas)
        self.map_tip_connec.clear(self.canvas)

    def set_widgets(self, dialog, db_return, field):

        widget = None
        label = None
        if field['label']:
            label = QLabel()
            label.setObjectName('lbl_' + field['widgetname'])
            label.setText(field['label'].capitalize())
            if field['stylesheet'] is not None and 'label' in field[
                    'stylesheet']:
                label = set_setStyleSheet(field, label)
            if 'tooltip' in field:
                label.setToolTip(field['tooltip'])
            else:
                label.setToolTip(field['label'].capitalize())
        if field['widgettype'] == 'text' or field['widgettype'] == 'typeahead':
            completer = QCompleter()
            widget = add_lineedit(field)
            widget = set_widget_size(widget, field)
            widget = set_data_type(field, widget)
            if field['widgettype'] == 'typeahead':
                widget = manage_lineedit(field, dialog, widget, completer)
        elif field['widgettype'] == 'combo':
            widget = add_combobox(field)
            widget = set_widget_size(widget, field)
        elif field['widgettype'] == 'check':
            widget = add_checkbox(field)
        elif field['widgettype'] == 'datetime':
            widget = add_calendar(dialog, field)
        elif field['widgettype'] == 'button':
            widget = add_button(dialog, field)
            widget = set_widget_size(widget, field)
        elif field['widgettype'] == 'hyperlink':
            widget = add_hyperlink(field)
            widget = set_widget_size(widget, field)
        elif field['widgettype'] == 'hspacer':
            widget = add_horizontal_spacer()
        elif field['widgettype'] == 'vspacer':
            widget = add_vertical_spacer()
        elif field['widgettype'] == 'textarea':
            widget = add_textarea(field)
        elif field['widgettype'] in 'spinbox':
            widget = add_spinbox(field)
        elif field['widgettype'] == 'tableview':
            widget = add_tableview(db_return, field)
            widget = set_headers(widget, field)
            widget = populate_table(widget, field)
            widget = set_columns_config(widget,
                                        field['widgetname'],
                                        sort_order=1,
                                        isQStandardItemModel=True)
            qt_tools.set_qtv_config(widget)
        widget.setObjectName(widget.property('columnname'))

        return label, widget
コード例 #29
0
class ProfileDockWidget(QDockWidget):
    """
    DockWidget class to display the profile
    """

    closeSignal = pyqtSignal()

    def __init__(self, iface):
        """
        Constructor
        :param iface: interface
        """
        QDockWidget.__init__(self)
        self.setWindowTitle(QCoreApplication.translate("VDLTools", "Profile Tool"))
        self.resize(1024, 400)
        self.__iface = iface
        self.__canvas = self.__iface.mapCanvas()
        self.__types = ['PDF', 'PNG']  # ], 'SVG', 'PS']
        self.__libs = []
        if Qwt5_loaded:
            self.__lib = 'Qwt5'
            self.__libs.append('Qwt5')
            if matplotlib_loaded:
                self.__libs.append('Matplotlib')
        elif matplotlib_loaded:
            self.__lib = 'Matplotlib'
            self.__libs.append('Matplotlib')
        else:
            self.__lib = None
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "No graph lib available (qwt5 or matplotlib)"),
                level=QgsMessageBar.CRITICAL, duration=0)

        self.__doTracking = False
        self.__vline = None

        self.__profiles = None
        self.__numLines = None
        self.__mntPoints = None

        self.__marker = None
        self.__tabmouseevent = None

        self.__contentWidget = QWidget()
        self.setWidget(self.__contentWidget)

        self.__boxLayout = QHBoxLayout()
        self.__contentWidget.setLayout(self.__boxLayout)

        self.__plotFrame = QFrame()
        self.__frameLayout = QHBoxLayout()
        self.__plotFrame.setLayout(self.__frameLayout)

        self.__printLayout = QHBoxLayout()
        self.__printLayout.addWidget(self.__plotFrame)

        self.__legendLayout = QVBoxLayout()
        self.__printLayout.addLayout(self.__legendLayout)

        self.__printWdg = QWidget()
        self.__printWdg.setLayout(self.__printLayout)

        self.__plotWdg = None
        self.__changePlotWidget()

        size = QSize(150, 20)

        self.__boxLayout.addWidget(self.__printWdg)

        self.__vertLayout = QVBoxLayout()

        self.__libCombo = QComboBox()
        self.__libCombo.setFixedSize(size)
        self.__libCombo.addItems(self.__libs)
        self.__vertLayout.addWidget(self.__libCombo)
        self.__libCombo.currentIndexChanged.connect(self.__setLib)

        self.__maxLabel = QLabel("y max")
        self.__maxLabel.setFixedSize(size)
        self.__vertLayout.addWidget(self.__maxLabel)
        self.__maxSpin = QSpinBox()
        self.__maxSpin.setFixedSize(size)
        self.__maxSpin.setRange(-10000, 10000)
        self.__maxSpin.valueChanged.connect(self.__reScalePlot)
        self.__vertLayout.addWidget(self.__maxSpin)
        self.__vertLayout.insertSpacing(10, 20)

        self.__minLabel = QLabel("y min")
        self.__minLabel.setFixedSize(size)
        self.__vertLayout.addWidget(self.__minLabel)
        self.__minSpin = QSpinBox()
        self.__minSpin.setFixedSize(size)
        self.__minSpin.setRange(-10000, 10000)
        self.__minSpin.valueChanged.connect(self.__reScalePlot)
        self.__vertLayout.addWidget(self.__minSpin)
        self.__vertLayout.insertSpacing(10, 40)

        self.__typeCombo = QComboBox()
        self.__typeCombo.setFixedSize(size)
        self.__typeCombo.addItems(self.__types)
        self.__vertLayout.addWidget(self.__typeCombo)
        self.__saveButton = QPushButton(QCoreApplication.translate("VDLTools", "Save"))
        self.__saveButton.setFixedSize(size)
        self.__saveButton.clicked.connect(self.__save)
        self.__vertLayout.addWidget(self.__saveButton)

        self.__boxLayout.addLayout(self.__vertLayout)

        self.__maxSpin.setEnabled(False)
        self.__minSpin.setEnabled(False)

        self.__colors = []
        for cn in QColor.colorNames():
            qc = QColor(cn)
            val = qc.red() + qc.green() + qc.blue()
            if 0 < val < 450:
                self.__colors.append(cn)

    def __changePlotWidget(self):
        """
        When plot widget is change (qwt <-> matplotlib)
        """
        self.__activateMouseTracking(False)
        while self.__frameLayout.count():
            child = self.__frameLayout.takeAt(0)
            child.widget().deleteLater()
        self.__plotWdg = None

        if self.__lib == 'Qwt5':
            self.__plotWdg = QwtPlot(self.__plotFrame)
            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            sizePolicy.setHorizontalStretch(10)
            sizePolicy.setVerticalStretch(0)
            self.__plotWdg.setSizePolicy(sizePolicy)
            self.__plotWdg.setAutoFillBackground(False)
            # Decoration
            self.__plotWdg.setCanvasBackground(Qt.white)
            self.__plotWdg.plotLayout().setAlignCanvasToScales(False)
            self.__plotWdg.plotLayout().setSpacing(100)
            self.__plotWdg.plotLayout().setCanvasMargin(10, QwtPlot.xBottom)
            self.__plotWdg.plotLayout().setCanvasMargin(10, QwtPlot.yLeft)
            title = QwtText(QCoreApplication.translate("VDLTools", "Distance [m]"))
            title.setFont(QFont("Helvetica", 10))
            self.__plotWdg.setAxisTitle(QwtPlot.xBottom, title)
            title.setText(QCoreApplication.translate("VDLTools", "Elevation [m]"))
            title.setFont(QFont("Helvetica", 10))
            self.__plotWdg.setAxisTitle(QwtPlot.yLeft, title)
            self.__zoomer = QwtPlotZoomer(QwtPlot.xBottom, QwtPlot.yLeft, QwtPicker.DragSelection, QwtPicker.AlwaysOff,
                                          self.__plotWdg.canvas())
            self.__zoomer.setRubberBandPen(QPen(Qt.blue))
            grid = QwtPlotGrid()
            grid.setPen(QPen(QColor('grey'), 0, Qt.DotLine))
            grid.attach(self.__plotWdg)
            self.__frameLayout.addWidget(self.__plotWdg)

        elif self.__lib == 'Matplotlib':
            # __plotWdg.figure : matplotlib.figure.Figure
            fig = Figure((1.0, 1.0), linewidth=0.0, subplotpars=SubplotParams(left=0, bottom=0, right=1, top=1,
                                                                              wspace=0, hspace=0))

            font = {'family': 'arial', 'weight': 'normal', 'size': 12}
            rc('font', **font)

            rect = fig.patch
            rect.set_facecolor((0.9, 0.9, 0.9))

            self.__axes = fig.add_axes((0.07, 0.16, 0.92, 0.82))
            self.__axes.set_xbound(0, 1000)
            self.__axes.set_ybound(0, 1000)
            self.__manageMatplotlibAxe(self.__axes)
            self.__plotWdg = FigureCanvasQTAgg(fig)
            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            self.__plotWdg.setSizePolicy(sizePolicy)
            self.__frameLayout.addWidget(self.__plotWdg)

    def setProfiles(self, profiles, numLines):
        """
        To set the profiles
        :param profiles: profiles : positions with elevations (for line and points)
        :param numLines: number of selected connected lines
        """
        self.__numLines = numLines
        self.__profiles = profiles
        if self.__lib == 'Matplotlib':
            self.__prepare_points()

    def __getLinearPoints(self):
        """
        To extract the linear points of the profile
        """
        profileLen = 0
        self.__profiles[0]['l'] = profileLen
        for i in range(0, len(self.__profiles)-1):
            x1 = float(self.__profiles[i]['x'])
            y1 = float(self.__profiles[i]['y'])
            x2 = float(self.__profiles[i+1]['x'])
            y2 = float(self.__profiles[i+1]['y'])
            profileLen += sqrt(((x2-x1)*(x2-x1)) + ((y2-y1)*(y2-y1)))
            self.__profiles[i+1]['l'] = profileLen

    def __getMnt(self, settings):
        """
        To get the MN data for the profile
        :param settings: settings containing MN url
        """
        if settings is None or settings.mntUrl is None or settings.mntUrl == "None":
            url = 'http://map.lausanne.ch/main/wsgi/profile.json'
        elif settings.mntUrl == "":
            return
        else:
            url = settings.mntUrl
        names = ['mnt', 'mns', 'toit_rocher']
        url += '?layers='
        pos = 0
        for name in names:
            if pos > 0:
                url += ','
            pos += 1
            url += name
        url += '&geom={"type":"LineString","coordinates":['
        pos = 0
        for i in range(len(self.__profiles)):
            if pos > 0:
                url += ','
            pos += 1
            url += '[' + str(self.__profiles[i]['x']) + ',' + str(self.__profiles[i]['y']) + ']'
        url = url + ']}&nbPoints=' + str(int(self.__profiles[len(self.__profiles)-1]['l']))
        try:
            response = urlopen(url)
            j = response.read()
            j_obj = json.loads(j)
            profile = j_obj['profile']
            self.__mntPoints = []
            self.__mntPoints.append(names)
            mnt_l = []
            mnt_z = []
            for p in range(len(names)):
                z = []
                mnt_z.append(z)
            for pt in profile:
                mnt_l.append(float(pt['dist']))
                values = pt['values']
                for p in range(len(names)):
                    if names[p] in values:
                        mnt_z[p].append(float(values[names[p]]))
                    else:
                        mnt_z[p].append(None)
            self.__mntPoints.append(mnt_l)
            self.__mntPoints.append(mnt_z)
        except HTTPError as e:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "HTTP Error"),
                QCoreApplication.translate("VDLTools", "status error [" + str(e.code) + "] : " + e.reason),
                level=QgsMessageBar.CRITICAL, duration=0)
        except URLError as e:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "URL Error"),
                e.reason, level=QgsMessageBar.CRITICAL, duration=0)

    def attachCurves(self, names, settings, usedMnts):
        """
        To attach the curves for the layers to the profile
        :param names: layers names
        """
        if (self.__profiles is None) or (self.__profiles == 0):
            return

        self.__getLinearPoints()
        if usedMnts is not None and (usedMnts[0] or usedMnts[1] or usedMnts[2]):
            self.__getMnt(settings)

        c = 0

        if self.__mntPoints is not None:
                for p in range(len(self.__mntPoints[0])):
                    if usedMnts[p]:
                        legend = QLabel("<font color='" + self.__colors[c] + "'>" + self.__mntPoints[0][p]
                                        + "</font>")
                        self.__legendLayout.addWidget(legend)

                        if self.__lib == 'Qwt5':

                            xx = [list(g) for k, g in itertools.groupby(self.__mntPoints[1],
                                                                        lambda x: x is None) if not k]
                            yy = [list(g) for k, g in itertools.groupby(self.__mntPoints[2][p], lambda x: x is None)
                                  if not k]

                            for j in range(len(xx)):
                                curve = QwtPlotCurve(self.__mntPoints[0][p])
                                curve.setData(xx[j], yy[j])
                                curve.setPen(QPen(QColor(self.__colors[c]), 3))
                                curve.attach(self.__plotWdg)

                        elif self.__lib == 'Matplotlib':
                            qcol = QColor(self.__colors[c])
                            self.__plotWdg.figure.get_axes()[0].plot(self.__mntPoints[1], self.__mntPoints[2][p],
                                                                     gid=self.__mntPoints[0][p], linewidth=3)
                            tmp = self.__plotWdg.figure.get_axes()[0].get_lines()
                            for t in range(len(tmp)):
                                if self.__mntPoints[0][p] == tmp[t].get_gid():
                                    tmp[c].set_color((old_div(qcol.red(), 255.0), old_div(qcol.green(), 255.0),
                                                      old_div(qcol.blue(), 255.0), old_div(qcol.alpha(), 255.0)))
                                    self.__plotWdg.draw()
                                    break
                        c += 1

        if 'z' in self.__profiles[0]:
            for i in range(len(self.__profiles[0]['z'])):
                if i < self.__numLines:
                    v = 0
                else:
                    v = i - self.__numLines + 1
                name = names[v]
                xx = []
                yy = []
                for prof in self.__profiles:
                    xx.append(prof['l'])
                    yy.append(prof['z'][i])

                for j in range(len(yy)):
                    if yy[j] is None:
                        xx[j] = None

                if i == 0 or i > (self.__numLines-1):
                    legend = QLabel("<font color='" + self.__colors[c] + "'>" + name + "</font>")
                    self.__legendLayout.addWidget(legend)

                if self.__lib == 'Qwt5':

                    # Split xx and yy into single lines at None values
                    xx = [list(g) for k, g in itertools.groupby(xx, lambda x: x is None) if not k]
                    yy = [list(g) for k, g in itertools.groupby(yy, lambda x: x is None) if not k]

                    # Create & attach one QwtPlotCurve per one single line
                    for j in range(len(xx)):
                        curve = QwtPlotCurve(name)
                        curve.setData(xx[j], yy[j])
                        curve.setPen(QPen(QColor(self.__colors[c]), 3))
                        if i > (self.__numLines-1):
                            curve.setStyle(QwtPlotCurve.Dots)
                            pen = QPen(QColor(self.__colors[c]), 8)
                            pen.setCapStyle(Qt.RoundCap)
                            curve.setPen(pen)
                        curve.attach(self.__plotWdg)

                elif self.__lib == 'Matplotlib':
                    qcol = QColor(self.__colors[c])
                    if i < self.__numLines:
                        self.__plotWdg.figure.get_axes()[0].plot(xx, yy, gid=name, linewidth=3)
                    else:
                        self.__plotWdg.figure.get_axes()[0].plot(xx, yy, gid=name, linewidth=5, marker='o',
                                                                 linestyle='None')
                    tmp = self.__plotWdg.figure.get_axes()[0].get_lines()
                    for t in range(len(tmp)):
                        if name == tmp[t].get_gid():
                            tmp[c].set_color((old_div(qcol.red(), 255.0), old_div(qcol.green(), 255.0),
                                              old_div(qcol.blue(), 255.0), old_div(qcol.alpha(), 255.0)))
                            self.__plotWdg.draw()
                            break
                c += 1

        # scaling this
        try:
            self.__reScalePlot(None, True)
        except:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Rescale problem... (trace printed)"),
                level=QgsMessageBar.CRITICAL, duration=0)
            print(
                QCoreApplication.translate("VDLTools", "rescale problem : "), sys.exc_info()[0], traceback.format_exc())
        if self.__lib == 'Qwt5':
            self.__plotWdg.replot()
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].redraw_in_frame()
            self.__plotWdg.draw()
            self.__activateMouseTracking(True)
            self.__marker.show()

    def __reScalePlot(self, value=None, auto=False):
        """
        To rescale the profile plot depending to the bounds
        """
        if (self.__profiles is None) or (self.__profiles == 0):
            self.__plotWdg.replot()
            return

        maxi = 0
        for i in range(len(self.__profiles)):
            if (int(self.__profiles[i]['l'])) > maxi:
                maxi = int(self.__profiles[i]['l']) + 1
        if self.__lib == 'Qwt5':
            self.__plotWdg.setAxisScale(2, 0, maxi, 0)
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].set_xbound(0, maxi)

        minimumValue = self.__minSpin.value()
        maximumValue = self.__maxSpin.value()

        # to set max y and min y displayed
        if auto:
            minimumValue = 1000000000
            maximumValue = -1000000000
            for i in range(len(self.__profiles)):
                if 'z' in self.__profiles[i]:
                    mini = self.__minTab(self.__profiles[i]['z'])
                    if int(mini) < minimumValue:
                        minimumValue = int(mini) - 1
                    maxi = self.__maxTab(self.__profiles[i]['z'])
                    if int(maxi) > maximumValue:
                        maximumValue = int(maxi) + 1
                if self.__mntPoints is not None:
                    for pts in self.__mntPoints[2]:
                        miniMnt = self.__minTab(pts)
                        if int(miniMnt) < minimumValue:
                            minimumValue = int(miniMnt) - 1
                        maxiMnt = self.__maxTab(pts)
                        if int(maxiMnt) > maximumValue:
                            maximumValue = int(maxiMnt) + 1
        self.__maxSpin.setValue(maximumValue)
        self.__minSpin.setValue(minimumValue)
        self.__maxSpin.setEnabled(True)
        self.__minSpin.setEnabled(True)

        if self.__lib == 'Qwt5':
            rect = QRectF(0, minimumValue, maxi, maximumValue-minimumValue)
            self.__zoomer.setZoomBase(rect)

        # to draw vertical lines
        for i in range(len(self.__profiles)):
            zz = []
            for j in range(self.__numLines):
                if self.__profiles[i]['z'][j] is not None:
                    zz.append(j)
            color = None
            if len(zz) == 2:
                width = 3
                color = QColor('red')
            else:
                width = 1

            if self.__lib == 'Qwt5':
                vertLine = QwtPlotMarker()
                vertLine.setLineStyle(QwtPlotMarker.VLine)
                pen = vertLine.linePen()
                pen.setWidth(width)
                if color is not None:
                    pen.setColor(color)
                vertLine.setLinePen(pen)
                vertLine.setXValue(self.__profiles[i]['l'])
                label = vertLine.label()
                label.setText(str(i))
                vertLine.setLabel(label)
                vertLine.setLabelAlignment(Qt.AlignLeft)
                vertLine.attach(self.__plotWdg)
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.get_axes()[0].vlines(self.__profiles[i]['l'], minimumValue, maximumValue,
                                                           linewidth=width)

        if minimumValue < maximumValue:
            if self.__lib == 'Qwt5':
                self.__plotWdg.setAxisScale(0, minimumValue, maximumValue, 0)
                self.__plotWdg.replot()
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.get_axes()[0].set_ybound(minimumValue, maximumValue)
                self.__plotWdg.figure.get_axes()[0].redraw_in_frame()
                self.__plotWdg.draw()

    @staticmethod
    def __minTab(tab):
        """
        To get the minimum value in a table
        :param tab: table to scan
        :return: minimum value
        """
        mini = 1000000000
        for t in tab:
            if t is None:
                continue
            if t < mini:
                mini = t
        return mini

    @staticmethod
    def __maxTab(tab):
        """
        To get the maximum value in a table
        :param tab: table to scan
        :return: maximum value
        """
        maxi = -1000000000
        for t in tab:
            if t is None:
                continue
            if t > maxi:
                maxi = t
        return maxi

    def __setLib(self):
        """
        To set the new widget library (qwt <-> matplotlib)
        """
        self.__lib = self.__libs[self.__libCombo.currentIndex()]
        self.__changePlotWidget()

    def __save(self):
        """
        To save the profile in a file, on selected format
        """
        idx = self.__typeCombo.currentIndex()
        if idx == 0:
            self.__outPDF()
        elif idx == 1:
            self.__outPNG()
        else:
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Invalid index ") + str(idx),
                level=QgsMessageBar.CRITICAL, duration=0)

    def __outPDF(self):
        """
        To save the profile as pdf file
        """
        fileName = QFileDialog.getSaveFileName(
            self.__iface.mainWindow(), QCoreApplication.translate("VDLTools", "Save As"),
            QCoreApplication.translate("VDLTools", "Profile.pdf"),"Portable Document Format (*.pdf)")
        if fileName is not None:
            if self.__lib == 'Qwt5':
                printer = QPrinter()
                printer.setCreator(QCoreApplication.translate("VDLTools", "QGIS Profile Plugin"))
                printer.setOutputFileName(fileName)
                printer.setOutputFormat(QPrinter.PdfFormat)
                printer.setOrientation(QPrinter.Landscape)
                self.__plotWdg.print_(printer)
            elif self.__lib == 'Matplotlib':
                self.__plotWdg.figure.savefig(str(fileName))
            # printer = QPrinter()
            # printer.setCreator(QCoreApplication.translate("VDLTools", "QGIS Profile Plugin"))
            # printer.setOutputFileName(fileName)
            # printer.setOutputFormat(QPrinter.PdfFormat)
            # printer.setOrientation(QPrinter.Landscape)
            # printer.setPaperSize(QSizeF(self.__printWdg.size()), QPrinter.Millimeter)
            # printer.setFullPage(True)
            # self.__printWdg.render(printer)

    def __outPNG(self):
        """
        To save the profile as png file
        """
        fileName = QFileDialog.getSaveFileName(
            self.__iface.mainWindow(), QCoreApplication.translate("VDLTools", "Save As"),
            QCoreApplication.translate("VDLTools", "Profile.png"),"Portable Network Graphics (*.png)")
        if fileName is not None:
            QPixmap.grabWidget(self.__printWdg).save(fileName, "PNG")

    def clearData(self):
        """
        To clear the displayed data
        """
        if self.__profiles is None:
            return
        if self.__lib == 'Qwt5':
            self.__plotWdg.clear()
            self.__profiles = None
            temp1 = self.__plotWdg.itemList()
            for j in range(len(temp1)):
                if temp1[j].rtti() == QwtPlotItem.Rtti_PlotCurve:
                    temp1[j].detach()
        elif self.__lib == 'Matplotlib':
            self.__plotWdg.figure.get_axes()[0].cla()
            self.__manageMatplotlibAxe(self.__plotWdg.figure.get_axes()[0])
        self.__maxSpin.setEnabled(False)
        self.__minSpin.setEnabled(False)
        self.__maxSpin.setValue(0)
        self.__minSpin.setValue(0)

        # clear legend
        while self.__legendLayout.count():
            child = self.__legendLayout.takeAt(0)
            child.widget().deleteLater()

    def __manageMatplotlibAxe(self, axe):
        """
        To manage the axes for matplotlib library
        :param axe: the axes element
        """
        axe.grid()
        axe.tick_params(axis="both", which="major", direction="out", length=10, width=1, bottom=True, top=False,
                        left=True, right=False)
        axe.minorticks_on()
        axe.tick_params(axis="both", which="minor", direction="out", length=5, width=1, bottom=True, top=False,
                        left=True, right=False)
        axe.set_xlabel(QCoreApplication.translate("VDLTools", "Distance [m]"))
        axe.set_ylabel(QCoreApplication.translate("VDLTools", "Elevation [m]"))

    def __activateMouseTracking(self, activate):
        """
        To (de)activate the mouse tracking on the profile for matplotlib library
        :param activate: true to activate, false to deactivate
        """
        if activate:
            self.__doTracking = True
            self.__loadRubber()
            self.cid = self.__plotWdg.mpl_connect('motion_notify_event', self.__mouseevent_mpl)
        elif self.__doTracking:
            self.__doTracking = False
            self.__plotWdg.mpl_disconnect(self.cid)
            if self.__marker is not None:
                self.__canvas.scene().removeItem(self.__marker)
            try:
                if self.__vline is not None:
                    self.__plotWdg.figure.get_axes()[0].lines.remove(self.__vline)
                    self.__plotWdg.draw()
            except Exception as e:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools", "Tracking exception : ") + str(e),
                    level=QgsMessageBar.CRITICAL, duration=0)

    def __mouseevent_mpl(self, event):
        """
        To manage matplotlib mouse tracking event
        :param event: mouse tracking event
        """
        if event.xdata is not None:
            try:
                if self.__vline is not None:
                    self.__plotWdg.figure.get_axes()[0].lines.remove(self.__vline)
            except Exception as e:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools", "Mouse event exception : ") + str(e),
                    level=QgsMessageBar.CRITICAL, duration=0)
            xdata = float(event.xdata)
            self.__vline = self.__plotWdg.figure.get_axes()[0].axvline(xdata, linewidth=2, color='k')
            self.__plotWdg.draw()
            i = 1
            while i < len(self.__tabmouseevent)-1 and xdata > self.__tabmouseevent[i][0]:
                i += 1
            i -= 1

            x = self.__tabmouseevent[i][1] + (self.__tabmouseevent[i + 1][1] - self.__tabmouseevent[i][1]) / (
            self.__tabmouseevent[i + 1][0] - self.__tabmouseevent[i][0]) * (xdata - self.__tabmouseevent[i][0])
            y = self.__tabmouseevent[i][2] + (self.__tabmouseevent[i + 1][2] - self.__tabmouseevent[i][2]) / (
            self.__tabmouseevent[i + 1][0] - self.__tabmouseevent[i][0]) * (xdata - self.__tabmouseevent[i][0])
            self.__marker.show()
            self.__marker.setCenter(QgsPoint(x, y))

    def __loadRubber(self):
        """
        To load te rubber band for mouse tracking on map
        """
        self.__marker = QgsVertexMarker(self.__canvas)
        self.__marker.setIconSize(5)
        self.__marker.setIconType(QgsVertexMarker.ICON_BOX)
        self.__marker.setPenWidth(3)

    def __prepare_points(self):
        """
        To prepare the points on map for mouse tracking on profile
        """
        self.__tabmouseevent = []
        length = 0
        for i, point in enumerate(self.__profiles):
            if i == 0:
                self.__tabmouseevent.append([0, point['x'], point['y']])
            else:
                length += ((self.__profiles[i]['x'] - self.__profiles[i-1]['x']) ** 2 +
                           (self.__profiles[i]['y'] - self.__profiles[i-1]['y']) ** 2) ** 0.5
                self.__tabmouseevent.append([float(length), float(point['x']), float(point['y'])])

    def closeEvent(self, event):
        """
        When the dock widget is closed
        :param event: close event
        """
        if self.__maxSpin is not None:
            Signal.safelyDisconnect(self.__maxSpin.valueChanged, self.__reScalePlot)
            self.__maxSpin = None
        if self.__minSpin is not None:
            Signal.safelyDisconnect(self.__minSpin.valueChanged, self.__reScalePlot)
            self.__minSpin = None
        if self.__saveButton is not None:
            Signal.safelyDisconnect(self.__saveButton.clicked, self.__save)
            self.__saveButton = None
        if self.__libCombo is not None:
            Signal.safelyDisconnect(self.__libCombo.currentIndexChanged, self.__setLib)
            self.__libCombo = None
        self.closeSignal.emit()
        if self.__marker is not None:
            self.__marker.hide()
        QDockWidget.closeEvent(self, event)
コード例 #30
0
class MoveNodeMapTool(ParentMapTool):
    ''' Button 16. Move node
    Execute SQL function: 'gw_fct_node2arc' '''        

    def __init__(self, iface, settings, action, index_action, controller, srid):
        ''' Class constructor '''        
        
        # Call ParentMapTool constructor     
        super(MoveNodeMapTool, self).__init__(iface, settings, action, index_action)  
        self.srid = srid  

        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(0, 255, 0))
        self.vertexMarker.setIconSize(9)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)
   
        # Rubber band
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)
        mFillColor = QColor(255, 0, 0);
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(3)           
        self.reset()        


    def reset(self):
                
        # Clear selected features 
        layer = self.canvas.currentLayer()
        if layer is not None:
            layer.removeSelection()

        # Graphic elements
        self.rubberBand.reset()
          
            
    def move_node(self, node_id, point):
        ''' Move selected node to the current point '''  
           
        if self.srid is None:
            self.srid = self.settings.value('db/srid')  
        if self.schema_name is None:
            self.schema_name = self.settings.value('db/schema_name')               
                   
        # Update node geometry
        the_geom = "ST_GeomFromText('POINT("+str(point.x())+" "+str(point.y())+")', "+str(self.srid)+")";
        sql = "UPDATE "+self.schema_name+".node SET the_geom = "+the_geom
        sql+= " WHERE node_id = '"+node_id+"'"
        status = self.controller.execute_sql(sql) 
        if status:
            # Execute SQL function and show result to the user
            function_name = "gw_fct_node2arc"
            sql = "SELECT "+self.schema_name+"."+function_name+"('"+str(node_id)+"');"
            self.controller.execute_sql(sql)
        else:
            message = "Move node: Error updating geometry"
            self.controller.show_warning(message, context_name='ui_message')
            
        # Refresh map canvas
        self.canvas.currentLayer().triggerRepaint()  

                
    
    ''' QgsMapTool inherited event functions '''    
       
    def activate(self):
        ''' Called when set as currently active map tool '''

        # Check button
        self.action().setChecked(True)

        # Store user snapping configuration
        self.snapperManager.storeSnappingOptions()

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to node
        self.snapperManager.snapToNode()
        self.snapperManager.snapToArc()

        # Change pointer
        cursor = QCursor()
        cursor.setShape(Qt.CrossCursor)

        # Get default cursor        
        self.stdCursor = self.parent().cursor()   
 
        # And finally we set the mapTool's parent cursor
        self.parent().setCursor(cursor)

        # Reset
        self.reset()

        # Show help message when action is activated
        if self.show_help:
            message = "Select the disconnected node by clicking on it, move the pointer to desired location inside a pipe and click again"
            self.controller.show_info(message, context_name='ui_message' )

        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_node)
        except:
            self.canvas.setCurrentLayer(self.layer_node)


    def deactivate(self):
        ''' Called when map tool is being deactivated '''

        # Check button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

        # Recover cursor
        self.canvas.setCursor(self.stdCursor)

        try:
            self.rubberBand.reset(QGis.Line)
        except AttributeError:
            pass


    def canvasMoveEvent(self, event):
        ''' Mouse movement event '''      
                        
        # Hide highlight
        self.vertexMarker.hide()
            
        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        eventPoint = QPoint(x,y)

        # Node layer
        layer = self.canvas.currentLayer()
        if layer is None:
            return

        # Select node or arc
        if layer.selectedFeatureCount() == 0:

            # Snap to node
            (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
            # That's the snapped point
            if result <> [] and (result[0].layer.name() == self.layer_node.name()):

                point = QgsPoint(result[0].snappedVertex)

                # Add marker    
                self.vertexMarker.setColor(QColor(0, 255, 0))
                self.vertexMarker.setCenter(point)
                self.vertexMarker.show()
                
                # Set a new point to go on with
                #self.appendPoint(point)
                self.rubberBand.movePoint(point)

            else:
                point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(),  x, y)
                self.rubberBand.movePoint(point)

        else:
                
            # Snap to arc
            result = []
            (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
            # That's the snapped point
            if (result <> []) and (result[0].layer.name() == self.layer_arc.name()) and (result[0].snappedVertexNr == -1):
            
                point = QgsPoint(result[0].snappedVertex)

                # Add marker
                self.vertexMarker.setColor(QColor(255, 0, 0))
                self.vertexMarker.setCenter(point)
                self.vertexMarker.show()
                
                # Select the arc
                self.layer_arc.removeSelection()
                self.layer_arc.select([result[0].snappedAtGeometry])

                # Bring the rubberband to the cursor i.e. the clicked point
                self.rubberBand.movePoint(point)
        
            else:
                
                # Bring the rubberband to the cursor i.e. the clicked point
                point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(),  x, y)
                self.rubberBand.movePoint(point)


    def canvasReleaseEvent(self, event):
        ''' Mouse release event '''         
        
        if event.button() == Qt.LeftButton:
            
            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x,y)

            # Node layer
            layer = self.canvas.currentLayer()

            # Select node or arc
            if layer.selectedFeatureCount() == 0:

                # Snap to node
                (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
                # That's the snapped point
                if result <> [] and (result[0].layer.name() == self.layer_node.name()):
            
                    point = QgsPoint(result[0].snappedVertex)

                    layer.select([result[0].snappedAtGeometry])
        
                    # Hide highlight
                    self.vertexMarker.hide()
                    
                    # Set a new point to go on with
                    self.rubberBand.addPoint(point)

            else:
                
                # Snap to arc
                (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
                # That's the snapped point
                if (result <> []) and (result[0].layer.name() == self.layer_arc.name()):
            
                    point = QgsPoint(result[0].snappedVertex)
                    
                    # Get selected feature (at this moment it will have one and only one)           
                    feature = layer.selectedFeatures()[0]
                    node_id = feature.attribute('node_id') 
        
                    # Move selected node to the released point
                    self.move_node(node_id, point)       
            
                    # Rubberband reset
                    self.reset()                    
            
                    # Refresh map canvas
                    self.iface.mapCanvas().refresh()               
        
        elif event.button() == Qt.RightButton:
            self.reset()
コード例 #31
0
ファイル: qgisred_createPipe.py プロジェクト: QAndrea/QGISRed
class QGISRedCreatePipeTool(QgsMapTool):
    def __init__(self, button, iface, projectDirectory, netwName, parent):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.ProjectDirectory = projectDirectory
        self.NetworkName = netwName
        self.parent = parent
        self.setAction(button)

        self.startMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.startMarker.setColor(QColor(255, 87, 51))
        self.startMarker.setIconSize(15)
        self.startMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.startMarker.setPenWidth(3)
        self.startMarker.hide()

        self.endMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.endMarker.setColor(QColor(255, 87, 51))
        self.endMarker.setIconSize(15)
        self.endMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.endMarker.setPenWidth(3)
        self.endMarker.hide()

        self.snapper = None
        self.rubberBand1 = None
        self.rubberBand2 = None
        self.resetProperties()

    def activate(self):
        QgsMapTool.activate(self)

        # Snapping
        self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())
        self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings())
        config = QgsSnappingConfig(QgsProject.instance())
        config.setType(1)  # Vertex
        config.setMode(2)  # All layers
        config.setTolerance(2)
        config.setUnits(2)  # Pixels
        config.setEnabled(True)
        self.snapper.setConfig(config)

    def deactivate(self):
        self.resetProperties()
        QgsMapTool.deactivate(self)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    """Methods"""

    def resetProperties(self):
        # self.toolbarButton.setChecked(False)
        if self.rubberBand1 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand1)
        if self.rubberBand2 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand2)
        self.startMarker.hide()
        self.endMarker.hide()

        self.mousePoints = []
        self.firstClicked = False
        self.objectSnapped = None

        self.rubberBand1 = None
        self.rubberBand2 = None

    def createRubberBand(self, points):
        myPoints1 = []
        for p in points:
            myPoints1.append(QgsPoint(p.x(), p.y()))
        myPoints1.remove(myPoints1[-1])
        if self.rubberBand1 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand1)
        self.rubberBand1 = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand1.setToGeometry(QgsGeometry.fromPolyline(myPoints1),
                                       None)
        self.rubberBand1.setColor(QColor(240, 40, 40))
        self.rubberBand1.setWidth(1)
        self.rubberBand1.setLineStyle(Qt.SolidLine)

        myPoints2 = []
        myPoints2.append(QgsPoint(points[-2].x(), points[-2].y()))
        myPoints2.append(QgsPoint(points[-1].x(), points[-1].y()))
        if self.rubberBand2 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand2)
        self.rubberBand2 = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand2.setToGeometry(QgsGeometry.fromPolyline(myPoints2),
                                       None)
        self.rubberBand2.setColor(QColor(240, 40, 40))
        self.rubberBand2.setWidth(1)
        self.rubberBand2.setLineStyle(Qt.DashLine)

    """Events"""

    def canvasPressEvent(self, event):
        if event.button() == Qt.LeftButton:
            if not self.firstClicked:
                self.firstClicked = True
                point = self.toMapCoordinates(event.pos())
                if self.objectSnapped is not None:
                    point = self.objectSnapped.point()
                self.mousePoints.append(point)
                self.mousePoints.append(point)
            else:
                self.mousePoints.append(self.mousePoints[-1])
            self.createRubberBand(self.mousePoints)

        if event.button() == Qt.RightButton:
            self.mousePoints.remove(self.mousePoints[-1])
            if self.firstClicked:
                if (len(self.mousePoints) == 2
                        and self.mousePoints[0] == self.mousePoints[1]):
                    createdPipe = False
                elif len(self.mousePoints) < 2:
                    createdPipe = False
                else:
                    createdPipe = True
            if createdPipe:
                self.parent.runCreatePipe(self.mousePoints)
            self.resetProperties()

    def canvasMoveEvent(self, event):
        # Mouse not clicked
        if not self.firstClicked:
            match = self.snapper.snapToMap(self.toMapCoordinates(event.pos()))
            if match.isValid():
                self.objectSnapped = match
                self.startMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.startMarker.show()
            else:
                self.objectSnapped = None
                self.startMarker.hide()
        # Mouse clicked
        else:
            point = self.toMapCoordinates(event.pos())
            match = self.snapper.snapToMap(point)
            if match.isValid():
                self.objectSnapped = match
                self.endMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.endMarker.show()
                self.mousePoints[-1] = match.point()
            else:
                self.objectSnapped = None
                self.endMarker.hide()
                self.mousePoints[-1] = point
            self.createRubberBand(self.mousePoints)
コード例 #32
0
class DeleteNodeMapTool(ParentMapTool):
    ''' Button 17. User select one node.
    Execute SQL function: 'gw_fct_delete_node' '''

    def __init__(self, iface, settings, action, index_action):
        ''' Class constructor '''

        # Call ParentMapTool constructor
        super(DeleteNodeMapTool, self).__init__(iface, settings, action, index_action)

        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(255, 25, 25))
        self.vertexMarker.setIconSize(12)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_CIRCLE)  # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)

    ''' QgsMapTools inherited event functions '''

    def canvasMoveEvent(self, event):

        # Hide highlight
        self.vertexMarker.hide()

        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        eventPoint = QPoint(x, y)

        # Snapping
        (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

        # That's the snapped point
        if result <> []:

            # Check Arc or Node
            for snapPoint in result:

                if snapPoint.layer.name() == self.layer_node.name():
                    # Get the point
                    point = QgsPoint(result[0].snappedVertex)

                    # Add marker
                    self.vertexMarker.setCenter(point)
                    self.vertexMarker.show()

                    break

    def canvasReleaseEvent(self, event):

        # With left click the digitizing is finished
        if event.button() == Qt.LeftButton:

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)

            snappFeat = None

            # Snapping
            (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

            # That's the snapped point
            if result <> []:

                # Check Arc or Node
                for snapPoint in result:

                    if snapPoint.layer.name() == self.layer_node.name():
                        # Get the point
                        point = QgsPoint(result[0].snappedVertex)

                        snappFeat = next(
                            result[0].layer.getFeatures(QgsFeatureRequest().setFilterFid(result[0].snappedAtGeometry)))

                        break

            if snappFeat is not None:

                # Get selected features and layer type: 'node'
                feature = snappFeat
                node_id = feature.attribute('node_id')

                # Execute SQL function and show result to the user
                function_name = "gw_fct_delete_node"
                sql = "SELECT " + self.schema_name + "." + function_name + "('" + str(node_id) + "');"
                status = self.controller.execute_sql(sql)
                if status:
                    message = "Node deleted successfully"
                    self.controller.show_warning(message, context_name='ui_message' )  

                # Refresh map canvas
                self.iface.mapCanvas().refresh()

    def activate(self):

        # Check button
        self.action().setChecked(True)

        # Store user snapping configuration
        self.snapperManager.storeSnappingOptions()

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to node
        self.snapperManager.snapToNode()

        # Change cursor
        self.canvas.setCursor(self.cursor)

        # Show help message when action is activated
        if self.show_help:
            message = "Select the node inside a pipe by clicking on it and it will be removed"
            self.controller.show_warning(message, context_name='ui_message')
               
        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_node)
        except:
            self.canvas.setCurrentLayer(self.layer_node)

    def deactivate(self):

        # Check button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

        # Recover cursor
        self.canvas.setCursor(self.stdCursor)

        # Removehighlight
        self.h = None
コード例 #33
0
ファイル: pointtool.py プロジェクト: havatv/raster_tracer
class PointTool(QgsMapToolEdit):
    '''
    Implementation of interactions of the user with the main map.
    Will called every time the user clicks on the map
    or hovers the mouse over the map.
    '''
    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()

    def __init__(self, canvas, iface, turn_off_snap, smooth=False):
        '''
        canvas - link to the QgsCanvas of the application
        iface - link to the Qgis Interface
        turn_off_snap - flag sets snapping to the nearest color
        smooth - flag sets smoothing of the traced path
        '''

        self.iface = iface

        # list of Anchors for current line
        self.anchors = []

        # for keeping track of mouse event for rubber band updating
        self.last_mouse_event_pos = None

        self.tracing_mode = TracingModes.PATH

        self.turn_off_snap = turn_off_snap
        self.smooth_line = smooth

        # possible variants: gray_diff, as_is, color_diff (using v from hsv)
        self.grid_conversion = "gray_diff"

        # QApplication.restoreOverrideCursor()
        # QApplication.setOverrideCursor(Qt.CrossCursor)
        QgsMapToolEmitPoint.__init__(self, canvas)

        self.rlayer = None
        self.grid_changed = None
        self.snap_tolerance = None
        self.vlayer = None
        self.grid = None
        self.sample = None

        self.tracking_is_active = False

        # False = not a polygon
        self.rubber_band = QgsRubberBand(self.canvas(), False)
        self.markers = []
        self.marker_snap = QgsVertexMarker(self.canvas())
        self.marker_snap.setColor(QColor(255, 0, 255))

        self.find_path_task = None

        self.change_state(WaitingFirstPointState)

    def display_message(
        self,
        title,
        message,
        level='Info',
        duration=2,
    ):
        '''
        Shows message bar to the user.
        `level` receives one of four possible string values:
            Info, Warning, Critical, Success
        '''

        LEVELS = {
            'Info': Qgis.Info,
            'Warning': Qgis.Warning,
            'Critical': Qgis.Critical,
            'Success': Qgis.Success,
        }

        self.iface.messageBar().pushMessage(title, message, LEVELS[level],
                                            duration)

    def change_state(self, state):
        self.state = state(self)

    def snap_tolerance_changed(self, snap_tolerance):
        self.snap_tolerance = snap_tolerance
        if snap_tolerance is None:
            self.marker_snap.hide()
        else:
            self.marker_snap.show()

    def trace_color_changed(self, color):
        r, g, b = self.sample

        if color is False:
            self.grid_changed = None
        else:
            r0, g0, b0, t = color.getRgb()
            self.grid_changed = np.abs((r0 - r)**2 + (g0 - g)**2 + (b0 - b)**2)

    def get_current_vector_layer(self):
        try:
            vlayer = self.iface.layerTreeView().selectedLayers()[0]
            if isinstance(vlayer, QgsVectorLayer):
                if vlayer.wkbType() == QgsWkbTypes.MultiLineString:
                    return vlayer
                else:
                    self.display_message(
                        " ",
                        "The active layer must be" +
                        " a MultiLineString vector layer",
                        level='Warning',
                        duration=2,
                    )
                    return None
            else:
                self.display_message(
                    "Missing Layer",
                    "Please select vector layer to draw",
                    level='Warning',
                    duration=2,
                )
                return None
        except IndexError:
            self.display_message(
                "Missing Layer",
                "Please select vector layer to draw",
                level='Warning',
                duration=2,
            )
            return None

    def raster_layer_has_changed(self, raster_layer):
        self.rlayer = raster_layer
        if self.rlayer is None:
            self.display_message(
                "Missing Layer",
                "Please select raster layer to trace",
                level='Warning',
                duration=2,
            )
            return

        try:
            sample, to_indexes, to_coords, to_coords_provider, \
                to_coords_provider2 = \
                get_whole_raster(self.rlayer,
                                 QgsProject.instance(),
                                 )
        except PossiblyIndexedImageError:
            self.display_message(
                "Missing Layer",
                "Can't trace indexed or gray image",
                level='Critical',
                duration=2,
            )
            return

        r = sample[0].astype(float)
        g = sample[1].astype(float)
        b = sample[2].astype(float)
        where_are_NaNs = np.isnan(r)
        r[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(g)
        g[where_are_NaNs] = 0
        where_are_NaNs = np.isnan(b)
        b[where_are_NaNs] = 0

        self.sample = (r, g, b)
        self.grid = r + g + b
        self.to_indexes = to_indexes
        self.to_coords = to_coords
        self.to_coords_provider = to_coords_provider
        self.to_coords_provider2 = to_coords_provider2

    def remove_last_anchor_point(self, undo_edit=True, redraw=True):
        '''
        Removes last anchor point and last marker point
        '''

        # check if we have at least one feature to delete
        vlayer = self.get_current_vector_layer()
        if vlayer is None:
            return
        if vlayer.featureCount() < 1:
            return

        # remove last marker
        if self.markers:
            last_marker = self.markers.pop()
            self.canvas().scene().removeItem(last_marker)

        # remove last anchor
        if self.anchors:
            self.anchors.pop()

        if undo_edit:
            # it's a very ugly way of triggering single undo event
            self.iface.editMenu().actions()[0].trigger()

        if redraw:
            self.update_rubber_band()
            self.redraw()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Backspace or e.key() == Qt.Key_B:
            # delete last segment if backspace is pressed
            self.remove_last_anchor_point()
        elif e.key() == Qt.Key_A:
            # change tracing mode
            self.tracing_mode = self.tracing_mode.next()
            self.update_rubber_band()
        elif e.key() == Qt.Key_S:
            # toggle snap mode
            self.turn_off_snap()
        elif e.key() == Qt.Key_Escape:
            # Abort tracing process
            self.abort_tracing_process()

    def add_anchor_points(self, x1, y1, i1, j1):
        '''
        Adds anchor points and markers to self.
        '''

        anchor = Anchor(x1, y1, i1, j1)
        self.anchors.append(anchor)

        marker = QgsVertexMarker(self.canvas())
        marker.setCenter(QgsPointXY(x1, y1))
        self.markers.append(marker)

    def trace_over_image(self, start, goal, do_it_as_task=False, vlayer=None):
        '''
        performs tracing
        '''

        i0, j0 = start
        i1, j1 = goal

        r, g, b, = self.sample

        try:
            r0 = r[i1, j1]
            g0 = g[i1, j1]
            b0 = b[i1, j1]
        except IndexError:
            raise OutsideMapError

        if self.grid_changed is None:
            grid = np.abs((r0 - r)**2 + (g0 - g)**2 + (b0 - b)**2)
        else:
            grid = self.grid_changed

        if do_it_as_task:
            # dirty hack to avoid QGIS crashing
            self.find_path_task = FindPathTask(
                grid.astype(np.dtype('l')),
                start,
                goal,
                self.draw_path,
                vlayer,
            )

            QgsApplication.taskManager().addTask(self.find_path_task, )
            self.tracking_is_active = True
        else:
            path, cost = FindPathFunction(
                grid.astype(np.dtype('l')),
                (i0, j0),
                (i1, j1),
            )
            return path, cost

    def trace(self, x1, y1, i1, j1, vlayer):
        '''
        Traces path from last point to given point.
        In case tracing is inactive just creates
        straight line.
        '''

        if self.tracing_mode.is_tracing():
            if self.snap_tolerance is not None:
                try:
                    i1, j1 = self.snap(i1, j1)
                except OutsideMapError:
                    return

            _, _, i0, j0 = self.anchors[-2]
            start_point = i0, j0
            end_point = i1, j1
            try:
                self.trace_over_image(start_point,
                                      end_point,
                                      do_it_as_task=True,
                                      vlayer=vlayer)
            except OutsideMapError:
                pass
        else:
            self.draw_path(
                None,
                vlayer,
                was_tracing=False,
                x1=x1,
                y1=y1,
            )

    def snap(self, i, j):
        if self.snap_tolerance is None:
            return i, j
        if not self.tracing_mode.is_tracing():
            return i, j
        if self.grid_changed is None:
            return i, j

        size_i, size_j = self.grid.shape
        size = self.snap_tolerance

        if i < size or j < size or i + size > size_i or j + size > size_j:
            raise OutsideMapError

        grid_small = self.grid_changed
        grid_small = grid_small[i - size:i + size, j - size:j + size]

        smallest_cells = np.where(grid_small == np.amin(grid_small))
        coordinates = list(zip(smallest_cells[0], smallest_cells[1]))

        if len(coordinates) == 1:
            delta_i, delta_j = coordinates[0]
            delta_i -= size
            delta_j -= size
        else:
            # find the closest to the center
            deltas = [(i - size, j - size) for i, j in coordinates]
            lengths = [(i**2 + j**2) for i, j in deltas]
            i = lengths.index(min(lengths))
            delta_i, delta_j = deltas[i]

        return i + delta_i, j + delta_j

    def canvasReleaseEvent(self, mouseEvent):
        '''
        Method where the actual tracing is performed
        after the user clicked on the map
        '''

        vlayer = self.get_current_vector_layer()

        if vlayer is None:
            return

        if not vlayer.isEditable():
            self.display_message(
                "Edit mode",
                "Please begin editing vector layer to trace",
                level='Warning',
                duration=2,
            )
            return

        if self.rlayer is None:
            self.display_message(
                "Missing Layer",
                "Please select raster layer to trace",
                level='Warning',
                duration=2,
            )
            return

        if mouseEvent.button() == Qt.RightButton:
            self.state.click_rmb(mouseEvent, vlayer)
        elif mouseEvent.button() == Qt.LeftButton:
            self.state.click_lmb(mouseEvent, vlayer)

        return

    def draw_path(self, path, vlayer, was_tracing=True,\
                  x1=None, y1=None):
        '''
        Draws a path after tracer found it.
        '''

        if was_tracing:
            if self.smooth_line:
                path = smooth(path, size=5)
                path = simplify(path)
            current_last_point = self.to_coords(*path[-1])
            path_ref = [self.to_coords_provider(i, j) for i, j in path]
        else:
            x0, y0, _, _ = self.anchors[-2]
            path_ref = [
                self.to_coords_provider2(x0, y0),
                self.to_coords_provider2(x1, y1)
            ]
            current_last_point = (x1, y1)

        self.ready = False
        if len(self.anchors) == 2:
            vlayer.beginEditCommand("Adding new line")
            add_feature_to_vlayer(vlayer, path_ref)
            vlayer.endEditCommand()
        else:
            x0, y0, _, _ = self.anchors[-2]
            last_point = self.to_coords_provider2(x0, y0)
            path_ref = [last_point] + path_ref[1:]
            vlayer.beginEditCommand("Adding new segment to the line")
            add_to_last_feature(vlayer, path_ref)
            vlayer.endEditCommand()
        _, _, current_last_point_i, current_last_point_j = self.anchors[-1]
        self.anchors[-1] = current_last_point[0], current_last_point[
            1], current_last_point_i, current_last_point_j
        self.redraw()
        self.tracking_is_active = False

    def update_rubber_band(self):
        # this is very ugly but I can't make another way
        if self.last_mouse_event_pos is None:
            return

        if not self.anchors:
            return

        x0, y0, _, _ = self.anchors[-1]
        qgsPoint = self.toMapCoordinates(self.last_mouse_event_pos)
        x1, y1 = qgsPoint.x(), qgsPoint.y()
        points = [QgsPoint(x0, y0), QgsPoint(x1, y1)]

        self.rubber_band.setColor(QColor(255, 0, 0))
        self.rubber_band.setWidth(3)

        self.rubber_band.setLineStyle(
            RUBBERBAND_LINE_STYLES[self.tracing_mode], )

        vlayer = self.get_current_vector_layer()
        if vlayer is None:
            return

        self.rubber_band.setToGeometry(
            QgsGeometry.fromPolyline(points),
            self.vlayer,
        )

    def canvasMoveEvent(self, mouseEvent):
        '''
        Store the mouse position for the correct
        updating of the rubber band
        '''

        # we need at least one point to draw
        if not self.anchors:
            return

        if self.snap_tolerance is not None and self.tracing_mode.is_tracing():
            qgsPoint = self.toMapCoordinates(mouseEvent.pos())
            x1, y1 = qgsPoint.x(), qgsPoint.y()
            # i, j = get_indxs_from_raster_coords(self.geo_ref, x1, y1)
            i, j = self.to_indexes(x1, y1)
            try:
                i1, j1 = self.snap(i, j)
            except OutsideMapError:
                return
            # x1, y1 = get_coords_from_raster_indxs(self.geo_ref, i1, j1)
            x1, y1 = self.to_coords(i1, j1)
            self.marker_snap.setCenter(QgsPointXY(x1, y1))

        self.last_mouse_event_pos = mouseEvent.pos()
        self.update_rubber_band()
        self.redraw()

    def abort_tracing_process(self):
        '''
        Terminate background process of tracing raster
        after the user hits Esc.
        '''

        # check if we have any tasks
        if self.find_path_task is None:
            return

        self.tracking_is_active = False

        try:
            # send terminate signal to the task
            self.find_path_task.cancel()
            self.find_path_task = None
        except RuntimeError:
            return
        else:
            self.remove_last_anchor_point(undo_edit=False, )

    def redraw(self):
        # If caching is enabled, a simple canvas refresh might not be
        # sufficient to trigger a redraw and you must clear the cached image
        # for the layer
        if self.iface.mapCanvas().isCachingEnabled():
            vlayer = self.get_current_vector_layer()
            if vlayer is None:
                return
            vlayer.triggerRepaint()

        self.iface.mapCanvas().refresh()
        QgsApplication.processEvents()

    def pan(self, x, y):
        '''
        Move the canvas to the x, y position
        '''
        currExt = self.iface.mapCanvas().extent()
        canvasCenter = currExt.center()
        dx = x - canvasCenter.x()
        dy = y - canvasCenter.y()
        xMin = currExt.xMinimum() + dx
        xMax = currExt.xMaximum() + dx
        yMin = currExt.yMinimum() + dy
        yMax = currExt.yMaximum() + dy
        newRect = QgsRectangle(xMin, yMin, xMax, yMax)
        self.iface.mapCanvas().setExtent(newRect)
コード例 #34
0
class captureGPSFeatures(FieldRestrictionTypeUtilsMixin):

    def __init__(self, iface, featuresWithGPSToolbar):

        TOMsMessageLog.logMessage("In captureGPSFeatures::init", level=Qgis.Info)

        FieldRestrictionTypeUtilsMixin.__init__(self, iface)

        # Save reference to the QGIS interface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        self.featuresWithGPSToolbar = featuresWithGPSToolbar
        self.gpsMapTool = False
        self.marker = None

        # This will set up the items on the toolbar
        # Create actions

        self.gnssToolGroup = QActionGroup(featuresWithGPSToolbar)
        self.actionCreateRestriction = QAction(QIcon(":/plugins/featureswithgps/resources/mActionAddTrack.svg"),
                               QCoreApplication.translate("MyPlugin", "Create Restriction"),
                               self.iface.mainWindow())
        self.actionCreateRestriction.setCheckable(True)

        self.actionAddGPSLocation = QAction(QIcon(":/plugins/featureswithgps/resources/greendot3.png"),
                               QCoreApplication.translate("MyPlugin", "Add vertex from gnss"),
                               self.iface.mainWindow())
        #self.actionAddGPSLocation.setCheckable(True)

        self.actionRemoveRestriction = QAction(QIcon(":plugins/featureswithgps/resources/mActionDeleteTrack.svg"),
                                        QCoreApplication.translate("MyPlugin", "Remove Restriction"),
                                        self.iface.mainWindow())
        self.actionRemoveRestriction.setCheckable(True)

        self.actionRestrictionDetails = QAction(QIcon(":/plugins/featureswithgps/resources/mActionGetInfo.svg"),
                                         QCoreApplication.translate("MyPlugin", "Get Restriction Details"),
                                         self.iface.mainWindow())
        self.actionRestrictionDetails.setCheckable(True)
        self.gnssToolGroup.addAction(self.actionRestrictionDetails)

        self.actionCreateSign = QAction(QIcon(":/plugins/featureswithgps/resources/mActionSetEndPoint.svg"),
                                                    QCoreApplication.translate("MyPlugin", "Create sign from gnss"),
                                                    self.iface.mainWindow())
        self.actionCreateSign.setCheckable(True)

        self.actionCreateMTR = QAction(QIcon(":/plugins/featureswithgps/resources/UK_traffic_sign_606F.svg"),
                                                    QCoreApplication.translate("MyPlugin", "Create moving traffic restriction"),
                                                    self.iface.mainWindow())
        self.actionCreateMTR.setCheckable(True)

        self.actionMoveFeatureToDifferentLayer = QAction(QIcon(""),
                                         QCoreApplication.translate("MyPlugin", "Move feature to different layer"),
                                         self.iface.mainWindow())
        self.actionMoveFeatureToDifferentLayer.setCheckable(True)
        self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer)

        # Add actions to the toolbar

        self.featuresWithGPSToolbar.addAction(self.actionCreateRestriction)
        self.featuresWithGPSToolbar.addAction(self.actionAddGPSLocation)
        self.featuresWithGPSToolbar.addAction(self.actionRestrictionDetails)
        #self.featuresWithGPSToolbar.addAction(self.actionRemoveRestriction)
        self.featuresWithGPSToolbar.addAction(self.actionCreateSign)
        #self.featuresWithGPSToolbar.addAction(self.actionCreateMTR)
        self.featuresWithGPSToolbar.addAction(self.actionMoveFeatureToDifferentLayer)

        self.gnssToolGroup.addAction(self.actionCreateRestriction)
        #self.gnssToolGroup.addAction(self.actionAddGPSLocation)
        #self.gnssToolGroup.addAction(self.actionRemoveRestriction)
        self.gnssToolGroup.addAction(self.actionRestrictionDetails)
        #self.gnssToolGroup.addAction(self.actionCreateSign)
        #self.gnssToolGroup.addAction(self.actionCreateMTR)
        self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer)

        self.gnssToolGroup.setExclusive(True)
        self.gnssToolGroup.triggered.connect(self.onGroupTriggered)

        # Connect action signals to slots

        self.actionCreateRestriction.triggered.connect(self.doCreateRestriction)
        self.actionAddGPSLocation.triggered.connect(self.doAddGPSLocation)
        self.actionRestrictionDetails.triggered.connect(self.doRestrictionDetails)
        #self.actionRemoveRestriction.triggered.connect(self.doRemoveRestriction)
        self.actionCreateSign.triggered.connect(self.doCreateSign)
        #self.actionCreateMTR.triggered.connect(self.doCreateMTR)
        self.actionMoveFeatureToDifferentLayer.triggered.connect(self.doMoveFeatureToDifferentLayer)

        self.actionCreateRestriction.setEnabled(False)
        self.actionAddGPSLocation.setEnabled(False)
        self.actionRestrictionDetails.setEnabled(False)
        #self.actionRemoveRestriction.setEnabled(False)
        self.actionCreateSign.setEnabled(False)
        #self.actionCreateMTR.setEnabled(False)
        self.actionMoveFeatureToDifferentLayer.setEnabled(False)

        self.searchBar = searchBar(self.iface, self.featuresWithGPSToolbar)
        self.searchBar.disableSearchBar()

        self.mapTool = None
        self.currGnssAction = None
        self.gpsConnection = None
        self.createMapToolDict = {}

    def enableFeaturesWithGPSToolbarItems(self):

        TOMsMessageLog.logMessage("In enablefeaturesWithGPSToolbarItems", level=Qgis.Warning)
        self.gpsAvailable = False
        self.closeTOMs = False

        self.tableNames = TOMsLayers(self.iface)
        self.params = gpsParams()

        self.tableNames.TOMsLayersNotFound.connect(self.setCloseTOMsFlag)
        #self.tableNames.gpsLayersNotFound.connect(self.setCloseCaptureGPSFeaturesFlag)
        self.params.TOMsParamsNotFound.connect(self.setCloseCaptureGPSFeaturesFlag)

        self.TOMsConfigFileObject = TOMsConfigFile()
        self.TOMsConfigFileObject.TOMsConfigFileNotFound.connect(self.setCloseTOMsFlag)
        self.TOMsConfigFileObject.initialiseTOMsConfigFile()

        self.tableNames.getLayers(self.TOMsConfigFileObject)

        self.prj = QgsProject().instance()
        self.dest_crs = self.prj.crs()
        TOMsMessageLog.logMessage("In captureGPSFeatures::init project CRS is " + self.dest_crs.description(),
                                 level=Qgis.Warning)
        self.transformation = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4326"), self.dest_crs,
                                                     self.prj)

        self.params.getParams()

        if self.closeTOMs:
            QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start editing tool ..."))
            #self.actionProposalsPanel.setChecked(False)
            return   # TODO: allow function to continue without GPS enabled ...

        # Now check to see if the port is set. If not assume that just normal tools

        gpsPort = self.params.setParam("gpsPort")
        TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems: GPS port is: {}".format(gpsPort), level=Qgis.Warning)
        self.gpsConnection = None

        if gpsPort:
            self.gpsAvailable = True

        if self.gpsAvailable == True:
            self.curr_gps_location = None
            self.curr_gps_info = None

            TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - GPS port is specified ",
                                     level=Qgis.Info)
            self.gps_thread = GPS_Thread(self.dest_crs, gpsPort)
            thread = QThread()
            self.gps_thread.moveToThread(thread)
            self.gps_thread.gpsActivated.connect(self.gpsStarted)
            self.gps_thread.gpsPosition.connect(self.gpsPositionProvided)
            self.gps_thread.gpsDeactivated.connect(functools.partial(self.gpsStopped))
            self.gps_thread.gpsError.connect(self.gpsErrorEncountered)
            #self.gps_thread.progress.connect(progressBar.setValue)
            thread.started.connect(self.gps_thread.startGPS)
            #thread.finished.connect(functools.partial(self.gpsStopped, thread))
            thread.start()
            self.thread = thread

            TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - attempting connection ",
                                     level=Qgis.Info)

            time.sleep(1.0)

            try:
                self.roamDistance = float(self.params.setParam("roamDistance"))
            except Exception as e:
                TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems:init: roamDistance issue: {}".format(e), level=Qgis.Warning)
                self.roamDistance = 5.0

        self.enableToolbarItems()

        self.createMapToolDict = {}

    def enableToolbarItems(self):
        TOMsMessageLog.logMessage("In enableToolbarItems", level=Qgis.Warning)
        self.actionCreateRestriction.setEnabled(True)
        self.actionRestrictionDetails.setEnabled(True)
        #self.actionRemoveRestriction.setEnabled(True)
        #self.actionCreateSign.setEnabled(True)
        #self.actionCreateMTR.setEnabled(True)
        self.actionMoveFeatureToDifferentLayer.setEnabled(True)

        self.searchBar.enableSearchBar()

        self.currMapTool = None
        self.theCurrentMapTool = None

        self.iface.currentLayerChanged.connect(self.changeCurrLayer2)
        self.canvas.mapToolSet.connect(self.changeMapTool2)
        self.canvas.extentsChanged.connect(self.changeExtents)

        # transaction for move ...
        self.localTransaction = MoveLayerTransaction(self.iface)

    def enableGnssToolbarItem(self):
        if self.gpsConnection:
            self.actionAddGPSLocation.setEnabled(True)
            self.actionCreateSign.setEnabled(True)
            self.lastCentre = QgsPointXY(0,0)

    def disableGnssToolbarItem(self):
        self.actionAddGPSLocation.setEnabled(False)
        self.actionCreateSign.setEnabled(False)

    def disableToolbarItems(self):

        self.actionCreateRestriction.setEnabled(False)
        self.actionRestrictionDetails.setEnabled(False)
        self.actionRemoveRestriction.setEnabled(False)
        self.actionCreateSign.setEnabled(False)
        #self.actionCreateMTR.setEnabled(False)
        self.actionMoveFeatureToDifferentLayer.setEnabled(False)

        self.searchBar.disableSearchBar()

        """if self.gpsConnection:
            self.actionAddGPSLocation.setEnabled(False)"""

    def setCloseTOMsFlag(self):
        self.closeTOMs = True
        QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Now closing TOMs ..."))

    def disableFeaturesWithGPSToolbarItems(self):

        TOMsMessageLog.logMessage("In disablefeaturesWithGPSToolbarItems", level=Qgis.Warning)
        if self.gpsConnection and not self.closeTOMs:
            self.gps_thread.endGPS()

        self.disableToolbarItems()

        # TODO: Need to delete any tools ...
        for layer, mapTool in self.createMapToolDict.items  ():
            try:
                status = layer.rollBack()
            except Exception as e:
                None
                """reply = QMessageBox.information(None, "Information",
                                                    "Problem rolling back changes" + str(self.currLayer.commitErrors()),
                                                    QMessageBox.Ok)"""
            del mapTool

        self.createMapToolDict = {}

        try:
            self.iface.currentLayerChanged.disconnect(self.changeCurrLayer2)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for currentLayerChanged {}".format(e),
                level=Qgis.Warning)

        try:
            self.canvas.mapToolSet.disconnect(self.changeMapTool2)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for mapToolSet {}".format(
                    e),
                level=Qgis.Warning)

        try:
            self.canvas.extentsChanged.disconnect(self.changeExtents)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for extentsChanged {}".format(
                    e),
                level=Qgis.Warning)

        self.tableNames.removePathFromLayerForms()

    def setCloseCaptureGPSFeaturesFlag(self):
        self.closeCaptureGPSFeatures = True
        self.gpsAvailable = True

    def onGroupTriggered(self, action):
        # hold the current action
        self.currGnssAction = action
        TOMsMessageLog.logMessage("In onGroupTriggered: curr action is {}".format(action.text()), level=Qgis.Info)

    """ 
        Using signals for ChangeTool and ChangeLayer to manage the tools - with the following functions
    """
    def isGnssTool(self, mapTool):

        if (isinstance(mapTool, CreateRestrictionTool) or
           isinstance(mapTool, GeometryInfoMapTool) or
           isinstance(mapTool, RemoveRestrictionTool)):
            return True

        return False

    def changeMapTool2(self):
        TOMsMessageLog.logMessage(
            "In changeMapTool2 ...", level=Qgis.Info)

        currMapTool = self.iface.mapCanvas().mapTool()

        if not self.isGnssTool(currMapTool):
            TOMsMessageLog.logMessage(
                "In changeMapTool2. Unchecking action ...", level=Qgis.Info)
            if self.currGnssAction:
                self.currGnssAction.setChecked(False)
        else:
            TOMsMessageLog.logMessage(
            "In changeMapTool2. No action for gnssTools.", level=Qgis.Info)

        TOMsMessageLog.logMessage(
            "In changeMapTool2. finished.", level=Qgis.Info)
        #print('tool unset')

    def changeCurrLayer2(self):
        TOMsMessageLog.logMessage("In changeLayer2 ... ", level=Qgis.Info)

        try:
            currMapTool = self.iface.mapCanvas().mapTool()
            self.currGnssAction.setChecked(False)
        except Exception as e:
            None

        """if self.isGnssTool(currMapTool):
            TOMsMessageLog.logMessage("In changeLayer2. Action triggered ... ", level=Qgis.Info)
            self.currGnssAction.trigger()  # assumption is that there is an action associated with the tool
        else:
            TOMsMessageLog.logMessage(
            "In changeLayer2. No action for currentMapTool.", level=Qgis.Info)"""

        TOMsMessageLog.logMessage(
            "In changeLayer2. finished.", level=Qgis.Info)
        print('layer changed')


    def doCreateRestriction(self):

        TOMsMessageLog.logMessage("In doCreateRestriction", level=Qgis.Info)

        self.currLayer = self.iface.activeLayer()
        if not self.currLayer:
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        # TODO: Check that this is a restriction layer

        if self.actionCreateRestriction.isChecked():

            TOMsMessageLog.logMessage("In doCreateRestriction - tool activated", level=Qgis.Info)
            TOMsMessageLog.logMessage(
                "In doCreateRestriction: current map tool {}".format(type(self.iface.mapCanvas().mapTool()).__name__),
                level=Qgis.Info)

            self.createRestrictionMapTool = self.createMapToolDict.get(self.currLayer)

            if not self.createRestrictionMapTool:
                TOMsMessageLog.logMessage("In doCreateRestriction. creating new map tool", level=Qgis.Info)
                self.createRestrictionMapTool = CreateRestrictionTool(self.iface, self.currLayer)
                self.createMapToolDict[self.currLayer] = self.createRestrictionMapTool

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 1", level=Qgis.Info)

            self.iface.mapCanvas().setMapTool(self.createRestrictionMapTool)

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 2", level=Qgis.Info)

            if not self.createRestrictionMapTool.isCapturing():
                if self.currLayer.isEditable() == True:
                    if self.currLayer.commitChanges() == False:
                        reply = QMessageBox.information(None, "Information",
                                                        "Problem committing changes" + str(self.currLayer.commitErrors()),
                                                        QMessageBox.Ok)
                    else:
                        TOMsMessageLog.logMessage("In doCreateRestriction: changes committed", level=Qgis.Info)

                if self.currLayer.readOnly() == True:
                    TOMsMessageLog.logMessage("In doCreateRestriction - Not able to start transaction ...",
                                             level=Qgis.Info)
                else:
                    if self.currLayer.startEditing() == False:
                        reply = QMessageBox.information(None, "Information",
                                                        "Could not start transaction on " + self.currLayer.name(),
                                                        QMessageBox.Ok)
                        return

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 3", level=Qgis.Info)

        else:

            TOMsMessageLog.logMessage("In doCreateRestriction - tool deactivated", level=Qgis.Info)

            if self.createRestrictionMapTool:
                self.iface.mapCanvas().unsetMapTool(self.createRestrictionMapTool)

            self.currMapTool = None
            self.currentlySelectedLayer = None

            self.actionCreateRestriction.setChecked(False)

            # TODO: stop editting on layers??

        TOMsMessageLog.logMessage("In doCreateRestriction. Here 4", level=Qgis.Info)



    # -- end of tools for signals

    def changeExtents(self):
        TOMsMessageLog.logMessage("In changeExtents ... ", level=Qgis.Info)

    def doAddGPSLocation(self):

        # need to have a addPointFromGPS function within each tool

        TOMsMessageLog.logMessage("In doAddGPSLocation", level=Qgis.Info)

        if self.gpsConnection:

            if self.curr_gps_location:
                try:
                    status = self.createRestrictionMapTool.addPointFromGPS(self.curr_gps_location, self.curr_gps_info)
                except Exception as e:
                    TOMsMessageLog.logMessage("In doAddGPSLocation: Problem adding gnss location: {}".format(e), level=Qgis.Warning)
                    reply = QMessageBox.information(self.iface.mainWindow(), "Error",
                                                    "Problem adding gnss location ... ",
                                                    QMessageBox.Ok)
            else:
                reply = QMessageBox.information(self.iface.mainWindow(), "Information",
                                                "No position found ...",
                                                QMessageBox.Ok)
        else:

            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "You need to activate the tool first ...",
                                            QMessageBox.Ok)

    def doRestrictionDetails(self):
        """
            Select point and then display details. Assume that there is only one of these map tools in existence at any one time ??
        """
        TOMsMessageLog.logMessage("In doRestrictionDetails", level=Qgis.Info)

        # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools

        if not self.iface.activeLayer():
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.actionRestrictionDetails.isChecked():

            TOMsMessageLog.logMessage("In doRestrictionDetails - tool activated", level=Qgis.Warning)

            self.showRestrictionMapTool = GeometryInfoMapTool(self.iface)
            self.iface.mapCanvas().setMapTool(self.showRestrictionMapTool)
            self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails)

        else:

            TOMsMessageLog.logMessage("In doRestrictionDetails - tool deactivated", level=Qgis.Warning)

            if self.showRestrictionMapTool:
                self.iface.mapCanvas().unsetMapTool(self.showRestrictionMapTool)

            self.actionRestrictionDetails.setChecked(False)

    #@pyqtSlot(str)
    def showRestrictionDetails(self, closestLayer, closestFeature):

        TOMsMessageLog.logMessage(
            "In showRestrictionDetails ... Layer: " + str(closestLayer.name()),
            level=Qgis.Info)

        self.showRestrictionMapTool.notifyFeatureFound.disconnect(self.showRestrictionDetails)

        # TODO: could improve ... basically check to see if transaction in progress ...
        if closestLayer.isEditable() == True:
            reply = QMessageBox.question(None, "Information",
                                            "There is a transaction in progress on this layer. This action will rollback back any changes. Do you want to continue?",
                                            QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.No:
                return
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Problem committing changes" + str(closestLayer.commitErrors()),
                                                QMessageBox.Ok)
            else:
                TOMsMessageLog.logMessage("In showRestrictionDetails: changes committed", level=Qgis.Info)

        """if self.iface.activeLayer().readOnly() == True:
            TOMsMessageLog.logMessage("In showSignDetails - Not able to start transaction ...",
                                     level=Qgis.Info)
        else:
            if self.iface.activeLayer().startEditing() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Could not start transaction on " + self.currLayer.name(),
                                                QMessageBox.Ok)
                return"""

        self.dialog = self.iface.getFeatureForm(closestLayer, closestFeature)
        #self.TOMsUtils.setupRestrictionDialog(self.dialog, closestLayer, closestFeature)
        self.setupFieldRestrictionDialog(self.dialog, closestLayer, closestFeature)

        self.dialog.show()

    """
        Decided that it is best to use the QGIS select/delete tools to manage removals. So these functions are not used
    """
    def doRemoveRestriction(self):

        TOMsMessageLog.logMessage("In doRemoveRestriction", level=Qgis.Info)

        self.currLayer = self.iface.activeLayer()

        if not self.currLayer:
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.currLayer.readOnly() == True:
            """reply = QMessageBox.information(None, "Information",
                                            "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok)"""
            TOMsMessageLog.logMessage("In doRemoveRestriction - Not able to start transaction ...", level=Qgis.Info)
            self.actionRemoveRestriction.setChecked(False)
            return

        if self.actionRemoveRestriction.isChecked():

            TOMsMessageLog.logMessage("In doRemoveRestriction - tool activated", level=Qgis.Warning)

            """self.mapTool = self.deleteMapToolDict.get(self.currLayer)

            if not self.mapTool:
                self.mapTool = RemoveRestrictionTool(self.iface)
                self.deleteMapToolDict[self.currLayer] =  self.mapTool"""

            self.mapTool = RemoveRestrictionTool(self.iface)
            #self.removeRestrictionMapTool.setAction(self.actionRemoveRestriction)
            self.iface.mapCanvas().setMapTool(self.removeRestrictionMapTool)
            #self.gpsMapTool = True
            #self.removeRestrictionMapTool.deactivated.connect(functools.partial(self.deactivateAction, self.actionRemoveRestriction))
            #self.iface.currentLayerChanged.connect(self.changeCurrLayer)
            #self.canvas.mapToolSet.connect(self.changeMapTool)

            self.removeRestrictionMapTool.notifyFeatureFound.connect(self.removeRestriction)

        else:

            TOMsMessageLog.logMessage("In doRemoveRestriction - tool deactivated", level=Qgis.Warning)

            self.removeRestrictionMapTool.notifyFeatureFound.disconnect(self.removeRestriction)

            #self.canvas.mapToolSet.disconnect(self.changeMapTool)
            #self.iface.currentLayerChanged.disconnect(self.changeCurrLayer)

            self.iface.mapCanvas().unsetMapTool(self.removeRestrictionMapTool)
            #self.removeRestrictionMapTool.deactivate()
            #self.mapTool = None
            self.actionRemoveRestriction.setChecked(False)

    #@pyqtSlot(str)
    def removeRestriction(self, closestLayer, closestFeature):

        TOMsMessageLog.logMessage(
            "In removeRestriction ... Layer: " + str(closestLayer.name()),
            level=Qgis.Info)

        if closestLayer.isEditable() == True:
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Problem committing changes" + str(closestLayer.commitErrors()),
                                                QMessageBox.Ok)
            else:
                TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info)

        if self.currLayer.startEditing() == False:
            reply = QMessageBox.information(None, "Information",
                                            "Could not start transaction on " + self.currLayer.name(),
                                            QMessageBox.Ok)
            return

        # TODO: Sort out this for UPDATE
        # self.setDefaultRestrictionDetails(closestFeature, closestLayer)

        closestLayer.deleteFeature(closestFeature.id())

        if closestLayer.commitChanges() == False:
            reply = QMessageBox.information(None, "Information",
                                            "Problem committing changes" + str(closestLayer.commitErrors()),
                                            QMessageBox.Ok)
        else:
            TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info)

    """
        This is a tool for adding a point feature. currently only used for signs, but could be used for any point
    """
    def doCreateSign(self):

        TOMsMessageLog.logMessage("In doCreateSign", level=Qgis.Info)

        if self.actionCreateSign.isChecked():

            self.currMapTool = self.canvas.mapTool()
            self.currentlySelectedLayer = self.iface.activeLayer()
            self.signsLayer = self.tableNames.setLayer("Signs")

            self.iface.setActiveLayer(self.signsLayer)

            self.createPointMapTool = CreatePointTool(self.iface, self.signsLayer)

            TOMsMessageLog.logMessage("In doCreateSign - tool activated", level=Qgis.Info)

            self.signsLayer.editingStopped.connect(self.reinstateMapTool)

            self.actionCreateSign.setChecked(False)

            self.iface.mapCanvas().setMapTool(self.createPointMapTool)

            """ add the point from the gnss """
            try:
                status = self.canvas.mapTool().addPointFromGPS(self.curr_gps_location, self.curr_gps_info)
            except Exception as e:
                TOMsMessageLog.logMessage("In doCreateSign: Problem adding gnss location: {}".format(e),
                                          level=Qgis.Warning)
                reply = QMessageBox.information(self.iface.mainWindow(), "Error",
                                                "Problem adding gnss location ... ",
                                                QMessageBox.Ok)

    """
        Not currently used, but want to develop ...
    """
    def doCreateMTR(self):

        TOMsMessageLog.logMessage("In doCreateMTR", level=Qgis.Info)

        if self.actionCreateMTR.isChecked():

            TOMsMessageLog.logMessage("In doCreateMTR - tool activated", level=Qgis.Info)

            # Open MTR form ...

            try:
                self.thisMtrForm
            except AttributeError:
                self.thisMtrForm = mtrForm(self.iface)

            #res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog)
            #self.mtrTypeCB = self.dialog.findChild(QComboBox, "cmb_MTR_list")
            #self.mtrTypeCB.activated[str].connect(self.onLocalChanged)
            #self.currDialog.findChild(QComboBox, "cmb_MTR_list").activated[str].connect(self.onChanged)


            """ Need to setup dialog:
                a. create drop down
                b. link structure of form to different options from drop down, e.g., Access Restriction needs ?? attributes and one point, Turn Restriction needs ?? attributes and two points
                c. link getPoint actions to buttons
            """
            status = self.thisMtrForm.show()
            # Run the dialog event loop
            result = self.thisMtrForm.exec_()
            #

        else:

            TOMsMessageLog.logMessage("In doCreateMTR - tool deactivated", level=Qgis.Info)

            #self.iface.mapCanvas().unsetMapTool(self.mapTool)
            #self.mapTool = None
            self.actionCreateMTR.setChecked(False)
            self.gpsMapTool = False

    def onLocalChanged(self, text):
        TOMsMessageLog.logMessage(
            "In generateFirstStageForm::selectionchange.  " + text, level=Qgis.Info)
        res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog, text)

    """
        Used with the createSign tool to reinstate the last used maptool, i.e., to allow the interupt of feature creation
    """

    def reinstateMapTool(self):

        TOMsMessageLog.logMessage("In reinstateMapTool ... ", level=Qgis.Info)
        self.iface.activeLayer().editingStopped.disconnect(self.reinstateMapTool)

        if self.currMapTool:

            TOMsMessageLog.logMessage(
                "In reinstateMapTool. layer to be reinstated {} using tool {}".format(self.currentlySelectedLayer.name(), self.currMapTool.toolName()),
                level=Qgis.Warning)
            # now reinstate
            if self.currentlySelectedLayer:
                self.iface.setActiveLayer(self.currentlySelectedLayer)

            self.iface.mapCanvas().setMapTool(self.currMapTool)


    def doMoveFeatureToDifferentLayer(self):
        """
            Select point and then display details. Assume that there is only one of these map tools in existence at any one time ??
        """
        TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer", level=Qgis.Info)

        # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools

        if not self.iface.activeLayer():
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.actionMoveFeatureToDifferentLayer.isChecked():

            TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool activated", level=Qgis.Warning)

            self.moveFeatureToDifferentLayerMapTool = ChangeLayerMapTool(self.iface, self.localTransaction)
            self.iface.mapCanvas().setMapTool(self.moveFeatureToDifferentLayerMapTool)
            #self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails)

        else:

            TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool deactivated", level=Qgis.Warning)

            if self.moveFeatureToDifferentLayerMapTool:
                self.iface.mapCanvas().unsetMapTool(self.moveFeatureToDifferentLayerMapTool)

            self.actionMoveFeatureToDifferentLayer.setChecked(False)


    #@pyqtSlot(QgsGpsConnection)
    def gpsStarted(self, connection):
        TOMsMessageLog.logMessage("In enableTools - GPS connection found ",
                                     level=Qgis.Info)

        self.gpsConnection = connection

        # marker
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.setColor(QColor(255, 0, 0))  # (R,G,B)
        self.marker.setIconSize(10)
        self.marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.marker.setPenWidth(3)

        self.enableGnssToolbarItem()
        reply = QMessageBox.information(None, "Information",
                                            "Connection found",
                                            QMessageBox.Ok)

    #@pyqtSlot()
    def gpsStopped(self):
        TOMsMessageLog.logMessage("In enableTools - GPS connection stopped ",
                                     level=Qgis.Warning)

        self.gps_thread.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()

        if self.gpsConnection:
            if self.canvas is not None:
                self.marker.hide()
                self.canvas.scene().removeItem(self.marker)

        self.gpsConnection = None
        self.disableGnssToolbarItem()

    #@pyqtSlot()
    def gpsPositionProvided(self, mapPointXY, gpsInfo):
        """reply = QMessageBox.information(None, "Information",
                                            "Position provided",
                                            QMessageBox.Ok)"""
        TOMsMessageLog.logMessage("In enableTools - ******** initial GPS location provided " + mapPointXY.asWkt(),
                                     level=Qgis.Info)

        self.curr_gps_location = mapPointXY
        self.curr_gps_info = gpsInfo

        wgs84_pointXY = QgsPointXY(gpsInfo.longitude, gpsInfo.latitude)
        wgs84_point = QgsPoint(wgs84_pointXY)
        wgs84_point.transform(self.transformation)
        x = wgs84_point.x()
        y = wgs84_point.y()
        new_mapPointXY = QgsPointXY(x, y)

        TOMsMessageLog.logMessage("In enableTools - ******** transformed GPS location provided " + str(gpsInfo.longitude) + ":" + str(gpsInfo.latitude) + "; " + new_mapPointXY.asWkt(),
                                     level=Qgis.Info)

        if gpsInfo.pdop >= 1:  # gps ok
            self.marker.setColor(QColor(0, 200, 0))
        else:
            self.marker.setColor(QColor(255, 0, 0))
        self.marker.setCenter(mapPointXY)
        self.marker.show()
        #self.canvas.setCenter(mapPointXY)

        """TOMsMessageLog.logMessage("In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)),
                                     level=Qgis.Info)"""
        if self.lastCentre.distance(mapPointXY) > self.roamDistance:
            self.lastCentre = mapPointXY
            self.canvas.setCenter(mapPointXY)
            TOMsMessageLog.logMessage(
                "In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)),
                level=Qgis.Warning)
            self.canvas.refresh()

        # TODO: populate message bar with details about satellites, etc

    #@pyqtSlot(Exception, str)
    def gpsErrorEncountered(self, e):
        TOMsMessageLog.logMessage("In enableTools - GPS connection has error {}".format(e),
                                     level=Qgis.Warning)
        """self.actionCreateRestriction.setEnabled(False)
        self.actionAddGPSLocation.setEnabled(False)"""
        self.disableGnssToolbarItem()
コード例 #35
0
class QGISRedSelectPointTool(QgsMapTool):
    def __init__(self, button, parent, method, type=1):
        QgsMapTool.__init__(self, parent.iface.mapCanvas())
        self.canvas = parent.iface.mapCanvas()
        self.iface = parent.iface
        self.parent = parent
        self.method = method
        self.setAction(button)
        self.type = type

        # type 1: points; 2: lines; 3: 2-points; 4: 2-line; 5: point-line

        self.startMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.startMarker.setColor(QColor(255, 87, 51))
        if self.type == 3 or self.type == 4 or self.type == 5:
            self.startMarker.setColor(QColor(139, 0, 0))
        self.startMarker.setIconSize(15)
        self.startMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        if self.type == 2 or self.type == 4:
            self.startMarker.setIconType(
                QgsVertexMarker.ICON_X)  # or ICON_CROSS, ICON_X
        self.startMarker.setPenWidth(3)
        self.startMarker.hide()

        self.endMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.endMarker.setColor(QColor(0, 128, 0))
        self.endMarker.setIconSize(15)
        self.endMarker.setIconType(
            QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        if self.type == 4 or self.type == 5:
            self.endMarker.setIconType(
                QgsVertexMarker.ICON_X)  # or ICON_CROSS, ICON_X
        self.endMarker.setPenWidth(3)
        self.endMarker.hide()
        self.firstPoint = None

        self.snapper = None
        self.resetProperties()

    def activate(self):
        QgsMapTool.activate(self)
        type = 1
        if self.type == 2 or self.type == 4:
            type = 2
        self.configSnapper(type)

    def deactivate(self):
        self.resetProperties()
        QgsMapTool.deactivate(self)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    """Methods"""

    def configSnapper(self, type):
        # Snapping
        self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())
        self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings())
        config = QgsSnappingConfig(QgsProject.instance())
        config.setType(type)  # 1: Vertex; 2:Segment
        config.setMode(2)  # All layers
        config.setTolerance(10)
        config.setUnits(1)  # Pixels
        config.setEnabled(True)
        self.snapper.setConfig(config)

    def resetProperties(self):
        self.firstPoint = None
        self.startMarker.hide()
        self.endMarker.hide()
        self.objectSnapped = None

    """Events"""

    def canvasReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self.objectSnapped is None:
                self.iface.messageBar().pushMessage(
                    "Warning",
                    "A not valid point was selected",
                    level=1,
                    duration=5)
                return
            if self.type == 3 or self.type == 4 or self.type == 5:
                if self.firstPoint is None:
                    self.firstPoint = self.objectSnapped.point()
                    if self.type == 5:
                        self.configSnapper(2)
                else:
                    point1 = self.firstPoint
                    point2 = self.objectSnapped.point()
                    # Call to parent method
                    self.method(point1, point2)
                    self.resetProperties()
                    if self.type == 5:
                        self.configSnapper(1)
            else:
                point = self.objectSnapped.point()
                # Call to parent method
                self.method(point)
                self.resetProperties()
        if event.button() == Qt.RightButton:
            if self.type == 3 or self.type == 5:
                if self.objectSnapped is None:
                    self.iface.messageBar().pushMessage(
                        "Warning",
                        "A not valid point was selected",
                        level=1,
                        duration=5)
                    return
                else:
                    point = self.objectSnapped.point()
                    # Call to parent method
                    # Tconnection & Split/merge Juncitons
                    self.method(point, None)
                    self.resetProperties()
            else:
                self.canvas.unsetMapTool(self)
                self.deactivate()
                return

    def canvasMoveEvent(self, event):
        match = self.snapper.snapToMap(self.toMapCoordinates(event.pos()))
        if match.isValid():
            self.objectSnapped = match
            if self.firstPoint is None:
                self.startMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.startMarker.show()
            else:
                self.endMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.endMarker.show()
        else:
            self.startMarker.hide()
            self.endMarker.hide()
            self.objectSnapped = None
コード例 #36
0
ファイル: gto_point.py プロジェクト: msgis/swwat-gzp-template
class GTOPointWidget(QWidget):
    isActive = pyqtSignal(bool)

    def __init__(self, gtoObj, parent=None):
        super(GTOPointWidget, self).__init__(parent)

        self.gtomain = gtoObj.gtomain
        self.info = self.gtomain.info
        self.debug = self.gtomain.debug

        try:
            # references
            self.helper = self.gtomain.helper
            self.iface = self.gtomain.iface
            self.prj = QgsProject.instance()
            self.canvas = self.iface.mapCanvas()
            # references
            self.x = 0
            self.y = 0
            self.xt = 0
            self.yt = 0
            self.snaped = False
            self.crs_transform = None
            self.crs_layer = None
            self.parent_widget = None  # e.g toolbar
            self.userEditX = False
            self.userEditY = False
            # config
            self.tools = []
            self.coordinatereferences = None
            self.scale = 0
            self.center = True
            self.enable_save = False
            self.precision = -1
            self.cboCoordSystems = None
            self.is_widgetaction = False
            self.show_tool_button = False
            self.addpoint_attributes = {}
            self.tools_after_addpoint = []
            # widgets:
            uic.loadUi(os.path.join(os.path.dirname(__file__), 'gto_point.ui'), self)
            # point tool
            self.btnPointTool = self.btnPoint
            # x
            self.coordX = self.coordX
            # self.validX = QDoubleValidator(sys.float_info.min, sys.float_info.max, 16, self.coordX)  # no negative numbers possible?
            # self.validX = QDoubleValidator(-999999999, 999999999, 16, self.coordX)  # working but no range limit
            self.validX = QDoubleValidator(self.coordX)  # so we use the standard:
            self.validX.setNotation(QDoubleValidator.StandardNotation)  # By default, this property is set to ScientificNotation: i.e. 1.5E-2  is possible
            self.coordX.setValidator(self.validX)

            self.btnCopyXt = self.btnCopyXt
            self.lblX = self.lblX
            # y
            self.coordY = self.coordY
            self.validY = QDoubleValidator(self.coordY)
            self.validY.setNotation(QDoubleValidator.StandardNotation)
            self.coordY.setValidator(self.validY)

            self.btnCopyYt = self.btnCopyYt
            self.lblY = self.lblY
            # show
            self.btnShow = self.btnShow
            self.btnShow.setIcon(self.helper.getIcon('mActionZoomPoint.png'))
            # add point
            self.btnAddPoint = self.btnAddPoint
            self.btnAddPoint.setIcon(self.helper.getIcon('mActionAddPoint.png'))
            self.btnAddPoint.setToolTip("Punkt erstellen")

            # marker
            self.marker = QgsVertexMarker(self.canvas)
            self.marker.setColor(Qt.yellow)
            self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
            self.marker.setIconSize(10)
            self.marker.setPenWidth(3)
            # See the enum IconType from http://www.qgis.org/api/classQgsVertexMarker.html

            # maptool
            self.mapTool = GTOPointTool(self.iface, self.canvas)
            self.mapTool.isActive.connect(self.setToolStatus)
            self.mapTool.canvasReleased.connect(self.setCoords)
            # signals
            # QToolButton.toggled()
            self.btnPoint.clicked.connect(self.setMapTool)

            # self.coordX.textChanged.connect(self.set_user_editX)
            # self.coordY.textChanged.connect(self.set_user_editY)
            self.coordX.textEdited.connect(self.set_user_editX)
            self.coordY.textEdited.connect(self.set_user_editY)
            # self.coordX.editingFinished.connect(self.check_coords)
            # self.coordY.editingFinished.connect(self.check_coords)

            self.btnShow.clicked.connect(self.showCoordinate)
            self.btnCopyXt.clicked.connect(self.copyXt)
            self.btnCopyYt.clicked.connect(self.copyYt)
            self.btnAddPoint.clicked.connect(self.add_point)
            self.prj.crsChanged.connect(self.prj_crs_changed)
            self.iface.mapCanvas().currentLayerChanged.connect(self.layer_changed)
        except Exception as e:
            self.info.err(e)

    def set_user_editX(self, *args):
        try:
            if self.debug: self.info.log("set_user_editX")
            self.userEditX = True
            self.marker.hide()
            self.marker.setColor(Qt.blue)
            self.snaped = False
        except Exception as e:
            self.info.err(e)

    def set_user_editY(self, *args):
        try:
            if self.debug: self.info.log("set_user_editY")
            self.userEditY = True
            self.marker.hide()
            self.marker.setColor(Qt.blue)
            self.snaped = False
        except Exception as e:
            self.info.err(e)

    def reset_user_edit(self):
        if self.debug: self.info.log("reset_user_edit")
        self.userEditX = False
        self.userEditY = False

    def check_coords(self):
        try:
            self.marker.hide()
            if self.debug: self.info.log("useredit: X:", self.userEditX, "userEditY:", self.userEditY)
            if self.coordX.text() == '':
                self.coordX.setText('0')
                self.x = 0
            if self.coordY.text() == '':
                self.coordY.setText('0')
                self.y = 0
            if self.userEditX or self.userEditY:
                self.snaped = False
                self.userEditX = False
                self.userEditY = False
                self.xt = float(self.coordX.text().replace(",", "."))
                self.yt = float(self.coordY.text().replace(",", "."))
            tr = QgsCoordinateTransform(self.crs_transform, self.prj.crs(), self.prj)
            trPoint = tr.transform(QgsPointXY(self.xt, self.yt))
            self.x = trPoint.x()
            self.y = trPoint.y()
            if self.debug: self.info.log("check_coords:", self.x, "/", self.y, "/snaped:", self.snaped)
        except Exception as e:
            self.info.err(e)

    def setMapTool(self):
        try:
            self.canvas.setMapTool(self.mapTool)
        except Exception as e:
            self.info.err(e)

    def set_parent_widget(self, widget):
        try:
            self.parent_widget = widget
            if self.parent_widget.action.isChecked():
                self.setMapTool()
        except Exception as e:
            self.info.err(e)

    def setToolStatus(self, isActive):
        try:
            self.btnPoint.setChecked(isActive)
            self.marker.hide()
            self.isActive.emit(isActive)
            if self.parent_widget is not None:
                self.parent_widget.set_status(isActive)
        except Exception as e:
            self.info.err(e)

    def setConfig(self, config):
        try:
            self.tools = config.get("tools", [])
            self.coordinatereferences = config.get("coordinatereferences", None)
            self.scale = config.get("scale", 0)
            self.center = config.get("center", True)
            self.enable_save = config.get('enable_save', False)
            self.precision = config.get('precision', -1)
            self.is_widgetaction = config.get('is_widgetaction', False)
            self.show_tool_button = config.get('show_tool_button', not self.is_widgetaction)
            self.addpoint_attributes = config.get("addpoint_attributes", {})
            self.tools_after_addpoint = config.get("tools_after_addpoint", [])
            if self.precision < 0:
                self.precision, type_conversion_ok = self.prj.readNumEntry("PositionPrecision", "DecimalPlaces", 3)
            # labels:
            self.lblX.setText(config.get('label_x', 'X:'))
            self.lblY.setText(config.get('label_y', 'Y:'))
            # text
            text = ''
            if self.scale > 0 and self.center:
                text = "Auf Koordinate zentrieren, Maßstab: " + str(self.scale)
            elif self.center:
                text = "Auf Koordinate zentrieren"
            elif self.scale > 0:
                text = "Maßstab: " + str(self.scale)
            elif len(self.tools) > 0:
                text = self.tools[0]
                act = self.gtomain.findAction(self.tools[0])
                if act is not None:
                    text = act.toolTip()
                    if act.icon() is not None:
                        self.btnShow.setIcon(act.icon())
            if self.debug: self.info.log(text)
            self.btnShow.setToolTip(text)
            if self.btnShow.toolTip() == '':
                self.btnShow.setHidden(True)
            # add point
            self.btnAddPoint.setHidden(not self.enable_save)
            # point tool
            self.btnPointTool.setHidden(not self.show_tool_button)
        except Exception as e:
            self.info.err(e)

    def added(self):  # widget was added to parent
        try:
            self.crs_transform = self.prj.crs()
            self.crs_layer = self.iface.activeLayer().crs()
            # set crs widget
            if self.coordinatereferences is None:
                # qgis transform
                self.cboCoordSys.setHidden(True)
                self.cboCoordSystems = self.mQgsProjectionSelectionWidget
                self.cboCoordSystems.setMinimumWidth(460)
                self.cboCoordSystems.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, True)
                self.cboCoordSystems.setCrs(self.prj.crs())
                self.setCrs(self.cboCoordSystems.crs())
                self.cboCoordSystems.crsChanged.connect(self.setCrs)
            else:
                # custom transform
                self.mQgsProjectionSelectionWidget.setHidden(True)
                self.cboCoordSystems = self.cboCoordSys
                self.cboCoordSystems.setMinimumWidth(400)

                self.cboCoordSystems.currentIndexChanged.connect(
                    lambda: self.setCrs(self.cboCoordSystems.currentData()))
                self.cboCoordSystems.addItem(
                    "Projekt CRS: " + self.crs_transform.authid() + " - " + self.crs_transform.description(),
                    self.crs_transform)
                for crsID in self.coordinatereferences:
                    try:
                        crs = QgsCoordinateReferenceSystem(crsID)
                        self.cboCoordSystems.addItem(crs.authid() + " - " + crs.description(), crs)
                    except Exception as e:
                        self.info.err(e)
                self.cboCoordSystems.setCurrentIndex(0)
            # here we know which type is cboCoordSystems!
            self.setIconSizes()
        except Exception as e:
            self.info.err(e)

    def setIconSizes(self):
        try:
            if self.parentWidget() is not None:
                btns = self.findChildren(QToolButton)
                for btn in btns:
                    try:
                        btn.setIconSize(self.iface.iconSize(False))
                    except:
                        pass
                # help for the QGIS widget :S
                self.cboCoordSystems.setMaximumHeight(self.cboCoordSys.height())
                btns = self.cboCoordSystems.findChildren(QToolButton)
                for btn in btns:
                    btn.setIconSize(self.iface.iconSize(False))
        except Exception as e:
            self.info.err(e)

    def layer_changed(self, layer):
        try:
            if layer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry:
                self.btnAddPoint.setEnabled(True)
            else:
                self.btnAddPoint.setEnabled(False)
        except Exception as e:
            self.info.err(e)

    def prj_crs_changed(self):
        try:
            self.reset_user_edit()
            if self.coordinatereferences is not None:  # my combo
                self.crs_transform = self.prj.crs()
                self.cboCoordSystems.setItemText(0,
                                                 "Projekt CRS: " + self.crs_transform.authid() + " - " + self.crs_transform.description())
                self.cboCoordSystems.setItemData(0, self.crs_transform)
                self.x = 0
                self.y = 0
                self.xt = 0
                self.yt = 0
                self.coordX.setText("---")
                self.coordY.setText("---")
        except Exception as e:
            self.info.err(e)

    def add_point(self):
        try:
            self.check_coords()
            layer = self.iface.activeLayer()
            if layer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry:
                self.prj.layerTreeRoot().findLayer(layer.id()).setItemVisibilityCheckedParentRecursive(True)
                if self.x != 0 and self.y != 0:
                    feat = QgsVectorLayerUtils.createFeature(layer)
                    tr = QgsCoordinateTransform(self.prj.crs(), self.crs_layer, self.prj)
                    trPoint = tr.transform(QgsPointXY(self.x, self.y))
                    feat.setGeometry(QgsGeometry.fromPointXY(trPoint))
                    # direct save
                    # (res, features) = layer.dataProvider().addFeatures([feat])
                    # if self.debug: self.info.log("new point:", res, features[0])
                    # set attributes

                    dic_info = {"x": self.x, "y": self.y, "snaped": self.snaped}
                    # self.info.err(None,"mapping:",dic_info)
                    # self.info.err(None, "addpoint_attributes:", self.addpoint_attributes)
                    for k, v in self.addpoint_attributes.items():
                        # self.info.err(None,"attribute:",k,"value:",dic_info[v])
                        feat[k] = layer.fields().field(k).convertCompatible(dic_info[v])
                    features = [feat]
                    layer.featureAdded.connect(self.select_new_feature)
                    self.save_features(layer, features)
                    layer.featureAdded.disconnect(self.select_new_feature)

                    self.marker.hide()
                    self.helper.refreshLayer(layer)
                    self.gtomain.runcmd(self.tools_after_addpoint)
                else:
                    self.info.gtoWarning('Ungültige Koordinaten! x:', self.x, "y:", self.y)
            else:
                self.info.gtoWarning('Kein Punktlayer ausgewählt!')
        except Exception as e:
            self.info.err(e)

    def select_new_feature(self, featId):
        try:
            if self.debug: self.info.log("new featue:", self.iface.activeLayer().name(), "/ fid:", featId)
            self.iface.activeLayer().selectByIds([featId])
            self.mapTool.reset_marker()
            self.marker.hide()
            self.helper.refreshLayer(self.iface.activeLayer())
        except Exception as e:
            self.info.err(e)

    def save_features(self, layer, features):
        if not layer.isEditable():
            layer.startEditing()
        layer.beginEditCommand("layer {0} edit".format(layer.name()))
        try:
            layer.addFeatures(features)
            layer.endEditCommand()
        except Exception as e:
            layer.destroyEditCommand()
            raise e

    def copyXt(self):
        self.check_coords()
        dsp = QDoubleSpinBox()
        dsp.setDecimals(16)
        self.helper.copyToClipboard(dsp.textFromValue(self.xt))

    def copyYt(self):
        self.check_coords()
        dsp = QDoubleSpinBox()
        dsp.setDecimals(16)
        self.helper.copyToClipboard(dsp.textFromValue(self.yt))

    def reset(self):
        if self.debug: self.info.log("widget reset")
        self.marker.hide()

    def setCoords(self, point, snaped):
        try:
            self.reset_user_edit()
            self.snaped = snaped
            self.x = point.x()
            self.y = point.y()
            if self.debug: self.info.log("setCoords", self.x, "/", self.y)
            self.setCrs(self.crs_transform)
            # marker
            self.marker.setCenter(QgsPointXY(self.x, self.y))
            if snaped:
                self.marker.setColor(Qt.red)
            else:
                self.marker.setColor(Qt.blue)
            self.marker.show()
        except Exception as e:
            self.info.err(e)

    def showCoordinate(self):
        try:
            self.check_coords()
            self.marker.hide()
            if self.x != 0 and self.y != 0:
                pt_center = QgsPointXY(self.x, self.y)
                self.marker.setCenter(pt_center)
                self.marker.show()

                # center map
                if self.center:
                    self.canvas.setCenter(pt_center)
                # scale map
                if self.scale is not None and self.scale > 0:
                    self.canvas.zoomScale(self.scale)
                self.canvas.refresh()
                # run tools
                self.gtomain.runcmd(self.tools)
            else:
                self.info.gtoWarning('Ungültige Koordinate! x:', self.x, "y:", self.y)
        except Exception as e:
            self.info.err(e)

    def setCrs(self, crs):
        try:
            if self.debug: self.info.log("setCrs")
            self.crs_transform = crs
            tr = QgsCoordinateTransform(self.prj.crs(), self.crs_transform, self.prj)
            trPoint = tr.transform(QgsPointXY(self.x, self.y))

            self.xt = trPoint.x()
            self.yt = trPoint.y()

            d = round(trPoint.x(), self.precision)
            display = str(d).replace(".", QLocale().decimalPoint())
            self.coordX.setText(display)

            d = round(trPoint.y(), self.precision)
            display = str(d).replace(".", QLocale().decimalPoint())
            self.coordY.setText(display)
        except Exception as e:
            self.info.err(e)
コード例 #37
0
class ManNodeDialog(ParentDialog):
    def __init__(self, dialog, layer, feature):
        """ Constructor class """

        self.geom_type = "node"
        self.field_id = "node_id"
        self.id = utils_giswater.getWidgetText(self.field_id, False)
        super(ManNodeDialog, self).__init__(dialog, layer, feature)
        self.init_config_form()
        self.controller.manage_translation('ud_man_node', dialog)
        if dialog.parent():
            dialog.parent().setFixedSize(625, 660)

    def init_config_form(self):
        """ Custom form initial configuration """

        # Define class variables
        self.filter = self.field_id + " = '" + str(self.id) + "'"

        # Get widget controls
        self.tab_main = self.dialog.findChild(QTabWidget, "tab_main")
        self.tbl_element = self.dialog.findChild(QTableView, "tbl_element")
        self.tbl_document = self.dialog.findChild(QTableView, "tbl_document")
        self.tbl_event_element = self.dialog.findChild(QTableView,
                                                       "tbl_event_element")
        self.tbl_event = self.dialog.findChild(QTableView, "tbl_event_node")
        self.tbl_scada = self.dialog.findChild(QTableView, "tbl_scada")
        self.tbl_scada_value = self.dialog.findChild(QTableView,
                                                     "tbl_scada_value")
        self.tbl_costs = self.dialog.findChild(QTableView, "tbl_masterplan")
        self.nodecat_id = self.dialog.findChild(QLineEdit, 'nodecat_id')
        self.node_type = self.dialog.findChild(QComboBox, 'node_type')
        state_type = self.dialog.findChild(QComboBox, 'state_type')
        dma_id = self.dialog.findChild(QComboBox, 'dma_id')

        # Tables
        self.tbl_upstream = self.dialog.findChild(QTableView, "tbl_upstream")
        self.tbl_upstream.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tbl_downstream = self.dialog.findChild(QTableView,
                                                    "tbl_downstream")
        self.tbl_downstream.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.dialog.findChild(QPushButton, "btn_catalog").clicked.connect(
            partial(self.catalog, 'ud', 'node'))

        self.tbl_upstream.doubleClicked.connect(
            partial(self.open_up_down_stream, self.tbl_upstream))
        self.tbl_downstream.doubleClicked.connect(
            partial(self.open_up_down_stream, self.tbl_downstream))

        feature = self.feature
        layer = self.iface.activeLayer()

        # Toolbar actions
        action = self.dialog.findChild(QAction, "actionEnabled")
        action.setChecked(layer.isEditable())
        self.dialog.findChild(QAction,
                              "actionCopyPaste").setEnabled(layer.isEditable())
        self.dialog.findChild(QAction,
                              "actionRotation").setEnabled(layer.isEditable())
        self.dialog.findChild(QAction, "actionZoom").triggered.connect(
            partial(self.action_zoom_in, feature, self.canvas, layer))
        self.dialog.findChild(QAction, "actionCentered").triggered.connect(
            partial(self.action_centered, feature, self.canvas, layer))
        self.dialog.findChild(QAction, "actionEnabled").triggered.connect(
            partial(self.action_enabled, action, layer))
        self.dialog.findChild(QAction, "actionZoomOut").triggered.connect(
            partial(self.action_zoom_out, feature, self.canvas, layer))
        self.dialog.findChild(QAction, "actionRotation").triggered.connect(
            self.action_rotation)
        self.dialog.findChild(QAction, "actionCopyPaste").triggered.connect(
            partial(self.action_copy_paste, self.geom_type))
        self.dialog.findChild(QAction, "actionLink").triggered.connect(
            partial(self.check_link, True))
        self.dialog.findChild(QAction, "actionHelp").triggered.connect(
            partial(self.action_help, 'ud', 'node'))

        # Manage custom fields
        cat_feature_id = utils_giswater.getWidgetText(self.node_type)
        tab_custom_fields = 1
        self.manage_custom_fields(cat_feature_id, tab_custom_fields)

        # Manage tab 'Scada'
        self.manage_tab_scada()

        # Check if exist URL from field 'link' in main tab
        self.check_link()

        # Check topology for new features
        continue_insert = True
        node_over_node = True
        check_topology_node = self.controller.plugin_settings_value(
            "check_topology_node", "0")
        check_topology_arc = self.controller.plugin_settings_value(
            "check_topology_arc", "0")

        # Check if feature has geometry object
        geometry = self.feature.geometry()
        if geometry:
            self.controller.log_info("check")
            if self.id.upper() == 'NULL' and check_topology_node == "0":
                self.get_topology_parameters()
                (continue_insert, node_over_node) = self.check_topology_node()

            if continue_insert and not node_over_node:
                if self.id.upper() == 'NULL' and check_topology_arc == "0":
                    self.check_topology_arc()

            # Create thread
            thread1 = Thread(self, self.controller, 3)
            thread1.start()

        self.filter = "node_id = '" + str(self.id) + "'"
        table_name = self.controller.schema_name + ".v_ui_node_x_connection_upstream"
        self.fill_table(self.tbl_upstream, table_name, self.filter)
        self.set_configuration(self.tbl_upstream,
                               "v_ui_node_x_connection_upstream")

        table_name = self.controller.schema_name + ".v_ui_node_x_connection_downstream"
        self.fill_table(self.tbl_downstream, table_name, self.filter)
        self.set_configuration(self.tbl_downstream,
                               "v_ui_node_x_connection_downstream")

        # Manage tab signal
        self.tab_connections_loaded = False
        self.tab_element_loaded = False
        self.tab_document_loaded = False
        self.tab_om_loaded = False
        self.tab_scada_loaded = False
        self.tab_cost_loaded = False
        self.tab_main.currentChanged.connect(self.tab_activation)

        # Load default settings
        widget_id = self.dialog.findChild(QLineEdit, 'node_id')
        if utils_giswater.getWidgetText(widget_id).lower() == 'null':
            self.load_default()
            self.load_type_default("nodecat_id", "nodecat_vdefault")

        self.load_state_type(state_type, self.geom_type)
        self.load_dma(dma_id, self.geom_type)

    def open_up_down_stream(self, qtable):
        """ Open selected node from @qtable """

        selected_list = qtable.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        row = selected_list[0].row()
        feature_id = qtable.model().record(row).value("feature_id")
        featurecat_id = qtable.model().record(row).value("featurecat_id")

        # Get sys_feature_cat.id from cat_feature.id
        sql = ("SELECT sys_feature_cat.id FROM " +
               self.controller.schema_name + ".cat_feature"
               " INNER JOIN " + self.controller.schema_name +
               ".sys_feature_cat ON cat_feature.system_id = sys_feature_cat.id"
               " WHERE cat_feature.id = '" + featurecat_id + "'")
        row = self.controller.get_row(sql)
        if not row:
            return

        layer = self.get_layer(row[0])
        if layer:
            field_id = self.controller.get_layer_primary_key(layer)
            aux = "\"" + field_id + "\" = "
            aux += "'" + str(feature_id) + "'"
            expr = QgsExpression(aux)
            if expr.hasParserError():
                message = "Expression Error"
                self.controller.show_warning(
                    message, parameter=expr.parserErrorString())
                return

            it = layer.getFeatures(QgsFeatureRequest(expr))
            features = [i for i in it]
            if features != []:
                self.iface.openFeatureForm(layer, features[0])
        else:
            message = "Layer not found"
            self.controller.show_warning(message, parameter=row[0])

    def get_topology_parameters(self):
        """ Get parameters 'node_proximity' and 'node2arc' from config table """

        self.node_proximity = 0.5
        self.node2arc = 0.5
        sql = "SELECT node_proximity, node2arc FROM " + self.schema_name + ".config"
        row = self.controller.get_row(sql)
        if row:
            self.node_proximity = row['node_proximity']
            self.node2arc = row['node2arc']

    def check_topology_arc(self):
        """ Check topology: Inserted node is over an existing arc? """

        # Initialize plugin parameters
        self.controller.plugin_settings_set_value("check_topology_arc", "0")
        self.controller.plugin_settings_set_value("close_dlg", "0")

        # Get selected srid and coordinates. Set SQL to check topology
        srid = self.controller.plugin_settings_value('srid')
        point = self.feature.geometry().asPoint()
        node_geom = "ST_SetSRID(ST_Point(" + str(point.x()) + ", " + str(
            point.y()) + "), " + str(srid) + ")"

        sql = ("SELECT arc_id, state FROM " + self.schema_name + ".v_edit_arc"
               " WHERE ST_DWithin(" + node_geom + ", v_edit_arc.the_geom, " +
               str(self.node2arc) + ")"
               " ORDER BY ST_Distance(v_edit_arc.the_geom, " + node_geom + ")"
               " LIMIT 1")
        row = self.controller.get_row(sql)
        if row:
            msg = (
                "We have detected you are trying to divide an arc with state "
                + str(row['state']) + ""
                "\nRemember that:"
                "\n\nIn case of arc has state 0, you are allowed to insert a new node, because state 0 has not topology rules, and as a result arc will not be broken."
                "\nIn case of arc has state 1, only nodes with state=1 can be part of node1 or node2 from arc. If the new node has state 0 or state 2 arc will be broken."
                "\nIn case of arc has state 2, nodes with state 1 or state 2 are enabled. If the new node has state 0 arc will not be broken"
                "\n\nWould you like to continue?")
            answer = self.controller.ask_question(msg,
                                                  "Divide intersected arc?")
            if answer:
                self.controller.plugin_settings_set_value(
                    "check_topology_arc", "1")
            else:
                self.controller.plugin_settings_set_value("close_dlg", "1")

    def check_topology_node(self):
        """ Check topology: Inserted node is over an existing node? """

        node_over_node = False
        continue_insert = True

        # Initialize plugin parameters
        self.controller.plugin_settings_set_value("check_topology_node", "0")
        self.controller.plugin_settings_set_value("close_dlg", "0")

        # Get selected srid and coordinates. Set SQL to check topology
        srid = self.controller.plugin_settings_value('srid')
        point = self.feature.geometry().asPoint()
        node_geom = "ST_SetSRID(ST_Point(" + str(point.x()) + ", " + str(
            point.y()) + "), " + str(srid) + ")"

        sql = ("SELECT node_id, state FROM " + self.schema_name +
               ".v_edit_node"
               " WHERE ST_Intersects(ST_Buffer(" + node_geom + ", " +
               str(self.node_proximity) + "), the_geom)"
               " ORDER BY ST_Distance(" + node_geom + ", the_geom)"
               " LIMIT 1")
        row = self.controller.get_row(sql)
        if row:
            node_over_node = True
            msg = (
                "We have detected you are trying to insert one node over another node with state "
                + str(row['state']) + ""
                "\nRemember that:"
                "\n\nIn case of old or new node has state 0, you are allowed to insert new one, because state 0 has not topology rules."
                "\nIn the rest of cases, remember that the state topology rules of Giswater only enables one node with the same state at the same position."
                "\n\nWould you like to continue?")
            answer = self.controller.ask_question(msg,
                                                  "Insert node over node?")
            if answer:
                self.controller.plugin_settings_set_value(
                    "check_topology_node", "1")
            else:
                self.controller.plugin_settings_set_value("close_dlg", "1")
                continue_insert = False

        return (continue_insert, node_over_node)

    def action_rotation(self):

        # Set map tool emit point and signals
        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.canvas.setMapTool(self.emit_point)
        self.snapper = QgsMapCanvasSnapper(self.canvas)
        self.canvas.xyCoordinates.connect(self.action_rotation_mouse_move)
        self.emit_point.canvasClicked.connect(
            self.action_rotation_canvas_clicked)

        # Store user snapping configuration
        self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper_manager.store_snapping_options()

        # Clear snapping
        self.snapper_manager.clear_snapping()

        # Set snapping
        layer = self.controller.get_layer_by_tablename("v_edit_arc")
        self.snapper_manager.snap_to_layer(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_connec")
        self.snapper_manager.snap_to_layer(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_node")
        self.snapper_manager.snap_to_layer(layer)

        # Set marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

    def action_rotation_mouse_move(self, point):
        """ Slot function when mouse is moved in the canvas. 
            Add marker if any feature is snapped 
        """

        # Hide marker and get coordinates
        self.vertex_marker.hide()
        map_point = self.canvas.getCoordinateTransform().transform(point)
        x = map_point.x()
        y = map_point.y()
        event_point = QPoint(x, y)

        # Snapping
        (retval, result) = self.snapper.snapToBackgroundLayers(
            event_point)  # @UnusedVariable

        if not result:
            return

        # Check snapped features
        for snapped_point in result:
            point = QgsPoint(snapped_point.snappedVertex)
            self.vertex_marker.setCenter(point)
            self.vertex_marker.show()
            break

    def action_rotation_canvas_clicked(self, point, btn):

        if btn == Qt.RightButton:
            self.disable_rotation()
            return

        viewname = self.controller.get_layer_source_table_name(self.layer)
        sql = ("SELECT ST_X(the_geom), ST_Y(the_geom)"
               " FROM " + self.schema_name + "." + viewname + ""
               " WHERE node_id = '" + self.id + "'")
        row = self.controller.get_row(sql)
        if row:
            existing_point_x = row[0]
            existing_point_y = row[1]

        sql = ("UPDATE " + self.schema_name + ".node"
               " SET hemisphere = (SELECT degrees(ST_Azimuth(ST_Point(" +
               str(existing_point_x) + ", " + str(existing_point_y) + "), "
               " ST_Point(" + str(point.x()) + ", " + str(point.y()) + "))))"
               " WHERE node_id = '" + str(self.id) + "'")
        status = self.controller.execute_sql(sql)
        if not status:
            self.disable_rotation()
            return

        sql = ("SELECT degrees(ST_Azimuth(ST_Point(" + str(existing_point_x) +
               ", " + str(existing_point_y) + "),"
               " ST_Point( " + str(point.x()) + ", " + str(point.y()) + ")))")
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.setWidgetText("hemisphere", str(row[0]))
            message = "Hemisphere of the node has been updated. Value is"
            self.controller.show_info(message, parameter=str(row[0]))

        self.disable_rotation()

    def disable_rotation(self):
        """ Disable actionRotation and set action 'Identify' """

        action_widget = self.dialog.findChild(QAction, "actionRotation")
        if action_widget:
            action_widget.setChecked(False)

        try:
            self.snapper_manager.recover_snapping_options()
            self.vertex_marker.hide()
            self.set_action_identify()
            self.canvas.xyCoordinates.disconnect()
            self.emit_point.canvasClicked.disconnect()
        except:
            pass

    def tab_activation(self):
        """ Call functions depend on tab selection """

        # Get index of selected tab
        index_tab = self.tab_main.currentIndex()

        # Tab 'Connections'
        if index_tab == (
                2 - self.tabs_removed) and not self.tab_connections_loaded:
            self.fill_tab_connections()
            self.tab_connections_loaded = True

        # Tab 'Element'
        elif index_tab == (3 -
                           self.tabs_removed) and not self.tab_element_loaded:
            self.fill_tab_element()
            self.tab_element_loaded = True

        # Tab 'Document'
        elif index_tab == (4 -
                           self.tabs_removed) and not self.tab_document_loaded:
            self.fill_tab_document()
            self.tab_document_loaded = True

        # Tab 'O&M'
        elif index_tab == (5 - self.tabs_removed) and not self.tab_om_loaded:
            self.fill_tab_om()
            self.tab_om_loaded = True

        # Tab 'Scada'
        elif index_tab == (6 -
                           self.tabs_removed) and not self.tab_scada_loaded:
            self.fill_tab_scada()
            self.tab_scada_loaded = True

        # Tab 'Cost'
        elif index_tab == (7 - self.tabs_removed) and not self.tab_cost_loaded:
            self.fill_tab_cost()
            self.tab_cost_loaded = True

    def fill_tab_connections(self):
        """ Fill tab 'Connections' """

        self.fill_tables(self.tbl_upstream, "v_ui_node_x_connection_upstream")
        self.fill_tables(self.tbl_downstream,
                         "v_ui_node_x_connection_downstream")

    def fill_tab_element(self):
        """ Fill tab 'Element' """

        table_element = "v_ui_element_x_node"
        self.fill_tbl_element_man(self.tbl_element, table_element, self.filter)
        self.set_configuration(self.tbl_element, table_element)

    def fill_tab_document(self):
        """ Fill tab 'Document' """

        table_document = "v_ui_doc_x_node"
        self.fill_tbl_document_man(self.tbl_document, table_document,
                                   self.filter)
        self.set_configuration(self.tbl_document, table_document)

    def fill_tab_om(self):
        """ Fill tab 'O&M' (event) """

        table_event_node = "v_ui_om_visit_x_node"
        self.fill_tbl_event(self.tbl_event,
                            self.schema_name + "." + table_event_node,
                            self.filter)
        self.tbl_event.doubleClicked.connect(self.open_selected_document_event)
        self.set_configuration(self.tbl_event, table_event_node)

    def fill_tab_scada(self):
        """ Fill tab 'Scada' """
        pass

    def fill_tab_cost(self):
        """ Fill tab 'Cost' """

        table_costs = "v_plan_node"
        self.fill_table(self.tbl_costs, self.schema_name + "." + table_costs,
                        self.filter)
        self.set_configuration(self.tbl_costs, table_costs)
コード例 #38
0
ファイル: add_pump_tool.py プロジェクト: mcgoldba/XPSS
class AddPumpTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.snapper = None
        self.snapped_pipe_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = -1

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = True

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        if not self.mouse_clicked:

            # Mouse not clicked: snapping to closest vertex
            # (retval, result) = self.snapper.snapMapPoint(self.toMapCoordinates(event.pos()))
            # if len(result) > 0:

            match = self.snapper.snapToMap(self.mouse_pt)
            if match.isValid():

                # It's a vertex on an existing pipe

                # self.snapped_pipe_id = result[0].snappedAtGeometry
                # snapped_vertex = result[0].snappedVertex
                # self.snapped_vertex_nr = result[0].snappedVertexNr
                # self.snapped_vertex = QgsPoint(snapped_vertex.x(), snapped_vertex.y())

                self.snapped_pipe_id = match.featureId()
                self.snapped_vertex = match.point()
                self.snapped_vertex_nr = match.vertexIndex()

                self.vertex_marker.setCenter(self.snapped_vertex)
                self.vertex_marker.setColor(QColor(255, 0, 0))
                self.vertex_marker.setIconSize(10)
                self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                self.vertex_marker.setPenWidth(3)
                self.vertex_marker.show()

            else:

                # It's a new, isolated vertex
                self.snapped_pipe_id = None
                self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return

        if event.button() == Qt.LeftButton:

            self.mouse_clicked = False

            # No pipe snapped: notify user
            if self.snapped_pipe_id is None:

                self.iface.messageBar().pushMessage(
                    Parameters.plug_in_name,
                    'You need to snap the cursor to a pipe to add a pump.',
                    Qgis.Info, 5)

            # A pipe has been snapped
            else:

                request = QgsFeatureRequest().setFilterFid(
                    self.snapped_pipe_id)
                feats = self.params.pipes_vlay.getFeatures(request)
                features = [feat for feat in feats]
                if len(features) == 1:

                    # Check whether the pipe has a start and an end node
                    (start_node, end_node) = NetworkUtils.find_start_end_nodes(
                        self.params, features[0].geometry())

                    if not start_node or not end_node:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'The pipe is missing the start or end nodes.',
                            Qgis.Warning, 5)  # TODO: softcode
                        return

                    # Find endnode closest to pump position
                    dist_1 = start_node.geometry().distance(
                        QgsGeometry.fromPointXY(self.snapped_vertex))
                    dist_2 = end_node.geometry().distance(
                        QgsGeometry.fromPointXY(self.snapped_vertex))

                    # Get the attributes of the closest junction
                    (start_node, end_node) = NetworkUtils.find_start_end_nodes(
                        self.params, features[0].geometry(), False, True, True)
                    if dist_1 < dist_2:
                        closest_junction_ft = start_node
                    else:
                        closest_junction_ft = end_node

                    # Create the pump
                    pump_param = ''
                    pump_head = None
                    pump_power = None
                    pump_speed = 0
                    pump_speed_pattern = 0

                    # Head and curve
                    if self.data_dock.cbo_pump_param.itemText(
                            self.data_dock.cbo_pump_param.currentIndex(
                            )) == Pump.parameters_head:
                        pump_param = Pump.parameters_head
                        curve = self.data_dock.cbo_pump_head.itemData(
                            self.data_dock.cbo_pump_head.currentIndex())
                        if curve is not None:
                            pump_head = curve.id
                        else:
                            pump_head = None

                    # Power and value
                    elif self.data_dock.cbo_pump_param.itemText(
                            self.data_dock.cbo_pump_param.currentIndex(
                            )) == Pump.parameters_power:
                        pump_param = Pump.parameters_power
                        pump_power = float(
                            self.data_dock.txt_pump_power.text())

                    # Speed
                    pump_speed_s = self.data_dock.txt_pump_speed.text()
                    if pump_speed_s is None or pump_speed_s == '':
                        pump_speed = 0
                    else:
                        pump_speed = float(pump_speed_s)

                    # Speed pattern
                    pump_speed_pattern = self.data_dock.cbo_pump_speed_pattern.itemText(
                        self.data_dock.cbo_pump_speed_pattern.currentIndex())

                    # Pump status
                    pump_status = self.data_dock.cbo_pump_status.itemData(
                        self.data_dock.cbo_pump_status.currentIndex())

                    # Pump description
                    pump_desc = self.data_dock.txt_pump_desc.text()

                    # Pump tag
                    pump_tag = self.data_dock.cbo_pump_tag.currentText()

                    try:
                        LinkHandler.create_new_pumpvalve(
                            self.params, self.data_dock, features[0],
                            closest_junction_ft, self.snapped_vertex,
                            self.params.pumps_vlay, {
                                Pump.field_name_param: pump_param,
                                Pump.field_name_head: pump_head,
                                Pump.field_name_power: pump_power,
                                Pump.field_name_speed: pump_speed,
                                Pump.field_name_speed_pattern:
                                pump_speed_pattern,
                                Pump.field_name_status: pump_status,
                                Pump.field_name_description: pump_desc,
                                Pump.field_name_tag: pump_tag
                            })

                        if pump_param == Pump.parameters_head and pump_head is None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'The pump was added, but with a NULL value.',
                                Qgis.Info, 5)

                    except PumpValveCreationException as ex:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name, ', '.join(ex.args),
                            Qgis.Info, 5)

            self.iface.mapCanvas().refresh()

        elif event.button() == Qt.RightButton:

            self.mouse_clicked = False

            # Check whether it clicked on a valve vertex
            if len(
                    NetworkUtils.find_adjacent_links(self.params,
                                                     self.snapped_vertex)
                ['pumps']) == 0 or self.snapped_pipe_id is None:
                return

            menu = QMenu()
            invert_action = menu.addAction(
                'Flip orientation')  # TODO: softcode
            action = menu.exec_(self.iface.mapCanvas().mapToGlobal(
                QPoint(event.pos().x(),
                       event.pos().y())))
            if action == invert_action:

                request = QgsFeatureRequest().setFilterFid(
                    self.snapped_pipe_id)
                feats = self.params.pipes_vlay.getFeatures(request)
                features = [feat for feat in feats]
                if len(features) == 1:
                    adj_links = NetworkUtils.find_links_adjacent_to_link(
                        self.params, self.params.pipes_vlay, features[0], True,
                        False, True)

                    for adj_link in adj_links['pumps']:
                        adj_link_pts = adj_link.geometry().asPolyline()
                        for adj_link_pt in adj_link_pts:
                            if NetworkUtils.points_overlap(
                                    adj_link_pt, self.snapped_vertex,
                                    self.params.tolerance):

                                geom = adj_link.geometry()

                                if geom.wkbType(
                                ) == QgsWkbTypes.MultiLineString:
                                    nodes = geom.asMultiPolyline()
                                    for line in nodes:
                                        line.reverse()
                                    newgeom = QgsGeometry.fromMultiPolyline(
                                        nodes)
                                    self.params.pumps_vlay.changeGeometry(
                                        adj_link.id(), newgeom)

                                if geom.wkbType() == QgsWkbTypes.LineString:
                                    nodes = geom.asPolyline()
                                    nodes.reverse()
                                    newgeom = QgsGeometry.fromPolylineXY(nodes)
                                    self.params.pumps_vlay.changeGeometry(
                                        adj_link.id(), newgeom)

                                self.iface.mapCanvas().refresh()

                                break

    def activate(self):

        # snap_layer_pipes = NetworkUtils.set_up_snap_layer(self.params.pipes_vlay, None, QgsSnapper.SnapToVertexAndSegment)

        self.update_snapper()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()
        if not self.params.pumps_vlay.isEditable():
            self.params.pumps_vlay.startEditing()

    def deactivate(self):

        # QgsProject.instance().setSnapSettingsForLayer(self.params.pipes_vlay.id(),
        #                                               True,
        #                                               QgsSnapper.SnapToSegment,
        #                                               QgsTolerance.MapUnits,
        #                                               0,
        #                                               True)

        self.data_dock.btn_add_pump.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def update_snapper(self):
        layers = {self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment}
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)
        self.snapper.toggleEnabled()

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
コード例 #39
0
class Coordinator():
    """YACUP plugin"""
    def __init__(self, iface, mainWindow=None):
        """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
        """
        # store references to important stuff from QGIS
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self._project = QgsProject.instance()

        self._observingLayer = None

        self._uiHook = mainWindow if isinstance(mainWindow,
                                                QMainWindow) else iface

        # region: LOCALE - UNUSED
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        #
        #initialize locale
        localeString = QSettings().value('locale/userLocale')
        if (localeString):
            locale = localeString[0:2]
        else:
            locale = QLocale().language()

        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'coordinator_{}.qm'.format(locale))

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

        # plugin housekeeping:
        self.openPanelAction = None
        self.pluginIsActive = False
        self.dockwidget = None

        # Init CRS Transformation:
        self._inputCrs = None
        self._outputCrs = None

        # self._transform : input -> output transformation
        # self._canvasTransform: input -> canvas transformation
        self.__initTransformers()

        # initialize canvas marker icon:
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.hide()
        self.marker.setColor(QColor(255, 0, 0))
        self.marker.setIconSize(14)
        self.marker.setIconType(
            QgsVertexMarker.ICON_CIRCLE
        )  # See the enum IconType from http://www.qgis.org/api/classQgsVertexMarker.html
        self.marker.setPenWidth(3)

        # init point picker:
        self.mapTool = QgsMapToolEmitPoint(self.canvas)

    # LIFECYCLE :
    def initGui(self):
        """Create the menu entry inside the QGIS GUI."""
        icon = QIcon(':/plugins/coordinator/icons/marker.svg')
        menuTitle = CT.tr("Open Coordinator")
        self.openPanelAction = QAction(icon, menuTitle)
        self.openPanelAction.triggered.connect(self.run)
        self.iface.pluginMenu().addAction(self.openPanelAction)

    #--------------------------------------------------------------------------

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""

        # remove the marker from the canvas:
        self.marker.hide()

        self.dockwidget.closingPlugin.disconnect(self.onClosePlugin)
        # disconnect from the GUI-signals
        self._disconnectExternalSignals()

        self.pluginIsActive = False

    def unload(self):
        """Removes the plugin menu item from QGIS GUI."""
        self.iface.pluginMenu().removeAction(self.openPanelAction)
        self.marker.hide()

        self._disconnectExternalSignals()

    #--------------------------------------------------------------------------

    # PRIVATE HELPERS:
    def __initTransformers(self):
        """Initializes both coordinate transform object needed: the transformation from the
        input CRS to the output CRS (self._transform) and a tranformer from the input CRS to
        the current canvas CRS."""
        inputCrs = self._inputCrs if self._inputCrs != None else QgsCoordinateReferenceSystem(
            "EPSG:4326")
        outputCrs = self._outputCrs if self._outputCrs != None else QgsCoordinateReferenceSystem(
            "EPSG:4326")

        self._transform = QgsCoordinateTransform(inputCrs, outputCrs,
                                                 self._project)

        canvasCrs = self.canvas.mapSettings().destinationCrs()
        #         coordinatorLog("init canvas transform with %s -> %s"
        #                        % (inputCrs.authid(), canvasCrs.authid() if canvasCrs else "NONE!!")
        #                        )

        self._canvasTransform = QgsCoordinateTransform(inputCrs, canvasCrs,
                                                       self._project)

    def __checkEnableAddFeatureButton(self):
        shouldEnable = bool(self.dockwidget.hasInput()
                            and self.__compatibleMapTool())
        return shouldEnable

    def __compatibleMapTool(self):
        newTool = self.canvas.mapTool()
        if (newTool != None and (newTool.flags() & QgsMapTool.EditTool)):

            newTool = sip.cast(newTool, QgsMapToolCapture)

            # pre-check probably fixing issue #3 regarding Enums with Qt >= 5.11:
            #  --> https://www.riverbankcomputing.com/static/Docs/PyQt5/gotchas.html#enums
            try:
                validModes = (QgsMapToolCapture.CaptureMode.CapturePoint,
                              QgsMapToolCapture.CaptureMode.CapturePolygon,
                              QgsMapToolCapture.CaptureMode.CaptureLine)
            except AttributeError:
                validModes = (QgsMapToolCapture.CapturePoint,
                              QgsMapToolCapture.CapturePolygon,
                              QgsMapToolCapture.CaptureLine)

            if newTool.mode() in validModes:
                return newTool

        return False

    def _disconnectExternalSignals(self):
        try:
            self.iface.mapCanvas().destinationCrsChanged.disconnect(
                self.mapCanvasCrsChanged)
        except TypeError:
            pass
        try:
            self.canvas.mapToolSet.disconnect(self.mapToolChanged)
        except TypeError:
            pass
        try:
            self.iface.currentLayerChanged.disconnect(self.currentLayerChanged)
        except TypeError:
            pass
        try:
            self.iface.projectRead.disconnect(self.projectRead)
        except TypeError:
            pass

        if (self._observingLayer != None) and sip.isdeleted(
                self._observingLayer):
            self._observingLayer = None

        if self._observingLayer:
            try:
                self._observingLayer.crsChanged.disconnect(
                    self.layerChangedCrs)
            except TypeError:
                pass

    def _currentEffectiveCrsInMap(self):
        activeLayer = self.iface.activeLayer()

        if (activeLayer):
            if type(activeLayer) == QgsVectorLayer:
                return activeLayer.sourceCrs()
            elif type(activeLayer) == QgsRasterLayer:
                return activeLayer.crs()
        else:
            return self.canvas.mapSettings().destinationCrs()

    def _warnIfPointOutsideCanvas(self):
        if (self.dockwidget.hasInput() and not self.canvas.extent().contains(
                self.inputCoordinatesInCanvasCrs())):
            self.setWarningMessage(CT.tr("outside of map extent"))
        else:
            self.setWarningMessage(None)

    #--------------------------------------------------------------------------

    # GETTERS/SETTERS
    def setInputCrs(self, crs):
        oldCrs = self._inputCrs

        if (oldCrs == None) or (crs.authid() != oldCrs.authid()):
            #coordinatorLog("setting input CRS to %s" % crs.authid())
            currentCoordinates = self.dockwidget.inputCoordinates()
            self._inputCrs = crs
            self.dockwidget.setSectionCrs(CoordinatorDockWidget.SectionInput,
                                          crs)
            self._transform.setSourceCrs(crs)
            self._canvasTransform.setSourceCrs(crs)

            if (oldCrs != None and self.dockwidget.hasInput()):
                # make sure we transform the currently set coordinate
                # to the new Coordinate System :
                t = QgsCoordinateTransform(oldCrs, crs, QgsProject.instance())
                transformedPoint = t.transform(
                    QgsPointXY(currentCoordinates[0], currentCoordinates[1]))
                self.dockwidget.setInputPoint(transformedPoint)
            else:
                self.dockwidget.clearSection(CoordinatorDockWidget.SectionBoth)

    def inputCrs(self):
        return self._inputCrs

    def setOutputCrs(self, crs):
        #coordinatorLog("changing output CRS %s -> %s" % (self._outputCrs.authid() if self._outputCrs else "NONE!", crs.authid()) )
        oldCrs = self._outputCrs
        if (oldCrs == None) or (oldCrs.authid() != crs.authid()):
            self._outputCrs = crs
            self.dockwidget.setSectionCrs(CoordinatorDockWidget.SectionOutput,
                                          crs)
            self._transform.setDestinationCrs(crs)
            self.process()

    def outputCrs(self):
        return self._outputCrs

    def setWarningMessage(self, message):
        self.dockwidget.setWarningMessage(message)

    # ACTIONS :
    def openCrsSelectionDialogForSection(self, section):
        projSelector = QgsProjectionSelectionDialog()
        if (projSelector.exec()):
            if section == CoordinatorDockWidget.SectionInput:
                self.setInputCrs(projSelector.crs())
            elif section == CoordinatorDockWidget.SectionOutput:
                self.setOutputCrs(projSelector.crs())

    def setOutputCrsToCanvasCrs(self):
        crs = self.canvas.mapSettings().destinationCrs()
        self.setOutputCrs(crs)

    def connectCrsToCanvas(self, section, connect):
        #coordinatorLog("%s %s" % (section, connect))

        if section == CoordinatorDockWidget.SectionOutput:

            if (connect):  # connect to map
                # disable dialog for selecting output CRS:
                self.dockwidget.outputCrs.clicked.disconnect()
                # set CRS to be canvas' CRS and follow it
                self.setOutputCrsToCanvasCrs()
            else:
                # enable dialog selection
                self.dockwidget.outputCrs.clicked.connect(
                    partial(self.openCrsSelectionDialogForSection,
                            CoordinatorDockWidget.SectionOutput))

    def addCurrentCoordinatesToDigitizeSession(self):
        editTool = self.__compatibleMapTool()
        if (not editTool):
            return False

        result = False

        point = self.inputCoordinatesInCanvasCrs()
        if (editTool.mode() == QgsMapToolCapture.CaptureMode.CapturePoint):
            #coordinatorLog("Point Capture!")
            layer = self.iface.activeLayer()
            geometry = QgsGeometry.fromPointXY(point)
            feature = QgsVectorLayerUtils.createFeature(
                layer, geometry, {}, layer.createExpressionContext())
            if ((len(layer.fields()) < 1)
                    or self.iface.openFeatureForm(layer, feature)):
                result = layer.addFeature(feature)
                if (result):
                    #coordinatorLog("Point successfully written to layer")
                    pass
                layer.triggerRepaint()

        elif ((editTool.mode() == QgsMapToolCapture.CaptureMode.CapturePolygon)
              or
              (editTool.mode() == QgsMapToolCapture.CaptureMode.CaptureLine)):
            #coordinatorLog("Rubberband Capture!")
            result = (editTool.addVertex(point) == 0)
        else:
            return False

        if (result):
            self.dockwidget.showInfoMessage(CT.tr("coordinate added"), 1500)
        else:
            self.setWarningMessage(CT.tr("adding coordinate failed"))

        return result

    def switchInputOutputCrs(self):
        inputCrs = self._inputCrs
        self.setInputCrs(self._outputCrs)
        self.setOutputCrs(inputCrs)

        if self.dockwidget.outputCrsConn.isChecked() and (
                self._outputCrs.authid() != self._inputCrs.authid()):
            self.dockwidget.outputCrsConn.setChecked(False)

    def _showMarker(self, show):
        if show and self.dockwidget.hasInput():
            self.marker.show()
        else:
            self.marker.hide()

    # API :
    def enableMarker(self, show):
        self._showMarker(show)
        self.dockwidget.showMarker.setChecked(show)

    # PIPELINE :
    def ensureValidInputGui(self):
        self.dockwidget.addFeatureButton.setEnabled(
            self.__checkEnableAddFeatureButton())
        self._warnIfPointOutsideCanvas()

        # make sure we show the marker now:
        if self.dockwidget.hasInput():
            if self.dockwidget.showMarker.isChecked():
                self.marker.show()
        else:
            self.marker.hide()

        self.dockwidget.setInputToDMS(self.dockwidget.inputAsDMS.isChecked()
                                      & self._inputCrs.isGeographic())

    def process(self):
        #coordinatorLog("about to process input")
        if (self.dockwidget.hasInput()):
            (x, y) = self.dockwidget.inputCoordinates()
            # coordinatorLog("Input: %f %f " %  (x, y)  )
            transformedPoint = self._transform.transform(QgsPointXY(x, y))
            # coordinatorLog("Transformed point: %f %f " %  (transformedPoint.x(), transformedPoint.y())  )
            self.dockwidget.setResultPoint(transformedPoint)
            self.marker.setCenter(self.inputCoordinatesInCanvasCrs())
        else:
            self.dockwidget.clearFieldsInSection(
                CoordinatorDockWidget.SectionOutput)

    def reset(self):
        self.__initTransformers()
        self.dockwidget.resetInterface()
        self.dockwidget.setEastingInverted(False)
        self.dockwidget.setNorthingInverted(False)

    def inputCoordinatesInCanvasCrs(self):
        (x, y) = self.dockwidget.inputCoordinates()
        result = self._canvasTransform.transform(QgsPointXY(x, y))
        #coordinatorLog("transformation: (%s,%s) are (%s,%s)" % (x,y, result.x(), result.y()))
        #coordinatorLog(" %s -> %s" % (self._canvasTransform.sourceCrs().authid(), self._canvasTransform.destinationCrs().authid()) )
        return result

    # SLOTS :
    def mapCanvasCrsChanged(self):
        self._canvasTransform.setDestinationCrs(
            self.canvas.mapSettings().destinationCrs())
        #if(self.dockwidget.outputCrsConn.isChecked()):
        #    self.setOutputCrs(self.canvas.mapSettings().destinationCrs())

    def inputCoordinatesChanged(self):
        #Coordinator.log("Input changed")
        self.process()
        self.ensureValidInputGui()

    def inputFormatChanged(self):
        self.ensureValidInputGui()

    def outputFormatChanged(self):
        self.process()

    def moveCanvasButtonClicked(self):
        self.canvas.setCenter(self.inputCoordinatesInCanvasCrs())

    def mapCrsConnectionButtonToggled(self, forSection, enabled):
        self.connectCrsToCanvas(forSection, enabled)

    def showMarkerButtonToggled(self, show):
        self._showMarker(show)

    def captureCoordsButtonToggled(self, enabled):
        #coordinatorLog( "enable Capture Coords: %s" % enabled)
        if (enabled):
            self.canvas.setMapTool(self.mapTool)
            self.mapTool.canvasClicked.connect(self.canvasClickedWithPicker)
        else:
            try:
                self.mapTool.canvasClicked.disconnect(
                    self.canvasClickedWithPicker)
            except TypeError:
                pass
            self.canvas.unsetMapTool(self.mapTool)

    def canvasClickedWithPicker(self, point, button):
        # button is the MouseButton
        #coordinatorLog(type(button).__name__)

        if QApplication.keyboardModifiers() and Qt.ControlModifier:
            self.setInputCrs(self.canvas.mapSettings().destinationCrs())

#         coordinatorLog("Current Canvas Transform is %s -> %s (we do the reverse to get input)"
#                        % (self._canvasTransform.sourceCrs().authid(), self._canvasTransform.destinationCrs().authid())
#                        )

        point = self._canvasTransform.transform(
            point, QgsCoordinateTransform.ReverseTransform)
        self.dockwidget.setInputPoint(point)

    def canvasMoved(self):
        self._warnIfPointOutsideCanvas()

    def mapToolChanged(self):
        #coordinatorLog("map tools changed")
        #coordinatorLog( type( self.canvas.mapTool() ).__name__ )

        currentMapTool = self.canvas.mapTool()

        if (currentMapTool == self.mapTool):
            # user selected our coordinate capture tool -> do nothing
            pass
        elif (self.__checkEnableAddFeatureButton()):
            # user selected a tool to modify features -> enable our add feature button
            self.dockwidget.addFeatureButton.setEnabled(True)
            self.dockwidget.captureCoordButton.setChecked(False)
        else:
            # user selected a totally unrelated tool -> make sure our coordinate capture tool is disabled
            self.dockwidget.captureCoordButton.setChecked(False)

    def addFeatureClicked(self):
        self.addCurrentCoordinatesToDigitizeSession()

    def projectRead(self):
        #coordinatorLog("new project")
        self._project = QgsProject.instance()
        self.reset()

    def currentLayerChanged(self, layer):

        if self._observingLayer:
            self._observingLayer.crsChanged.disconnect(self.layerChangedCrs)

        if layer:
            self._observingLayer = layer
            self._observingLayer.crsChanged.connect(self.layerChangedCrs)

        #coordinatorLog("%s" % type(layer).__name__)
        if self.dockwidget.outputCrsConn.isChecked():
            self.setOutputCrs(self._currentEffectiveCrsInMap())

    def layerChangedCrs(self):
        #coordinatorLog("%s" % type(layer).__name__)
        if self.dockwidget.outputCrsConn.isChecked():
            self.setOutputCrs(self._currentEffectiveCrsInMap())

    def run(self):
        """Run method that loads and starts the plugin"""
        #coordinatorLog("run", "Coordinator")
        if not self.pluginIsActive:
            self.pluginIsActive = True

            #QgsMessageLog.logMessage("Starting", "Coordinator")

            # dockwidget may not exist if:
            #    first run of plugin
            #    removed on close (see self.onClosePlugin method)
            if self.dockwidget == None:
                # Create the dockwidget (after translation) and keep reference
                self.dockwidget = CoordinatorDockWidget()

            #for child in self.dockwidget.children():
            #    self.log("Child: %s" % child.objectName())

            # MA LOGIC:

            # EXTERNAL connections
            self.canvas.destinationCrsChanged.connect(self.mapCanvasCrsChanged)
            self.canvas.mapToolSet.connect(self.mapToolChanged)
            self.canvas.extentsChanged.connect(self.canvasMoved)
            self.iface.projectRead.connect(self.projectRead)
            self.iface.currentLayerChanged.connect(self.currentLayerChanged)

            # CONNECT the initially active buttons from the GUI:
            self.dockwidget.selectCrsButton.clicked.connect(
                partial(self.openCrsSelectionDialogForSection,
                        CoordinatorDockWidget.SectionInput))
            self.dockwidget.mapConnectionChanged.connect(
                self.mapCrsConnectionButtonToggled)

            # set the inital CRS:
            self.setInputCrs(QgsCoordinateReferenceSystem("EPSG:4326"))
            self.setOutputCrs(self.canvas.mapSettings().destinationCrs())

            # connect the marker button :
            self.dockwidget.showMarker.clicked.connect(
                self.showMarkerButtonToggled)
            self.dockwidget.moveCanvas.clicked.connect(
                self.moveCanvasButtonClicked)
            self.dockwidget.captureCoordButton.clicked.connect(
                self.captureCoordsButtonToggled)

            self.dockwidget.addFeatureButton.clicked.connect(
                self.addFeatureClicked)

            self.dockwidget.inputFormatButtonGroup.buttonClicked.connect(
                self.inputFormatChanged)
            self.dockwidget.resultFormatButtonGroup.buttonClicked.connect(
                self.outputFormatChanged)

            self.dockwidget.inputChanged.connect(self.inputCoordinatesChanged)

            # connect to provide cleanup on closing of dockwidget
            self.dockwidget.closingPlugin.connect(self.onClosePlugin)

            # SETUP:
            self.enableMarker(True)
            self._canvasTransform.setDestinationCrs(
                self.canvas.mapSettings().destinationCrs())

            # show the dockwidget
            # TODO: fix to allow choice of dock location
            self._uiHook.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget)
            self.dockwidget.show()
コード例 #40
0
# coding: utf-8
from PyQt4.QtGui import QColor
from qgis.utils import iface
from qgis.core import QgsPoint
from qgis.gui import QgsVertexMarker

canvas = iface.mapCanvas()
m = QgsVertexMarker(canvas)
m.setCenter(QgsPoint(0, 0))

m.setColor(QColor(0, 0, 255))
m.setIconSize(7)
m.setIconType(
    QgsVertexMarker.ICON_BOX
)  # See the enum IconType from http://www.qgis.org/api/classQgsVertexMarker.html
m.setPenWidth(3)

m.hide()
m.show()

# Remove the element
# canvas.scene().removeItem(m)
コード例 #41
0
class addPolygon(QgsMapTool):
    cut = pyqtSignal()
    deact = pyqtSignal()

    def __init__(self, iface, action, geometryClass):
        self.canvas = iface.mapCanvas()
        self.iface = iface
        self.action = action
        self.geometryClass = geometryClass

        obj_color = QColor(254, 0, 0)
        obj_color_alpha = QColor(254, 0, 0)
        obj_color_alpha.setAlpha(60)
        vert_color = QColor(0, 0, 255)

        QgsMapTool.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.GeometryType(3))
        self.rubberBand.setWidth(1)
        self.rubberBand.setStrokeColor(obj_color)
        self.rubberBand.setFillColor(obj_color_alpha)

        self.rubberBand_click = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.GeometryType(3))
        self.rubberBand_click.setWidth(0)
        self.rubberBand_click.setFillColor(obj_color_alpha)

        # snap marker
        self.snap_mark = QgsVertexMarker(self.canvas)
        self.snap_mark.setColor(vert_color)
        self.snap_mark.setPenWidth(2)
        self.snap_mark.setIconType(QgsVertexMarker.ICON_BOX)
        self.snap_mark.setIconSize(10)

        self.points = []

    def activate(self):
        self.action.setChecked(True)
        self.setCursor(Qt.CrossCursor)

    def canvasMoveEvent(self, e):
        self.snap_mark.hide()
        self.snapPoint = False
        self.snapPoint = self.checkSnapToPoint(e.pos())

        if self.snapPoint[0]:
            self.snap_mark.setCenter(self.snapPoint[1])
            self.snap_mark.show()

        if len(self.points) > 0:
            self.rubberBand.reset(QgsWkbTypes.GeometryType(3))
            point = self.toMapCoordinates(self.canvas.mouseLastXY())
            temp_points = self.points[:]
            temp_points.append(point)
            polygon = QgsGeometry.fromPolygonXY([temp_points])
            self.rubberBand.setToGeometry(polygon, None)
            self.rubberBand.show()

    def canvasPressEvent(self, e):
        # Left mouse button
        if e.button() == Qt.LeftButton:
            if self.snapPoint[0]:
                point = self.snapPoint[1]
            else:
                point = self.toMapCoordinates(self.canvas.mouseLastXY())

            self.points.append(point)
            polygon = QgsGeometry.fromPolygonXY([self.points])
            self.rubberBand_click.reset(QgsWkbTypes.GeometryType(3))
            self.rubberBand_click.setToGeometry(polygon, None)
            self.rubberBand_click.show()

        # Right mouse button
        if e.button() == Qt.RightButton:
            geometry = QgsGeometry.fromPolygonXY([self.points])
            self.geometryClass.geometry = geometry
            self.cut.emit()
            self.reset()

    def checkSnapToPoint(self, point):
        snapped = False
        snap_point = self.toMapCoordinates(point)
        snapper = self.canvas.snappingUtils()
        snapMatch = snapper.snapToMap(point)
        if snapMatch.hasVertex():
            snap_point = snapMatch.point()
            snapped = True
        return snapped, snap_point

    def deactivate(self):
        self.action.setChecked(False)
        self.reset()
        self.deact.emit()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.reset()

    def reset(self):
        self.rubberBand_click.reset(QgsWkbTypes.GeometryType(3))
        self.rubberBand.reset(QgsWkbTypes.GeometryType(3))
        self.snap_mark.hide()
        self.points = []
コード例 #42
0
class ConnecMapTool(ParentMapTool):
    """ Button 20. User select connections from layer 'connec'
    Execute SQL function: 'gw_fct_connect_to_network' """

    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        # Call ParentMapTool constructor
        super(ConnecMapTool, self).__init__(iface, settings, action, index_action)

        self.dragging = False

        # Vertex marker
        self.vertexMarker = QgsVertexMarker(self.canvas)
        self.vertexMarker.setColor(QColor(255, 25, 25))
        self.vertexMarker.setIconSize(11)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(5)

        # Rubber band
        self.rubberBand = QgsRubberBand(self.canvas, True)
        mFillColor = QColor(100, 0, 0)
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(3)
        mBorderColor = QColor(254, 58, 29)
        self.rubberBand.setBorderColor(mBorderColor)

        # Select rectangle
        self.selectRect = QRect()

    def reset(self):
        """ Clear selected features """

        layer = self.layer_connec
        if layer is not None:
            layer.removeSelection()

        # Graphic elements
        self.rubberBand.reset()

    """ QgsMapTools inherited event functions """

    def canvasMoveEvent(self, event):
        """ With left click the digitizing is finished """

        if event.buttons() == Qt.LeftButton:

            if not self.dragging:
                self.dragging = True
                self.selectRect.setTopLeft(event.pos())

            self.selectRect.setBottomRight(event.pos())
            self.set_rubber_band()

        else:

            # Hide highlight
            self.vertexMarker.hide()

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)

            # Snapping
            (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

            # That's the snapped point
            if result <> []:

                # Check Arc or Node
                for snapPoint in result:

                    if snapPoint.layer == self.layer_connec:

                        # Get the point
                        point = QgsPoint(result[0].snappedVertex)

                        # Add marker
                        self.vertexMarker.setCenter(point)
                        self.vertexMarker.show()

                        break

    def canvasPressEvent(self, event):

        self.selectRect.setRect(0, 0, 0, 0)
        self.rubberBand.reset()

    def canvasReleaseEvent(self, event):
        """ With left click the digitizing is finished """

        if event.button() == Qt.LeftButton:

            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)

            # Node layer
            layer = self.layer_connec

            # Not dragging, just simple selection
            if not self.dragging:

                # Snap to node
                (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint)  # @UnusedVariable

                # That's the snapped point
                if result <> [] and (result[0].layer.name() == self.layer_connec.name()):

                    point = QgsPoint(result[0].snappedVertex)  # @UnusedVariable
                    layer.removeSelection()
                    layer.select([result[0].snappedAtGeometry])

                    # Create link
                    self.link_connec()

                    # Hide highlight
                    self.vertexMarker.hide()

            else:

                # Set valid values for rectangle's width and height
                if self.selectRect.width() == 1:
                    self.selectRect.setLeft(self.selectRect.left() + 1)

                if self.selectRect.height() == 1:
                    self.selectRect.setBottom(self.selectRect.bottom() + 1)

                self.set_rubber_band()
                selectGeom = self.rubberBand.asGeometry()  # @UnusedVariable
                self.select_multiple_features(self.selectRectMapCoord)
                self.dragging = False

                # Create link
                self.link_connec()

        elif event.button() == Qt.RightButton:

            # Create link
            self.link_connec()

    def activate(self):

        # Check button
        self.action().setChecked(True)

        # Rubber band
        self.rubberBand.reset()

        # Store user snapping configuration
        self.snapperManager.storeSnappingOptions()

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to arc and node
        self.snapperManager.snapToConnec()

        # Change cursor
        self.canvas.setCursor(self.cursor)

        # Show help message when action is activated
        if self.show_help:
            message = (
                "Right click to use current selection, select connec points by clicking or dragging (selection box)"
            )
            self.controller.show_info(message, context_name="ui_message")

        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_connec)
        except:
            self.canvas.setCurrentLayer(self.layer_connec)

    def deactivate(self):

        # Check button
        self.action().setChecked(False)

        # Rubber band
        self.rubberBand.reset()

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

        # Recover cursor
        self.canvas.setCursor(self.stdCursor)

    def link_connec(self):
        """ Link selected connec to the pipe """

        # Get selected features (from layer 'connec')
        aux = "{"
        layer = self.layer_connec
        if layer.selectedFeatureCount() == 0:
            message = "You have to select at least one feature!"
            self.controller.show_warning(message, context_name="ui_message")

            return
        features = layer.selectedFeatures()
        for feature in features:
            connec_id = feature.attribute("connec_id")
            aux += str(connec_id) + ", "
        connec_array = aux[:-2] + "}"

        # Execute function
        function_name = "gw_fct_connect_to_network"
        sql = "SELECT " + self.schema_name + "." + function_name + "('" + connec_array + "');"
        self.controller.execute_sql(sql)

        # Refresh map canvas
        self.rubberBand.reset()
        self.iface.mapCanvas().refresh()

    def set_rubber_band(self):

        # Coordinates transform
        transform = self.canvas.getCoordinateTransform()

        # Coordinates
        ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom())
        lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom())
        ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top())
        ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top())

        # Rubber band
        self.rubberBand.reset()
        self.rubberBand.addPoint(ll, False)
        self.rubberBand.addPoint(lr, False)
        self.rubberBand.addPoint(ur, False)
        self.rubberBand.addPoint(ul, False)
        self.rubberBand.addPoint(ll, True)

        self.selectRectMapCoord = QgsRectangle(ll, ur)

    def select_multiple_features(self, selectGeometry):

        # Default choice
        behaviour = QgsVectorLayer.SetSelection

        # Modifiers
        modifiers = QApplication.keyboardModifiers()

        if modifiers == Qt.ControlModifier:
            behaviour = QgsVectorLayer.AddToSelection
        elif modifiers == Qt.ShiftModifier:
            behaviour = QgsVectorLayer.RemoveFromSelection

        if self.layer_connec is None:
            return

        # Change cursor
        QApplication.setOverrideCursor(Qt.WaitCursor)

        # Selection
        self.layer_connec.selectByRect(selectGeometry, behaviour)

        # Old cursor
        QApplication.restoreOverrideCursor()