class LineDrawer(QgsMapToolEmitPoint):

    def __init__(self, canvas):
        # call the parent constructor
        QgsMapToolEmitPoint.__init__(self, canvas)
        # store the passed canvas
        self.canvas = canvas

        # flag to know whether the tool is performing a drawing operation 
        self.isDrawing = False

        # create and setup the rubber band to display the line
        self.rubberBand = QgsRubberBand( self.canvas, False )    # False = not a polygon = a line
        self.rubberBand.setColor( Qt.red )
        self.rubberBand.setWidth( 1 )


    def clear(self):
        self.rubberBand.reset( False )    # False = not a polygon = a line

    def delete(self):
        self.canvas.scene().removeItem( self.rubberBand )

    def canvasPressEvent(self, e):
        # which the mouse button?
        if e.button() == Qt.LeftButton:
            # left click

            # if it's the first left click, clear the rubberband 
            if not self.isDrawing:
                self.clear()

            # we are drawing now
            self.isDrawing = True

            # convert the clicked position to map coordinates
            point = self.toMapCoordinates( e.pos() )
            # add a new point to the rubber band
            self.rubberBand.addPoint( point, True )    # True = display updates on the canvas
            # and finally show the rubber band
            self.rubberBand.show()

        elif e.button() == Qt.RightButton:
            # right click, stop drawing
            self.isDrawing = False
            # emit a signal
            self.emit( SIGNAL("editingFinished()") )

    def canvasMoveEvent(self, e):
        # check if it's already drawing
        if not self.isDrawing:
            return

        # convert the mouse position to map coordinates
        point = self.toMapCoordinates( e.pos() )
        # move the last point to the new coordinates
        self.rubberBand.movePoint( point )

    def geometry(self):
        return self.rubberBand.asGeometry()
Beispiel #2
0
class LineDrawer(QgsMapToolEmitPoint):
    def __init__(self, canvas):
        # call the parent constructor
        QgsMapToolEmitPoint.__init__(self, canvas)
        # store the passed canvas
        self.canvas = canvas

        # flag to know whether the tool is performing a drawing operation
        self.isDrawing = False

        # create and setup the rubber band to display the line
        self.rubberBand = QgsRubberBand(
            self.canvas, False)  # False = not a polygon = a line
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)

    def clear(self):
        self.rubberBand.reset(False)  # False = not a polygon = a line

    def delete(self):
        self.canvas.scene().removeItem(self.rubberBand)

    def canvasPressEvent(self, e):
        # which the mouse button?
        if e.button() == Qt.LeftButton:
            # left click

            # if it's the first left click, clear the rubberband
            if not self.isDrawing:
                self.clear()

            # we are drawing now
            self.isDrawing = True

            # convert the clicked position to map coordinates
            point = self.toMapCoordinates(e.pos())
            # add a new point to the rubber band
            self.rubberBand.addPoint(
                point, True)  # True = display updates on the canvas
            # and finally show the rubber band
            self.rubberBand.show()

        elif e.button() == Qt.RightButton:
            # right click, stop drawing
            self.isDrawing = False
            # emit a signal
            self.emit(SIGNAL("editingFinished()"))

    def canvasMoveEvent(self, e):
        # check if it's already drawing
        if not self.isDrawing:
            return

        # convert the mouse position to map coordinates
        point = self.toMapCoordinates(e.pos())
        # move the last point to the new coordinates
        self.rubberBand.movePoint(point)

    def geometry(self):
        return self.rubberBand.asGeometry()
class DrawPolygonMapTool(QgsMapTool):

    polygonSelected = pyqtSignal(object)

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

        self.canvas = canvas
        self.extent = None
        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setFillColor(RB_FILL)
        self.rubberBand.setStrokeColor(RB_STROKE)
        self.rubberBand.setWidth(1)
        self.vertex_count = 1  # two points are dropped initially

    def canvasReleaseEvent(self, event):
        if event.button() == Qt.RightButton:
            if self.rubberBand is None:
                return
            # TODO: validate geom before firing signal
            self.extent.removeDuplicateNodes()
            self.polygonSelected.emit(self.extent)
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
            del self.rubberBand
            self.rubberBand = None
            self.vertex_count = 1  # two points are dropped initially
            return
        elif event.button() == Qt.LeftButton:
            if self.rubberBand is None:
                self.rubberBand = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PolygonGeometry)
                self.rubberBand.setFillColor(RB_FILL)
                self.rubberBand.setStrokeColor(RB_STROKE)
                self.rubberBand.setWidth(1)
            self.rubberBand.addPoint(event.mapPoint())
            self.extent = self.rubberBand.asGeometry()
            self.vertex_count += 1

    def canvasMoveEvent(self, event):
        if self.rubberBand is None:
            pass
        elif not self.rubberBand.numberOfVertices():
            pass
        elif self.rubberBand.numberOfVertices() == self.vertex_count:
            if self.vertex_count == 2:
                mouse_vertex = self.rubberBand.numberOfVertices() - 1
                self.rubberBand.movePoint(mouse_vertex, event.mapPoint())
            else:
                self.rubberBand.addPoint(event.mapPoint())
        else:
            mouse_vertex = self.rubberBand.numberOfVertices() - 1
            self.rubberBand.movePoint(mouse_vertex, event.mapPoint())

    def deactivate(self):
        QgsMapTool.deactivate(self)
        if self.rubberBand is not None:
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        self.deactivated.emit()
Beispiel #4
0
class QgepMapToolAddFeature( QgsMapTool ):
    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas() )
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() )
        self.rubberband.setColor( QColor( "#ee5555" ) )
        self.rubberband.setWidth( 2 )
        self.tempRubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() )
        self.tempRubberband.setColor( QColor( "#ee5555" ) )
        self.tempRubberband.setWidth( 2 )
        self.tempRubberband.setLineStyle(Qt.DotLine)

    def activate(self):
        QgsMapTool.activate( self )
        self.canvas.setCursor( QCursor( Qt.CrossCursor ) )
        pass

    def deactivate(self):
        QgsMapTool.deactivate( self )
        self.canvas.unsetCursor()
        pass

    def isZoomTool( self ):
        return False

    #===========================================================================
    # Events
    #===========================================================================

    def canvasMoveEvent( self, event ):
        self.mouseMoved( event )

    def canvasReleaseEvent( self, event ):
        if event.button() == Qt.RightButton:
            self.rightClicked ( event )
        else:
            self.leftClicked( event )

    def leftClicked(self, event):
        mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() )
        self.rubberband.addPoint( mousePos )
        self.tempRubberband.reset()

    def rightClicked(self, event):
        f = QgsFeature( self.layer.pendingFields() )
        f.setGeometry( self.rubberband.asGeometry() )
        dlg = self.iface.getFeatureForm( self.layer, f )
        dlg.setIsAddDialog(True)
        dlg.exec_()
        self.rubberband.reset()
        self.tempRubberband.reset()

    def mouseMoved(self, event):
        mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() )
        self.tempRubberband.movePoint( mousePos )
class FreehandPolygonMaptool(QgsMapTool, QObject):
    trigger = pyqtSignal(QgsGeometry)
    
    def __init__(self, canvas):
        
        QgsMapTool.__init__(self,canvas)
        self.canvas = canvas
        self.rb = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(QColor(255, 0, 0, 50))
    
    def activate(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        
    def deactivate(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        
    def canvasMoveEvent(self, ev):
        
        worldPoint = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), ev.pos().x(), ev.pos().y())
        self.rb.movePoint(worldPoint)
        
    def canvasPressEvent(self, ev):
        
        if ev.button() == Qt.LeftButton:
            """ Add a new point to the rubber band """
            worldPoint = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), ev.pos().x(), ev.pos().y())
            self.rb.addPoint(worldPoint)
        
        elif ev.button() == Qt.RightButton:
            """ Send back the geometry to the calling class """
            self.trigger.emit(self.rb.asGeometry())

    def isZoomTool(self):
        return False
    
    def isTransient(self):
        return False
      
    def isEditTool(self):
        return False
Beispiel #6
0
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()
Beispiel #7
0
class DsgLineTool(QgsMapTool):

    lineCreated = pyqtSignal(QgsGeometry)

    def __init__(self, canvas):
        """
        Constructor
        """
        super(DsgLineTool, self).__init__(canvas)
        
        self.canvas = canvas
        self.rubberBand = None
        self.reset()

    def deactivate(self):
        """
        Deativates this tool
        """
        self.canvas.scene().removeItem(self.rubberBand)
        super(DsgLineTool, self).deactivate()
        
    def defineRubberBand(self):
        """
        Defines the rubber band style
        """
        settings = QSettings()
        myRed = int(settings.value("/qgis/default_measure_color_red", 222))
        myGreen = int(settings.value("/qgis/default_measure_color_green", 155))
        myBlue = int(settings.value("/qgis/default_measure_color_blue", 67))

        self.rubberBand = QgsRubberBand(self.canvas)
        self.rubberBand.setColor(QColor(myRed, myGreen, myBlue, 100))
        self.rubberBand.setWidth(3)
        
    def reset(self):
        """
        Resets the tool
        """
        if self.rubberBand:
            self.rubberBand.reset(QGis.Line)
        self.isEmittingPoint = False
        self.defineRubberBand()

    def canvasPressEvent(self, e):
        """
        Reimplementation to add a point to the rubber band or reset it
        """
        if self.isEmittingPoint:
            point = self.snapPoint(e.pos())
            self.rubberBand.addPoint(point, True)
        else:
            self.reset()

        self.isEmittingPoint = True
        
    def canvasReleaseEvent(self, e):
        """
        Reimplementation to add a vertex to the rubber band or to finish the rubber band according to the button used
        """
        point = self.snapPoint(e.pos())
        if e.button() == Qt.RightButton:
            geom = self.rubberBand.asGeometry()
            self.reset()
            self.lineCreated.emit(geom)
        elif e.button() == Qt.LeftButton:
            self.isEmittingPoint = True
            
        self.rubberBand.addPoint(point, True)

    def canvasMoveEvent(self, e):
        """
        Reimplementation to move the rubber band
        """
        if not self.isEmittingPoint:
            return
        
        point = self.snapPoint(e.pos())
        self.rubberBand.movePoint(point)
        
    def snapPoint(self, p):
        """
        Reimplementation to make use of the snap
        """
        m = self.canvas.snappingUtils().snapToMap(p)
        if m.isValid():
            return m.point()
        else:
            return self.canvas.getCoordinateTransform().toMapCoordinates(p)  
class QgepMapToolAddFeature(QgsMapToolAdvancedDigitizing):
    """
    Base class for adding features
    """
    def __init__(self, iface, layer):
        QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType())
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(1)
        self.tempRubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType())
        self.tempRubberband.setColor(QColor("#ee5555"))
        self.tempRubberband.setWidth(1)
        self.tempRubberband.setLineStyle(Qt.DotLine)

    def activate(self):
        """
        When activating the map tool
        """
        QgsMapToolAdvancedDigitizing.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))

    def deactivate(self):
        """
        On deactivating the map tool
        """
        QgsMapToolAdvancedDigitizing.deactivate(self)
        self.canvas.unsetCursor()

    # pylint: disable=no-self-use
    def isZoomTool(self):
        """
        This is no zoom tool
        """
        return False

    # ===========================================================================
    # Events
    # ===========================================================================

    def cadCanvasReleaseEvent(self, event):
        """
        Called when a mouse button is
        :param event:
        :return:
        """
        if event.button() == Qt.RightButton:
            self.rightClicked(event)
        else:
            self.leftClicked(event)

    def leftClicked(self, event):
        """
        When the canvas is left clicked we add a new point to the rubberband.
        :type event: QMouseEvent
        """
        mousepos = self.canvas.getCoordinateTransform()\
            .toMapCoordinates(event.pos().x(), event.pos().y())
        self.rubberband.addPoint(mousepos)
        self.tempRubberband.reset()

    def rightClicked(self, _):
        """
        On a right click we create a new feature from the existing rubberband and show the add
        dialog
        """
        f = QgsFeature(self.layer.pendingFields())
        f.setGeometry(self.rubberband.asGeometry())
        dlg = self.iface.getFeatureForm(self.layer, f)
        dlg.setIsAddDialog(True)
        dlg.exec_()
        self.rubberband.reset()
        self.tempRubberband.reset()

    def cadCanvasMoveEvent(self, event):
        """
        When the mouse is moved the rubberband needs to be updated
        :param event: The coordinates etc.
        """

        # When a generated event arrives it's a QMoveEvent... No idea why, but this prevents from an exception
        try:
            QgsMapToolAdvancedDigitizing.cadCanvasMoveEvent(self, event)
            mousepos = event.mapPoint()
            self.tempRubberband.movePoint(mousepos)
        except TypeError:
            pass
Beispiel #9
0
class DsgLineTool(QgsMapTool):

    lineCreated = pyqtSignal(QgsGeometry)

    def __init__(self, canvas):
        super(DsgLineTool, self).__init__(canvas)
        
        self.canvas = canvas
        self.rubberBand = None
        self.reset()

    def deactivate(self):
        self.canvas.scene().removeItem(self.rubberBand)
        super(DsgLineTool, self).deactivate()
        
    def defineRubberBand(self):
        settings = QSettings()
        myRed = int(settings.value("/qgis/default_measure_color_red", 222))
        myGreen = int(settings.value("/qgis/default_measure_color_green", 155))
        myBlue = int(settings.value("/qgis/default_measure_color_blue", 67))

        self.rubberBand = QgsRubberBand(self.canvas)
        self.rubberBand.setColor(QColor(myRed, myGreen, myBlue, 100))
        self.rubberBand.setWidth(3)
        
    def reset(self):
        if self.rubberBand:
            self.rubberBand.reset(QGis.Line)
        self.isEmittingPoint = False
        self.defineRubberBand()

    def canvasPressEvent(self, e):
        if self.isEmittingPoint:
            point = self.snapPoint(e.pos())
            self.rubberBand.addPoint(point, True)
        else:
            self.reset()

        self.isEmittingPoint = True
        
    def canvasReleaseEvent(self, e):
        point = self.snapPoint(e.pos())
        if e.button() == Qt.RightButton:
            geom = self.rubberBand.asGeometry()
            self.reset()
            self.lineCreated.emit(geom)
        elif e.button() == Qt.LeftButton:
            self.isEmittingPoint = True
            
        self.rubberBand.addPoint(point, True)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        
        point = self.snapPoint(e.pos())
        self.rubberBand.movePoint(point)
        
    def snapPoint(self, p):
        m = self.canvas.snappingUtils().snapToMap(p)
        if m.isValid():
            return m.point()
        else:
            return self.canvas.getCoordinateTransform().toMapCoordinates(p)  
class QgepMapToolDigitizeDrainageChannel(QgsMapTool):
    '''
    This is used to digitize a drainage channel.

    It lets you digitize two points and then creates a polygon based on these two points
    by adding an orthogonal offset at each side.

    Input:

       x==============x

    Output:

       ----------------
       |              |
       ----------------

    Usage:
      Connect to the signals deactivated() and geometryDigitized()
      If geometryDigitized() is called you can use the member variable geometry
      which will contain a rectangle polygon
      deactivated() will be emited after a right click
    '''

    geometryDigitized = pyqtSignal()

    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand(iface.mapCanvas(), QGis.Line)
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(2)
        self.firstPoint = None
        self.messageBarItem = None
        self.geometry = None

    def activate(self):
        """
        Map tool is activated
        """
        QgsMapTool.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))
        msgtitle = self.tr('Digitizing Drainage Channel')
        msg = self.tr('Digitize start and end point. Rightclick to abort.')
        self.messageBarItem = QgsMessageBar.createMessage(msgtitle,
                                                          msg)
        self.iface.messageBar().pushItem(self.messageBarItem)

    def deactivate(self):
        """
        Map tool is deactivated
        """
        QgsMapTool.deactivate(self)
        self.iface.messageBar().popWidget(self.messageBarItem)
        try:
            self.iface.mapCanvas().scene().removeItem(self.rubberband)
            del self.rubberband
        except AttributeError:
            # Called repeatedly... bail out
            pass
        self.canvas.unsetCursor()

    def canvasMoveEvent(self, event):
        """
        Mouse is moved: Update rubberband
        :param event: coordinates etc.
        """
        mousepos = self.canvas.getCoordinateTransform()\
            .toMapCoordinates(event.pos().x(), event.pos().y())
        self.rubberband.movePoint(mousepos)

    def canvasReleaseEvent(self, event):
        """
        Canvas is released. This means:
          * start digitizing
          * stop digitizing (create a rectangle
            * if the Ctrl-modifier is pressed, ask for the rectangle width
        :param event: coordinates etc.
        """
        if event.button() == Qt.RightButton:
            self.deactivate()
        else:
            mousepos = self.canvas.getCoordinateTransform()\
                .toMapCoordinates(event.pos().x(), event.pos().y())
            self.rubberband.addPoint(mousepos)
            if self.firstPoint:  # If the first point was set before, we are doing the second one
                lp1 = self.rubberband.asGeometry().asPolyline()[0]
                lp2 = self.rubberband.asGeometry().asPolyline()[1]
                width = 0.2
                if QApplication.keyboardModifiers() & Qt.ControlModifier:
                    dlg = QDialog()
                    dlg.setLayout(QGridLayout())
                    dlg.layout().addWidget(QLabel(self.tr('Enter width')))
                    txt = QLineEdit('0.2')
                    dlg.layout().addWidget(txt)
                    bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
                    dlg.layout().addWidget(bb)
                    bb.accepted.connect(dlg.accept)
                    bb.rejected.connect(dlg.reject)
                    if dlg.exec_():
                        try:
                            width = float(txt.text())
                        except ValueError:
                            width = 0.2

                length = math.sqrt(math.pow(lp1.x() - lp2.x(), 2) + math.pow(lp1.y() - lp2.y(), 2))
                xd = lp2.x() - lp1.x()
                yd = lp2.y() - lp1.y()

                pt1 = QgsPoint(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length))
                pt2 = QgsPoint(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length))
                pt3 = QgsPoint(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length))
                pt4 = QgsPoint(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length))

                self.geometry = QgsGeometry.fromPolygon([[pt1, pt2, pt3, pt4, pt1]])

                self.geometryDigitized.emit()

            self.firstPoint = mousepos
Beispiel #11
0
class ProfileTool(QgsMapTool):
    """ Narzędzie do tworzenia krzywej """

    def __init__(self, parent):
        canvas = iface.mapCanvas()
        super(ProfileTool, self).__init__(canvas)
        
        set_cursor(self)
        self.editing = False
        self.parent = parent
        self.task = None

        self.tempGeom = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempGeom.setColor(QColor('red'))
        self.tempGeom.setWidth(2)

        self.tempLine = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempLine.setColor(QColor('red'))
        self.tempLine.setWidth(2)
        self.tempLine.setLineStyle(Qt.DotLine)

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Delete:
            pointsCount = self.tempLine.numberOfVertices() 
            if pointsCount > 2 and self.editing:
                self.tempGeom.removePoint(pointsCount-2)
                self.tempLine.removePoint(pointsCount-2)
                len_m = self.calculateDistance(self.tempGeom.asGeometry())
                self.parent.dsbLineLength.setValue(len_m)
                if self.tempGeom.numberOfVertices() == 1:
                    self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                    self.tempLine.reset(QgsWkbTypes.LineGeometry)
                    self.parent.dsbLineLength.setValue(0)           
            else:
                self.reset()
        elif e.key() == Qt.Key_Escape:
            self.reset()

    def canvasMoveEvent(self, e):
        #Poruszanie" wierzchołkiem linii tymczasowej zgodnie z ruchem myszki
        if self.tempGeom.numberOfVertices()>1:
            point = e.snapPoint()
            self.tempLine.movePoint(point)

    def canvasReleaseEvent(self, e):
        point = e.snapPoint()
        if self.task:
            self.parent.on_message.emit('Trwa genrowanie profilu. Aby wygenerować następny poczekaj na pobranie danych', Qgis.Warning, 4)
            return
        if e.button() == int(Qt.LeftButton):
            #Dodawanie kolejnych wierzchołków
            if not self.editing:
                #Nowy obiekt, pierwszy wierzchołek
                self.tempLine.reset(QgsWkbTypes.LineGeometry)
                self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                self.editing = True
            self.tempGeom.addPoint(point)
            self.tempLine.addPoint(point)
            len_m = self.calculateDistance(self.tempGeom.asGeometry())
            self.parent.dsbLineLength.setValue(len_m)
        elif e.button() == int(Qt.RightButton):
            if self.tempGeom.numberOfVertices() < 2:
                return
            #Zakończenie rysowania obiektu
            self.tempLine.reset()
            self.editing = False
            geometry = self.tempGeom.asGeometry()
            errors = geometry.validateGeometry()
            if errors:
            #Niepoprawna geometria                    
                for error in errors:
                    if self.tempGeom.numberOfVertices() > 2:
                        self.parent.on_message.emit('Niepoprawna geometria', Qgis.Critical, 4)
                    self.tempGeom.reset()
                return
            self.get_interval()

    def get_interval(self):
        interval, ok = QInputDialog.getDouble(self.parent, 'Podaj interwał', 'Interwał [m]:')
        if not ok:
            self.reset()
            return
        geom = self.tempGeom.asGeometry()
        
        activeCrs = QgsProject.instance().crs().authid()
        fromCrs = QgsCoordinateReferenceSystem(activeCrs)
        toCrs = QgsCoordinateReferenceSystem(2180)
        transformation = QgsCoordinateTransform(fromCrs, toCrs, QgsProject.instance())
        geom.transform(transformation)
        
        meters_len = geom.length()
        if meters_len <= interval:
            self.parent.on_message.emit('Długość linii krótsza lub równa podanemu interwałowi', Qgis.Critical, 5)
            self.reset()
            return
        try:
            num_points = meters_len/interval
        except ZeroDivisionError:
            self.parent.on_message.emit('Interwał musi być większy od 0', Qgis.Critical, 4)
            self.reset()
            return
        points_on_line = []
        max_interval = 0
        intervals = []
        for i in range(int(num_points)+1):
            pt = geom.interpolate(float(max_interval))
            points_on_line.append(pt)
            intervals.append(max_interval)
            max_interval += interval
        data = {'points':points_on_line, 'intervals':intervals}
        self.task = QgsTask.fromFunction('Pobieranie wysokości dla przekroju...', self.generateProfileFromPoints, data=data)
        QgsApplication.taskManager().addTask(self.task)

    def generateProfileFromPoints(self, task: QgsTask, data):
        points_on_line = data.get('points')
        intervals = data.get('intervals')
        heights = []
        total = 100/len(points_on_line)
        for idx, pt in enumerate(points_on_line):
            height = self.parent.getHeight(pt, special=True)
            heights.append(height)
        try:
            self.task.setProgress( idx*total )
        except AttributeError as e:
            pass
        if heights and intervals:   
            self.fillTable(heights, intervals)
        self.parent.on_message.emit('Pomyślnie wygenerowano profil', Qgis.Success, 4)
        self.task = None

    def fillTable(self, heights, intervals):
        for idx, interval in enumerate(intervals):
            self.parent.twData.setRowCount(idx+1)
            self.parent.twData.setItem(idx, 0, QTableWidgetItem(f'{interval}'))
            self.parent.twData.setItem(idx, 1, QTableWidgetItem(heights[idx]))

    def calculateDistance(self, geometry):
        distanceArea = QgsDistanceArea()
        distanceArea.setEllipsoid('GRS80')
        distanceArea.setSourceCrs(QgsProject.instance().crs(), QgsCoordinateTransformContext())
        length = distanceArea.measureLength(geometry)
        result = distanceArea.convertLengthMeasurement(length, QgsUnitTypes.DistanceMeters)
        return result
        
    def reset(self):
        self.tempLine.reset(QgsWkbTypes.LineGeometry)
        self.tempGeom.reset(QgsWkbTypes.LineGeometry)
        self.parent.dsbLineLength.setValue(0)
        self.parent.twData.setRowCount(0)

    def deactivate(self):
        self.reset()
        self.parent.dsbLineLength.setEnabled(False) 
        self.button().setChecked(False)
Beispiel #12
0
class QGISRedMoveNodesTool(QgsMapTool):
    ownMainLayers = [
        "Pipes", "Valves", "Pumps", "Junctions", "Tanks", "Reservoirs",
        "Demands", "Sources"
    ]
    myNodeLayers = ["Junctions", "Tanks", "Reservoirs", "Demands", "Sources"]

    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.mousePoint = None

        self.mouseClicked = False
        self.clickedPoint = None
        self.objectSnapped = None
        self.selectedNodeFeature = None
        self.selectedNodeLayer = None
        self.adjacentFeatures = 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(1)  # Vertex
        config.setMode(2)  # All layers
        config.setTolerance(1)
        config.setUnits(2)  # Pixels
        config.setEnabled(True)
        self.snapper.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 findAdjacentElements(self, nodeGeometry):
        adjacentElements = {}
        layers = self.getLayers()
        for layer in layers:
            openedLayerPath = self.getLayerPath(layer)
            for name in self.ownMainLayers:
                layePath = self.generatePath(
                    self.ProjectDirectory,
                    self.NetworkName + "_" + name + ".shp")
                if openedLayerPath == layePath:
                    adjacentFeatures = []
                    for feature in layer.getFeatures():
                        featureGeometry = feature.geometry()
                        if layer.geometryType() == 0:  # Point
                            if self.areOverlapedPoints(nodeGeometry,
                                                       featureGeometry):
                                adjacentFeatures.append(feature)
                        elif layer.geometryType() == 1:
                            if featureGeometry.isMultipart():
                                for part in featureGeometry.get(
                                ):  # only one part
                                    first_vertex = part[0]
                                    last_vertex = part[-1]
                            else:
                                first_vertex = featureGeometry.get()[0]
                                last_vertex = featureGeometry.get()[-1]

                            firsVertex = QgsGeometry.fromPointXY(
                                QgsPointXY(first_vertex.x(), first_vertex.y()))
                            lastVertex = QgsGeometry.fromPointXY(
                                QgsPointXY(last_vertex.x(), last_vertex.y()))
                            if self.areOverlapedPoints(nodeGeometry, firsVertex) or\
                                    self.areOverlapedPoints(nodeGeometry, lastVertex):
                                adjacentFeatures.append(feature)
                    if len(adjacentFeatures) > 0:
                        adjacentElements[layer] = adjacentFeatures

        return adjacentElements

    def areOverlapedPoints(self, point1, point2):
        tolerance = 0.1
        if point1.distance(point2) < tolerance:
            return True
        else:
            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 moveNodePoint(self, layer, nodeFeature, newPosition):
        if layer.isEditable():
            layer.beginEditCommand('Move node')
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.moveVertex(newPosition.x(), newPosition.y(),
                                      nodeFeature.id(), 0)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

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

    """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.mouseClicked = True
            self.clickedPoint = self.objectSnapped.point()

            self.selectedNodeFeature = None
            self.adjacentFeatures = None

            foundNode = False
            layers = self.getLayers()
            for layer in layers:
                openedLayerPath = self.getLayerPath(layer)
                for name in self.myNodeLayers:
                    layerPath = self.generatePath(
                        self.ProjectDirectory,
                        self.NetworkName + "_" + name + ".shp")
                    if openedLayerPath == layerPath:
                        locatedPoint = self.snapper.locatorForLayer(layer)
                        match = locatedPoint.nearestVertex(
                            self.objectSnapped.point(), 1)
                        if match.isValid():
                            featureId = match.featureId()
                            request = QgsFeatureRequest().setFilterFid(
                                featureId)
                            node = list(layer.getFeatures(request))
                            self.selectedNodeLayer = layer
                            foundNode = True

            if not foundNode:
                return

            self.selectedNodeFeature = QgsFeature(node[0])
            self.adjacentFeatures = self.findAdjacentElements(
                self.selectedNodeFeature.geometry())
            self.createRubberBand(
                [self.objectSnapped.point(),
                 self.objectSnapped.point()])

    def canvasMoveEvent(self, event):
        self.mousePoint = self.toMapCoordinates(event.pos())
        # Mouse not clicked
        if not self.mouseClicked:
            match = self.snapper.snapToMap(self.mousePoint)
            if match.isValid():
                self.objectSnapped = match
                vertex = match.point()
                self.vertexMarker.setCenter(QgsPointXY(vertex.x(), vertex.y()))
                self.vertexMarker.show()
            else:
                self.objectSnapped = None
                self.selectedNodeFeature = None
                self.vertexMarker.hide()
        # Mouse clicked
        else:
            # Update rubber band
            if self.objectSnapped is not None and self.rubberBand is not None:
                snappedPoint = self.objectSnapped.point()
                self.newPositionVector = QgsVector(
                    self.mousePoint.x() - snappedPoint.x(),
                    self.mousePoint.y() - snappedPoint.y())
                self.updateRubberBand()

    def canvasReleaseEvent(self, event):
        mousePoint = self.toMapCoordinates(event.pos())
        if not self.mouseClicked:
            return

        if event.button() == 1:
            self.mouseClicked = False

            if self.objectSnapped is not None:
                if self.selectedNodeFeature is not None:
                    for adjLayer in self.adjacentFeatures:
                        for feature in self.adjacentFeatures[adjLayer]:
                            if adjLayer.geometryType() == 0:  # Point
                                self.moveNodePoint(adjLayer, feature,
                                                   mousePoint)
                            else:
                                nodeGeometry = self.selectedNodeFeature.geometry(
                                )
                                featureGeometry = feature.geometry()

                                if featureGeometry.isMultipart():
                                    for part in featureGeometry.get(
                                    ):  # only one part
                                        firstVertex = part[0]
                                        vertices = len(part)
                                else:
                                    firstVertex = featureGeometry.get()[0]
                                    vertices = 2
                                firstPoint = QgsGeometry.fromPointXY(
                                    QgsPointXY(firstVertex.x(),
                                               firstVertex.y()))
                                if self.areOverlapedPoints(
                                        nodeGeometry, firstPoint):
                                    index = 0
                                else:
                                    index = vertices - 1
                                self.moveVertexLink(adjLayer, feature,
                                                    mousePoint, index)
                self.objectSnapped = None
                self.selectedNodeFeature = None
                self.iface.mapCanvas().refresh()

            # Remove vertex marker and rubber band
            self.vertexMarker.hide()
            self.iface.mapCanvas().scene().removeItem(self.rubberBand)
            self.newVertexMarker.hide()
Beispiel #13
0
class SignatureTool(QgsMapTool):
    """
        On Double click it will callback with an array with a single pixel.
        On Single click without releasing it will draw a square and callback
        the starting and ending point in an array.
        On Single click with releasing it will start drawing a polygon and
        every subsequent single click will add a new vertex in the polygon.
        On Right click it will callback with an array with all the vertex in
        the polygon.
        On Escape it will clean up the array and start over.
    """
    def __init__(self, canvas, layer, callback):
        QgsMapTool.__init__(self, canvas)
        self._canvas = canvas
        self._layer = layer
        self._callback = callback
        self._pixels = []
        self._start_point = None
        self._mode = Mode.NONE
        self._rubber_band = QgsRubberBand(self._canvas)
        self._rubber_band.setColor(Qt.red)
        self._rubber_band.setWidth(1)
        self.parent().setCursor(Qt.CrossCursor)

    def getPoint(self, pos):
        x = pos.x()
        y = pos.y()
        return self._canvas.getCoordinateTransform().toMapCoordinates(x, y)

    def getRowCol(self, point):
        # clicked position on screen to map coordinates
        data_provider = self._layer.dataProvider()
        extent = data_provider.extent()
        width = data_provider.xSize() if data_provider.capabilities() \
            & data_provider.Size else 1000
        height = data_provider.ySize() if data_provider.capabilities() \
            & data_provider.Size else 1000
        xres = extent.width() / width
        yres = extent.height() / height
        if extent.xMinimum() <= point.x() <= extent.xMaximum() and \
            extent.yMinimum() <= point.y() <= extent.yMaximum():
            col = int(floor((point.x() - extent.xMinimum()) / xres))
            row = int(floor((extent.yMaximum() - point.y()) / yres))
            return (row, col)
        else:
            return None

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self._pixels = []
            self.finish()

    def canvasMoveEvent(self, event):
        point = self.getPoint(event.pos())
        if self._mode is Mode.SQUARE:
            if not point.compare(self._start_point):
                self._rubber_band.reset()
                self._rubber_band.addPoint(self._start_point, False)
                self._rubber_band.addPoint(
                    QgsPointXY(self._start_point.x(), point.y()), False)
                self._rubber_band.addPoint(point, False)
                self._rubber_band.addPoint(
                    QgsPointXY(point.x(), self._start_point.y()), False)
                self._rubber_band.closePoints()
        elif self._mode is Mode.POLYGON:
            self._rubber_band.movePoint(
                self._rubber_band.numberOfVertices() - 1, point)

    def canvasReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            point = self.getPoint(event.pos())
            if self._mode is Mode.SQUARE:
                if self._start_point.compare(point):
                    self._mode = Mode.POLYGON
                    self._rubber_band.addPoint(point)
                    self._start_point = None
                else:
                    self._pixels = []
                    # The last vertex is repeated
                    for i in range(self._rubber_band.numberOfVertices() - 1):
                        self._pixels.append(
                            self.getRowCol(self._rubber_band.getPoint(0, i)))
                    self.finish()
            elif self._mode is Mode.POLYGON:
                self._rubber_band.addPoint(point)

    def canvasPressEvent(self, event):
        if event.button() == Qt.LeftButton:
            point = self.getPoint(event.pos())
            pixel = self.getRowCol(point)
            if self._mode is Mode.NONE:
                self._mode = Mode.SQUARE
                self._start_point = QgsPointXY(point.x(), point.y())
            elif self._mode is Mode.POLYGON:
                self._rubber_band.removePoint(
                    self._rubber_band.numberOfVertices() - 1)
            else:
                self._mode = Mode.POLYGON
            if pixel:
                self._rubber_band.addPoint(point)
                self._pixels.append(pixel)
        elif event.button() == Qt.RightButton:
            self.finish()

    def finish(self):
        self._canvas.unsetMapTool(self)
        self._rubber_band.reset()
        self._mode = Mode.NONE
        self._start_point = None
        if len(self._pixels) > 0:
            self._callback(self._layer.hiperqube_id(), self._pixels)
Beispiel #14
0
class RubberBand():
    def __init__(self, iface):
        self.iface = iface

    def initGui(self):

        # cria uma ação que iniciará a configuração do plugin
        #self.myMapTool = QgsMapToolEmitPoint( self.iface.mapCanvas() )
        self.initVariables()
        self.initSignals()

    def initVariables(self):
        self.coordinates = []

        # Criação da action e da toolbar
        self.toolbar = self.iface.addToolBar("My_ToolBar")
        pai = self.iface.mainWindow()
        icon_path = ':/plugins/RubberBand/icon.png'
        self.action = QAction(QIcon(icon_path), u"Cria RubberBand de Polygon.",
                              pai)
        self.action.setObjectName("Cria RubberBand de Polygon.")
        self.action.setStatusTip(None)
        self.action.setWhatsThis(None)
        self.action.setCheckable(True)
        self.toolbar.addAction(self.action)

        self.previousMapTool = self.iface.mapCanvas().mapTool()
        self.myMapTool = QgsMapToolEmitPoint(self.iface.mapCanvas())
        self.isEditing = 0

        # self.vlyr = QgsVectorLayer("Polygon?crs=EPSG:31982", "temporary_polygons", "memory")
        # self.dprov = self.vlyr.dataProvider()

        # # Add field to virtual layer
        # self.dprov.addAttributes([QgsField("name", QVariant.String),
        #                     QgsField("size", QVariant.Double)])

        # self.vlyr.updateFields()
        # Access ID
        # self.fields = self.dprov.fields()

    def initSignals(self):
        self.action.toggled.connect(self.initRubberBand)
        self.myMapTool.canvasClicked.connect(self.mouseClick)

    def initRubberBand(self, b):
        if b:
            self.myRubberBand = QgsRubberBand(self.iface.mapCanvas(),
                                              QGis.Polygon)
            color = QColor(78, 97, 114)
            color.setAlpha(190)
            self.myRubberBand.setColor(color)
            self.myRubberBand.setFillColor(QColor(255, 0, 0, 40))
            self.myRubberBand.setBorderColor(QColor(255, 0, 0, 200))

            # Set MapTool
            self.iface.mapCanvas().setMapTool(self.myMapTool)
            self.iface.mapCanvas().xyCoordinates.connect(self.mouseMove)
        else:
            self.disconnect()

    def disconnect(self):

        self.iface.mapCanvas().unsetMapTool(self.myMapTool)
        try:
            self.iface.mapCanvas().xyCoordinates.disconnect(self.mouseMove)
        except:
            pass

        try:
            self.myRubberBand.reset()
        except:
            pass

    def unChecked(self):
        pass

    def unload(self):
        self.disconnect()

    def mouseClick(self, currentPos, clickedButton):
        if clickedButton == Qt.LeftButton:  # and myRubberBand.numberOfVertices() == 0:
            self.myRubberBand.addPoint(QgsPoint(currentPos))
            self.coordinates.append(QgsPoint(currentPos))
            self.isEditing = 1

        elif clickedButton == Qt.RightButton and self.myRubberBand.numberOfVertices(
        ) > 2:
            self.isEditing = 0

            # open input dialog
            (description, False) = QInputDialog.getText(
                self.iface.mainWindow(), "Description",
                "Description for Polygon at x and y", QLineEdit.Normal,
                'My Polygon')

            #create feature and set geometry
            poly = QgsFeature()
            geomP = self.myRubberBand.asGeometry()
            poly.setGeometry(geomP)
            print geomP.exportToWkt()

            #set attributes
            # indexN = self.dprov.fieldNameIndex('name')
            # indexA = self.dprov.fieldNameIndex('size')
            # poly.setAttributes([QgsDistanceArea().measurePolygon(self.coordinates), indexA])
            # poly.setAttributes([description, indexN])

            # add feature
            # self.dprov.addFeatures([poly])
            # self.vlyr.updateExtents()

            #add layer
            # self.vlyr.triggerRepaint()
            # QgsMapLayerRegistry.instance().addMapLayers([self.vlyr])
            # self.myRubberBand.reset(QGis.Polygon)

    def mouseMove(self, currentPos):
        if self.isEditing == 1:
            self.myRubberBand.movePoint(QgsPoint(currentPos))
Beispiel #15
0
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
Beispiel #16
0
class ProfileTool(QgsMapTool):
    """ Narzędzie do tworzenia krzywej """
    def __init__(self, parent):
        canvas = iface.mapCanvas()
        super(ProfileTool, self).__init__(canvas)

        set_cursor(self)
        self.editing = False
        self.parent = parent
        self.task = None
        #Konfiguracja geometrii tymczasowych
        self.tempGeom = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempGeom.setColor(QColor('red'))
        self.tempGeom.setWidth(2)
        self.tempLine = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempLine.setColor(QColor('red'))
        self.tempLine.setWidth(2)
        self.tempLine.setLineStyle(Qt.DotLine)

    def keyPressEvent(self, e):
        """ 
        Usuwanie ostatniego dodanego punktu/segmentu lub
        czyszczenie całości
        """
        if e.key() == Qt.Key_Delete:
            pointsCount = self.tempLine.numberOfVertices()
            if pointsCount > 2 and self.editing:
                self.tempGeom.removePoint(pointsCount - 2)
                self.tempLine.removePoint(pointsCount - 2)
                len_m = self.calculateDistance(self.tempGeom.asGeometry())
                self.parent.dsbLineLength.setValue(len_m)
                if self.tempGeom.numberOfVertices() == 1:
                    self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                    self.tempLine.reset(QgsWkbTypes.LineGeometry)
                    self.parent.dsbLineLength.setValue(0)
            else:
                self.reset()
        elif e.key() == Qt.Key_Escape:
            self.reset()

    def canvasMoveEvent(self, e):
        """ 'Poruszanie' wierzchołkiem linii tymczasowej zgodnie z ruchem myszki """
        if self.tempGeom.numberOfVertices() > 1:
            point = e.snapPoint()
            self.tempLine.movePoint(point)

    def canvasReleaseEvent(self, e):
        """ Rysowanie obiektu """
        point = e.snapPoint()
        if self.task is not None:
            self.parent.on_message.emit(
                'Trwa genrowanie profilu. Aby wygenerować następny poczekaj na pobranie danych',
                Qgis.Warning, 4)
            return
        if e.button() == int(Qt.LeftButton):
            #Dodawanie kolejnych wierzchołków
            if not self.editing:
                #Nowy obiekt, pierwszy wierzchołek
                self.tempLine.reset(QgsWkbTypes.LineGeometry)
                self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                self.editing = True
            self.tempGeom.addPoint(point)
            self.tempLine.addPoint(point)
            len_m = self.calculateDistance(self.tempGeom.asGeometry())
            self.parent.dsbLineLength.setValue(len_m)
        elif e.button() == int(Qt.RightButton):
            if self.tempGeom.numberOfVertices() < 2:
                return
            #Zakończenie rysowania obiektu
            self.tempLine.reset()
            self.editing = False
            geometry = self.tempGeom.asGeometry()
            errors = geometry.validateGeometry()
            if errors:
                #Niepoprawna geometria
                for error in errors:
                    if self.tempGeom.numberOfVertices() > 2:
                        self.parent.on_message.emit('Niepoprawna geometria',
                                                    Qgis.Critical, 4)
                    self.tempGeom.reset()
                return
            self.getInterval()

    def getInterval(self):
        """ Zebranie geometrii punktów na linii zgodnie z zadanym interwałem """
        interval, ok = QInputDialog.getDouble(self.parent, 'Podaj interwał',
                                              'Interwał [m]:')
        if not ok:
            self.reset()
            return
        geom = self.parent.transformGeometry(
            self.tempGeom.asGeometry(),
            current_crs=QgsProject.instance().crs().authid(),
        )
        meters_len = geom.length()
        if meters_len <= interval:
            self.parent.on_message.emit(
                'Długość linii krótsza lub równa podanemu interwałowi',
                Qgis.Critical, 5)
            self.reset()
            return
        try:
            num_points = meters_len / interval
        except ZeroDivisionError:
            self.parent.on_message.emit('Interwał musi być większy od 0',
                                        Qgis.Critical, 4)
            self.reset()
            return
        points_on_line = []
        max_interval = 0
        intervals = []
        for i in range(int(num_points) + 1):
            pt = geom.interpolate(float(max_interval)).asPoint()
            points_on_line.append(f'{pt.y()}%20{pt.x()}')
            intervals.append(max_interval)
            max_interval += interval
        data = {'points': points_on_line, 'intervals': intervals}
        self.task = QgsTask.fromFunction(
            'Pobieranie wysokości dla przekroju...',
            self.generateProfileFromPoints,
            data=data)
        QgsApplication.taskManager().addTask(self.task)

    def generateProfileFromPoints(self, task: QgsTask, data):
        """ Pobranie wysokości dla punktów na linii """
        points_on_line = data.get('points')
        intervals = data.get('intervals')
        response = self.parent.getPointsHeights(points_on_line).split(',')
        heights = []
        for r in response:
            _, height = r.rsplit(' ', 1)
            heights.append(height)
        if heights and intervals:
            self.fillTable(heights, intervals)
        self.parent.on_message.emit('Pomyślnie wygenerowano profil',
                                    Qgis.Success, 4)
        self.task = None

    def fillTable(self, heights, intervals):
        """ Wypełnienie tabelii interwałami i wysokościami dla nich """
        for idx, interval in enumerate(intervals):
            try:
                self.parent.twData.setRowCount(idx + 1)
                self.parent.twData.setItem(idx, 0,
                                           QTableWidgetItem(f'{interval}'))
                self.parent.twData.setItem(idx, 1,
                                           QTableWidgetItem(heights[idx]))
            except:
                return

    def calculateDistance(self, geometry):
        """ Obliczenie długości linii w odpowiedniej jednostce """
        distance_area = QgsDistanceArea()
        distance_area.setEllipsoid('GRS80')
        distance_area.setSourceCrs(QgsProject.instance().crs(),
                                   QgsCoordinateTransformContext())
        length = distance_area.measureLength(geometry)
        result = distance_area.convertLengthMeasurement(
            length, QgsUnitTypes.DistanceMeters)
        return result

    def reset(self):
        """ Czyszczenie narzędzia """
        self.tempLine.reset(QgsWkbTypes.LineGeometry)
        self.tempGeom.reset(QgsWkbTypes.LineGeometry)
        self.parent.dsbLineLength.setValue(0)
        self.parent.twData.setRowCount(0)

    def deactivate(self):
        """ Reagowanie zmiany aktywności narzędzia """
        self.reset()
        self.parent.dsbLineLength.setEnabled(False)
        self.button().setChecked(False)
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
Beispiel #18
0
class MeasureAngleTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))
        self.rubber_band_curve = QgsRubberBand(self.canvas)
        self.rubber_band_curve.setWidth(2)
        self.rubber_band_curve.setColor(QColor(255, 153, 0, 100))

        crs = self.canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(
            crs,
            QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        self.msglog.logMessage("")
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
        self.rubber_band_curve.reset()

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())
        if self.start_point and self.middle_point:
            angle_start_to_middle = self.distance_calc.bearing(
                self.middle_point, self.start_point)
            angle_end_to_middle = self.distance_calc.bearing(
                self.middle_point, point)
            angle = degrees(angle_end_to_middle - angle_start_to_middle)
            if angle < -180:
                angle = 360 + angle
            elif angle > 180:
                angle = angle - 360

            anglemsg = QMessageBox(self.parent())
            anglemsg.finished.connect(self.deactivate)
            anglemsg.setWindowTitle("Measure angle tool")
            anglemsg.setText("Angle: {:.3F} º".format(abs(angle)))
            anglemsg.exec()
            self.finish()

        elif self.start_point:
            self.middle_point = point
            self.rubber_band.addPoint(self.middle_point)
            self.rubber_band_points.addPoint(self.middle_point)

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)

        if self.start_point and self.middle_point and not self.end_point:
            angle_start_to_middle = self.distance_calc.bearing(
                self.middle_point, self.start_point)
            angle_end_to_middle = self.distance_calc.bearing(
                self.middle_point, point)
            angle = degrees(angle_end_to_middle - angle_start_to_middle)

            if angle < -180:
                angle = 360 + angle
            elif angle > 180:
                angle = angle - 360

            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current angle: {:.3F} º".format(abs(angle)), "Measure angle:",
                0)

            self.rubber_band_curve.reset()

            # get the distance from center to point
            dist_mid_to_p = sqrt((point.x() - self.middle_point.x()) *
                                 (point.x() - self.middle_point.x()) +
                                 (point.y() - self.middle_point.y()) *
                                 (point.y() - self.middle_point.y()))
            dist_mid_to_start = sqrt(
                (self.start_point.x() - self.middle_point.x()) *
                (self.start_point.x() - self.middle_point.x()) +
                (self.start_point.y() - self.middle_point.y()) *
                (self.start_point.y() - self.middle_point.y()))

            # get angle
            angle_start = atan2(self.start_point.y() - self.middle_point.y(),
                                self.start_point.x() - self.middle_point.x())
            angle_p = atan2(point.y() - self.middle_point.y(),
                            point.x() - self.middle_point.x())

            # smaller distance
            if dist_mid_to_p < dist_mid_to_start:
                dist = dist_mid_to_p
            else:
                dist = dist_mid_to_start

            y_p = dist * sin(angle_p)
            x_p = dist * cos(angle_p)
            y_start = dist * sin(angle_start)
            x_start = dist * cos(angle_start)

            circular_ring = QgsCircularString()
            circular_ring = circular_ring.fromTwoPointsAndCenter(
                QgsPoint(self.middle_point.x() + x_start / 2,
                         self.middle_point.y() + y_start / 2),
                QgsPoint(self.middle_point.x() + x_p / 2,
                         self.middle_point.y() + y_p / 2),
                QgsPoint(self.middle_point.x(), self.middle_point.y()), True)

            circular_geometry = QgsGeometry(circular_ring)

            self.rubber_band_curve.addGeometry(
                circular_geometry,
                QgsCoordinateReferenceSystem(
                    4326, QgsCoordinateReferenceSystem.EpsgCrsId))

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Beispiel #19
0
class VideoWidget(QVideoWidget):

    def __init__(self, parent=None):
        ''' Constructor '''
        super().__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.setAttribute(Qt.WA_OpaquePaintEvent)

        self.Tracking_Video_RubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        color_blue = QColor(Qt.blue)
        color_black = QColor(Qt.black)
        color_amber = QColor(252, 215, 108)

        pal_blue = QPalette()
        pal_blue.setBrush(QPalette.Highlight, QBrush(color_blue))
        self.Tracking_Video_RubberBand.setPalette(pal_blue)

        pal_black = QPalette()
        pal_black.setBrush(QPalette.Highlight, QBrush(color_black))
        self.Censure_RubberBand.setPalette(pal_black)

        self._interaction = InteractionState()
        self._filterSatate = FilterState()

        self._isinit = False
        self._MGRS = False
        self.gt = None

        self.drawCesure = []
        self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawMeasureDistance, self.drawMeasureArea, self.drawPolygon = [], [], [], [], [], []
        # Draw Polygon Canvas Rubberband
        self.poly_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), True)  # Polygon type
        # set rubber band style
        self.poly_Canvas_RubberBand.setColor(color_amber)
        self.poly_Canvas_RubberBand.setWidth(3)

        # Tracking Canvas Rubberband
        self.Track_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), QgsWkbTypes.LineGeometry)
        # set rubber band style
        self.Track_Canvas_RubberBand.setColor(color_blue)
        self.Track_Canvas_RubberBand.setWidth(5)

        # Cursor Canvas Rubberband
        self.Cursor_Canvas_RubberBand = QgsRubberBand(
            iface.mapCanvas(), QgsWkbTypes.PointGeometry)
        self.Cursor_Canvas_RubberBand.setWidth(4)
        self.Cursor_Canvas_RubberBand.setColor(QColor(255, 100, 100, 250))
        self.Cursor_Canvas_RubberBand.setIcon(QgsRubberBand.ICON_FULL_DIAMOND)

        self.parent = parent.parent()

        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.transparent)
        self.setPalette(palette)

        self.origin, self.dragPos = QPoint(), QPoint()
        self.tapTimer = QBasicTimer()
        self.brush = QBrush(color_black)
        self.blue_Pen = QPen(color_blue, 3)

    def removeLastLine(self):
        ''' Remove Last Line Objects '''
        if self.drawLines:
            try:
                if self.drawLines[-1][3] == "mouseMoveEvent":
                    del self.drawLines[-1]  # Remove mouseMoveEvent element
            except Exception:
                None
            for pt in range(len(self.drawLines) - 1, -1, -1):
                del self.drawLines[pt]
                try:
                    if self.drawLines[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeLastSegmentLine(self):
        ''' Remove Last Segment Line Objects '''
        try:
            if self.drawLines[-1][3] == "mouseMoveEvent":
                del self.drawLines[-1]  # Remove mouseMoveEvent element
        except Exception:
            None
        if self.drawLines:
            if self.drawLines[-1][0] is None:
                del self.drawLines[-1]

            del self.drawLines[-1]
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeAllLines(self):
        ''' Resets Line List '''
        if self.drawLines:
            self.drawLines = []
            self.UpdateSurface()
            # Clear all Layer
            RemoveAllDrawLineOnMap()

    def ResetDrawMeasureDistance(self):
        ''' Resets Measure Distance List '''
        self.drawMeasureDistance = []

    def ResetDrawMeasureArea(self):
        ''' Resets Measure Area List '''
        self.drawMeasureArea = []

    def removeAllCensure(self):
        ''' Remove All Censure Objects '''
        if self.drawCesure:
            self.drawCesure = []
            self.UpdateSurface()

    def removeLastCensured(self):
        ''' Remove Last Censure Objects '''
        if self.drawCesure:
            del self.drawCesure[-1]
            self.UpdateSurface()

    def removeLastPoint(self):
        ''' Remove All Point Drawer Objects '''
        if self.drawPtPos:
            del self.drawPtPos[-1]
            self.UpdateSurface()
            RemoveLastDrawPointOnMap()
        return

    def removeAllPoint(self):
        ''' Remove All Point Drawer Objects '''
        if self.drawPtPos:
            self.drawPtPos = []
            self.UpdateSurface()
            # Clear all Layer
            RemoveAllDrawPointOnMap()
        return

    def removeAllPolygon(self):
        ''' Remove All Polygon Drawer Objects '''
        if self.drawPolygon:
            self.drawPolygon = []
            self.UpdateSurface()
            # Clear all Layer
            RemoveAllDrawPolygonOnMap()

    def removeLastPolygon(self):
        ''' Remove Last Polygon Drawer Objects '''
        if self.drawPolygon:
            try:
                if self.drawPolygon[-1][3] == "mouseMoveEvent":
                    del self.drawPolygon[-1]  # Remove mouseMoveEvent element
            except Exception:
                None
            for pt in range(len(self.drawPolygon) - 1, -1, -1):
                del self.drawPolygon[pt]
                try:
                    if self.drawPolygon[pt - 1][0] is None:
                        break
                except Exception:
                    None

            self.UpdateSurface()
            # remove last index layer
            RemoveLastDrawPolygonOnMap()

    def keyPressEvent(self, event):
        '''Exit fullscreen
        :type event: QKeyEvent
        :param event:
        :return:
        '''
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super().keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
         Mouse double click event
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self.gt is not None and self._interaction.lineDrawer:
            self.drawLines.append([None, None, None])
            return

        if self.gt is not None and self._interaction.measureDistance:
            self.drawMeasureDistance.append([None, None, None])
            return

        if self.gt is not None and self._interaction.measureArea:
            self.drawMeasureArea.append([None, None, None])
            return

        if self.gt is not None and self._interaction.polygonDrawer:

            ok = AddDrawPolygonOnMap(self.poly_coordinates)
            # Prevent invalid geometry (Polygon with 2 points)
            if not ok:
                return

            self.drawPolygon.append([None, None, None])

            # Empty RubberBand
            for _ in range(self.poly_Canvas_RubberBand.numberOfVertices()):
                self.poly_Canvas_RubberBand.removeLastPoint()
            # Empty List
            self.poly_coordinates = []
            return

        self.UpdateSurface()
        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        ''' Return video Surface '''
        return self.surface

    def UpdateSurface(self):
        ''' Update Video Surface only is is stopped or paused '''
        if self.parent.playerState in (QMediaPlayer.StoppedState,
                                       QMediaPlayer.PausedState):
            self.update()
        QApplication.processEvents()

    def sizeHint(self):
        ''' This property holds the recommended size for the widget '''
        return self.surface.surfaceFormat().sizeHint()

    def currentFrame(self):
        ''' Return current frame QImage '''
        return self.surface.image

    def SetInvertColor(self, value):
        '''Set Invert color filter
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.invertColorFilter = value

    def SetObjectTracking(self, value):
        '''Set Object Tracking
        @type value: bool
        @param value:
        @return:
        '''
        self._interaction.objectTracking = value

    def SetMeasureDistance(self, value):
        '''Set measure Distance
        @type value: bool
        @param value:
        @return:
        '''
        self._interaction.measureDistance = value

    def SetMeasureArea(self, value):
        '''Set measure Area
        @type value: bool
        @param value:
        @return:
        '''
        self._interaction.measureArea = value

    def SetHandDraw(self, value):
        '''Set Hand Draw
        @type value: bool
        @param value:
        @return:
        '''
        self._interaction.HandDraw = value

    def SetCensure(self, value):
        '''Set Censure Video Parts
        @type value: bool
        @param value:
        @return:
        '''
        self._interaction.censure = value

    def SetMGRS(self, value):
        '''Set MGRS Cursor Coordinates
        @type value: bool
        @param value:
        @return:
        '''
        self._MGRS = value

    def SetGray(self, value):
        '''Set gray scale
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.grayColorFilter = value

    def SetMirrorH(self, value):
        '''Set Horizontal Mirror
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.MirroredHFilter = value

    def SetNDVI(self, value):
        '''Set NDVI
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.NDVI = value

    def SetEdgeDetection(self, value):
        '''Set Canny Edge filter
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        '''Set Automatic Contrast filter
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.contrastFilter = value

    def SetMonoFilter(self, value):
        '''Set mono filter
        @type value: bool
        @param value:
        @return:
        '''
        self._filterSatate.monoFilter = value

    def RestoreFilters(self):
        ''' Remove and restore all video filters '''
        self._filterSatate.clear()

    def RestoreDrawer(self):
        ''' Remove and restore all Drawer Options '''
        self._interaction.clear()
        # Magnifier Glass
        self.dragPos = QPoint()
        self.tapTimer.stop()

    def RemoveCanvasRubberbands(self):
        ''' Remove Canvas Rubberbands '''
        self.poly_Canvas_RubberBand.reset()
        self.Track_Canvas_RubberBand.reset(QgsWkbTypes.LineGeometry)
        self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry)

    def paintEvent(self, event):
        """
        @type event: QPaintEvent
        @param event:
        @return:
        """
        if not self.surface.isActive():
            return

        self.painter = QPainter(self)
        self.painter.setRenderHint(QPainter.HighQualityAntialiasing)

        region = event.region()
        self.painter.fillRect(region.boundingRect(), self.brush)  # Background painter color

        try:
            self.surface.paint(self.painter)
            SetImageSize(self.currentFrame().width(),
                         self.currentFrame().height())
        except Exception:
            None

        # Prevent draw on video if not started or finished
        if self.parent.player.position() == 0:
            self.painter.end()
            return

        self.gt = GetGCPGeoTransform()

        # Draw On Video
        draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon,
                         self.drawMeasureDistance, self.drawMeasureArea, self.drawCesure, self.painter, self.surface, self.gt)

        # Draw On Video Object tracking test
        if self._interaction.objectTracking and self._isinit:
            frame = convertQImageToMat(self.currentFrame())
            offset = self.surface.videoRect()
            # Update tracker
            result = resize(frame, (offset.width(), offset.height()))
            ok, bbox = self.tracker.update(result)
            # Draw bounding box
            if ok:
                # check negative values
                x = bbox[0] + offset.x()
                y = bbox[1] + offset.y()
                if vut.IsPointOnScreen(x, y, self.surface):
                    self.painter.setPen(self.blue_Pen)
                    self.painter.drawRect(x, y, bbox[2], bbox[3])

                    # Get Track object center
                    xc = x + (bbox[2] / 2)
                    yc = y + (bbox[3] / 2)
                    p = QPoint(xc, yc)
                    Longitude, Latitude, _ = vut.GetPointCommonCoords(
                        p, self.surface)
                    # Draw Rubber Band on canvas
                    self.Track_Canvas_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))

            else:
                self._isinit = False
                del self.tracker

        # Magnifier Glass
        if self._interaction.magnifier and not self.dragPos.isNull():
            draw.drawMagnifierOnVideo(self, self.dragPos, self.currentFrame(), self.painter)

        # Stamp On Video
        if self._interaction.stamp:
            draw.drawStampOnVideo(self, self.painter)

        self.painter.end()
        return

    def resizeEvent(self, _):
        """
        @type _: QMouseEvent
        @param _:
        @return:
        """
        self.surface.updateVideoRect()
        self.update()
        # Magnifier Glass
        if self._interaction.magnifier and not self.dragPos.isNull():
            draw.drawMagnifierOnVideo(self, self.dragPos, self.currentFrame(), self.painter)
        # QApplication.processEvents()

    def AddMoveEventValue(self, values, Longitude, Latitude, Altitude):
        """
        Remove and Add move value for fluid drawing

        @type values: list
        @param values: Points list

        @type Longitude: float
        @param Longitude: Longitude value

        @type Latitude: float
        @param Latitude: Latitude value

        @type Altitude: float
        @param Altitude: Altitude value

        """
        for idx, pt in enumerate(values):
            if pt[-1] == "mouseMoveEvent":
                del values[idx]
        values.append([Longitude, Latitude, Altitude, "mouseMoveEvent"])

        self.UpdateSurface()

    def mouseMoveEvent(self, event):
        """
        @type event: QMouseEvent
        @param event:
        @return:
        """
        # Magnifier mouseMoveEvent
        # Magnifier can move on black screen for show image borders
        if self._interaction.magnifier:
            if event.buttons():
                self.dragPos = event.pos()
                self.UpdateSurface()

        # check if the point  is on picture (not in black borders)
        if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            self.setCursor(QCursor(Qt.ArrowCursor))
            self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry)
            return

        # Prevent draw on video if not started or finished
        if self.parent.player.position() == 0:
            return

        # Mouser cursor drawing
        if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.measureDistance or self._interaction.measureArea or self._interaction.censure or self._interaction.objectTracking:
            self.setCursor(QCursor(Qt.CrossCursor))

        # Cursor Coordinates
        if self.gt is not None:

            Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                event, self.surface)

            tr = QgsCoordinateTransform( QgsCoordinateReferenceSystem( 'EPSG:4326' ), iface.mapCanvas().mapSettings().destinationCrs(), QgsProject.instance().transformContext() )
            mapPt = tr.transform( QgsPointXY(Longitude, Latitude) )
            
            vertices = self.Cursor_Canvas_RubberBand.numberOfVertices()
            if vertices > 0:
                self.Cursor_Canvas_RubberBand.removePoint(0, True, 0)
                self.Cursor_Canvas_RubberBand.movePoint( mapPt, 0)
            else:
                self.Cursor_Canvas_RubberBand.addPoint( mapPt )

            if self._MGRS:
                try:
                    mgrsCoords = mgrs.toMgrs(Latitude, Longitude)
                except Exception:
                    mgrsCoords = ""

                txt = "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%s" % mgrsCoords) + "</span>"

            else:

                txt = "<span style='font-size:10pt; font-weight:bold;'>Lon : </span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%.3f" % Longitude) + "</span>"
                txt += "<span style='font-size:10pt; font-weight:bold;'> Lat : </span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%.3f" % Latitude) + "</span>"

                if hasElevationModel():
                    txt += "<span style='font-size:10pt; font-weight:bold;'> Alt : </span>"
                    txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                        ("%.0f" % Altitude) + "</span>"
                else:
                    txt += "<span style='font-size:10pt; font-weight:bold;'> Alt : </span>"
                    txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>"

            self.parent.lb_cursor_coord.setText(txt)

            # Polygon drawer mouseMoveEvent
            if self._interaction.polygonDrawer:
                self.AddMoveEventValue(self.drawPolygon, Longitude, Latitude, Altitude)

            # Line drawer mouseMoveEvent
            if self._interaction.lineDrawer:
                self.AddMoveEventValue(self.drawLines, Longitude, Latitude, Altitude)

            # Measure Distance drawer mouseMoveEvent
            if self._interaction.measureDistance and self.drawMeasureDistance:
                self.AddMoveEventValue(self.drawMeasureDistance, Longitude, Latitude, Altitude)

            # Measure Area drawer mouseMoveEvent
            if self._interaction.measureArea and self.drawMeasureArea:
                self.AddMoveEventValue(self.drawMeasureArea, Longitude, Latitude, Altitude)

        else:
            self.parent.lb_cursor_coord.setText("<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                                                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                                                "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>")

        if not event.buttons():
            return

        # Object tracking rubberband
        if not self.Tracking_Video_RubberBand.isHidden():
            self.Tracking_Video_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        # Censure rubberband
        if not self.Censure_RubberBand.isHidden():
            self.Censure_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

    def timerEvent(self, _):
        """ Time Event (Magnifier method)"""
        if not self._interaction.magnifier:
            self.activateMagnifier()

    def mousePressEvent(self, event):
        """
        @type event: QMouseEvent
        @param event:
        @return:
        """
        if GetImageHeight() == 0:
            return

        # Prevent draw on video if not started or finished
        if self.parent.player.position() == 0:
            return

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

            # Magnifier Glass
            if self._interaction.magnifier:
                self.dragPos = event.pos()
                self.tapTimer.stop()
                self.tapTimer.start(10, self)

            if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
                return

            # point drawer
            if self.gt is not None and self._interaction.pointDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                pointIndex = len(self.drawPtPos) + 1
                AddDrawPointOnMap(pointIndex, Longitude,
                                  Latitude, Altitude)

                self.drawPtPos.append([Longitude, Latitude, Altitude])

            # polygon drawer
            if self.gt is not None and self._interaction.polygonDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.poly_Canvas_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))
                self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude))
                self.drawPolygon.append([Longitude, Latitude, Altitude])

            # line drawer
            if self.gt is not None and self._interaction.lineDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                self.drawLines.append([Longitude, Latitude, Altitude])

                AddDrawLineOnMap(self.drawLines)

            self.origin = event.pos()
            # Object Tracking Interaction
            if self._interaction.objectTracking:
                self.Tracking_Video_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Tracking_Video_RubberBand.show()

            # Censure Interaction
            if self._interaction.censure:
                self.Censure_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Censure_RubberBand.show()

            # Measure Distance drawer
            if self.gt is not None and self._interaction.measureDistance:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.drawMeasureDistance.append([Longitude, Latitude, Altitude])

            # Measure Distance drawer
            if self.gt is not None and self._interaction.measureArea:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.drawMeasureArea.append([Longitude, Latitude, Altitude])

            # if not called, the paint event is not triggered.
            self.UpdateSurface()

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.tapTimer.stop()
        self.UpdateSurface()

    def SetMagnifier(self, value):
        """Set Magnifier Glass
        @type value: bool
        @param value:
        """
        self._interaction.magnifier = value
        # We avoid that the second time we activate the tool, save the previous position.
        # Always keep the same behavior of the tool
        if not value:
            self.dragPos = QPoint()
            self.tapTimer.stop()

    def SetStamp(self, value):
        """Set Stamp
        @type value: bool
        @param value:
        """
        self._interaction.stamp = value

    def SetPointDrawer(self, value):
        """Set Point Drawer
        @type value: bool
        @param value:
        """
        self._interaction.pointDrawer = value

    def SetLineDrawer(self, value):
        """Set Line Drawer
        @type value: bool
        @param value:
        """
        self._interaction.lineDrawer = value

    def SetPolygonDrawer(self, value):
        """Set Polygon Drawer
        @type value: bool
        @param value:
        """
        self._interaction.polygonDrawer = value

    def mouseReleaseEvent(self, _):
        """
        @type event: QMouseEvent
        @param event:
        @return:
        """
        # Prevent draw on video if not started or finished
        if self.parent.player.position() == 0:
            return

        # Censure Draw Interaction
        if self._interaction.censure:
            geom = self.Censure_RubberBand.geometry()
            self.Censure_RubberBand.hide()
            self.drawCesure.append([geom])

        # Object Tracking Interaction
        if self._interaction.objectTracking:
            geom = self.Tracking_Video_RubberBand.geometry()
            offset = self.surface.videoRect()
            bbox = (geom.x() - offset.x(), geom.y() - offset.y(), geom.width(), geom.height())
            img = self.currentFrame()
            frame = convertQImageToMat(img)
            # Remo rubberband on canvas and video
            self.Tracking_Video_RubberBand.hide()
            self.Track_Canvas_RubberBand.reset()

            self.tracker = TrackerMOSSE_create()
            result = resize(frame, (offset.width(), offset.height()))

            try:
                ok = self.tracker.init(result, bbox)
            except Exception:
                return
            if ok:
                self._isinit = True
                # Get Traker center
                xc = bbox[0] + (geom.width() / 2)
                yc = bbox[1] + (geom.height() / 2)
                p = QPoint(xc, yc)
                Longitude, Latitude, _ = vut.GetPointCommonCoords(
                    p, self.surface)
                # Draw Rubber Band on canvas
                self.Track_Canvas_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))
            else:
                self._isinit = False

    def leaveEvent(self, _):
        """
        @type _: QEvent
        @param _:
        @return:
        """
        # Remove coordinates label value
        self.parent.lb_cursor_coord.setText("")
        # Change cursor
        self.setCursor(QCursor(Qt.ArrowCursor))
        # Reset mouse rubberband
        self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry)
Beispiel #20
0
class MeasureAreaTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas,
                                         QgsWkbTypes.PolygonGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))

        crs = self.canvas.mapSettings().destinationCrs()
        self.area_calc = QgsDistanceArea()
        self.area_calc.setSourceCrs(crs,
                                    QgsProject.instance().transformContext())
        self.area_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        """ Reset log message and rubber band"""
        self.msglog.logMessage("")
        self.start_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())

        if self.start_point and event.button() == Qt.RightButton:
            multipoint = self.rubber_band.asGeometry()
            area = self.area_calc.measureArea(multipoint)
            anglemsg = QMessageBox(self.parent())
            anglemsg.finished.connect(self.deactivate)
            anglemsg.setWindowTitle("Measure area tool")
            anglemsg.setText("Area: {} ".format(
                self.area_calc.formatArea(area, 3,
                                          QgsUnitTypes.AreaSquareMeters,
                                          True)))
            anglemsg.exec()
            self.finish()
        elif self.start_point:
            self.rubber_band.addPoint(point)
            self.rubber_band_points.addPoint(point)

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)

            multipoint = self.rubber_band.asGeometry()
            area = self.area_calc.measureArea(multipoint)
            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current area: {} ".format(
                    self.area_calc.formatArea(area, 3,
                                              QgsUnitTypes.AreaSquareMeters,
                                              True)), "Measure Area:", 0)

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Beispiel #21
0
class QvPrint(QWidget):
    """Una classe del tipus QWidget que servirà per imprimir un area determinada.
    El widget conté un botó per imprimir, un per tornar a posicionar l'area d'impresió, i un comboBox per escollir l'escala.
    """
    def __init__(self, project, canvas, poligon, parent=None):
        """Inicialització de la clase:
            Arguments:
                project {QgsProject().instance()} -- El projecte actiu
                canvas {QgsVectorLayer} -- El canvas sobre el que es coloca la rubberband.   
                poligon {QgsPoligon} -- Poligon inicial. A revisar.
        """
        # We inherit our parent's properties and methods.
        QWidget.__init__(self, parent)
        self.parent = parent
        # Creating a memory layer to draw later the rubberband.
        estatDirtybit = self.parent.canvisPendents

        self.layer = QgsVectorLayer('Point?crs=epsg:23031',
                                    "Capa temporal d'impressió", "memory")
        project.addMapLayer(self.layer, False)

        # We store safely the parameters as class variables.
        self.canvas = canvas
        self.project = project
        self.poligon = poligon

        # Offset inicial del rectangle d'impressió- TODO
        self.incX = 100
        self.incY = 150

        # Semafor per deixar fix el rectangle un cop fet click.
        self.pucMoure = True

        # Diccionari d'escales i proporcions que fixen el tamany del rectangle en pantalla.
        # Podria fer-se millor, pero Practicality beats Purity...
        self.dictEscales = {
            '100': 20,
            '200': 40,
            '250': 45,
            '500': 100,
            '1000': 200,
            '2000': 400,
            '2500': 450,
            '5000': 1000,
            '10000': 2000,
            '20000': 4000,
            '25000': 4500,
            '50000': 10000
        }

        # We instanciate de PointTool tool, to wait for clicks
        # After that, we assign the tool to the canvas.
        rp = PointTool(self, self.canvas)
        canvas.setMapTool(rp)

        self.setupUI()

        self.rubberband = QgsRubberBand(self.canvas)
        self.rubberband.setColor(QColor(0, 0, 0, 50))
        self.rubberband.setWidth(4)

        self.canvas.xyCoordinates.connect(self.mocMouse)
        self.pintarRectangle(self.poligon)
        self.rubberband.hide()

        self.parent.setDirtyBit(estatDirtybit)

    def setupUI(self):
        self.layout = QVBoxLayout(self)
        self.setLayout(self.layout)
        self.layout.setContentsMargins(10, 20, 10, 20)
        self.layout.setSpacing(14)
        # self.layout.setAlignment(Qt.AlignTop)

        self.layoutTitol = QHBoxLayout()
        self.lblTitol = QLabel("Títol: ")
        self.leTitol = QLineEdit(self)
        self.leTitol.setText(self.parent.titolProjecte)
        self.layoutTitol.addWidget(self.lblTitol)
        self.layoutTitol.addWidget(self.leTitol)

        self.cbOrientacio = QComboBox(self)
        self.cbOrientacio.addItems(['Vertical', 'Horitzontal'])
        self.cbOrientacio.SelectedItem = "Vertical"
        self.cbOrientacio.setCurrentIndex(1)
        self.cbOrientacio.currentTextChanged.connect(self.canviOrientacio)
        self.lblCBOrientacio = QLabel("Orientació: ")
        self.layoutCBOrientacio = QHBoxLayout()
        self.layoutCBOrientacio.addWidget(self.lblCBOrientacio)
        self.layoutCBOrientacio.addWidget(self.cbOrientacio)

        self.combo = QComboBox(self)
        llistaEscales = [key for key in self.dictEscales]
        self.combo.addItems(llistaEscales)
        self.combo.currentTextChanged.connect(self.canviEscala)
        self.lblEscales = QLabel("Escales")
        self.layEscales = QHBoxLayout()
        self.layEscales.addWidget(self.lblEscales)
        self.layEscales.addWidget(self.combo)

        self.cbMida = QComboBox(self)
        self.cbMida.addItems(['A0', 'A1', 'A2', 'A3', 'A4'])
        self.cbMida.currentTextChanged.connect(self.canviEscala)
        self.cbMida.setCurrentIndex(4)
        self.lblCBmida = QLabel("Paper: ")
        self.layoutCBmida = QHBoxLayout()
        self.layoutCBmida.addWidget(self.lblCBmida)
        self.layoutCBmida.addWidget(self.cbMida)

        self.boto = QvPushButton(text='Generar PDF',
                                 destacat=True,
                                 parent=self)
        self.boto.clicked.connect(self.printPlanol)
        self.boto.setFixedWidth(220)
        self.boto2 = QvPushButton(text='Emmarcar zona a imprimir', parent=self)
        self.boto2.clicked.connect(self.potsMoure)
        self.boto2.setFixedWidth(220)

        self.nota = QLabel(
            "NOTA: Alguns navegadors web alteren l'escala d'impressió dels PDFs. Per màxima exactitud imprimiu des de l'Adobe Acrobat."
        )
        styleheetLabel = '''
            QLabel {
                color: grey;
            }'''
        self.nota.setStyleSheet(styleheetLabel)
        self.nota.setMaximumWidth(200)
        self.nota.setWordWrap(True)

        self.layout.addLayout(self.layoutTitol)
        self.layout.addLayout(self.layEscales)
        self.layout.addLayout(self.layoutCBmida)
        self.layout.addLayout(self.layoutCBOrientacio)
        self.layout.addWidget(self.boto2)
        self.layout.addWidget(self.boto)
        self.layout.addWidget(self.nota)
        # self.layout.addWidget(self.wFormat)
        # self.layout.addWidget(self.rbVertical)
        # self.layout.addWidget(self.rbHoritzontal)
        self.layout.addStretch()

    def potsMoure(self):
        # self.canvas.scene().removeItem(self.rubberband)
        self.pucMoure = True

    def canviEscala(self):
        self.pucMoure = True
        escala = int(self.dictEscales[self.combo.currentText()])
        mida = self.cbMida.currentText()
        if mida == 'A3':
            escala *= math.sqrt(2)
        elif mida == 'A2':
            escala *= math.sqrt(2) * 2
        elif mida == 'A1':
            escala *= math.sqrt(2) * 3
        elif mida == 'A0':
            escala *= math.sqrt(2) * 4

        if self.cbOrientacio.SelectedItem == "Horitzontal":
            self.incX = escala
            self.incY = escala * 1.5
        else:
            self.incX = escala * 1.5
            self.incY = escala

    def canviOrientacio(self):
        self.pucMoure = True
        if self.cbOrientacio.SelectedItem == "Vertical":
            self.cbOrientacio.SelectedItem = "Horitzontal"
        else:
            self.cbOrientacio.SelectedItem = "Vertical"
        self.incX, self.incY = self.incY, self.incX

    def canvasClickat(self):  #???
        print('Clickat, si')

    def mocMouse(self, p):
        if not self.isVisible():
            self.rubberband.hide()
            self.pucMoure

        elif self.pucMoure:
            if self.canvas.rotation() == 0:
                self.posXY = [p.x() + self.incX / 2, p.y() + self.incY / 2]
                self.rubberband.movePoint(
                    0, QgsPointXY(p.x() + self.incX,
                                  p.y() + self.incY), 0)
                self.rubberband.movePoint(1,
                                          QgsPointXY(p.x() + self.incX, p.y()),
                                          0)
                self.rubberband.movePoint(2, QgsPointXY(p.x(), p.y()), 0)
                self.rubberband.movePoint(3,
                                          QgsPointXY(p.x(),
                                                     p.y() + self.incY), 0)
                self.rubberband.movePoint(
                    4, QgsPointXY(p.x() + self.incX,
                                  p.y() + self.incY), 0)
            else:
                alpha = math.radians(self.canvas.rotation())
                beta = math.atan(self.incY / self.incX)
                d = math.sqrt(self.incX**2 + self.incY**2)
                self.posXY = [(2 * p.x() + d * math.cos(alpha + beta)) / 2,
                              (2 * p.y() + d * math.sin(alpha + beta)) / 2]
                self.rubberband.movePoint(
                    0,
                    QgsPointXY(p.x() + d * math.cos(alpha + beta),
                               p.y() + d * math.sin(alpha + beta)), 0)
                self.rubberband.movePoint(
                    1,
                    QgsPointXY(p.x() + self.incX * math.cos(alpha),
                               p.y() + self.incX * math.sin(alpha)), 0)
                self.rubberband.movePoint(2, QgsPointXY(p.x(), p.y()), 0)
                self.rubberband.movePoint(
                    3,
                    QgsPointXY(
                        p.x() + self.incY * math.cos(math.radians(90 + 45)),
                        p.y() + self.incY * math.sin(math.radians(90 + 45))),
                    0)
                self.rubberband.movePoint(
                    4,
                    QgsPointXY(p.x() + d * math.cos(alpha + beta),
                               p.y() + d * math.sin(alpha + beta)), 0)
            self.rubberband.show()

    def pintarRectangle(self, poligon):
        points = [
            QgsPointXY(0, 0),
            QgsPointXY(0, 10),
            QgsPointXY(10, 10),
            QgsPointXY(0, 10),
            QgsPointXY(0, 0)
        ]
        poligono = QgsGeometry.fromRect(self.poligon)
        self.rubberband.setToGeometry(poligono, self.layer)

    def printPlanol(self):
        #
        # if self.checkRotacio.checkState():
        #     rotacio=44.75
        # else:
        #     rotacio=0

        rotacio = self.canvas.rotation()
        if self.cbOrientacio.currentText() == "Vertical":
            if self.cbMida.currentText() == "A4":
                self.plantillaMapa = pathPlantilles + 'plantillaMapa.qpt'
            elif self.cbMida.currentText() == "A3":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA3.qpt'
            elif self.cbMida.currentText() == "A2":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA2.qpt'
            elif self.cbMida.currentText() == "A1":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA1.qpt'
            elif self.cbMida.currentText() == "A0":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA0.qpt'

        else:
            if self.cbMida.currentText() == "A4":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaH.qpt'
            elif self.cbMida.currentText() == "A3":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA3H.qpt'
            elif self.cbMida.currentText() == "A2":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA2H.qpt'
            elif self.cbMida.currentText() == "A1":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA1H.qpt'
            elif self.cbMida.currentText() == "A0":
                self.plantillaMapa = pathPlantilles + 'plantillaMapaA0H.qpt'

        t = time.localtime()
        timestamp = time.strftime('%d-%b-%Y_%H%M%S', t)
        sortida = tempdir + 'sortida_' + timestamp

        self.imprimirPlanol(self.posXY[0], self.posXY[1],
                            int(self.combo.currentText()), rotacio,
                            self.cbMida.currentText(), self.plantillaMapa,
                            sortida, 'PDF')

        QvApp().logRegistre('Impressió: ' + self.combo.currentText())

    def imprimirPlanol(self, x, y, escala, rotacion, midaPagina, templateFile,
                       fitxerSortida, tipusSortida):
        tInicial = time.time()

        template = QFile(templateFile)
        doc = QDomDocument()
        doc.setContent(template, False)

        layout = QgsLayout(self.project)
        # page=QgsLayoutItemPage(layout)
        # page.setPageSize(midaPagina)
        # layout.pageCollection().addPage(page)

        # layout.initializeDefaults()
        # p=layout.pageCollection().pages()[0]
        # p.setPageSize(midaPagina)

        context = QgsReadWriteContext()
        [items, ok] = layout.loadFromTemplate(doc, context)
        # p=layout.pageCollection().pages()[0]
        # p.setPageSize(midaPagina)

        if ok:
            refMap = layout.referenceMap()

            titol = layout.itemById('idNomMapa')
            dataMapa = layout.itemById('idData')
            if self.leTitol.text() != '':
                titol.setText(self.leTitol.text())  #comentat pk peta
            else:
                titol.setText('')
            try:
                t = time.localtime()
                dataMapa.setText(strftime('%b-%d-%Y %H:%M', t))
            except:
                pass

            rect = refMap.extent()
            vector = QgsVector(x - rect.center().x(), y - rect.center().y())
            rect += vector
            refMap.setExtent(rect)
            refMap.setScale(escala)
            refMap.setMapRotation(rotacion)
            #Depenent del tipus de sortida...

            exporter = QgsLayoutExporter(layout)
            # image_settings = exporter.ImageExportSettings()
            # image_settings.dpi = 30

            # result = exporter.exportToImage('d:/dropbox/qpic/preview.png',  image_settings)
            # imatge = QPixmap('d:/dropbox/qpic/preview.png')
            # self.ui.lblImatgeResultat.setPixmap(imatge)

            if tipusSortida == 'PDF':
                settings = QgsLayoutExporter.PdfExportSettings()
                settings.dpi = 300
                settings.exportMetadata = False

                # fitxerSortida='d:/sortida_'+timestamp+'.PDF'
                fitxerSortida += '.PDF'
                result = exporter.exportToPdf(
                    fitxerSortida, settings)  #Cal desar el resultat (???)

                print(fitxerSortida)

            if tipusSortida == 'PNG':
                settings = QgsLayoutExporter.ImageExportSettings()
                settings.dpi = 300

                # fitxerSortida='d:/sortida_'+timestamp+'.PNG'
                fitxerSortida += '.PNG'
                result = exporter.exportToImage(
                    fitxerSortida, settings)  #Cal desar el resultat (???)

            #Obra el document si està marcat checkObrirResultat
            QDesktopServices().openUrl(QUrl(fitxerSortida))

            segonsEmprats = round(time.time() - tInicial, 1)  #???
            layersTemporals = self.project.mapLayersByName(
                "Capa temporal d'impressió")

            estatDirtybit = self.parent.canvisPendents
            for layer in layersTemporals:
                self.project.removeMapLayer(layer.id())
            self.parent.setDirtyBit(estatDirtybit)

    def oculta(self):
        #Eliminem la capa temporal
        estatDirtybit = self.parent.canvisPendents
        layersTemporals = self.project.mapLayersByName(
            "Capa temporal d'impressió")
        for layer in layersTemporals:
            self.project.removeMapLayer(layer.id())
        self.parent.setDirtyBit(estatDirtybit)
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()
Beispiel #23
0
class QgepMapToolConnectNetworkElements(QgsMapTool):
    """
    This map tool connects wastewater networkelements.

    It works on two lists of layers:
      source layers with fields with a foreign key to a networkelement
      target layers which depict networkelements (reaches and network nodes)

    The tool will snap to source layers first and once one is chosen to a target layer.

    It will then ask which field(s) should be connected and perform the update on the database
    """

    def __init__(self, iface, action):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.action = action

        self.rbline = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
        self.rbline.setColor(QColor('#f4530e'))
        self.rbline.setWidth(3)
        self.rbmarkers = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rbmarkers.setColor(QColor('#f4530e'))
        self.rbmarkers.setIconSize(6)

        self.source_snapper = QgepAreaSnapper(self.iface.mapCanvas())
        self.target_snapper = QgepAreaSnapper(self.iface.mapCanvas())

        self.source_feature = QgsFeature()
        self.rb_source_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_source_feature.setColor(QColor('#f49e79'))
        self.rb_source_feature.setWidth(3)
        self.target_feature = QgsFeature()
        self.rb_target_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_target_feature.setColor(QColor('#f49e79'))
        self.rb_target_feature.setWidth(3)

    def activate(self):
        """
        Called by QGIS whenever the tool is activated.
        """
        source_snap_layers = list()
        target_snap_layers = list()

        # A dict of layers and the fields that are foreign keys
        # pointing to wastewater networkelements
        self.network_element_sources = {
            QgepLayerManager.layer('vw_qgep_reach'): [
                ('rp_to_fk_wastewater_networkelement',
                 QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point To')),
                ('rp_from_fk_wastewater_networkelement',
                 QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point From'))
            ],
            QgepLayerManager.layer('od_catchment_area'): [
                ('fk_wastewater_networkelement_rw_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater current')),
                ('fk_wastewater_networkelement_rw_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater planned')),
                ('fk_wastewater_networkelement_ww_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater current')),
                ('fk_wastewater_networkelement_ww_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater planned'))
            ]
        }

        # A list of layers that can be used as wastewater networkelement
        # targets
        self.network_element_targets = [
            QgepLayerManager.layer('vw_wastewater_node'),
            QgepLayerManager.layer('vw_qgep_reach')
        ]

        for layer in self.network_element_sources.keys():
            if layer:
                snap_layer = QgsSnappingUtils.LayerConfig(
                    layer, QgsPointLocator.All, 16, QgsTolerance.Pixels)
                source_snap_layers.append(snap_layer)

        for layer in self.network_element_targets:
            if layer:
                snap_layer = QgsSnappingUtils.LayerConfig(
                    layer, QgsPointLocator.All, 16, QgsTolerance.Pixels)
                target_snap_layers.append(snap_layer)

        self.source_snapper.setLayers(source_snap_layers)
        self.source_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)

        self.target_snapper.setLayers(target_snap_layers)
        self.target_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)

        self.reset()

        self.action.setChecked(True)

        self.iface.mapCanvas().setCursor(QCursor(Qt.CrossCursor))

    def canvasMoveEvent(self, event):
        """
        When the mouse moves, update the rubberbands.
        """
        pt = event.originalMapPoint()
        snap_match = self.snapper.snapToMap(pt)

        if snap_match.isValid():
            if snap_match.type() != QgsPointLocator.Area:
                pt = snap_match.point()
            self.matchpoint = pt

            if self.source_match:
                if self.target_feature.id() != snap_match.featureId():
                    self.target_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_target_feature.setToGeometry(
                        self.target_feature.geometry(), snap_match.layer())
                self.rb_target_feature.show()
                self.rbmarkers.movePoint(pt)
            else:
                if self.source_feature.id() != snap_match.featureId():
                    self.source_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_source_feature.setToGeometry(
                        self.source_feature.geometry(), snap_match.layer())
                self.rb_source_feature.show()
                self.rbmarkers.movePoint(pt, 0)
            self.rbmarkers.show()
        else:
            self.rbmarkers.hide()
            if self.source_match:
                self.rb_target_feature.hide()
            else:
                self.rb_source_feature.hide()

        self.rbline.movePoint(pt)

        self.snapresult = snap_match

    def canvasReleaseEvent(self, event):
        """
        On a click update the rubberbands and the snapping results if it's a left click. Reset if it's a right click.
        """
        if event.button() == Qt.LeftButton:
            if self.snapresult.isValid():
                if self.source_match:
                    self.connect_features(self.source_match, self.snapresult)
                else:
                    self.rbline.show()
                    self.rbline.addPoint(self.matchpoint)
                    self.source_match = self.snapresult
                    self.snapper = self.target_snapper
        else:
            self.reset()

    def deactivate(self):
        """
        Called by QGIS whenever this tool is deactivated.
        """
        self.reset()
        self.action.setChecked(False)

    def reset(self):
        """
        Resets the tool to a pristine state
        """
        self.source_match = None
        self.rbline.hide()
        self.rbline.reset()
        self.rbmarkers.hide()
        self.rbmarkers.reset(QGis.Point)
        self.rbmarkers.addPoint(QgsPoint())
        self.snapresult = None
        self.source_match = None
        self.snapper = self.source_snapper
        self.source_feature = QgsFeature()
        self.target_feature = QgsFeature()
        self.rb_source_feature.reset()
        self.rb_target_feature.reset()

    def get_feature_for_match(self, match):
        """
        Get the feature for a snapping result
        @param match: The QgsPointLocator.SnapMatch object
        @return: A feature
        """
        return next(match.layer().getFeatures(QgsFeatureRequest().setFilterFid(match.featureId())))

    def connect_features(self, source, target):
        """
        Connects the source feature with the target feature.

        @param source: A QgsPointLocator.Match object. Its foreign key will be updated.
                       A dialog will be opened which asks the user for which foreign key(s) he wants to update.
        @param target: A QgsPointLocator.Match object. This feature will be used as link target.
                       Its obj_id attribute will be used as primary key.
        """
        dlg = QDialog(self.iface.mainWindow())
        dlg.setWindowTitle(self.tr('Select properties to connect'))
        dlg.setLayout(QFormLayout())

        properties = list()

        for prop in self.network_element_sources[source.layer()]:
            cbx = QCheckBox(prop[1])
            cbx.setObjectName(prop[0])
            properties.append(cbx)
            dlg.layout().addWidget(cbx)

        btn_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        dlg.layout().addWidget(btn_box)
        btn_box.accepted.connect(dlg.accept)
        btn_box.rejected.connect(dlg.reject)

        source_feature = self.get_feature_for_match(source)
        target_feature = self.get_feature_for_match(target)

        if dlg.exec_():
            for cbx in properties:
                if cbx.isChecked():
                    source_feature[cbx.objectName()] = target_feature['obj_id']
            if source.layer().updateFeature(source_feature):
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr('Connected {} to {}').format(
                                                        source_feature[
                                                            'identifier'],
                                                        target_feature['identifier']),
                                                    QgsMessageBar.INFO, 5)
            else:
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr(
                                                        'Error connecting features'),
                                                    QgsMessageBar.WARNING, 5)

        self.reset()
class QgepMapToolAddFeature(QgsMapTool):
    """
    Base class for adding features
    """
    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType())
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(2)
        self.tempRubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType())
        self.tempRubberband.setColor(QColor("#ee5555"))
        self.tempRubberband.setWidth(2)
        self.tempRubberband.setLineStyle(Qt.DotLine)

    def activate(self):
        """
        When activating the map tool
        """
        QgsMapTool.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))

    def deactivate(self):
        """
        On deactivating the map tool
        """
        QgsMapTool.deactivate(self)
        self.canvas.unsetCursor()

    # pylint: disable=no-self-use
    def isZoomTool(self):
        """
        This is no zoom tool
        """
        return False

    # ===========================================================================
    # Events
    # ===========================================================================

    def canvasReleaseEvent(self, event):
        """
        Called when a mouse button is
        :param event:
        :return:
        """
        if event.button() == Qt.RightButton:
            self.rightClicked(event)
        else:
            self.leftClicked(event)

    def leftClicked(self, event):
        """
        When the canvas is left clicked we add a new point to the rubberband.
        :type event: QMouseEvent
        """
        mousepos = self.canvas.getCoordinateTransform()\
            .toMapCoordinates(event.pos().x(), event.pos().y())
        self.rubberband.addPoint(mousepos)
        self.tempRubberband.reset()

    def rightClicked(self, _):
        """
        On a right click we create a new feature from the existing rubberband and show the add
        dialog
        """
        f = QgsFeature(self.layer.pendingFields())
        f.setGeometry(self.rubberband.asGeometry())
        dlg = self.iface.getFeatureForm(self.layer, f)
        dlg.setIsAddDialog(True)
        dlg.exec_()
        self.rubberband.reset()
        self.tempRubberband.reset()

    def canvasMoveEvent(self, event):
        """
        When the mouse is moved the rubberband needs to be updated
        :param event: The coordinates etc.
        """
        mousepos = self.canvas.getCoordinateTransform()\
            .toMapCoordinates(event.pos().x(), event.pos().y())
        self.tempRubberband.movePoint(mousepos)
Beispiel #25
0
class MeasureDistanceTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))
        crs = self.canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(
            crs,
            QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        self.msglog.logMessage("")
        self.start_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())
        if self.start_point:
            self.end_point = point
            self.rubber_band.addPoint(self.end_point)
            self.rubber_band_points.addPoint(self.end_point)
            distance = self.distance_calc.measureLine(
                [self.start_point, self.end_point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            distancemsg = QMessageBox(self.parent())
            distancemsg.finished.connect(self.deactivate)
            distancemsg.setWindowTitle("Measure tool")
            distancemsg.setText("Distance: {:.3F} m. Bearing: {:.3F} º".format(
                distance, degrees(bearing)))
            distancemsg.exec()
            self.finish()

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)
            distance = self.distance_calc.measureLine(
                [self.start_point, point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current distance: {:.3F} m. Bearing: {:.3F} º".format(
                    distance, degrees(bearing)), "Measure distance:", 0)

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Beispiel #26
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()
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 is not None and polygon is not None:
                pointGeom = self.getPointGeometry(point)
                polygonGeom = self.getPolygonGeometry(polygon)
                if pointGeom is not None and polygonGeom is not None:
                    self.mappingFinished.emit(
                        pointGeom, polygonGeom,
                        self.canvas.mapSettings().destinationCrs())
                else:
                    self.clearScene()
            else:
                self.clearScene()

    def canvasMoveEvent(self, event):
        if self.tempRubberBand is not 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 is not None and polygon is not None:
                pointGeom = self.getPointGeometry(point)
                polygonGeom = self.getPolygonGeometry(polygon)
                if pointGeom is not None and polygonGeom is not 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,
                                        QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setWidth(2)
        self.rubberBand.setFillColor(QColor(220, 0, 0, 120))
        self.rubberBand.setStrokeColor(QColor(220, 0, 0))
        self.rubberBand.setLineStyle(Qt.DotLine)
        self.rubberBand.show()

        self.tempRubberBand = QgsRubberBand(self.canvas,
                                            QgsWkbTypes.PolygonGeometry)
        self.tempRubberBand.setWidth(2)
        self.tempRubberBand.setFillColor(QColor(0, 0, 0, 0))
        self.tempRubberBand.setStrokeColor(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(QgsWkbTypes.PolygonGeometry)
        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(QgsWkbTypes.PolygonGeometry)

        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 is None:
            return None
        else:
            return point

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

    def getPolygonGeometry(self, geom):
        p = QgsGeometry.fromPolygonXY([geom])
        if p.isGeosValid() and not p.isEmpty():
            return p
        else:
            return None
class LineCreateTool(QgsMapTool):
    '''
    classdocs
    '''


    def __init__(self, canvas, disType = DistanceUnits.M):
        '''
        Constructor
        '''
        self.canvas = canvas
        QgsMapTool.__init__(self, self.canvas)
        self.mSnapper = QgsMapCanvasSnapper(self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas,QGis.Line)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.rubberBandPt = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandPt.setColor(Qt.red)
        self.rubberBandPt.setWidth(10)
        self.type = disType
        self.reset()

    def reset(self):
        self.startPoint = None
        self.endPoint = None
        self.isDrawing = False
        self.distance = 0.0
    def canvasReleaseEvent(self, e):
        if ( e.button() == Qt.RightButton ):
            self.emit(SIGNAL("resultLineCreate"), self.rubberBand.asGeometry())
            self.reset()
            self.isDrawing = False
        else:
            self.rubberBandPt.reset(QGis.Point)
            snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)            
            if self.startPoint == None:
                self.rubberBand.reset(QGis.Line)
                if snapPoint == None:
                    self.startPoint = self.toMapCoordinates(e.pos())
                else:
                    self.startPoint = snapPoint
                self.rubberBand.addPoint(self.startPoint)
                self.isDrawing = True
            else:
                if snapPoint == None:
                    self.endPoint = self.toMapCoordinates(e.pos())
                else:
                    self.endPoint = snapPoint
                self.rubberBand.addPoint(self.endPoint)
                self.startPoint = self.endPoint
    def canvasMoveEvent(self, e):
        self.rubberBandPt.reset(QGis.Point)
        snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)
        if snapPoint != None:
            self.rubberBandPt.addPoint(snapPoint)
            self.rubberBandPt.show()
        if self.isDrawing:
            if self.isDrawing:
                if snapPoint == None:
                    self.endPoint = self.toMapCoordinates(e.pos())
                else:
                    self.endPoint = snapPoint
            self.rubberBand.movePoint(self.endPoint)
    def deactivate(self):
        self.rubberBandPt.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Beispiel #29
0
class GeomFilterEPSG():
    def __init__(self, iface):
        self.iface = iface

    def initGui(self):

        # cria uma ação que iniciará a configuração do plugin
        #self.myMapTool = QgsMapToolEmitPoint( self.iface.mapCanvas() )
        self.initVariables()
        self.initSignals()

    def initVariables(self):
        self.coordinates = []

        # Criação da action e da toolbar
        self.toolbar = self.iface.addToolBar("My_ToolBar")
        pai = self.iface.mainWindow()
        icon_path = ':/plugins/GeomFilterEPSG/icon.png'
        self.action = QAction(QIcon(icon_path), u"Filtro EPSG.", pai)
        self.action.setObjectName("Filtro EPSG.")
        self.action.setStatusTip(None)
        self.action.setWhatsThis(None)
        self.action.setCheckable(True)
        self.toolbar.addAction(self.action)

        self.previousMapTool = self.iface.mapCanvas().mapTool()
        self.myMapTool = QgsMapToolEmitPoint(self.iface.mapCanvas())
        self.isEditing = 0

    def initSignals(self):
        self.action.toggled.connect(self.RubberBand)
        self.myMapTool.canvasClicked.connect(self.mouseClick)

    def RubberBand(self, bolean):
        if bolean:
            self.myRubberBand = QgsRubberBand(self.iface.mapCanvas(),
                                              QGis.Polygon)
            color = QColor(78, 97, 114)
            color.setAlpha(190)
            self.myRubberBand.setColor(color)
            self.myRubberBand.setFillColor(QColor(255, 0, 0, 40))
            self.myRubberBand.setBorderColor(QColor(255, 0, 0, 200))

            # Set MapTool
            self.iface.mapCanvas().setMapTool(self.myMapTool)
            self.iface.mapCanvas().xyCoordinates.connect(self.mouseMove)
        else:
            self.disconnect()

    def disconnect(self):

        self.iface.mapCanvas().unsetMapTool(self.myMapTool)
        try:
            self.iface.mapCanvas().xyCoordinates.disconnect(self.mouseMove)
        except:
            pass

        try:
            self.myRubberBand.reset()
        except:
            pass

    def unChecked(self):
        self.action.setCheckable(False)
        self.action.setCheckable(True)

    def unload(self):
        self.disconnect()

    def mouseClick(self, currentPos, clickedButton):
        if clickedButton == Qt.LeftButton:  # and myRubberBand.numberOfVertices() == 0:
            self.myRubberBand.addPoint(QgsPoint(currentPos))
            self.coordinates.append(QgsPoint(currentPos))
            self.isEditing = 1

        elif clickedButton == Qt.RightButton and self.myRubberBand.numberOfVertices(
        ) > 2:
            self.isEditing = 0

            # create feature and set geometry.

            poly = QgsFeature()
            geomP = self.myRubberBand.asGeometry()
            poly.setGeometry(geomP)
            g = geomP.exportToWkt()  # Get WKT coordenates.
            #print g
            canvas = self.iface.mapCanvas()
            c = canvas.mapRenderer().destinationCrs().authid()  # Get EPSG.
            rep = c.replace("EPSG:", "")
            string = U"st_intersects(geom,st_geomfromewkt('SRID=" + rep + ";" + g + "'))"

            self.layers = self.iface.mapCanvas().layers()

            for layer in self.layers:
                layer.setSubsetString(string)

            self.myRubberBand.reset(QGis.Polygon)
            self.disconnect()
            self.unChecked()

    def mouseMove(self, currentPos):
        if self.isEditing == 1:
            self.myRubberBand.movePoint(QgsPoint(currentPos))
class QgepMapToolDigitizeDrainageChannel(QgsMapTool):
    '''
    This is used to digitize a drainage channel.

    It lets you digitize two points and then creates a polygon based on these two points
    by adding an orthogonal offset at each side.

    Input:

       x==============x

    Output:

       ----------------
       |              |
       ----------------

    Usage:
      Connect to the signals deactivated() and geometryDigitized()
      If geometryDigitized() is called you can use the member variable geometry
      which will contain a rectangle polygon
      deactivated() will be emited after a right click
    '''

    geometryDigitized = pyqtSignal()

    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand(iface.mapCanvas(), QGis.Line)
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(2)
        self.firstPoint = None
        self.messageBarItem = None
        self.geometry = None

    def activate(self):
        """
        Map tool is activated
        """
        QgsMapTool.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))
        msgtitle = self.tr('Digitizing Drainage Channel')
        msg = self.tr('Digitize start and end point. Rightclick to abort.')
        self.messageBarItem = QgsMessageBar.createMessage(msgtitle,
                                                          msg)
        self.iface.messageBar().pushItem(self.messageBarItem)

    def deactivate(self):
        """
        Map tool is deactivated
        """
        QgsMapTool.deactivate(self)
        self.iface.messageBar().popWidget(self.messageBarItem)
        try:
            self.iface.mapCanvas().scene().removeItem(self.rubberband)
            del self.rubberband
        except AttributeError:
            # Called repeatedly... bail out
            pass
        self.canvas.unsetCursor()

    def canvasMoveEvent(self, event):
        """
        Mouse is moved: Update rubberband
        :param event: coordinates etc.
        """
        mousepos = event.mapPoint()
        self.rubberband.movePoint(mousepos)

    def canvasReleaseEvent(self, event):
        """
        Canvas is released. This means:
          * start digitizing
          * stop digitizing (create a rectangle
            * if the Ctrl-modifier is pressed, ask for the rectangle width
        :param event: coordinates etc.
        """
        if event.button() == Qt.RightButton:
            self.deactivate()
        else:
            mousepos = self.canvas.getCoordinateTransform()\
                .toMapCoordinates(event.pos().x(), event.pos().y())
            self.rubberband.addPoint(mousepos)
            if self.firstPoint:  # If the first point was set before, we are doing the second one
                lp1 = self.rubberband.asGeometry().asPolyline()[0]
                lp2 = self.rubberband.asGeometry().asPolyline()[1]
                width = 0.2
                if QApplication.keyboardModifiers() & Qt.ControlModifier:
                    dlg = QDialog()
                    dlg.setLayout(QGridLayout())
                    dlg.layout().addWidget(QLabel(self.tr('Enter width')))
                    txt = QLineEdit('0.2')
                    dlg.layout().addWidget(txt)
                    bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
                    dlg.layout().addWidget(bb)
                    bb.accepted.connect(dlg.accept)
                    bb.rejected.connect(dlg.reject)
                    if dlg.exec_():
                        try:
                            width = float(txt.text())
                        except ValueError:
                            width = 0.2

                length = math.sqrt(math.pow(lp1.x() - lp2.x(), 2) + math.pow(lp1.y() - lp2.y(), 2))
                xd = lp2.x() - lp1.x()
                yd = lp2.y() - lp1.y()

                pt1 = QgsPoint(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length))
                pt2 = QgsPoint(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length))
                pt3 = QgsPoint(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length))
                pt4 = QgsPoint(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length))

                self.geometry = QgsGeometry.fromPolygon([[pt1, pt2, pt3, pt4, pt1]])

                self.geometryDigitized.emit()

            self.firstPoint = mousepos
class EditTool(QgsMapTool):
    wp_clicked = pyqtSignal(int)

    def __init__(self, mission_track, canvas, msglog):
        QgsMapTool.__init__(self, canvas)
        self.setCursor(Qt.CrossCursor)
        self.mission_track = mission_track
        self.msglog = msglog
        self.dragging = False
        self.feature = None
        self.vertex = None
        self.startcoord = None
        self.layer = self.mission_track.get_mission_layer()
        logger.info(self.mission_track.get_mission_name())

        self.rubber_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry)
        self.rubber_band.setWidth(2)
        self.rubber_band.setColor(QColor("green"))

        self.point_cursor_band = QgsRubberBand(self.canvas(), QgsWkbTypes.LineGeometry)
        self.point_cursor_band.setWidth(1)
        self.point_cursor_band.setLineStyle(Qt.DashLine)
        self.point_cursor_band.setColor(QColor(255, 0, 0, 100))

        self.mid_point_band = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry)
        self.mid_point_band.setColor(QColor(255, 0, 0, 100))
        self.mid_point_band.setIconSize(18)

        self.rubber_band_points = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setColor(QColor("green"))
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)

        self.mission_track.mission_changed.connect(self.update_rubber_bands)

        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.start_end_marker = StartEndMarker(canvas, self.mission_track.find_waypoints_in_mission(), QColor("green"))

        self.layer.startEditing()

        self.wp = []
        self.mCtrl = False
        # handler for mission feature
        self.update_rubber_bands(0)

        crs = canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(crs, QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())

    def update_rubber_bands(self, current_wp):
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
        self.wp = self.mission_track.find_waypoints_in_mission()

        self.start_end_marker.update_markers(self.wp)

        if len(self.wp) > 0:

            for v in self.wp:
                pc = self.toLayerCoordinates(self.layer, QgsPointXY(v))
                self.rubber_band.addPoint(pc)
                self.rubber_band_points.addPoint(pc)
            logger.debug("MISSION UPDATE: now we have {} waypoints".format(len(self.wp)))

            self.vertex_marker.setCenter(QgsPointXY(self.wp[current_wp].x(), self.wp[current_wp].y()))
            self.vertex_marker.setColor(QColor(25, 255, 0))
            self.vertex_marker.setIconSize(7)
            self.vertex_marker.setIconType(QgsVertexMarker.ICON_X)  # ICON_BOX, ICON_CROSS, ICON_X
            self.vertex_marker.setPenWidth(2)
            self.vertex_marker.show()

            self.set_geometry()
        else:

            self.vertex_marker.hide()

    def set_control_state(self, state):
        self.mCtrl = state

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control and not self.dragging:
            self.mCtrl = True
            pos = self.canvas().mouseLastXY()
            if not self.find_on_feature(pos, self.calc_tolerance()):
                self.show_dist_and_bearing_to_point()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = False
            pos = self.canvas().mouseLastXY()
            if not self.find_on_feature(pos, self.calc_tolerance()) and not self.dragging:
                self.show_dist_and_bearing_to_point()
        return

    def canvasDoubleClickEvent(self, event):
        self.canvasPressEvent(event)

    def canvasPressEvent(self, event):
        if self.dragging:
            self.canvasReleaseEvent(event)

        map_pt, layer_pt = self.transform_coordinates(event.pos())
        tolerance = self.calc_tolerance()

        if not self.find_on_feature(event.pos(), tolerance):
            if event.button() == Qt.LeftButton:
                # we have clicked outside the track
                logger.debug("We have clicked outside the track")
                self.point_cursor_band.reset(QgsWkbTypes.LineGeometry)
                if not self.mCtrl:
                    # add step to mission at the end
                    self.mission_track.add_step(len(self.wp), layer_pt)
                    self.show_waypoint_distances(len(self.wp)-1)
                else:
                    self.mission_track.add_step(0, layer_pt)
                    self.show_waypoint_distances(0)
        else:

            logger.debug("We have clicked on the track")
            vertex = self.find_vertex_at(event.pos(), tolerance)

            if event.button() == Qt.LeftButton:
                if vertex is None:
                    logger.debug("We have clicked between vertexs")
                    # we have clicked in between vertex, add intermediate point
                    initial_vertex = self.find_segment_at(event.pos())
                    # self.mission_track.add_step(initial_vertex + 1, layerPt)

                    intersection = intersect_point_to_line(self.toLayerCoordinates(self.layer, event.pos()),
                                                           QgsPointXY(self.wp[initial_vertex]),
                                                           QgsPointXY(self.wp[initial_vertex + 1]))
                    logger.debug("intersection point: {} {}".format(str(intersection.x()), str(intersection.y())))
                    logger.debug("{} {} {} {}".format(self.wp[initial_vertex].x(), self.wp[initial_vertex].y(),
                                 self.wp[initial_vertex + 1].x(), self.wp[initial_vertex + 1].y()))
                    # layerPtIntersection = self.toLayerCoordinates(self.layer,intersection)
                    self.mission_track.add_step(initial_vertex + 1, intersection)
                    self.mid_point_band.reset(QgsWkbTypes.PointGeometry)
                    self.show_waypoint_distances(initial_vertex+1)
                else:
                    logger.debug("We have clicked on vertex {}".format(vertex))
                    # we have clicked on a vertex

                    # Left click -> move vertex.
                    self.dragging = True
                    self.vertex = vertex
                    self.startcoord = event.pos()
                    # self.moveVertexTo(layerPt)

            elif event.button() == Qt.RightButton:
                if vertex is not None and not self.dragging:
                    # Right click -> delete vertex.
                    self.delete_vertex(vertex)

                    if self.find_on_feature(event.pos(), tolerance):  # If cursor still over track
                        vertex = self.find_vertex_at(event.pos(), tolerance)
                        if vertex is None:  # Cursor is between vertexes
                            self.show_mid_point(event.pos())
                        else:  # Cursor is over a vertex
                            self.show_waypoint_distances(vertex)
                    else:
                        self.show_dist_and_bearing_to_point()

    def transform_coordinates(self, canvas_pt):
        return (self.toMapCoordinates(canvas_pt),
                self.toLayerCoordinates(self.layer, canvas_pt))

    def canvasMoveEvent(self, event):
        if self.dragging:
            self.move_vertex_to(self.toLayerCoordinates(self.layer, event.pos()))
            self.mission_track.hide_start_end_markers()
            self.vertex_marker.hide()
            self.start_end_marker.hide_markers()
            self.show_waypoint_distances(self.vertex)

        else:
            tolerance = self.calc_tolerance()
            if self.find_on_feature(event.pos(), tolerance):  # if mouse is over the track
                self.point_cursor_band.reset(QgsWkbTypes.LineGeometry)
                self.mid_point_band.reset(QgsWkbTypes.PointGeometry)
                vertex = self.find_vertex_at(event.pos(), tolerance)

                if vertex is None:  # Cursor is between vertexes
                    self.show_mid_point(event.pos())
                else:  # Cursor is over a vertex
                    self.show_waypoint_distances(vertex)

            else:
                self.mid_point_band.reset(QgsWkbTypes.PointGeometry)
                self.show_dist_and_bearing_to_point()

    def show_dist_and_bearing_to_point(self):
        """
        Finds distance and bearing from the last point (first if pressing ctrl) to the specified point and shows them
        in the message log. Also draws a line between the points.
        """
        bearing = 0.0

        self.point_cursor_band.reset(QgsWkbTypes.LineGeometry)
        point = self.canvas().mouseLastXY()
        if len(self.wp) > 0:
            cursor_point = self.toMapCoordinates(point)
            if self.mCtrl:
                anchor_point = QgsPointXY(self.wp[0])
            else:
                anchor_point = QgsPointXY(self.wp[len(self.wp) - 1])
            self.point_cursor_band.addPoint(cursor_point)
            self.point_cursor_band.addPoint(anchor_point)
            distance = self.distance_calc.measureLine([anchor_point, cursor_point])
            if distance != 0.0:
                bearing = self.distance_calc.bearing(anchor_point, cursor_point)
            self.msglog.logMessage("")
            if self.mCtrl:
                msg = "Distance to next point: "
            else:
                msg = "Distance to previous point: "
            self.msglog.logMessage(msg + "{:.3F} m.  Bearing: {:.3F} º.".format(distance, math.degrees(bearing)),
                                   "Distance and bearing", 0)
        else:
            self.msglog.logMessage("")

    def show_mid_point(self, cursor):
        """
        Finds the projection of the cursor over the track and draws a circle in that point.
        Finds the distances between this projection point and the previous and next points in the mission
        and shows them in the message log.
        :param cursor: position to be projected over the track
        """
        prev_vertex = self.find_segment_at(cursor)
        prev_point = QgsPointXY(self.wp[prev_vertex])
        next_point = QgsPointXY(self.wp[prev_vertex + 1])
        cursor_point = self.toMapCoordinates(cursor)
        intersection = intersect_point_to_line(cursor_point, prev_point, next_point)
        self.mid_point_band.addPoint(intersection)
        distance1 = self.distance_calc.measureLine([prev_point, intersection])
        distance2 = self.distance_calc.measureLine([intersection, next_point])
        self.msglog.logMessage("")
        self.msglog.logMessage("Distance to previous point: {:.3F} m.  Distance to next point: {:.3F} m."
                               .format(distance1, distance2), "Distance between points", 0)

    def show_waypoint_distances(self, vertex):
        """
        Finds the distances to adjacent waypoints of vertex and shows them in the message log
        :param vertex: index of the waypoint from the mission
        """
        curr_point = self.rubber_band_points.getPoint(QgsWkbTypes.PointGeometry, vertex)
        if vertex == 0:
            if len(self.wp) > 1:
                next_point = QgsPointXY(self.wp[vertex+1])
                distance = self.distance_calc.measureLine([curr_point, next_point])
                bearing = self.distance_calc.bearing(next_point, curr_point)
                msg = "Distance to next point: {:.3F} m.  Bearing: {:.3F} º.".format(distance, math.degrees(bearing))
            else:
                msg = ""
            self.msglog.logMessage("")
            self.msglog.logMessage(msg+" (Waypoint {}) ".format(vertex+1), "Vertex distances", 0)
        elif vertex == len(self.wp) - 1:
            prev_point = QgsPointXY(self.wp[vertex-1])
            distance = self.distance_calc.measureLine([prev_point, curr_point])
            bearing = self.distance_calc.bearing(prev_point, curr_point)
            msg = "Distance to previous point: {:.3F} m.  Bearing: {:.3F} º.".format(distance, math.degrees(bearing))
            self.msglog.logMessage("")
            self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0)
        else:
            prev_point = QgsPointXY(self.wp[vertex-1])
            next_point = QgsPointXY(self.wp[vertex+1])
            distance1 = self.distance_calc.measureLine(prev_point, curr_point)
            distance2 = self.distance_calc.measureLine(curr_point, next_point)
            msg = "Distance to previous point: {:.3F} m.  Distance to next point: {:.3F} m."\
                .format(distance1, distance2)
            self.msglog.logMessage("")
            self.msglog.logMessage(msg+" (Waypoint {})".format(vertex+1), "Vertex distances", 0)

    def hide_point_cursor_band(self):
        """
        Hides the rubber band drawn from last (or first) point to cursor
        """
        self.point_cursor_band.reset(QgsWkbTypes.LineGeometry)

    def canvasReleaseEvent(self, event):
        if self.dragging and event.button() == Qt.LeftButton:
            self.dragging = False
            self.vertex_marker.show()
            mapPt, layerPt = self.transform_coordinates(event.pos())
            # Check distance with initial point
            dist = math.sqrt(
                (self.startcoord.x() - event.pos().x()) ** 2 + (self.startcoord.y() - event.pos().y()) ** 2)
            tolerance = self.calc_tolerance()
            if dist > tolerance:
                self.move_vertex_to(layerPt)
                self.mission_track.change_position(self.vertex, layerPt)
                self.wp_clicked.emit(self.vertex)
                self.feature = None
                self.vertex = None
                self.layer.updateExtents()
            else:
                # If release point is the same, has been just a click
                self.move_vertex_to(self.toLayerCoordinates(self.layer, QgsPointXY(self.wp[self.vertex])))
                self.wp_clicked.emit(self.vertex)
                self.feature = None
                self.vertex = None

    def calc_tolerance(self):
        """
        Compute the tolerance on canvas

        :return: tolerance
        """
        # 2% of tolerance
        width_tolerance = 0.02 * self.canvas().width()
        height_tolerance =  0.02 * self.canvas().height()
        if width_tolerance < height_tolerance:
            tolerance = width_tolerance
        else:
            tolerance = height_tolerance
        return tolerance

    def move_vertex_to(self, layerPt):
        """
        Move current vertex to layerPt position.

        :param layerPt: layer point
        :type: QgsPointXY
        """
        if len(self.wp) > 1:
            self.rubber_band.movePoint(self.vertex, layerPt)
            self.rubber_band_points.movePoint(self.vertex, layerPt)
        elif len(self.wp) == 1:
            # A rubber band with PointGeometry and only 1 point acts as if it had 2 points, we need to reset it in
            # order to move the point.
            self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
            self.rubber_band_points.addPoint(layerPt)


    def delete_vertex(self, vertex):
        """
        Delete step 'vertex'.
        :param vertex: step

        """
        self.mission_track.remove_step(vertex)
        self.dragging = False
        self.vertex = None

    def find_on_feature(self, pos, tolerance):
        """
        if clicked point has some segment at a smaller distance than tolerance means that we've clicked on the track

        :param pos: The point that we've clicked
        :param tolerance: The tolerance of pos
        :return: bool
        """
        if len(self.wp) > 1:
            dist_to_segment = []
            for v in range(0, len(self.wp) - 1):
                # convert layer coordinates to canvas coordinates
                a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v]))
                b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1]))

                dist_to_segment.append(
                    self.dist_to_segment(a1.x(),
                                         a1.y(),
                                         b1.x(),
                                         b1.y(),
                                         pos.x(),
                                         pos.y()))
                logger.debug("dist to segment: {}".format(dist_to_segment))
                if dist_to_segment[v] < tolerance:
                    return True

            return False
        else:
            # last waypoint
            vertex = self.find_vertex_at(pos, tolerance)
            if vertex is None:
                return False
            else:
                return True

    def find_segment_at(self, pos):
        """
        get the segment that is closer to the clicked point and return its initial vertex

        :param pos: the point that we've clicked
        :return: initial vertex of the segment
        """
        dist_to_segment = []
        for v in range(0, len(self.wp) - 1):
            a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v]))
            b1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v + 1]))
            dist_to_segment.append(self.dist_to_segment(a1.x(),
                                                        a1.y(),
                                                        b1.x(),
                                                        b1.y(),
                                                        pos.x(),
                                                        pos.y()))

        vertex = dist_to_segment.index(min(dist_to_segment))
        return vertex

    def find_vertex_at(self, pos, tolerance):
        """
        get the vertex that is closer to the clicked point


        :param pos: The point that we've clicked
        :param tolerance: The tolerance of pos
        :return: vertex or None
        """
        if len(self.wp) > 0:
            dist_to_vertex = []
            logger.debug("tolerance {}".format(tolerance))
            for v in range(0, len(self.wp)):
                a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v]))
                dist_to_vertex.append(math.sqrt((pos.x() - a1.x()) ** 2 + (pos.y() - a1.y()) ** 2))
                logger.debug("dist to vertex: {}".format(dist_to_vertex))

            vertex = dist_to_vertex.index(min(dist_to_vertex))
            if min(dist_to_vertex) > tolerance:
                return None
            else:
                logger.debug("ON VERTEX")
                return vertex
        else:
            return None

    def dist_to_segment(self, ax, ay, bx, by, cx, cy):
        """
        Computes the minimum distance between a point (cx, cy) and a line segment with endpoints (ax, ay) and (bx, by).
        :param ax: endpoint 1, x-coordinate
        :param ay: endpoint 1, y-coordinate
        :param bx: endpoint 2, x-coordinate
        :param by: endpoint 2, y-coordinate
        :param cx: point, x-coordinate
        :param cy: point, x-coordinate
        :return: minimum distance between point and line segment
        """
        # calculate tolerance
        tolerance = self.calc_tolerance()
        # get distance between points c-a and c-b
        dist_to_a = math.sqrt((cx - ax) ** 2 + (cy - ay) ** 2)
        dist_to_b = math.sqrt((cx - bx) ** 2 + (cy - by) ** 2)
        # if distance to point a or distance to point b is smaller than tolerance, return -1
        if (dist_to_a < tolerance) or (dist_to_b < tolerance):
            return -1

        # if one coordinate are between a coordinates or b coordinates
        if is_between(ax, ay, bx, by, cx, cy):

            y = (by - ay)
            x = (bx - ax)

            # line defined by two points formula
            num = abs((y * cx) - (x * cy) + (bx * ay) - (by * ax))
            den = math.sqrt(y ** 2 + x ** 2)
            dl = num / den
            return dl

        else:
            return tolerance + 1

    def set_geometry(self):
        """
        Save rubber band to geometry of the layer
        """
        if self.layer.featureCount() == 0:
            # no feature yet created
            f = QgsFeature()
            if len(self.wp) == 1:
                f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y())))
            else:
                f.setGeometry(QgsGeometry.fromPolyline(self.wp))
            # self.layer.dataProvider().addFeatures([f])
            self.layer.addFeatures([f])
        else:
            # mission feature present, edit geometry
            feats = self.layer.getFeatures()
            for f in feats:
                if len(self.wp) == 1:
                    self.layer.changeGeometry(f.id(),
                                              QgsGeometry.fromPointXY(QgsPointXY(self.wp[0].x(), self.wp[0].y())))
                else:
                    self.layer.changeGeometry(f.id(), QgsGeometry.fromPolyline(self.wp))
        self.layer.commitChanges()
        self.layer.startEditing()

    def close_band(self):
        self.start_end_marker.close_markers()
        self.vertex_marker.hide()
        self.canvas().scene().removeItem(self.vertex_marker)
        self.vertex_marker = None
        self.mission_track.mission_changed.disconnect()
        self.layer.commitChanges()
        self.rubber_band.hide()
        self.mid_point_band.hide()
        self.rubber_band_points.hide()
        self.point_cursor_band.hide()
        self.canvas().scene().removeItem(self.rubber_band)
        self.canvas().scene().removeItem(self.mid_point_band)
        self.canvas().scene().removeItem(self.rubber_band_points)
        self.canvas().scene().removeItem(self.point_cursor_band)
        self.rubber_band = None
        self.mid_point_band = None
        self.rubber_band_points = None
        self.point_cursor_band = None
        self.msglog.logMessage("")
Beispiel #32
0
class ALKISPolygonInfo(QgsMapTool):
    def __init__(self, plugin):
        QgsMapTool.__init__(self, plugin.iface.mapCanvas())
        self.plugin = plugin
        self.iface = plugin.iface
        self.cursor = QCursor(QPixmap([
            "16 16 3 1",
            "      c None",
            ".     c #FF0000",
            "+     c #FFFFFF",
            "                ",
            "       +.+      ",
            "      ++.++     ",
            "     +.....+    ",
            "    +.     .+   ",
            "   +.   .   .+  ",
            "  +.    .    .+ ",
            " ++.    .    .++",
            " ... ...+... ...",
            " ++.    .    .++",
            "  +.    .    .+ ",
            "   +.   .   .+  ",
            "   ++.     .+   ",
            "    ++.....+    ",
            "      ++.++     ",
            "       +.+      "
        ]))

        self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), self.plugin.PolygonGeometry)
        self.areaMarkerLayer = None

    def canvasPressEvent(self, e):
        if self.areaMarkerLayer is None:
            (layerId, ok) = QgsProject.instance().readEntry("alkis", "/areaMarkerLayer")
            if ok:
                self.areaMarkerLayer = self.plugin.mapLayer(layerId)

        if self.areaMarkerLayer is None:
            QMessageBox.warning(None, "ALKIS", u"Fehler: Flächenmarkierungslayer nicht gefunden!")

    def canvasMoveEvent(self, e):
        if self.rubberBand.numberOfVertices() > 0:
            point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y())
            self.rubberBand.movePoint(point)

    def canvasReleaseEvent(self, e):
        point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y())
        if e.button() == Qt.LeftButton:
            self.rubberBand.addPoint(point)
            return

        QApplication.setOverrideCursor(Qt.WaitCursor)

        if self.rubberBand.numberOfVertices() >= 3:
            g = self.plugin.transform(
                self.rubberBand.asGeometry()
            )

            self.rubberBand.reset(self.plugin.PolygonGeometry)

            fs = self.plugin.highlight(
                where=u"st_intersects(wkb_geometry,st_geomfromtext('POLYGON((%s))'::text,%d))" % (
                    ",".join(["%.3lf %.3lf" % (p[0], p[1]) for p in g.asPolygon()[0]]),
                    self.plugin.getepsg()
                )
            )

            if len(fs) == 0:
                QApplication.restoreOverrideCursor()
                QMessageBox.information(None, u"Fehler", u"Keine Flurstücke gefunden.")
                return

            gmlids = []
            for e in fs:
                gmlids.append(e['gmlid'])

            try:
                s = QSettings("norBIT", "EDBSgen/PRO")
                for i in range(0, len(fs)):
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    sock.connect(("localhost", int(s.value("norGISPort", "6102"))))
                    sock.send("NORGIS_MAIN#EDBS#ALBKEY#{}#{}#".format(fs[i]['flsnr'], 0 if i + 1 == len(fs) else 1).encode("utf-8"))
                    sock.close()

                if win32:
                    window = win32gui.FindWindow(None, s.value("albWin", "norGIS"))
                    win32gui.SetForegroundWindow(window)

            except socket.error:
                QMessageBox.information(None, u"Fehler", u"Verbindung zu norGIS schlug fehl.")
        else:
            self.rubberBand.reset(self.plugin.PolygonGeometry)

        QApplication.restoreOverrideCursor()
class QgsMapToolCaptureSpatialOperand (QgsMapTool):
    """
    QGIS map tool. Draw a point, line, polygon or bounding box
    and convert it to WKT format.
    """
    
    selectionFinished = QtCore.pyqtSignal(str)
    
    def __init__(self, canvas, gmlOperand = "gml:Envelope", srsName="", parent = None):
        QgsMapTool.__init__ (self, canvas)
        self.canvas = canvas
        self.parent = parent
        if gmlOperand == "gml:Point":
            self.minPoints = 1 
            self.maxPoints = 1
            self.isPolygon = False
        elif gmlOperand == "gml:Envelope":
            self.minPoints = 2
            self.maxPoints = 2
            self.isPolygon = True
        elif gmlOperand == "gml:Polygon":
            self.minPoints = 3
            self.maxPoints = 0
            self.isPolygon = True
        elif gmlOperand == "gml:LineString":
            self.minPoints = 2
            self.maxPoints = 0
            self.isPolygon = False
        else:
            pass
        
        self.srsName = srsName
        self.rect = QtCore.QRect() if self.isPolygon and self.maxPoints == 2 else None

        if self.isPolygon:
            self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        else:
            self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)
            
        self.rubberBand.setColor(QtGui.QColor (255, 0,0, 150))
        self.rubberBand.setWidth(1)
        
        self.cursor = QtGui.QCursor (QtCore.Qt.CrossCursor)
        
        self.vertexMarkers = []
        self.captureList = []
        self.crs = QgsCoordinateReferenceSystem()
        self.crs.createFromUserInput(self.srsName)
        self.yx = self.crs.axisInverted()

    def canvasPressEvent(self, event):
        pass
                
    def canvasMoveEvent(self, event):
        if isinstance (self.rect, QtCore.QRect):
            self.rect.setBottomRight(event.pos())
            
        self.moveVertex(self.toMapCoordinates(event.pos()))

    def canvasReleaseEvent(self, event):
        numPoints = self.addVertex(self.toMapCoordinates(event.pos()))
        
        if numPoints == 1 and isinstance (self.rect, QtCore.QRect):
            self.rect.setTopLeft(event.pos())
        
        if  (event.button() == QtCore.Qt.RightButton and numPoints >= self.minPoints) or \
            (numPoints == self.maxPoints):
            self.finishGeom (numPoints)
            
    def keyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.selectionFinished.emit(None)
            
    def activate(self):
        QgsMapTool.activate(self)
        self.canvas.setCursor(self.cursor)
  
    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.canvas.unsetCursor()
        self.clearMapCanvas()
  
    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return False

    def addVertex(self, pt):
        self.rubberBand.addPoint(pt)
        m = QgsVertexMarker(self.canvas)
        m.setCenter(pt)
        self.vertexMarkers.append(m)
        
        #if self.yx: pt = QgsPoint(pt.y(),pt.x())
        self.captureList.append (pt)
        
        return len(self.captureList)

    def moveVertex(self, pt):
        if self.rubberBand.numberOfVertices() > 1:
            if isinstance (self.rect, QtCore.QRect):
                transform = self.canvas.getCoordinateTransform()
                ll = transform.toMapCoordinates( self.rect.left(), self.rect.bottom() );
                ur = transform.toMapCoordinates( self.rect.right(), self.rect.top() );
                self.rubberBand.reset(QGis.Polygon)
                self.rubberBand.addPoint( ll, False )
                self.rubberBand.addPoint( QgsPoint( ur.x(), ll.y() ), False )
                self.rubberBand.addPoint( ur, False )
                self.rubberBand.addPoint( QgsPoint( ll.x(), ur.y() ), True )
            else:
                self.rubberBand.movePoint(pt)
            
    def finishGeom (self, numPoints):
        if self.maxPoints == 1:
            geom = QgsGeometry.fromPoint(self.captureList[0])
        elif self.isPolygon and numPoints == 2:
            geom = QgsGeometry.fromPolyline(self.captureList)
            #geom = QgsGeometry.fromRect(geom.boundingBox())
        elif self.isPolygon:
            geom = QgsGeometry.fromPolygon([self.captureList])
        else:
            geom = QgsGeometry.fromPolyline(self.captureList)

        geom.simplify(0.00001)
        geom.transform(QgsCoordinateTransform(
                                              self.canvas.mapSettings().destinationCrs(),
                                              self.crs))
        
        if self.yx:
            i = 0
            vertex = geom.vertexAt(i)
            while (vertex != QgsPoint(0,0)):
                x = vertex.x()
                y = vertex.y()
                geom.moveVertex(y, x, i)
                i+=1
                vertex = geom.vertexAt(i) 
        
        self.selectionFinished.emit(geom.exportToWkt())
        self.clearMapCanvas()

    def clearMapCanvas(self):
        """
        Clears the map canvas and in particular the rubberband.
        A warning is thrown when the markers are removed.
        """
        # Reset the capture list
        self.captureList = []

        # Create an empty rubber band
        if self.isPolygon:
            self.rubberBand.reset(QGis.Polygon)
        else:
            self.rubberBand.reset(QGis.Line)

        # Delete also all vertex markers
        for marker in self.vertexMarkers:
            self.canvas.scene().removeItem(marker)
            del marker
  
        self.canvas.refresh()
Beispiel #34
0
class QgepMapToolConnectNetworkElements(QgsMapTool):
    """
    This map tool connects wastewater networkelements.

    It works on two lists of layers:
      source layers with fields with a foreign key to a networkelement
      target layers which depict networkelements (reaches and network nodes)

    The tool will snap to source layers first and once one is chosen to a target layer.

    It will then ask which field(s) should be connected and perform the update on the database
    """

    def __init__(self, iface, action):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.action = action

        self.rbline = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
        self.rbline.setColor(QColor('#f4530e'))
        self.rbline.setWidth(3)
        self.rbmarkers = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rbmarkers.setColor(QColor('#f4530e'))
        self.rbmarkers.setIconSize(6)

        self.source_snapper = QgepAreaSnapper(self.iface.mapCanvas())
        self.target_snapper = QgepAreaSnapper(self.iface.mapCanvas())

        self.source_feature = QgsFeature()
        self.rb_source_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_source_feature.setColor(QColor('#f49e79'))
        self.rb_source_feature.setWidth(3)
        self.target_feature = QgsFeature()
        self.rb_target_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_target_feature.setColor(QColor('#f49e79'))
        self.rb_target_feature.setWidth(3)

    def activate(self):
        """
        Called by QGIS whenever the tool is activated.
        """

        # A dict of layers
        #  and for each layer the fields to use as foreign key
        #  as well as the possible target layers
        # Reaches can be connected to reaches and nodes
        # Catchment areas only to nodes
        self.network_element_sources = {
            QgepLayerManager.layer('vw_qgep_reach'): {
                'fields': [
                    ('rp_to_fk_wastewater_networkelement',
                     QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point To')),
                    ('rp_from_fk_wastewater_networkelement',
                     QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point From'))
                ],
                'target_layers': [
                    QgepLayerManager.layer('vw_wastewater_node'),
                    QgepLayerManager.layer('vw_qgep_reach')
                ]},
            QgepLayerManager.layer('od_catchment_area'): {'fields': [
                ('fk_wastewater_networkelement_rw_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater current')),
                ('fk_wastewater_networkelement_rw_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater planned')),
                ('fk_wastewater_networkelement_ww_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater current')),
                ('fk_wastewater_networkelement_ww_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater planned'))
            ],
                'target_layers': [
                QgepLayerManager.layer('vw_wastewater_node')
            ]}
        }

        self.setSnapLayers(self.source_snapper,
                           self.network_element_sources.keys())

        self.reset()

        self.action.setChecked(True)

        self.iface.mapCanvas().setCursor(QCursor(Qt.CrossCursor))

    def setSnapLayers(self, snapper, layers):
        snap_layers = list()
        for layer in layers:
            if layer:
                snap_layer = QgsSnappingUtils.LayerConfig(
                    layer, QgsPointLocator.All, 16, QgsTolerance.Pixels)
                snap_layers.append(snap_layer)

        snapper.setLayers(snap_layers)
        snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)

    def canvasMoveEvent(self, event):
        """
        When the mouse moves, update the rubberbands.
        """
        pt = event.originalMapPoint()
        snap_match = self.snapper.snapToMap(pt)

        if snap_match.isValid():
            if snap_match.type() != QgsPointLocator.Area:
                pt = snap_match.point()
            self.matchpoint = pt

            if self.source_match:
                # There is already a source feature : snap to target feature
                # candidates
                if self.target_feature.id() != snap_match.featureId():
                    self.target_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_target_feature.setToGeometry(
                        self.target_feature.geometry(), snap_match.layer())
                self.rb_target_feature.show()
                self.rbmarkers.movePoint(pt)
            else:
                # Snapped to source feature, update source feature rubber band
                # and target layer snapper
                if self.source_feature.id() != snap_match.featureId():
                    self.source_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_source_feature.setToGeometry(
                        self.source_feature.geometry(), snap_match.layer())
                    self.setSnapLayers(self.target_snapper, self.network_element_sources[
                                       snap_match.layer()]['target_layers'])
                self.rb_source_feature.show()
                self.rbmarkers.movePoint(pt, 0)
            self.rbmarkers.show()
        else:
            self.rbmarkers.hide()
            if self.source_match:
                self.rb_target_feature.hide()
            else:
                self.rb_source_feature.hide()

        self.rbline.movePoint(pt)

        self.snapresult = snap_match

    def canvasReleaseEvent(self, event):
        """
        On a click update the rubberbands and the snapping results if it's a left click. Reset if it's a right click.
        """
        if event.button() == Qt.LeftButton:
            if self.snapresult.isValid():
                if self.source_match:
                    self.connect_features(self.source_match, self.snapresult)
                else:
                    self.rbline.show()
                    self.rbline.addPoint(self.matchpoint)
                    self.source_match = self.snapresult
                    self.snapper = self.target_snapper
        else:
            self.reset()

    def deactivate(self):
        """
        Called by QGIS whenever this tool is deactivated.
        """
        self.reset()
        self.action.setChecked(False)

    def reset(self):
        """
        Resets the tool to a pristine state
        """
        self.source_match = None
        self.rbline.hide()
        self.rbline.reset()
        self.rbmarkers.hide()
        self.rbmarkers.reset(QGis.Point)
        self.rbmarkers.addPoint(QgsPoint())
        self.snapresult = None
        self.source_match = None
        self.snapper = self.source_snapper
        self.source_feature = QgsFeature()
        self.target_feature = QgsFeature()
        self.rb_source_feature.reset()
        self.rb_target_feature.reset()

    def get_feature_for_match(self, match):
        """
        Get the feature for a snapping result
        @param match: The QgsPointLocator.SnapMatch object
        @return: A feature
        """
        return next(match.layer().getFeatures(QgsFeatureRequest().setFilterFid(match.featureId())))

    def connect_features(self, source, target):
        """
        Connects the source feature with the target feature.

        @param source: A QgsPointLocator.Match object. Its foreign key will be updated.
                       A dialog will be opened which asks the user for which foreign key(s) he wants to update.
        @param target: A QgsPointLocator.Match object. This feature will be used as link target.
                       Its obj_id attribute will be used as primary key.
        """
        dlg = QDialog(self.iface.mainWindow())
        dlg.setWindowTitle(self.tr('Select properties to connect'))
        dlg.setLayout(QFormLayout())

        properties = list()

        for prop in self.network_element_sources[source.layer()]['fields']:
            cbx = QCheckBox(prop[1])
            cbx.setObjectName(prop[0])
            properties.append(cbx)
            dlg.layout().addWidget(cbx)

        btn_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        dlg.layout().addWidget(btn_box)
        btn_box.accepted.connect(dlg.accept)
        btn_box.rejected.connect(dlg.reject)

        source_feature = self.get_feature_for_match(source)
        target_feature = self.get_feature_for_match(target)

        if dlg.exec_():
            for cbx in properties:
                if cbx.isChecked():
                    source_feature[cbx.objectName()] = target_feature['obj_id']
            if source.layer().updateFeature(source_feature):
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr('Connected {} to {}').format(
                                                        source_feature[
                                                            'identifier'],
                                                        target_feature['identifier']),
                                                    QgsMessageBar.INFO, 5)
            else:
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr(
                                                        'Error connecting features'),
                                                    QgsMessageBar.WARNING, 5)

        self.reset()
class SplitMapTool(QgsMapToolEdit):
    def __init__(self, canvas, layer, actionMoveVertices, actionAddVertices,
                 actionRemoveVertices, actionMoveSegment, actionLineClose,
                 actionLineOpen, actionMoveLine):
        super(SplitMapTool, self).__init__(canvas)
        self.canvas = canvas
        self.scene = canvas.scene()
        self.layer = layer
        self.actionMoveVertices = actionMoveVertices
        self.actionAddVertices = actionAddVertices
        self.actionRemoveVertices = actionRemoveVertices
        self.actionMoveSegment = actionMoveSegment
        self.actionLineClose = actionLineClose
        self.actionLineOpen = actionLineOpen
        self.actionMoveLine = actionMoveLine
        self.initialize()

    def initialize(self):
        try:
            self.canvas.renderStarting.disconnect(self.mapCanvasChanged)
        except:
            pass
        self.canvas.renderStarting.connect(self.mapCanvasChanged)
        try:
            self.layer.editingStopped.disconnect(self.stopCapturing)
        except:
            pass
        self.layer.editingStopped.connect(self.stopCapturing)

        self.selectedFeatures = self.layer.selectedFeatures()
        self.rubberBand = None
        self.tempRubberBand = None
        self.capturedPoints = []
        self.capturing = False
        self.setCursor(Qt.CrossCursor)
        self.proj = QgsProject.instance()
        self.labels = []
        self.vertices = []
        self.calculator = QgsDistanceArea()
        self.calculator.setSourceCrs(self.layer.dataProvider().crs(),
                                     QgsProject.instance().transformContext())
        self.calculator.setEllipsoid(
            self.layer.dataProvider().crs().ellipsoidAcronym())
        self.drawingLine = False
        self.movingVertices = False
        self.addingVertices = False
        self.removingVertices = False
        self.movingSegment = False
        self.movingLine = False
        self.showingVertices = False
        self.movingVertex = -1
        self.movingSegm = -1
        self.movingLineInitialPoint = None
        self.lineClosed = False

    def restoreAction(self):
        self.addingVertices = False
        self.removingVertices = False
        self.movingVertices = False
        self.movingSegment = False
        self.movingLine = False
        self.showingVertices = False
        self.drawingLine = True
        self.movingVertex = -1
        self.movingLineInitialPoint = None
        self.deleteVertices()
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.canvas.scene().addItem(self.tempRubberBand)
        self.redrawActions()

    def mapCanvasChanged(self):
        self.redrawAreas()
        if self.showingVertices:
            self.redrawVertices()

    def canvasMoveEvent(self, event):
        if self.drawingLine and not self.lineClosed:
            if self.tempRubberBand != None and self.capturing:
                mapPoint = self.toMapCoordinates(event.pos())
                self.tempRubberBand.movePoint(mapPoint)
                self.redrawAreas(event.pos())

        if self.movingVertices and self.movingVertex >= 0:
            layerPoint = self.toLayerCoordinates(self.layer, event.pos())
            self.capturedPoints[self.movingVertex] = layerPoint

            if self.lineClosed and self.movingVertex == 0:
                self.capturedPoints[len(self.capturedPoints) - 1] = layerPoint

            self.redrawRubberBand()
            self.redrawVertices()
            self.redrawAreas()

        if self.movingSegment and self.movingSegm >= 0:
            currentPoint = self.toLayerCoordinates(self.layer, event.pos())
            distance = self.distancePoint(currentPoint,
                                          self.movingLineInitialPoint)
            bearing = self.movingLineInitialPoint.azimuth(currentPoint)

            self.capturedPoints[self.movingSegm] = self.projectPoint(
                self.capturedPoints[self.movingSegm], distance, bearing)
            self.capturedPoints[self.movingSegm + 1] = self.projectPoint(
                self.capturedPoints[self.movingSegm + 1], distance, bearing)

            if self.lineClosed:
                if self.movingSegm == 0:
                    self.capturedPoints[
                        len(self.capturedPoints) - 1] = self.projectPoint(
                            self.capturedPoints[len(self.capturedPoints) - 1],
                            distance, bearing)
                elif self.movingSegm == len(self.capturedPoints) - 2:
                    self.capturedPoints[0] = self.projectPoint(
                        self.capturedPoints[0], distance, bearing)

            self.redrawRubberBand()
            self.redrawVertices()
            self.redrawAreas()
            self.movingLineInitialPoint = currentPoint

        if self.movingLine and self.movingLineInitialPoint != None:
            currentPoint = self.toLayerCoordinates(self.layer, event.pos())
            distance = self.distancePoint(currentPoint,
                                          self.movingLineInitialPoint)
            bearing = self.movingLineInitialPoint.azimuth(currentPoint)
            for i in range(len(self.capturedPoints)):
                self.capturedPoints[i] = self.projectPoint(
                    self.capturedPoints[i], distance, bearing)
            self.redrawRubberBand()
            self.redrawAreas()
            self.movingLineInitialPoint = currentPoint

    def projectPoint(self, point, distance, bearing):
        rads = bearing * pi / 180.0
        dx = distance * sin(rads)
        dy = distance * cos(rads)
        return QgsPointXY(point.x() + dx, point.y() + dy)

    def redrawAreas(self, mousePos=None):
        self.deleteLabels()

        if self.capturing and len(self.capturedPoints) > 0:
            for i in range(len(self.selectedFeatures)):
                geometry = QgsGeometry(self.selectedFeatures[i].geometry())
                movingPoints = list(self.capturedPoints)

                if mousePos != None:
                    movingPoints.append(
                        self.toLayerCoordinates(self.layer, mousePos))

                result, newGeometries, topoTestPoints = geometry.splitGeometry(
                    movingPoints, self.proj.topologicalEditing())

                self.addLabel(geometry)
                if newGeometries != None and len(newGeometries) > 0:
                    for i in range(len(newGeometries)):
                        self.addLabel(newGeometries[i])

    def addLabel(self, geometry):
        area = self.calculator.measureArea(geometry)
        labelPoint = geometry.pointOnSurface().vertexAt(0)
        label = QGraphicsTextItem("%.2f" % round(area, 2))
        label.setHtml(
            "<div style=\"color:#ffffff;background:#111111;padding:5px\">" +
            "%.2f" % round(area, 2) + " " +
            areaUnits[self.calculator.areaUnits()] + "</div>")
        point = self.toMapCoordinatesV2(self.layer, labelPoint)
        label.setPos(self.toCanvasCoordinates(QgsPointXY(point.x(),
                                                         point.y())))

        self.scene.addItem(label)
        self.labels.append(label)

    def deleteLabels(self):
        for i in range(len(self.labels)):
            self.scene.removeItem(self.labels[i])
        self.labels = []

    def canvasPressEvent(self, event):
        if self.movingVertices:
            for i in range(len(self.capturedPoints)):
                point = self.toMapCoordinates(self.layer,
                                              self.capturedPoints[i])
                currentVertex = self.toCanvasCoordinates(
                    QgsPointXY(point.x(), point.y()))
                if self.distancePoint(event.pos(),
                                      currentVertex) <= maxDistanceHitTest:
                    self.movingVertex = i
                    break

        if self.movingSegment:
            for i in range(len(self.capturedPoints) - 1):
                vertex1 = self.toMapCoordinates(self.layer,
                                                self.capturedPoints[i])
                currentVertex1 = self.toCanvasCoordinates(
                    QgsPointXY(vertex1.x(), vertex1.y()))
                vertex2 = self.toMapCoordinates(self.layer,
                                                self.capturedPoints[i + 1])
                currentVertex2 = self.toCanvasCoordinates(
                    QgsPointXY(vertex2.x(), vertex2.y()))
                if self.distancePointLine(
                        event.pos().x(),
                        event.pos().y(), currentVertex1.x(),
                        currentVertex1.y(), currentVertex2.x(),
                        currentVertex2.y()) <= maxDistanceHitTest:
                    self.movingSegm = i
                    break

        self.movingLineInitialPoint = self.toLayerCoordinates(
            self.layer, event.pos())

    def distancePoint(self, eventPos, vertexPos):
        return sqrt((eventPos.x() - vertexPos.x())**2 +
                    (eventPos.y() - vertexPos.y())**2)

    def canvasReleaseEvent(self, event):
        if self.movingVertices or self.movingSegment or self.movingLine:
            if event.button() == Qt.RightButton:
                self.finishOperation()
        elif self.addingVertices:
            if event.button() == Qt.LeftButton:
                self.addVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()
        elif self.removingVertices:
            if event.button() == Qt.LeftButton:
                self.removeVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()
        else:
            if event.button() == Qt.LeftButton:
                if not self.lineClosed:
                    if not self.capturing:
                        self.startCapturing()
                    self.addEndingVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()

        self.movingVertex = -1
        self.movingSegm = -1
        self.movingLineInitialPoint = None
        self.redrawActions()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.stopCapturing()
        if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete:
            self.removeLastVertex()
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
            self.finishOperation()

        event.accept()
        self.redrawActions()

    def finishOperation(self):
        self.doSplit()
        self.stopCapturing()
        self.initialize()
        self.startCapturing()

    def doSplit(self):
        if self.capturedPoints != None:
            self.layer.splitFeatures(self.capturedPoints,
                                     self.proj.topologicalEditing())

    def startCapturing(self):
        self.prepareRubberBand()
        self.prepareTempRubberBand()

        self.drawingLine = True
        self.capturing = True

        self.redrawActions()

    def prepareRubberBand(self):
        color = QColor("red")
        color.setAlphaF(0.78)

        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubberBand.setWidth(1)
        self.rubberBand.setColor(color)
        self.rubberBand.show()

    def prepareTempRubberBand(self):
        color = QColor("red")
        color.setAlphaF(0.78)

        self.tempRubberBand = QgsRubberBand(self.canvas,
                                            QgsWkbTypes.LineGeometry)
        self.tempRubberBand.setWidth(1)
        self.tempRubberBand.setColor(color)
        self.tempRubberBand.setLineStyle(Qt.DotLine)
        self.tempRubberBand.show()

    def redrawRubberBand(self):
        self.canvas.scene().removeItem(self.rubberBand)
        self.prepareRubberBand()
        for i in range(len(self.capturedPoints)):
            point = self.capturedPoints[i]
            if point.__class__ == QgsPoint:
                vertexCoord = self.toMapCoordinatesV2(self.layer,
                                                      self.capturedPoints[i])
                vertexCoord = QgsPointXY(vertexCoord.x(), vertexCoord.y())
            else:
                vertexCoord = self.toMapCoordinates(self.layer,
                                                    self.capturedPoints[i])

            self.rubberBand.addPoint(vertexCoord)

    def redrawTempRubberBand(self):
        if self.tempRubberBand != None:
            self.tempRubberBand.reset(QgsWkbTypes.LineGeometry)
            self.tempRubberBand.addPoint(
                self.toMapCoordinates(
                    self.layer,
                    self.capturedPoints[len(self.capturedPoints) - 1]))

    def stopCapturing(self):
        self.deleteLabels()
        self.deleteVertices()
        if self.rubberBand:
            self.canvas.scene().removeItem(self.rubberBand)
            self.rubberBand = None
        if self.tempRubberBand:
            self.canvas.scene().removeItem(self.tempRubberBand)
            self.tempRubberBand = None
        self.drawingLine = False
        self.movingVertices = False
        self.showingVertices = False
        self.capturing = False
        self.capturedPoints = []
        self.canvas.refresh()

        self.redrawActions()

    def addEndingVertex(self, canvasPoint):
        mapPoint = self.toMapCoordinates(canvasPoint)
        layerPoint = self.toLayerCoordinates(self.layer, canvasPoint)

        self.rubberBand.addPoint(mapPoint)
        self.capturedPoints.append(layerPoint)

        self.tempRubberBand.reset(QgsWkbTypes.LineGeometry)
        self.tempRubberBand.addPoint(mapPoint)

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

        rubberBandSize = self.rubberBand.numberOfVertices()
        tempRubberBandSize = self.tempRubberBand.numberOfVertices()
        numPoints = len(self.capturedPoints)

        if rubberBandSize < 1 or numPoints < 1:
            return

        self.rubberBand.removePoint(-1)

        if rubberBandSize > 1:
            if tempRubberBandSize > 1:
                point = self.rubberBand.getPoint(0, rubberBandSize - 2)
                self.tempRubberBand.movePoint(tempRubberBandSize - 2, point)
        else:
            self.tempRubberBand.reset(self.bandType())

        del self.capturedPoints[-1]

    def addVertex(self, pos):
        newCapturedPoints = []
        for i in range(len(self.capturedPoints) - 1):
            newCapturedPoints.append(self.capturedPoints[i])
            vertex1 = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            currentVertex1 = self.toCanvasCoordinates(
                QgsPointXY(vertex1.x(), vertex1.y()))
            vertex2 = self.toMapCoordinates(self.layer,
                                            self.capturedPoints[i + 1])
            currentVertex2 = self.toCanvasCoordinates(
                QgsPointXY(vertex2.x(), vertex2.y()))

            distance = self.distancePointLine(pos.x(), pos.y(),
                                              currentVertex1.x(),
                                              currentVertex1.y(),
                                              currentVertex2.x(),
                                              currentVertex2.y())
            if distance <= maxDistanceHitTest:
                layerPoint = self.toLayerCoordinates(self.layer, pos)
                newCapturedPoints.append(layerPoint)

        newCapturedPoints.append(self.capturedPoints[len(self.capturedPoints) -
                                                     1])
        self.capturedPoints = newCapturedPoints

        self.redrawRubberBand()
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def removeVertex(self, pos):
        deletedFirst = False
        deletedLast = False
        newCapturedPoints = []
        for i in range(len(self.capturedPoints)):
            vertex = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            currentVertex = self.toCanvasCoordinates(
                QgsPointXY(vertex.x(), vertex.y()))
            if not self.distancePoint(pos,
                                      currentVertex) <= maxDistanceHitTest:
                newCapturedPoints.append(self.capturedPoints[i])
            elif i == 0:
                deletedFirst = True
            elif i == len(self.capturedPoints) - 1:
                deletedLast = True

        self.capturedPoints = newCapturedPoints

        if deletedFirst and deletedLast:
            self.lineClosed = False

        self.redrawRubberBand()
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

        if len(self.capturedPoints) <= 2:
            self.stopRemovingVertices()

    def startMovingVertices(self):
        self.stopMovingLine()
        self.stopAddingVertices()
        self.stopRemovingVertices()
        self.stopMovingSegment()

        self.actionMoveVertices.setChecked(True)
        self.movingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopMovingVertices(self):
        self.movingVertices = False
        self.actionMoveVertices.setChecked(False)
        self.restoreAction()

    def startAddingVertices(self):
        self.stopMovingVertices()
        self.stopRemovingVertices()
        self.stopMovingLine()
        self.stopMovingSegment()

        self.actionAddVertices.setChecked(True)
        self.addingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopAddingVertices(self):
        self.addVertices = False
        self.actionAddVertices.setChecked(False)
        self.restoreAction()

    def startRemovingVertices(self):
        self.stopMovingVertices()
        self.stopAddingVertices()
        self.stopMovingLine()
        self.stopMovingSegment()

        self.actionRemoveVertices.setChecked(True)
        self.removingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopRemovingVertices(self):
        self.removingVertices = False
        self.actionRemoveVertices.setChecked(False)
        self.restoreAction()

    def startMovingSegment(self):
        self.stopMovingVertices()
        self.stopMovingLine()
        self.stopAddingVertices()
        self.stopRemovingVertices()

        self.actionMoveSegment.setChecked(True)
        self.movingSegment = True
        self.showingVertices = False
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopMovingSegment(self):
        self.movingSegment = False
        self.actionMoveSegment.setChecked(False)
        self.restoreAction()

    def startMovingLine(self):
        self.stopMovingVertices()
        self.stopAddingVertices()
        self.stopRemovingVertices()
        self.stopMovingSegment()

        self.actionMoveLine.setChecked(True)
        self.movingLine = True
        self.showingVertices = False
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawAreas()
        self.redrawActions()

    def stopMovingLine(self):
        self.actionMoveLine.setChecked(False)
        self.restoreAction()

    def lineClose(self):
        self.lineClosed = True
        self.capturedPoints.append(self.capturedPoints[0])
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.redrawAreas()
        self.redrawActions()

    def lineOpen(self):
        self.lineClosed = False
        del self.capturedPoints[-1]
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.redrawAreas()
        self.redrawActions()

    def showVertices(self):
        for i in range(len(self.capturedPoints)):
            vertexc = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            vertexCoords = self.toCanvasCoordinates(
                QgsPointXY(vertexc.x(), vertexc.y()))
            if i == self.movingVertex:
                vertex = self.scene.addRect(vertexCoords.x() - 5,
                                            vertexCoords.y() - 5, 10, 10,
                                            QPen(QColor("green")),
                                            QBrush(QColor("green")))
                self.vertices.append(vertex)
            elif i == len(self.capturedPoints
                          ) - 1 and self.movingVertex == 0 and self.lineClosed:
                vertex = self.scene.addRect(vertexCoords.x() - 5,
                                            vertexCoords.y() - 5, 10, 10,
                                            QPen(QColor("green")),
                                            QBrush(QColor("green")))
                self.vertices.append(vertex)
            else:
                vertex = self.scene.addRect(vertexCoords.x() - 4,
                                            vertexCoords.y() - 4, 8, 8,
                                            QPen(QColor("red")),
                                            QBrush(QColor("red")))
                self.vertices.append(vertex)

    def deleteVertices(self):
        for i in range(len(self.vertices)):
            self.scene.removeItem(self.vertices[i])
        self.vertices = []

    def lineMagnitude(self, x1, y1, x2, y2):
        return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2))

    def distancePointLine(self, px, py, x1, y1, x2, y2):
        magnitude = self.lineMagnitude(x1, y1, x2, y2)

        if magnitude < 0.00000001:
            distance = 9999
            return distance

        u1 = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1)))
        u = u1 / (magnitude * magnitude)

        if (u < 0.00001) or (u > 1):
            ix = self.lineMagnitude(px, py, x1, y1)
            iy = self.lineMagnitude(px, py, x2, y2)
            if ix > iy:
                distance = iy
            else:
                distance = ix
        else:
            ix = x1 + u * (x2 - x1)
            iy = y1 + u * (y2 - y1)
            distance = self.lineMagnitude(px, py, ix, iy)

        return distance

    def redrawVertices(self):
        self.deleteVertices()
        self.showVertices()

    def redrawActions(self):
        self.redrawActionMoveVertices()
        self.redrawActionAddVertices()
        self.redrawActionRemoveVertices()
        self.redrawActionMoveSegment()
        self.redrawActionLineClose()
        self.redrawActionLineOpen()
        self.redrawActionMoveLine()

    def redrawActionMoveVertices(self):
        self.actionMoveVertices.setEnabled(False)
        if len(self.capturedPoints) > 0:
            self.actionMoveVertices.setEnabled(True)

    def redrawActionAddVertices(self):
        self.actionAddVertices.setEnabled(False)
        if len(self.capturedPoints) >= 2:
            self.actionAddVertices.setEnabled(True)

    def redrawActionRemoveVertices(self):
        self.actionRemoveVertices.setEnabled(False)
        if len(self.capturedPoints) > 2:
            self.actionRemoveVertices.setEnabled(True)

    def redrawActionMoveSegment(self):
        self.actionMoveSegment.setEnabled(False)
        if len(self.capturedPoints) > 2:
            self.actionMoveSegment.setEnabled(True)

    def redrawActionLineClose(self):
        self.actionLineClose.setEnabled(False)
        if not self.lineClosed and len(self.capturedPoints) >= 3:
            self.actionLineClose.setEnabled(True)

    def redrawActionLineOpen(self):
        self.actionLineOpen.setEnabled(False)
        if self.lineClosed:
            self.actionLineOpen.setEnabled(True)

    def redrawActionMoveLine(self):
        self.actionMoveLine.setEnabled(False)
        if len(self.capturedPoints) > 0:
            self.actionMoveLine.setEnabled(True)
class VertexTracerTool(QgsMapTool):

    traceFound = pyqtSignal(QgsGeometry)

    def __init__(self, canvas):
        # some stuff we need from qgis
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.snapper = QgsSnappingUtils()
        # some stuff to control our state
        self.mCtrl = False
        self.started = False
        self.firstTimeOnSegment = True
        self.lastPointMustStay = False
        # some stuff to put our temp output
        self.lastPoint = None
        self.rb = None
        self.isPolygon = False

        # our own fancy cursor
        self.cursor = QCursor(
            QPixmap([
                "16 16 3 1", "      c None", ".     c #00FF00",
                "+     c #FFFFFF", "                ", "       +.+      ",
                "      ++.++     ", "     +.....+    ", "    +.     .+   ",
                "   +.   .   .+  ", "  +.    .    .+ ", " ++.    .    .++",
                " ... ...+... ...", " ++.    .    .++", "  +.    .    .+ ",
                "   +.   .   .+  ", "   ++.     .+   ", "    ++.....+    ",
                "      ++.++     ", "       +.+      "
            ]))

    # we need to know, if ctrl-key is pressed
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = True

    # and also if ctrl-key is released
    def keyReleaseEvent(self, event):
        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.rb.removeLastPoint()

    def canvasPressEvent(self, event):
        # on left click, we add a point
        if event.button() == 1:
            layer = self.canvas.currentLayer()
            # if it is the start of a new trace, set the rubberband up
            if not self.started:
                if layer.geometryType() == 1:
                    self.isPolygon = False
                if layer.geometryType() == 2:
                    self.isPolygon = True
                self.rb = QgsRubberBand(self.canvas, layer.geometryType())
                self.rb.setColor(QColor(255, 0, 0))
                # declare, that are we going to work, now!
            self.started = True
            if layer is not None:
                x = event.pos().x()
                y = event.pos().y()
                selPoint = QPoint(x, y)
                # try to get something snapped
                (retval,
                 result) = self.snapper.snapToBackgroundLayers(selPoint)

                # 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.rb.movePoint(point)
                # and 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):
        # QgsMessageLog.logMessage('fts: '+str(self.firstTimeOnSegment), 'state', 0)
        # QgsMessageLog.logMessage('lpc: '+str(self.lastPointMustStay), 'state', 0)
        if self.started:
            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x, y)
            # only if the ctrl key is pressed
            if self.mCtrl:
                layer = self.canvas.currentLayer()
                if layer is not None:
                    (retval,
                     result) = self.snapper.snapToBackgroundLayers(eventPoint)

                # so if we have found a snapping
                if result != []:
                    # pydevd.settrace()
                    # that's the snapped point
                    point = QgsPoint(result[0].snappedVertex)
                    # if it is a vertex, not a point on a segment
                    if result[0].snappedVertexNr != -1:
                        self.rb.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.rb.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 segemnt, we have to test, if this point is realy needed
                        else:
                            # but only if we have already enough points
                            # TODO: check if this is correct for lines also (they only need two points, to be vaild)
                            if self.rb.numberOfVertices() >= 3:
                                max = self.rb.numberOfVertices()
                                lastRbP = self.rb.getPoint(0, max - 2)
                                # QgsMessageLog.logMessage(str(self.rb.getPoint(0, max-1)), 'rb', 0)
                                nextToLastRbP = self.rb.getPoint(0, max - 3)
                                # QgsMessageLog.logMessage(str(self.rb.getPoint(0, max-2)), 'rb', 0)
                                # QgsMessageLog.logMessage(str(point), 'rb', 0)
                                if not self.pointOnLine(
                                        lastRbP, nextToLastRbP,
                                        QgsPoint(point)):
                                    self.appendPoint(point)
                                    self.lastPointMustStay = False
                                else:
                                    # TODO: schauen, ob der letzte punkt ein klick war, dann nicht löschen. entsrpechend auch die "punkt auf linie" neu berechenen.
                                    if not self.lastPointMustStay:
                                        self.rb.removeLastPoint()
                                        self.rb.movePoint(point)
                                        # QgsMessageLog.logMessage('point removed', 'click', 0)
                                # else:
                                # QgsMessageLog.logMessage('sleep', 'rb', 0)
                            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.rb.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
                (retval,
                 result) = self.snapper.snapToBackgroundLayers(eventPoint)
                if result != []:
                    point = QgsPoint(result[0].snappedVertex)
                else:
                    point = QgsMapToPixel.toMapCoordinates(
                        self.canvas.getCoordinateTransform(), x, y)
                self.rb.movePoint(point)

    def canvasReleaseEvent(self, event):
        # with right click the digitizing is finished
        if event.button() == 2:

            layer = self.canvas.currentLayer()
            x = event.pos().x()
            y = event.pos().y()
            if layer is not None and self.started:
                selPoint = QPoint(x, y)
                (retval,
                 result) = self.snapper.snapToBackgroundLayers(selPoint)

                if result != []:
                    point = result[0].snappedVertex
                else:
                    point = QgsMapToPixel.toMapCoordinates(
                        self.canvas.getCoordinateTransform(), x, y)

                # add this last point
                self.appendPoint(QgsPoint(point))
                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.rb.addPoint(point)
            self.lastPoint = QgsPoint(point)
        else:
            pass

    # see: double QgsGeometryValidator::distLine2Point( QgsPoint p, QgsVector v, QgsPoint q )
    # distance of point q from line through p in direction v
    def pointOnLine(self, pntAft, pntBef, pntTest):
        p = QgsPoint(pntAft)
        vx = pntBef.x() - pntAft.x()
        vy = pntBef.y() - pntAft.y()
        vlength = math.sqrt(vy * vy + vx * vx)
        if vlength == 0:
            return False
        q = QgsPoint(pntTest)

        res = (vx * (q.y() - p.y()) - vy * (q.x() - p.x())) / vlength
        # res = 0 means point is on line, but we are not in a perfect world, so a tolerance is needed
        # to get rid of some numerical problems. Tolerance estimated by solid engenieering work (rule of thumb...)
        if res < 1E-10:
            return True
        else:
            return False

    def sendGeometry(self):
        layer = self.canvas.currentLayer()
        coords = []

        # backward compatiblity for a bug in qgsRubberband, that was fixed in 1.7
        if Qgis.QGIS_VERSION_INT >= 10700:
            [
                coords.append(self.rb.getPoint(0, i))
                for i in range(self.rb.numberOfVertices())
            ]
        else:
            [
                coords.append(self.rb.getPoint(0, i))
                for i in range(1, self.rb.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)

        coords_tmp = coords[:]
        coords = []
        lastPt = None
        for pt in coords_tmp:
            if (lastPt != pt):
                coords.append(pt)
                lastPt = pt

        # Add geometry to feature.
        if self.isPolygon:
            g = QgsGeometry().fromPolygon([coords])
        else:
            g = QgsGeometry().fromPolyline(coords)

        self.traceFound.emit(g)
        self.rb.reset(self.isPolygon)
        self.started = False

    def activate(self):
        self.canvas.setCursor(self.cursor)

    def deactivate(self):
        try:
            self.rb.reset()
        except AttributeError:
            pass

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True
class QgsMapToolCaptureSpatialOperand(QgsMapTool):
    """
    QGIS map tool. Draw a point, line, polygon or bounding box
    and convert it to WKT format.
    """

    selectionFinished = QtCore.pyqtSignal(str)

    def __init__(self,
                 canvas,
                 gmlOperand="gml:Envelope",
                 srsName="",
                 parent=None):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.parent = parent
        if gmlOperand == "gml:Point":
            self.minPoints = 1
            self.maxPoints = 1
            self.isPolygon = False
        elif gmlOperand == "gml:Envelope":
            self.minPoints = 2
            self.maxPoints = 2
            self.isPolygon = True
        elif gmlOperand == "gml:Polygon":
            self.minPoints = 3
            self.maxPoints = 0
            self.isPolygon = True
        elif gmlOperand == "gml:LineString":
            self.minPoints = 2
            self.maxPoints = 0
            self.isPolygon = False
        else:
            pass

        self.srsName = srsName
        self.rect = QtCore.QRect(
        ) if self.isPolygon and self.maxPoints == 2 else None

        if self.isPolygon:
            self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        else:
            self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)

        self.rubberBand.setColor(QtGui.QColor(255, 0, 0, 150))
        self.rubberBand.setWidth(1)

        self.cursor = QtGui.QCursor(QtCore.Qt.CrossCursor)

        self.vertexMarkers = []
        self.captureList = []
        self.crs = QgsCoordinateReferenceSystem()
        self.crs.createFromUserInput(self.srsName)
        self.yx = self.crs.axisInverted()

    def canvasPressEvent(self, event):
        pass

    def canvasMoveEvent(self, event):
        if isinstance(self.rect, QtCore.QRect):
            self.rect.setBottomRight(event.pos())

        self.moveVertex(self.toMapCoordinates(event.pos()))

    def canvasReleaseEvent(self, event):
        numPoints = self.addVertex(self.toMapCoordinates(event.pos()))

        if numPoints == 1 and isinstance(self.rect, QtCore.QRect):
            self.rect.setTopLeft(event.pos())

        if  (event.button() == QtCore.Qt.RightButton and numPoints >= self.minPoints) or \
            (numPoints == self.maxPoints):
            self.finishGeom(numPoints)

    def keyReleaseEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.selectionFinished.emit(None)

    def activate(self):
        QgsMapTool.activate(self)
        self.canvas.setCursor(self.cursor)

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.canvas.unsetCursor()
        self.clearMapCanvas()

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return False

    def addVertex(self, pt):
        self.rubberBand.addPoint(pt)
        m = QgsVertexMarker(self.canvas)
        m.setCenter(pt)
        self.vertexMarkers.append(m)

        #if self.yx: pt = QgsPoint(pt.y(),pt.x())
        self.captureList.append(pt)

        return len(self.captureList)

    def moveVertex(self, pt):
        if self.rubberBand.numberOfVertices() > 1:
            if isinstance(self.rect, QtCore.QRect):
                transform = self.canvas.getCoordinateTransform()
                ll = transform.toMapCoordinates(self.rect.left(),
                                                self.rect.bottom())
                ur = transform.toMapCoordinates(self.rect.right(),
                                                self.rect.top())
                self.rubberBand.reset(QGis.Polygon)
                self.rubberBand.addPoint(ll, False)
                self.rubberBand.addPoint(QgsPoint(ur.x(), ll.y()), False)
                self.rubberBand.addPoint(ur, False)
                self.rubberBand.addPoint(QgsPoint(ll.x(), ur.y()), True)
            else:
                self.rubberBand.movePoint(pt)

    def finishGeom(self, numPoints):
        if self.maxPoints == 1:
            geom = QgsGeometry.fromPoint(self.captureList[0])
        elif self.isPolygon and numPoints == 2:
            geom = QgsGeometry.fromPolyline(self.captureList)
            #geom = QgsGeometry.fromRect(geom.boundingBox())
        elif self.isPolygon:
            geom = QgsGeometry.fromPolygon([self.captureList])
        else:
            geom = QgsGeometry.fromPolyline(self.captureList)

        geom.simplify(0.00001)
        geom.transform(
            QgsCoordinateTransform(self.canvas.mapSettings().destinationCrs(),
                                   self.crs))

        if self.yx:
            i = 0
            vertex = geom.vertexAt(i)
            while (vertex != QgsPoint(0, 0)):
                x = vertex.x()
                y = vertex.y()
                geom.moveVertex(y, x, i)
                i += 1
                vertex = geom.vertexAt(i)

        self.selectionFinished.emit(geom.exportToWkt())
        self.clearMapCanvas()

    def clearMapCanvas(self):
        """
        Clears the map canvas and in particular the rubberband.
        A warning is thrown when the markers are removed.
        """
        # Reset the capture list
        self.captureList = []

        # Create an empty rubber band
        if self.isPolygon:
            self.rubberBand.reset(QGis.Polygon)
        else:
            self.rubberBand.reset(QGis.Line)

        # Delete also all vertex markers
        for marker in self.vertexMarkers:
            self.canvas.scene().removeItem(marker)
            del marker

        self.canvas.refresh()
class MeasureTool(QgsMapTool):
    '''
    classdocs
    '''
    def __init__(self, canvas, txtBearing, disType=DistanceUnits.M):
        '''
        Constructor
        '''
        self.canvas = canvas
        self.txtBearing = txtBearing
        QgsMapTool.__init__(self, self.canvas)
        self.mSnapper = QgsMapCanvasSnapper(self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.rubberBandPt = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandPt.setColor(Qt.red)
        self.rubberBandPt.setWidth(10)
        self.type = disType
        self.reset()

    def reset(self):
        self.startPoint = None
        self.endPoint = None
        self.isDrawing = False
        self.distance = 0.0

    def canvasReleaseEvent(self, e):
        if (e.button() == Qt.RightButton):
            self.reset()
            self.emit(SIGNAL("captureFinished"))
        else:
            self.rubberBandPt.reset(QGis.Point)
            snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper,
                                             define._canvas, True)
            if self.startPoint == None:
                self.rubberBand.reset(QGis.Line)
                if snapPoint == None:
                    self.startPoint = self.toMapCoordinates(e.pos())
                else:
                    self.startPoint = snapPoint
                self.rubberBand.addPoint(self.startPoint)
                self.isDrawing = True
            else:
                if snapPoint == None:
                    self.endPoint = self.toMapCoordinates(e.pos())
                else:
                    self.endPoint = snapPoint
                self.rubberBand.addPoint(self.endPoint)
                dist = MathHelper.calcDistance(self.startPoint, self.endPoint)

                self.distance = self.distance + dist
                if self.type == DistanceUnits.M:
                    self.txtBearing.setText("%f" % round(self.distance, 4))
                elif self.type == DistanceUnits.NM:
                    self.txtBearing.setText(
                        "%f" % round(Unit.ConvertMeterToNM(self.distance), 4))
                elif self.type == DistanceUnits.FT:
                    self.txtBearing.setText(
                        "%f" %
                        round(Unit.ConvertMeterToFeet(self.distance), 4))
                elif self.type == DistanceUnits.KM:
                    self.txtBearing.setText("%f" % round(
                        (self.distance / 1000), 4))
                elif self.type == DistanceUnits.MM:
                    self.txtBearing.setText(str(int(self.distance * 1000)))
                self.startPoint = self.endPoint

    def canvasMoveEvent(self, e):
        self.rubberBandPt.reset(QGis.Point)
        snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper,
                                         define._canvas, True)
        if snapPoint != None:
            self.rubberBandPt.addPoint(snapPoint)
            self.rubberBandPt.show()
        if self.isDrawing:
            if self.isDrawing:
                if snapPoint == None:
                    self.endPoint = self.toMapCoordinates(e.pos())
                else:
                    self.endPoint = snapPoint
            self.rubberBand.movePoint(self.endPoint)
            dist1 = MathHelper.calcDistance(self.startPoint, self.endPoint)
            dist1 = self.distance + dist1
            if self.type == DistanceUnits.M:
                self.txtBearing.setText("%f" % round(dist1, 4))
            elif self.type == DistanceUnits.NM:
                self.txtBearing.setText("%f" %
                                        round(Unit.ConvertMeterToNM(dist1), 4))
            elif self.type == DistanceUnits.FT:
                self.txtBearing.setText(
                    "%f" % round(Unit.ConvertMeterToFeet(dist1), 4))
            elif self.type == DistanceUnits.KM:
                self.txtBearing.setText("%f" % round((dist1 / 1000), 4))
            elif self.type == DistanceUnits.MM:
                self.txtBearing.setText(str(int(dist1 * 1000)))

    def deactivate(self):
        self.rubberBandPt.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Beispiel #39
0
class ALKISPolygonInfo(QgsMapTool):
    def __init__(self, plugin):
        QgsMapTool.__init__(self, plugin.iface.mapCanvas())
        self.plugin = plugin
        self.iface = plugin.iface
        self.cursor = QCursor(QPixmap([
            "16 16 3 1",
            "      c None",
            ".     c #FF0000",
            "+     c #FFFFFF",
            "                ",
            "       +.+      ",
            "      ++.++     ",
            "     +.....+    ",
            "    +.     .+   ",
            "   +.   .   .+  ",
            "  +.    .    .+ ",
            " ++.    .    .++",
            " ... ...+... ...",
            " ++.    .    .++",
            "  +.    .    .+ ",
            "   +.   .   .+  ",
            "   ++.     .+   ",
            "    ++.....+    ",
            "      ++.++     ",
            "       +.+      "
        ]))

        self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), self.plugin.PolygonGeometry)
        self.areaMarkerLayer = None

    def canvasPressEvent(self, e):
        if self.areaMarkerLayer is None:
            (layerId, ok) = QgsProject.instance().readEntry("alkis", "/areaMarkerLayer")
            if ok:
                self.areaMarkerLayer = self.plugin.mapLayer(layerId)

        if self.areaMarkerLayer is None:
            QMessageBox.warning(None, "ALKIS", u"Fehler: Flächenmarkierungslayer nicht gefunden!")

    def canvasMoveEvent(self, e):
        if self.rubberBand.numberOfVertices() > 0:
            point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y())
            self.rubberBand.movePoint(point)

    def canvasReleaseEvent(self, e):
        point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y())
        if e.button() == Qt.LeftButton:
            self.rubberBand.addPoint(point)
            return

        QApplication.setOverrideCursor(Qt.WaitCursor)

        if self.rubberBand.numberOfVertices() >= 3:
            g = self.plugin.transform(
                self.rubberBand.asGeometry()
            )

            self.rubberBand.reset(self.plugin.PolygonGeometry)

            fs = self.plugin.highlight(
                where=u"st_intersects(wkb_geometry,st_geomfromtext('POLYGON((%s))'::text,%d))" % (
                    ",".join(["%.3lf %.3lf" % (p[0], p[1]) for p in g.asPolygon()[0]]),
                    self.plugin.getepsg()
                )
            )

            if len(fs) == 0:
                QApplication.restoreOverrideCursor()
                QMessageBox.information(None, u"Fehler", u"Keine Flurstücke gefunden.")
                return

            gmlids = []
            for e in fs:
                gmlids.append(e['gmlid'])

            try:
                s = QSettings("norBIT", "EDBSgen/PRO")
                for i in range(0, len(fs)):
                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    sock.connect(("localhost", int(s.value("norGISPort", "6102"))))
                    sock.send("NORGIS_MAIN#EDBS#ALBKEY#{}#{}#".format(fs[i]['flsnr'], 0 if i + 1 == len(fs) else 1).encode("utf-8"))
                    sock.close()

                if win32:
                    window = win32gui.FindWindow(None, s.value("albWin", "norGIS"))
                    win32gui.SetForegroundWindow(window)

            except socket.error:
                QMessageBox.information(None, u"Fehler", u"Verbindung zu norGIS schlug fehl.")
        else:
            self.rubberBand.reset(self.plugin.PolygonGeometry)

        QApplication.restoreOverrideCursor()