def zoomAndShowWKT(self, wtk):
        geom = QgsGeometry.fromWkt(wtk)
        canvas = self.iface.mapCanvas() 
        self.clear()

        r = QgsRubberBand(canvas, geom.type() == 3 )
        r.setToGeometry(geom, None)
        r.setColor(QColor(0, 0, 255))
        r.setFillColor(QColor(0, 0, 255, 50))
        r.setWidth(3)

        pt = geom.pointOnSurface().asPoint()
        m = QgsVertexMarker(canvas)
        m.setCenter( pt )
        m.setColor(QColor(0, 0, 255))
        m.setIconSize(5)
        m.setIconType(QgsVertexMarker.ICON_BOX)  
        m.setPenWidth(3)

        if geom.type() == 3 or geom.type() == 2:
           rec = geom.boundingBox()
           canvas.setExtent(rec)
        else:
           self.moveMapTo( pt[0], pt[1], 0)

        self.graphics.append(r) 
        self.graphics.append(m) 
        self._refresh_layers()
	def loadLines(self, lines, points, markers, suffix):
		no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0]
		if no:
			no = int(no)
			for i in range(no):
				a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0]
				a = a.split('~~')
				b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0]
				b = b.split('~~')
				points.clear()
				for j in range(len(a)):
					x = float(a[j])
					y = float(b[j])
					point = QgsPoint(x, y)
					points.append(point)
					if i + 1 == no:
						marker = QgsVertexMarker(self.tuView.canvas)
						if suffix == 'cs':
							marker.setColor(Qt.red)
							marker.setIconSize(10)
							marker.setIconType(QgsVertexMarker.ICON_BOX)
						else:  # 'q'
							marker.setColor(Qt.blue)
							marker.setIconSize(12)
							marker.setIconType(QgsVertexMarker.ICON_DOUBLE_TRIANGLE)
						marker.setCenter(QgsPointXY(point))
						markers.append(marker)
				line = QgsRubberBand(self.tuView.canvas, False)
				line.setWidth(2)
				if suffix == 'cs':
					line.setColor(QColor(Qt.red))
				else:  # 'q'
					line.setColor(QColor(Qt.blue))
				line.setToGeometry(QgsGeometry.fromPolyline(points), None)
				lines.append(line)
Пример #3
0
class MarkerErrorGeometry():

    def __init__(self, mapCanvas):
        self.__canvas = mapCanvas
        self.__marker = None

    def __del__(self):
        self.reset()

    def __createMarker(self, point):
        self.__marker = QgsVertexMarker(self.__canvas)
        self.__marker.setCenter(point)
        self.__marker.setIconType(QgsVertexMarker.ICON_X)
        self.__marker.setPenWidth(3)

    def setGeom(self, p):
        if self.__marker is not None:
            self.reset()
        if self.__marker is None:
            self.__createMarker(p)
        else:
            self.__marker.setCenter(p)

    def reset(self):
        if self.__marker is not None:
            self.__canvas.scene().removeItem(self.__marker)
            del self.__marker
            self.__marker = None
    def wtkClicked(self):
       wktStr = self.ui.wktTxt.toPlainText()
       geom = QgsGeometry.fromWkt(wktStr)
       if geom is None: return

       self.manualLoc_lam72 = geom
       self.manualLocationName = wktStr

       self.ui.manualLocationTxt.setText(wktStr)
   
       if geom.type() == QGis.Point: 
          marker = QgsVertexMarker(self.iface.mapCanvas())
          marker.setCenter( geom.asPoint() )
          marker.setColor(QtGui.QColor(0, 255, 255))
          marker.setIconSize(5)
       else:
          marker = QgsRubberBand(self.iface.mapCanvas(), geom.type() == QGis.Polygon )
          marker.setToGeometry(geom , None)
          marker.setColor(QtGui.QColor(0, 255, 255))
          marker.setFillColor(QtGui.QColor(0, 255, 255, 100))
          marker.setWidth(3)    
       self._clearGraphicLayer()
       self.graphicsLayer.append(marker)

       self.ui.inputGeomTabs.setCurrentWidget(self.ui.drawInputTab)
Пример #5
0
    def draw(self, rows, con, args, geomType, canvasItemList, mapCanvas):
        ''' draw the result '''
        resultNodesVertexMarkers = canvasItemList['markers']
        schema = """%(edge_schema)s""" % args
        table = """%(edge_table)s_vertices_pgr""" % args
        srid, geomType = Utils.getSridAndGeomType(con, schema, table, 'the_geom')
        Utils.setTransformQuotes(args, srid, args['canvas_srid'])

        for row in rows:
            cur2 = con.cursor()
            if args['version'] < 2.1:
                args['result_node_id'] = row[1]
                args['result_edge_id'] = row[2]
                args['result_cost'] = row[3]
            else:
                args['result_node_id'] = row[3]
                args['result_edge_id'] = row[4]
                args['result_cost'] = row[5]

            query2 = sql.SQL("""
                    SELECT ST_AsText(%(transform_s)s the_geom %(transform_e)s)
                    FROM %(edge_table)s_vertices_pgr
                    WHERE  id = %(result_node_id)d
                    """).format(**args)
            cur2.execute(query2)
            row2 = cur2.fetchone()
            if (row2):
                geom = QgsGeometry().fromWkt(str(row2[0]))
                pt = geom.asPoint()
                vertexMarker = QgsVertexMarker(mapCanvas)
                vertexMarker.setColor(Qt.red)
                vertexMarker.setPenWidth(2)
                vertexMarker.setIconSize(5)
                vertexMarker.setCenter(QgsPointXY(pt))
                resultNodesVertexMarkers.append(vertexMarker)
 def _zoomLoc(self, txt):
     self._clearGraphicsLayer()
     locations = self.gp.fetchLocation(txt)
     if type( locations ) is list and len(locations):
         loc = locations[0]
     
         LowerLeftX = loc['BoundingBox']['LowerLeft']['X_Lambert72']
         LowerLeftY = loc['BoundingBox']['LowerLeft']['Y_Lambert72']
         UpperRightX = loc['BoundingBox']['UpperRight']['X_Lambert72']
         UpperRightY = loc['BoundingBox']['UpperRight']['Y_Lambert72']
     
         self.gh.zoomtoRec(QgsPoint(LowerLeftX,LowerLeftY),QgsPoint(UpperRightX, UpperRightY), 31370)
     
         xlb, ylb = loc["Location"]["X_Lambert72"], loc["Location"]["Y_Lambert72"]
         x, y = self.gh.prjPtToMapCrs(QgsPoint( xlb , ylb), 31370)
     
         m = QgsVertexMarker(self.iface.mapCanvas())
         self.graphicsLayer.append(m)
         m.setCenter(QgsPoint(x,y))
         m.setColor(QtGui.QColor(255,255,0))
         m.setIconSize(1)
         m.setIconType(QgsVertexMarker.ICON_BOX) 
         m.setPenWidth(9)
     
     elif type( locations ) is str:
       self.bar.pushMessage(
         QtCore.QCoreApplication.translate("geopunt4QgisAdresDialog","Waarschuwing"), 
             locations, level=QgsMessageBar.WARNING, duration=3)
     else:
       self.bar.pushMessage("Error", 
         QtCore.QCoreApplication.translate("geopunt4QgisAdresDialog","onbekende fout"),
             level=QgsMessageBar.CRITICAL, duration=3)
Пример #7
0
class MapToolEmitPoint(MapToolInteractive):

    """Tool to emit mouse clicks as map points."""

    canvasClicked = pyqtSignal(QgsPointV2, Qt.MouseButton)

    def __init__(self, canvas):
        super(MapToolEmitPoint, self).__init__(canvas)

        self._vertexMarker = QgsVertexMarker(canvas)
        self._vertexMarker.setIconType(QgsVertexMarker.ICON_NONE)

    def deactivate(self):
        self._vertexMarker.setCenter(QgsPoint())
        super(MapToolEmitPoint, self).deactivate()

    def canvasReleaseEvent(self, e):
        super(MapToolEmitPoint, self).canvasReleaseEvent(e)
        if e.isAccepted():
            return
        # Emit mode
        mapPoint, mapPointV2, snapped = self._snapCursorPoint(e.pos())
        self._vertexMarker.setCenter(mapPoint)
        self.canvasClicked.emit(mapPointV2, e.button())
        e.accept()

    def setVertexIcon(self, iconType, iconSize=None, penWidth=None, color=None):
        self._vertexMarker.setIconType(iconType)
        if iconSize is not None:
            self._vertexMarker.setIconSize(iconSize)
        if iconSize is not None:
            self._vertexMarker.setPenWidth(penWidth)
        if iconSize is not None:
            self._vertexMarker.setColor(color)
Пример #8
0
Файл: BAG.py Проект: g1tos/CRABB
    def showFlandersPointOnCanvas(self):

        try:

            self.__setMapSrs()

            inputtext = self.dlg.lineEditFlanders.text().encode("utf8").strip()

            params = urllib.urlencode({"q": inputtext})

            result2 = urllib2.urlopen(self.location + params).read()

            doc = json.loads(result2)

            if len(doc) > 0 and len(doc["LocationResult"]) > 0:

                x = doc["LocationResult"][0]["Location"]["X_Lambert72"]
                y = doc["LocationResult"][0]["Location"]["Y_Lambert72"]

                canv = self.iface.mapCanvas()

                canv.clear()

                marker = QgsVertexMarker(canv)

                marker.setPenWidth(3)
                marker.setIconType(QgsVertexMarker.ICON_CROSS)  # or, ICON_X ICON_BOX
                point = QgsPoint(x, y)

                marker.setCenter(point)
                self.markers.append(marker)

                scale = 100

                # Create a rectangle to cover the new extent
                rect = QgsRectangle(
                    doc["LocationResult"][0]["BoundingBox"]["LowerLeft"]["X_Lambert72"],
                    doc["LocationResult"][0]["BoundingBox"]["LowerLeft"]["Y_Lambert72"],
                    doc["LocationResult"][0]["BoundingBox"]["UpperRight"]["X_Lambert72"],
                    doc["LocationResult"][0]["BoundingBox"]["UpperRight"]["Y_Lambert72"],
                )
                # Set the extent to our new rectangle
                canv.setExtent(rect)

                canv.refresh()

                # QMessageBox.information( self.iface.mainWindow(),"Info", "x, y = %s" %str(x) + ", " + str(y) )

                # keeps the window alive

                self.run()

            else:

                QMessageBox.information(self.iface.mainWindow(), "Info", "Geen locatie gevonden voor: %s" % inputtext)

        except:

            QMessageBox.warning(self.iface.mainWindow(), "Warning", "error: %s" % sys.exc_info()[0])
Пример #9
0
 def _setPointMarker(self, pointgeom):
     m = QgsVertexMarker(self.qgisIface.mapCanvas())
     m.setColor(QColor(self.config['marker_color']))
     m.setIconType(self.config['marker_icon'])
     m.setPenWidth(self.config['marker_width'])
     m.setIconSize(self.config['marker_size'])
     m.setCenter(pointgeom.asPoint())
     return m
Пример #10
0
def addMarker(iface, pnt, clr=QColor(255, 255, 0), ico=QgsVertexMarker.ICON_BOX ):
    m = QgsVertexMarker(iface.mapCanvas())
    m.setCenter(pnt)
    m.setColor(clr)
    m.setIconSize(1)
    m.setIconType(ico)
    m.setPenWidth(9)
    return m
Пример #11
0
 def _addMarker(self, pnt, clr=QColor(255,255,0)):
     m = QgsVertexMarker(self.iface.mapCanvas())
     m.setCenter( pnt )
     m.setColor(clr)
     m.setIconSize(1)
     m.setIconType(QgsVertexMarker.ICON_BOX) 
     m.setPenWidth(9)
     self.graphicsLayer.append(m)
     return m
 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)
Пример #13
0
 def addPointGraphic(self, xy, color="#FFFF00", size=1, pen=10, markerType=QgsVertexMarker.ICON_BOX ):
     "create a point Graphic at location xy and return it"
     pt = QgsPointXY(xy[0], xy[1]) if isinstance( xy, Iterable) else QgsPointXY(xy)
     m = QgsVertexMarker(self.canvas)
     m.setCenter(pt)
     m.setColor(QColor(color))
     m.setIconSize(size)
     m.setIconType(markerType) 
     m.setPenWidth(pen)
     return m
Пример #14
0
 def addPointGraphic(self, xy, color="#FFFF00", size=1, pen=10, markerType=QgsVertexMarker.ICON_BOX ):
     "create a point Graphic at location xy and return it"
     x, y = list( xy )[:2]
     m = QgsVertexMarker(self.canvas)
     m.setCenter(QgsPoint(x,y))
     m.setColor(QColor(color))
     m.setIconSize(size)
     m.setIconType(markerType) 
     m.setPenWidth(pen)
     return m
Пример #15
0
 def addTempGeometry(self, chunkId, geometryType, geometry):
     """ Add geometries as rubber bands or vertex objects """     
     if geometryType == "Polygon" or geometryType == "LineString":
         self.__tmpGeometry[chunkId].addGeometry(geometry, None)      
     elif geometryType == "Point":
         vertex = QgsVertexMarker(self.iface.mapCanvas())
         vertex.setCenter(geometry.asPoint())
         vertex.setColor(QColor(0,255,0))
         vertex.setIconSize(6)
         vertex.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X
         vertex.setPenWidth(3)
         self.__tmpGeometry[chunkId].append(vertex)
Пример #16
0
 def _createSnappableMarkers(self):
     if (not self._showSnappableVertices or not self._snappingEnabled):
         return
     extent = self.canvas().extent()
     for vertex in self._snappableVertices.asMultiPoint():
         if (extent.contains(vertex)):
             marker = QgsVertexMarker(self.canvas())
             marker.setIconType(QgsVertexMarker.ICON_X)
             marker.setColor(Qt.gray)
             marker.setPenWidth(1)
             marker.setCenter(vertex)
             self._snappableMarkers.append(marker)
Пример #17
0
 def updateTrack(self):
     if self.pos and self.trackLen:
         if len(self.track) >= self.trackLen:
             tpr = self.track.popleft()
             self.canvas.scene().removeItem(tpr)
             del(tpr)
         tp = QgsVertexMarker(self.canvas)
         tp.setCenter(self.pos)
         tp.setIconType(QgsVertexMarker.ICON_CROSS)
         tp.setColor(self.trackColor)
         tp.setZValue(self.zValue() - 0.1)
         tp.setIconSize(3)
         tp.setPenWidth(3)
         self.track.append(tp)
Пример #18
0
 def onSelectionChanged(self):
     selPois = self._getSelectedPois()
     canvas = self.iface.mapCanvas()
     self.clearGraphicsLayer()
 
     pts = [ self.gh.prjPtToMapCrs( n['location']['points'][0]['Point']['coordinates'], 4326)
                   for n in selPois ] 
     for pt in pts:
         x,y = pt
         m = QgsVertexMarker(canvas)
         self.graphicsLayer.append(m)
         m.setCenter(QgsPointXY(x,y))
         m.setColor(QColor(255,255,0))
         m.setIconSize(1)
         m.setIconType(QgsVertexMarker.ICON_BOX) 
         m.setPenWidth(10)
class MarkerCursor(QObject):

    def __init__(self, mapCanvas, srsOL):
        QObject.__init__(self)
        self.__srsOL = srsOL
        self.__canvas = mapCanvas
        self.__marker = None
        self.__showMarker = True

    def __del__(self):
        self.reset()

    def __refresh(self, pointCenter):
        if self.__marker is not None:
            self.reset()
        self.__marker = QgsVertexMarker(self.__canvas)
        self.__marker.setCenter(pointCenter)
        self.__marker.setIconType(QgsVertexMarker.ICON_X)
        self.__marker.setPenWidth(4)

    def setVisible(self, visible):
        self.__showMarker = visible

    def reset(self):
        self.__canvas.scene().removeItem(self.__marker)
        del self.__marker
        self.__marker = None

    @pyqtSlot(str)
    def changeMarker(self, strListExtent):
        if not self.__showMarker:
            return
        # left, bottom, right, top
        left, bottom, right, top = [float(item) for item in
                                    strListExtent.split(',')]
        pointCenter = QgsRectangle(QgsPointXY(left, top),
                                   QgsPointXY(right, bottom)).center()
        crsCanvas = self.__canvas.mapSettings().destinationCrs()
        if self.__srsOL != crsCanvas:
            coodTrans = QgsCoordinateTransform(self.__srsOL, crsCanvas,
                                               QgsProject.instance())
            pointCenter = coodTrans.transform(
                pointCenter,
                QgsCoordinateTransform.ForwardTransform)
        self.__refresh(pointCenter)
Пример #20
0
 def mouseMoved(self, event):
     pClicked = QPoint( event.pos().x(), event.pos().y() )
     ( _, snappedPoints ) = self.networkAnalyzer.getSnapper().snapPoint( pClicked, [] )
     
     for marker in self.highLightedPoints:
         self.canvas.scene().removeItem( marker )
     
     self.highLightedPoints = []
     
     if len( snappedPoints ) > 0:
         for point in snappedPoints:
             marker = QgsVertexMarker( self.canvas )
             marker.setCenter( point.snappedVertex )
             marker.setColor( QColor( "#FFFF33" ) )
             marker.setIconSize( 10 )
             marker.setIconType( QgsVertexMarker.ICON_X )
             marker.setPenWidth( 2 )
             self.highLightedPoints.append(marker)
	def loadPoints(self, points, markers):
		a = self.project.readEntry("TUVIEW", "pointsx")[0]
		if a:
			a = a.split('~~')
			b = self.project.readEntry("TUVIEW", "pointsy")[0]
			b = b.split('~~')
			for i in range(len(a)):
				x = float(a[i])
				y = float(b[i])
				point = QgsPoint(x, y)
				points.append(point)
				marker = QgsVertexMarker(self.tuView.canvas)
				marker.setColor(Qt.red)
				marker.setFillColor(Qt.red)
				marker.setIconSize(10)
				marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
				marker.setCenter(QgsPointXY(point))
				markers.append(marker)
Пример #22
0
    def _addGeometryError(self, error):
        self._geometryErrors.append(error)

        if (self._tip != ''):
            self._tip += '\n'
        self._tip += error.what()

        if (error.hasWhere()):
            marker = QgsVertexMarker(self.canvas())
            marker.setCenter(error.where())
            marker.setIconType(QgsVertexMarker.ICON_X)
            marker.setPenWidth(2)
            marker.setToolTip(error.what())
            marker.setColor(Qt.green)
            marker.setZValue(marker.zValue() + 1)
            self._geometryErrorMarkers.append(marker)

        self._iface.mainWindow().statusBar().showMessage(error.what())
        if (self._tip != ''):
            self._iface.mainWindow().statusBar().setToolTip(self._tip)
Пример #23
0
    def canvasMoveEvent(self, event):
        """
        Whenever the mouse is moved update the rubberband and the snapping.
        :param event: QMouseEvent with coordinates
        """
        point_clicked = QPoint(event.pos().x(), event.pos().y())
        (_, snapped_points) = self.networkAnalyzer.getSnapper().snapPoint(point_clicked, [])

        for marker in self.highLightedPoints:
            self.canvas.scene().removeItem(marker)

        self.highLightedPoints = []

        if len(snapped_points) > 0:
            for point in snapped_points:
                marker = QgsVertexMarker(self.canvas)
                marker.setCenter(point.snappedVertex)
                marker.setColor(QColor("#FFFF33"))
                marker.setIconSize(10)
                marker.setIconType(QgsVertexMarker.ICON_X)
                marker.setPenWidth(2)
                self.highLightedPoints.append(marker)
Пример #24
0
class ParentManage(ParentAction, object):

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

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

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

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


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

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


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

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


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

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

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

        self.canvas.refresh()
    
    
    def reset_widgets(self, dialog, table_object):
        """ Clear contents of input widgets """
        
        if table_object == "doc":
            utils_giswater.setWidgetText(dialog, "doc_type", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
        elif table_object == "element":
            utils_giswater.setWidgetText(dialog, "elementcat_id", "")
            utils_giswater.setWidgetText(dialog, "state", "")
            utils_giswater.setWidgetText(dialog, "expl_id","")
            utils_giswater.setWidgetText(dialog, "ownercat_id", "")
            utils_giswater.setWidgetText(dialog, "location_type", "")
            utils_giswater.setWidgetText(dialog, "buildercat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id_end", "")
            utils_giswater.setWidgetText(dialog, "comment", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
            utils_giswater.setWidgetText(dialog, "rotation", "")
            utils_giswater.setWidgetText(dialog, "verified", "")
            utils_giswater.setWidgetText(dialog, dialog.num_elements, "")

    def fill_widgets(self, dialog, table_object, row):
        """ Fill input widgets with data int he @row """

        if table_object == "doc":

            utils_giswater.setWidgetText(dialog, "doc_type", row["doc_type"])
            utils_giswater.setWidgetText(dialog, "observ", row["observ"])
            utils_giswater.setWidgetText(dialog, "path", row["path"])

        elif table_object == "element":

            state = ""
            if row['state']:
                sql = ("SELECT name FROM " + self.schema_name + ".value_state"
                                                                " WHERE id = '" + str(row['state']) + "'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    state = row_aux[0]

            expl_id = ""
            if row['expl_id']:
                sql = ("SELECT name FROM " + self.schema_name + ".exploitation"
                                                                " WHERE expl_id = '" + str(row['expl_id']) + "'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    expl_id = row_aux[0]

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

            utils_giswater.setWidgetText(dialog, "elementcat_id", row['elementcat_id'])
            utils_giswater.setWidgetText(dialog, "num_elements", row['num_elements'])
            utils_giswater.setWidgetText(dialog, "state", state)
            utils_giswater.setWidgetText(dialog, "expl_id", expl_id)
            utils_giswater.setWidgetText(dialog, "ownercat_id", row['ownercat_id'])
            utils_giswater.setWidgetText(dialog, "location_type", row['location_type'])
            utils_giswater.setWidgetText(dialog, "buildercat_id", row['buildercat_id'])
            builtdate = QDate.fromString(str(row['builtdate']), 'yyyy-MM-dd')
            dialog.builtdate.setDate(builtdate)
            utils_giswater.setWidgetText(dialog, "workcat_id", row['workcat_id'])
            utils_giswater.setWidgetText(dialog, "workcat_id_end", row['workcat_id_end'])
            utils_giswater.setWidgetText(dialog, "comment", row['comment'])
            utils_giswater.setWidgetText(dialog, "observ", row['observ'])
            utils_giswater.setWidgetText(dialog, "link", row['link'])
            utils_giswater.setWidgetText(dialog, "verified", row['verified'])
            utils_giswater.setWidgetText(dialog, "rotation", row['rotation'])
            if str(row['undelete']) == 'True':
                dialog.undelete.setChecked(True)

              
    def get_records_geom_type(self, dialog, table_object, geom_type):
        """ Get records of @geom_type associated to selected @table_object """
        
        object_id = utils_giswater.getWidgetText(dialog, table_object + "_id")
        table_relation = table_object + "_x_" + geom_type
        widget_name = "tbl_" + table_relation           
        
        exists = self.controller.check_table(table_relation)
        if not exists:
            self.controller.log_info("Not found: " + str(table_relation))
            return
              
        sql = ("SELECT " + geom_type + "_id"
               " FROM " + self.schema_name + "." + table_relation + ""
               " WHERE " + table_object + "_id = '" + str(object_id) + "'")
        rows = self.controller.get_rows(sql, log_info=False)
        if rows:
            for row in rows:
                self.list_ids[geom_type].append(str(row[0]))
                self.ids.append(str(row[0]))

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

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

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


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

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

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

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


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

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


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


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


    def add_point(self):
        """ Create the appropriate map tool and connect to the corresponding signal """
        active_layer = self.iface.activeLayer()
        if active_layer is None:
            active_layer = self.controller.get_layer_by_tablename('version')
            self.iface.setActiveLayer(active_layer)

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

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

        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.previous_map_tool = self.canvas.mapTool()
        self.canvas.setMapTool(self.emit_point)
        #self.canvas.connect(self.canvas, SIGNAL("xyCoordinates(const QgsPoint&)"), self.mouse_move)
        self.canvas.xyCoordinates.connect(self.mouse_move)
        self.xyCoordinates_conected = True
        self.emit_point.canvasClicked.connect(partial(self.get_xy))



    def mouse_move(self, p):
        self.snapped_point = None
        self.vertex_marker.hide()
        map_point = self.canvas.getCoordinateTransform().transform(p)
        x = map_point.x()
        y = map_point.y()
        eventPoint = QPoint(x, y)

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

        # That's the snapped point
        if result:
            # Check feature
            for snapped_point in result:
                self.snapped_point = QgsPoint(snapped_point.snappedVertex)
                self.vertex_marker.setCenter(self.snapped_point)
                self.vertex_marker.show()
        else:
            self.vertex_marker.hide()

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

        if self.snapped_point:
            self.x = self.snapped_point.x()
            self.y = self.snapped_point.y()
        else:
            self.x = point.x()
            self.y = point.y()
        message = "Geometry has been added!"
        self.controller.show_info(message)
        self.emit_point.canvasClicked.disconnect()
        self.canvas.xyCoordinates.disconnect()
        self.xyCoordinates_conected = False
        self.iface.mapCanvas().refreshAllLayers()
        self.vertex_marker.hide()


    def get_values_from_form(self, dialog):
        self.enddate = utils_giswater.getCalendarDate(dialog, "enddate")
        self.workcat_id_end = utils_giswater.getWidgetText(dialog, "workcat_id_end")
        self.description = utils_giswater.getWidgetText(dialog, "descript")
        
    def tab_feature_changed(self, dialog, table_object, feature_id=None):
        """ Set geom_type and layer depending selected tab
            @table_object = ['doc' | 'element' | 'cat_work']
        """
        self.get_values_from_form(dialog)
        if dialog.tab_feature.currentIndex() == 3:
            dialog.btn_snapping.setEnabled(False)
        else:
            dialog.btn_snapping.setEnabled(True)

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

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

    def set_completer_object(self, dialog, table_object):
        """ Set autocomplete of widget @table_object + "_id" 
            getting id's from selected @table_object 
        """
                     
        widget = utils_giswater.getWidget(dialog, table_object + "_id")
        if not widget:
            return
        
        # Set SQL
        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        sql = ("SELECT DISTINCT(" + field_object_id + ")"
               " FROM " + self.schema_name + "." + table_object)
        row = self.controller.get_rows(sql, commit=self.autocommit)
        for i in range(0, len(row)):
            aux = row[i]
            row[i] = str(aux[0])

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

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

        return expr


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


    def lazy_configuration(self, widget, init_function):
        """set the init_function where all necessary events are set.
        This is necessary to allow a lazy setup of the events because set_table_events
        can create a table with a None model loosing any event connection."""
        # TODO: create a dictionary with key:widged.objectName value:initFuction
        # to allow multiple lazy initialization
        self.lazy_widget = widget
        self.lazy_init_function = init_function


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

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

        self.disconnect_signal_selection_changed()

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

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

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

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

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

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

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

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

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

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


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

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



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

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


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

        self.disconnect_signal_selection_changed()
        field_id = geom_type + "_id"

        if self.remove_ids:
            self.ids = []

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

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

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

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


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

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


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


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

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

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

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

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

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

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

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

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


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

        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        for i in range(len(self.ids)):
            sql = ("SELECT " + geom_type + "_id"
                   " FROM " + self.schema_name + "." + self.plan_om + "_psector_x_" + geom_type + ""
                   " WHERE " + geom_type + "_id = '" + str(self.ids[i]) + "' AND psector_id = '" + str(value) + "'")

            row = self.controller.get_row(sql)
            if not row:
                sql = ("INSERT INTO " + self.schema_name + "." + self.plan_om + "_psector_x_" + geom_type + ""
                       "(" + geom_type + "_id, psector_id) VALUES('" + str(self.ids[i]) + "', '" + str(value) + "')")
                self.controller.execute_sql(sql)
            self.reload_qtable(dialog, geom_type, self.plan_om)


    def reload_qtable(self, dialog, geom_type, plan_om):
        """ Reload QtableView """
        
        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        sql = ("SELECT * FROM " + self.schema_name + "." + plan_om + "_psector_x_" + geom_type + ""
               " WHERE psector_id = '" + str(value) + "'")
        qtable = utils_giswater.getWidget(dialog, 'tbl_psector_x_' + geom_type)
        self.fill_table_by_query(qtable, sql)
        self.set_table_columns(dialog, qtable, plan_om + "_psector_x_"+geom_type)
        self.refresh_map_canvas()


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

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


    def fill_table_object(self, widget, table_name, expr_filter=None):
        """ Set a model with selected filter. Attach that model to selected table """
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name
        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.sort(0, 1)
        if expr_filter:
            model.setFilter(expr_filter)            
        model.select()

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

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


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

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


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

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

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

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

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

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

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

        row = selected_list[0].row()

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

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

        # set previous dialog
        # if hasattr(self, 'previous_dialog'):

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

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

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

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


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

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

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

        # Attach model to table view
        if widget:
            widget.setModel(model)
        else:
            self.controller.log_info("set_model_to_table: widget not found")
Пример #25
0
class FlyingTrackerDialog(QtGui.QDockWidget, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        super(FlyingTrackerDialog, self).__init__(parent)

        self.setupUi(self)
        self.iface = iface

        self.course_comboBox.clear()
        self.lcdNumberWpt.display(1)

        self.GpsFixlcdNumber.display(0)
        self.SatelliteslcdNumber.display(0)

        self.pushButtonDisconnect.hide()
        self.pushButtonConnect.clicked.connect(self.Connect)
        self.pushButtonDisconnect.clicked.connect(self.Disconnect)
        self.pushCloseButton.clicked.connect(self.Close)
        self.LoadtoolButton.clicked.connect(self.FillComboBox)
        self.wptplus_toolButton.clicked.connect(self.NextWpt)
        self.wptmin_toolButton.clicked.connect(self.BackWpt)
        QtCore.QObject.connect(self.wptplus_toolButton,
                               QtCore.SIGNAL("valueChanged(int)"),
                               self.AdjNxtWpt)
        QtCore.QObject.connect(self.wptmin_toolButton,
                               QtCore.SIGNAL("valueChanged(int)"),
                               self.AdjNxtWpt)
        self.ZoomIntoolButton.clicked.connect(self.ZoomIn)
        self.ZoomOuttoolButton.clicked.connect(self.ZoomOut)

        shortcut = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_S),
                                   self.iface.mainWindow())
        shortcut.setContext(QtCore.Qt.ApplicationShortcut)
        shortcut.activated.connect(self.ZoomIn)
        shortcut2 = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_A),
                                    self.iface.mainWindow())
        shortcut2.setContext(QtCore.Qt.ApplicationShortcut)
        shortcut2.activated.connect(self.ZoomOut)
        shortcut3 = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_X),
                                    self.iface.mainWindow())
        shortcut3.setContext(QtCore.Qt.ApplicationShortcut)
        shortcut3.activated.connect(self.NextWpt)
        shortcut4 = QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Z),
                                    self.iface.mainWindow())
        shortcut4.setContext(QtCore.Qt.ApplicationShortcut)
        shortcut4.activated.connect(self.BackWpt)

        self.timer = QtCore.QTimer()
        QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"),
                               self.SendSerial)

        self.NxtWptRubber = False
        self.PositionMarker = False
        self.RubberBand = False
        self.WptVertexSignal = False

        self.trackCounter = 4

    def AdjNxtWpt(self):

        if self.WptVertexSignal == True:
            self.iface.mapCanvas().scene().removeItem(self.WptVertex)
            del self.WptVertex
            self.WptVertexSignal = False

        if self.NxtWptRubber == True:
            self.iface.mapCanvas().scene().removeItem(self.rdue)
            del self.rdue
            self.iface.mapCanvas().scene().removeItem(self.rtre)
            del self.rtre
            self.NxtWptRubber = False

        canvas = self.iface.mapCanvas()
        mapRenderer = canvas.mapRenderer()
        crsSrc = QgsCoordinateReferenceSystem(4326)  # NMEA is in WGS 84
        crsDest = mapRenderer.destinationCrs()
        xform = QgsCoordinateTransform(crsSrc, crsDest)

        WptValue = int(self.lcdNumberWpt.value())

        try:
            Wpt = self.pts[WptValue - 1]

        except IndexError:
            return

        self.WptVertex = QgsVertexMarker(self.iface.mapCanvas())
        self.WptVertex.setIconSize(20)
        self.WptVertex.setIconType(QgsVertexMarker.ICON_X)
        self.WptVertex.setPenWidth(20)
        self.WptVertex.setCenter(xform.transform(Wpt))
        self.WptVertexSignal = True

        if WptValue != 1:

            Wpt2 = self.pts[WptValue - 2]
            self.rdue = QgsRubberBand(self.iface.mapCanvas(),
                                      False)  # False = not a polygon
            pointsdue = [xform.transform(Wpt), xform.transform(Wpt2)]

            self.rdue.setColor(QtGui.QColor(255, 0, 0))
            self.rdue.setWidth(8)
            self.rdue.setLineStyle(QtCore.Qt.PenStyle(QtCore.Qt.DotLine))
            self.rdue.setToGeometry(QgsGeometry.fromPolyline(pointsdue),
                                    None)  #creation of NextWayPoint rubberband

            self.rtre = QgsRubberBand(self.iface.mapCanvas(), False)
            pointstre = self.pts[0:WptValue - 1]

            for i in xrange(len(pointstre)):
                pointstre[i] = xform.transform(pointstre[i])

            self.rtre.setColor(QtGui.QColor(127, 0, 255))
            self.rtre.setWidth(8)
            self.rtre.setLineStyle(QtCore.Qt.PenStyle(QtCore.Qt.DotLine))
            self.rtre.setToGeometry(QgsGeometry.fromPolyline(pointstre), None)

            self.NxtWptRubber = True

    def Connect(self):

        try:

            self.positionMarker = PositionMarker(self.iface.mapCanvas())
            self.PositionMarker = True
            portName = self.comboBox.currentText()
            self.ser = serial.Serial(portName, 38400)
            layername = self.course_comboBox.itemData(
                self.course_comboBox.currentIndex())
            RouteLayer = QgsMapLayerRegistry.instance().mapLayer(layername)
            RouteLayer.selectAll()
            feats = RouteLayer.selectedFeatures()
            RouteLayer.removeSelection()
            feat = feats[0]
            geom = feat.geometry()
            self.pts = geom.asPolyline()
            SourceIntCRS = int(RouteLayer.crs().authid().split(':')[1])

            if SourceIntCRS != 4326:
                SourceIntCRS = int(RouteLayer.crs().authid().split(':')[1])
                SourceCRS = QgsCoordinateReferenceSystem(SourceIntCRS)
                DestCRS = QgsCoordinateReferenceSystem(4326)
                xformRouteLayer = QgsCoordinateTransform(SourceCRS, DestCRS)
                for i in xrange(len(self.pts)):
                    x = self.pts[i][0]
                    y = self.pts[i][
                        1]  #if track layer is not in WGS84 Geographic every coordinate is transformed
                    TmpPoint = QgsPoint(x, y)
                    Tmp2Point = xformRouteLayer.transform(TmpPoint)
                    self.pts[i] = Tmp2Point

            self.TrackLayer = QgsVectorLayer("Point?crs=epsg:4326&index=yes",
                                             "Flight_track", "memory")
            self.TrackLayerProvider = self.TrackLayer.dataProvider()
            self.TrackLayerProvider.addAttributes([
                QgsField("id", QtCore.QVariant.Int),
                QgsField('Time', QtCore.QVariant.String),
                QgsField('Ele', QtCore.QVariant.String),
            ])

            QgsMapLayerRegistry.instance().addMapLayer(self.TrackLayer)
            symbols = self.TrackLayer.rendererV2().symbols()
            symbol = symbols[0]
            symbol.setColor(QtGui.QColor(0, 255, 0))
            self.iface.legendInterface().refreshLayerSymbology(self.TrackLayer)

            if self.lcdNumberWpt.value() == 0:
                self.lcdNumberWpt.display(1)

            elif self.lcdNumberWpt.value() > len(self.pts):
                self.lcdNumberWpt.display(1)

            self.InRouteTolerance = float(
                self.DTrack_spinBox.value()
            )  #if we are distant from route less than this value path become green, otherwise red
            self.CompassTolerance = self.DCompass_spinBox.value(
            )  #if compass to next wpt confront to actual compass diverge less than this value projection of direction become green, otherwise red
            self.WptArrivedTolerance = float(
                self.DWpt_spinBox.value()
            )  #if we pass near a wpt less than this value (in meters) the program will set the next wpt
            self.EleTolerance = float(
                self.DHeightspinBox.value()
            )  #if our elevation diverge from planned elevation more than this value our cursor will be red, otherwise green

            canvas = self.iface.mapCanvas()
            mapRenderer = canvas.mapRenderer()
            crsSrc = QgsCoordinateReferenceSystem(4326)  # NMEA is in WGS 84
            crsDest = mapRenderer.destinationCrs()

            self.backxform = QgsCoordinateTransform(crsDest, crsSrc)

            self.xform = QgsCoordinateTransform(
                crsSrc, crsDest)  #usage: xform.transform(QgsPoint)
            self.AdjNxtWpt()
            self.timer.start(1000)

        except:
            pass

    def SendSerial(self):
        thread = Thread(target=self.ReadSerial)
        thread.start()
        thread.join()

    def Disconnect(self, serialPort):

        self.timer.stop()
        self.lcdNumberSpeed.display(0)
        self.lcdNumberCompass.display(0)
        try:
            self.iface.mapCanvas().scene().removeItem(self.WptVertex)
            self.ser.close()
            self.iface.mapCanvas().scene().removeItem(self.r)
            self.iface.mapCanvas().scene().removeItem(self.runo)
            self.iface.mapCanvas().scene().removeItem(self.positionMarker)
            del self.WptVertex
            del self.r
            del self.runo
        except:
            pass

        self.iface.mapCanvas().setRotation(0)

        self.RubberBand = False

        if self.NxtWptRubber == True:
            self.iface.mapCanvas().scene().removeItem(self.rdue)
            self.iface.mapCanvas().scene().removeItem(self.rtre)
            del self.rdue
            del self.rtre
            self.NxtWptRubber = False

        else:
            pass

        self.WptVertexSignal = False
        self.lcdNumberHeights.display(0)
        self.lcdNumberSpeed.display(0)
        self.lcdNumberCompass.display(0)
        self.lcdCompassWpt.display(0)
        self.GpsFixlcdNumber.display(0)
        self.SatelliteslcdNumber.display(0)

    def FillComboBox(self):
        try:
            self.comboBox.clear()
            portlist = []
            system_name = platform.system()
            if system_name == "Windows":
                # Scan for available ports.
                available = []
                for i in range(256):
                    try:
                        s = serial.Serial(i)
                        available.append(i)
                        s.close()
                    except serial.SerialException:  #Search for active serial port
                        pass
                #print available
                list1 = available
            elif system_name == "Darwin":
                # Mac
                #print glob.glob('/dev/tty*') + glob.glob('/dev/cu*')
                list1 = glob.glob('/dev/tty*') + glob.glob('/dev/cu*')
            else:
                # Assume Linux or something else
                #print glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*')
                list1 = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*')
            for i in list1:
                try:
                    serial.Serial(i).close()
                    portlist.append(i)
                except IOError:
                    pass

            for x in portlist:
                self.comboBox.addItem(x)

            self.course_comboBox.clear()

            LayerRegistryItem = QgsMapLayerRegistry.instance().mapLayers()
            for id, layer in LayerRegistryItem.iteritems():
                if layer.type() == QgsMapLayer.VectorLayer:
                    self.course_comboBox.addItem(layer.name(), id)

            layername = self.course_comboBox.itemData(
                self.course_comboBox.currentIndex())
            RouteLayer = QgsMapLayerRegistry.instance().mapLayer(layername)
            RouteLayer.selectAll()
            RouteLayer.featureCount()
            feats = RouteLayer.selectedFeatures()
            RouteLayer.removeSelection()
            feat = feats[0]
            geom = feat.geometry()
            self.pts = geom.asPolyline()
            SourceIntCRS = int(RouteLayer.crs().authid().split(':')[1])

            if SourceIntCRS != 4326:
                SourceIntCRS = int(RouteLayer.crs().authid().split(':')[1])
                SourceCRS = QgsCoordinateReferenceSystem(SourceIntCRS)
                DestCRS = QgsCoordinateReferenceSystem(4326)
                xformRouteLayer = QgsCoordinateTransform(SourceCRS, DestCRS)
                for i in xrange(len(self.pts)):
                    x = self.pts[i][0]
                    y = self.pts[i][
                        1]  #if track layer is not in WGS84 Geographic every coordinate is transformed
                    TmpPoint = QgsPoint(x, y)
                    Tmp2Point = xformRouteLayer.transform(TmpPoint)
                    self.pts[i] = Tmp2Point

            self.AdjNxtWpt()
        except:
            pass

    def Close(self):

        self.timer.stop()
        self.lcdNumberHeights.display(0)
        self.lcdNumberSpeed.display(0)
        self.lcdNumberCompass.display(0)
        self.lcdCompassWpt.display(0)

        self.course_comboBox.clear()
        if self.PositionMarker == True:
            self.iface.mapCanvas().scene().removeItem(self.positionMarker)

        if self.NxtWptRubber == True:
            self.iface.mapCanvas().scene().removeItem(self.rdue)
            self.iface.mapCanvas().scene().removeItem(self.rtre)
            del self.rdue
            del self.rtre
            self.NxtWptRubber = False

        else:
            pass

        if self.WptVertexSignal == True:
            self.iface.mapCanvas().scene().removeItem(self.WptVertex)
            del self.WptVertex
            self.WptVertexSignal = False

        self.close()

    def ZoomIn(self):
        self.iface.mapCanvas().zoomIn()

    def ZoomOut(self):
        self.iface.mapCanvas().zoomOut()

    def NextWpt(self):
        try:
            currentValue = self.lcdNumberWpt.value()
            if currentValue == len(self.pts):
                pass
            else:
                self.lcdNumberWpt.display(currentValue + 1)
                self.AdjNxtWpt()
        except:
            pass

    def BackWpt(self):
        try:
            currentValue = self.lcdNumberWpt.value()
            if currentValue >= 2:
                self.lcdNumberWpt.display(currentValue - 1)
                self.AdjNxtWpt()
        except:
            pass

    def ReadSerial(self):

        if self.trackCounter > 5:
            self.trackCounter = 4
        self.trackCounter = self.trackCounter + 1  # when it arrive to 5 a gps point is painted (default is 4)

        GPGGA = 0
        GPVTG = 0

        data = self.ser.read(1)
        n = self.ser.inWaiting()
        if n:
            data = data + self.ser.read(n)

        if re.search("\r\n", data):
            # Since we found a CRLF, split it out
            data2 = data.split("\r\n")

            for i in range(len(data2)):

                if data2[i][0:6] == '$GPGGA':
                    GPGGA = data2[i].split(',')
                    #print GPGGA

                elif data2[i][0:6] == '$GPVTG':
                    GPVTG = data2[i].split(',')
                    #print GPRMC

            if GPGGA == 0:
                #print 'mancato'
                return

            elif GPVTG == 0:
                #print 'mancato'
                return

            else:

                decimalsLat = (float(GPGGA[2][2:])) / 60
                degreeLat = float(GPGGA[2][0:2])
                decimalsLon = (float(GPGGA[4][3:])) / 60
                degreeLon = float(GPGGA[4][0:3])

                Lat = degreeLat + decimalsLat
                Lon = degreeLon + decimalsLon

                if GPGGA[5] == 'W':
                    Lon = -Lon
                if GPGGA[3] == 'S':
                    Lat = -Lat

                Ele = float(GPGGA[9])
                Compass = float(GPVTG[1])
                Speed = (float(GPVTG[7]))  # in Km/h
                GpsFix = int(GPGGA[6])
                GpsSatellites = int(GPGGA[7])

                self.ser.flushInput()
                self.ser.flushOutput()

                self.GpsFixlcdNumber.display(GpsFix)
                self.SatelliteslcdNumber.display(GpsSatellites)

                if self.RubberBand == True:
                    self.iface.mapCanvas().scene().removeItem(self.r)
                    del self.r

                    self.RubberBand = False

                Point = QgsPoint()
                Point.set(Lon, Lat)

                TransfPoint = self.xform.transform(Point)

                canvas = self.iface.mapCanvas()
                if Compass <= 180:
                    #canvas.setRotation(-(Compass-self.rotation))
                    canvas.setRotation(
                        -Compass
                    )  # set canvas rotation according to:  UP of the map = Compass Direction
                else:
                    Compass = 360 - Compass
                    canvas.setRotation(Compass)

                canvas.setCenter(TransfPoint)

                self.positionMarker.newCoords(
                    TransfPoint)  # Put the arrow on screen
                #self.positionMarker.angle = 0.0

                WptValue = int(self.lcdNumberWpt.value())
                WptE = self.pts[WptValue - 1][0]
                WptN = self.pts[WptValue - 1][1]

                GeodesicAircraftToWpt = Geodesic.WGS84.Inverse(
                    Lat, Lon, WptN, WptE)
                distance = GeodesicAircraftToWpt['s12']
                azim = GeodesicAircraftToWpt[
                    'azi1']  #determine azimuth from next wpt
                if azim < 0:
                    azim += 360

                if distance <= self.WptArrivedTolerance:  # tolerance in meter for next wpt
                    self.NextWpt()

                #feetEle = Ele * 3.2808399            #meters to feet

                if self.comboBox_2.currentText() == 'ft.':
                    feetEle = Ele * 3.2808399  #Convert if needed
                    self.lcdNumberHeights.display(feetEle)
                else:
                    self.lcdNumberHeights.display(Ele)

                if self.comboBox_3.currentText() != 'km/h':
                    Speed = Speed * 0.53995694  #Convert if needed
                    self.lcdNumberSpeed.display(float(Speed))
                else:
                    self.lcdNumberSpeed.display(float(Speed))

                self.lcdNumberCompass.display(float(Compass))
                self.lcdCompassWpt.display(azim)

                canvasInPixel = canvas.getCoordinateTransform()
                ExtentHeightInPixel = canvasInPixel.mapHeight()
                ExtentWidthInPixel = canvasInPixel.mapWidth()

                LocateCompassProjectionEndInMapUnit = canvasInPixel.toMapPoint(
                    ExtentWidthInPixel / 2.0,
                    ExtentHeightInPixel - (ExtentHeightInPixel * 0.95))

                self.r = QgsRubberBand(self.iface.mapCanvas(),
                                       False)  # False = not a polygon

                #points = [TransfPoint, QgsPoint(x,y)]							#creazione della proiezione della prua su mappa
                points = [TransfPoint, LocateCompassProjectionEndInMapUnit]
                self.r.setWidth(8)
                self.r.setToGeometry(QgsGeometry.fromPolyline(points), None)

                if abs(Compass -
                       azim) <= self.CompassTolerance:  #Compass tolerance
                    self.r.setColor(QtGui.QColor(0, 255, 0))
                else:
                    self.r.setColor(QtGui.QColor(255, 0, 0))

                self.RubberBand = True

                try:
                    self.iface.mapCanvas().scene().removeItem(
                        self.runo)  # remove track for first waypoint
                except:
                    pass

                if WptValue != 1:

                    #DistanceFromLineTolerance = 100   #meter      set distance from route

                    BackwardLat = self.rdue.asGeometry().asPolyline()[1][
                        1]  #start to design a QgsRectangle buffer around current route to confront to Point
                    BackwardLon = self.rdue.asGeometry().asPolyline()[1][0]
                    BackwardPoint = QgsPoint(BackwardLon, BackwardLat)

                    BackwardPointTransformed = self.backxform.transform(
                        BackwardPoint)

                    GeodesicWptWpt = Geodesic.WGS84.Inverse(
                        BackwardPointTransformed.y(),
                        BackwardPointTransformed.x(), WptN, WptE)
                    #GeodesicWptWpt = Geodesic.WGS84.Inverse(BackwardLat, BackwardLon, WptN, WptE)
                    WptWptCompass = GeodesicWptWpt['azi1']

                    if WptWptCompass < 0:
                        WptWptCompass += 360
                    #print WptWptCompass

                    WptWptCompassRight = WptWptCompass + 90
                    if WptWptCompassRight > 360:
                        WptWptCompassRight = WptWptCompassRight - 360
                    #print WptWptCompassRight

                    WptWptCompassLeft = WptWptCompass - 90
                    if WptWptCompassLeft < 0:
                        WptWptCompassLeft += 360
                    #print WptWptCompassLeft

                    origin = geopy.Point(WptN, WptE)
                    URBufferVertex = vincenty(
                        meters=self.InRouteTolerance).destination(
                            origin, WptWptCompassRight)
                    URBufferVertexPoint = QgsPoint(URBufferVertex.longitude,
                                                   URBufferVertex.latitude)

                    ULBufferVertex = vincenty(
                        meters=self.InRouteTolerance).destination(
                            origin, WptWptCompassLeft)
                    ULBufferVertexPoint = QgsPoint(ULBufferVertex.longitude,
                                                   ULBufferVertex.latitude)
                    del origin

                    origin = geopy.Point(BackwardPointTransformed.y(),
                                         BackwardPointTransformed.x())
                    DRBufferVertex = vincenty(
                        meters=self.InRouteTolerance).destination(
                            origin, WptWptCompassRight)
                    DRBufferVertexPoint = QgsPoint(DRBufferVertex.longitude,
                                                   DRBufferVertex.latitude)

                    DLBufferVertex = vincenty(
                        meters=self.InRouteTolerance).destination(
                            origin, WptWptCompassLeft)
                    DLBufferVertexPoint = QgsPoint(DLBufferVertex.longitude,
                                                   DLBufferVertex.latitude)
                    del origin

                    gPolygon = QgsGeometry.fromPolygon([[
                        URBufferVertexPoint, ULBufferVertexPoint,
                        DLBufferVertexPoint, DRBufferVertexPoint
                    ]])

                    if not gPolygon.contains(Point):
                        self.rdue.setColor(QtGui.QColor(255, 0, 0))
                        #print 'noncontiene'
                    else:
                        self.rdue.setColor(QtGui.QColor(0, 255, 0))
                        #print 'contiene'
                else:
                    self.runo = QgsRubberBand(self.iface.mapCanvas(), False)
                    points = [TransfPoint,
                              self.xform.transform(self.pts[0])
                              ]  # draw track for first waypoint
                    self.runo.setColor(QtGui.QColor(255, 0, 0))
                    self.runo.setWidth(6)
                    self.runo.setLineStyle(
                        QtCore.Qt.PenStyle(QtCore.Qt.DotLine))
                    self.runo.setToGeometry(QgsGeometry.fromPolyline(points),
                                            None)

                #if abs(float((self.fixedHeightspinBox.value()/ 3.2808399)) - (feetEle/ 3.2808399)) <= self.EleTolerance:         #ele tolerance expressed in meters
                if abs(self.fixedHeightspinBox.value() -
                       Ele) <= self.EleTolerance:
                    self.positionMarker.setHasPosition(
                        True)  #True or False to change color
                else:
                    self.positionMarker.setHasPosition(False)

                if self.trackCounter == 5:
                    #pass
                    fc = int(self.TrackLayerProvider.featureCount())
                    time = str(GPGGA[1])[0:2] + ':' + str(
                        GPGGA[1])[2:4] + ':' + str(
                            GPGGA[1])[4:6]  # timestamp for GPX layer

                    feature = QgsFeature()
                    feature.setGeometry(QgsGeometry.fromPoint(Point))
                    feature.setAttributes([fc, time, Ele])
                    self.TrackLayer.startEditing()
                    self.TrackLayer.addFeature(feature, True)
                    self.TrackLayer.commitChanges()
                    self.TrackLayer.setCacheImage(None)
                    self.TrackLayer.triggerRepaint()
                    self.trackCounter = 0

                return
Пример #26
0
class DrawMonoLineMapTool(QgsMapToolEmitPoint):

    azimuth_calcul = pyqtSignal(QgsPoint, QgsPoint)

    def __init__(self, canvas):
        self.canvas = canvas
        s = QSettings()
        s.beginGroup('qgis')
        color = QColor(int(s.value('default_measure_color_red', 222)),
                       int(s.value('default_measure_color_green', 17)),
                       int(s.value('default_measure_color_blue', 28)))
        s.endGroup()
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubberBandDraw = QgsRubberBand(self.canvas,
                                            QgsWkbTypes.LineGeometry)
        self.rubberBandDraw.setColor(color)
        self.rubberBandDraw.setWidth(1)
        self.rubberBand.setColor(color)
        self.rubberBand.setWidth(1)
        # self.rubberBand.setLineStyle(Qt.DashLine)
        self.points = []
        self.vertex = None
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandDraw.reset(QgsWkbTypes.LineGeometry)

    def canvasPressEvent(self, e):
        self.isEmittingPoint = False

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = True
        pt = self.snappoint(e.originalPixelPoint())
        self.startPoint = pt
        if len(self.points) < 2:
            self.rubberBandDraw.reset(QgsWkbTypes.LineGeometry)
            self.rubberBand.reset(QgsWkbTypes.LineGeometry)
            self.points.append(self.startPoint)
        if len(self.points) == 2:
            self.rubberBandDraw.setToGeometry(
                QgsGeometry.fromPolyline([
                    QgsPoint(self.points[0].x(), self.points[0].y()),
                    QgsPoint(self.points[1].x(), self.points[1].y())
                ]), None)
            self.points = []
            self.isEmittingPoint = False

    def canvasMoveEvent(self, e):
        self.snappoint(e.originalPixelPoint())  # input is QPoint
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates(e.pos())
        if len(self.points) > 0:
            start = QgsPoint(self.startPoint.x(), self.startPoint.y())
            end = QgsPoint(self.endPoint.x(), self.endPoint.y())
            geom = QgsGeometry.fromPolyline([start, end])
            self.rubberBand.setToGeometry(geom, None)
            if ((self.startPoint is not None and self.endPoint is not None
                 and self.startPoint != self.endPoint)):
                self.azimuth_calcul.emit(start, end)

    def activate(self):
        self.reset()
        super(DrawMonoLineMapTool, self).activate()
        self.snapcolor = QgsSettings().value("/qgis/digitizing/snap_color",
                                             QColor(Qt.magenta))
        self.activated.emit()

    def deactivate(self):
        self.reset()
        super(DrawMonoLineMapTool, self).deactivate()
        self.removeVertexMarker()
        self.deactivated.emit()

    def removeVertexMarker(self):
        if self.vertex is not None:
            self.canvas.scene().removeItem(self.vertex)
            self.vertex = None

    def snappoint(self, qpoint):
        match = self.canvas.snappingUtils().snapToMap(qpoint)
        if match.isValid():
            if self.vertex is None:
                self.vertex = QgsVertexMarker(self.canvas)
                self.vertex.setIconSize(12)
                self.vertex.setPenWidth(2)
                self.vertex.setColor(self.snapcolor)
                self.vertex.setIconType(QgsVertexMarker.ICON_BOX)
            self.vertex.setCenter(match.point())
            return (match.point())  # Returns QgsPointXY
        else:
            self.removeVertexMarker()
            return self.toMapCoordinates(
                qpoint)  # QPoint input, returns QgsPointXY
Пример #27
0
class StartDrawing(QgsMapToolEmitPoint):
    def __init__(self, canvas, iface):
        QgsMapToolEmitPoint.__init__(self, canvas)

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

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

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

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

        self.reset()

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

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

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

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

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

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

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

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

        layer = self.iface.activeLayer()

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

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

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

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

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

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

        points = [[
            QgsPointXY(  # Left Top corner
                x - (self.rubberBand_width / 2),
                y + (self.rubberBand_height / 2)),
            QgsPointXY(  # Right Top corner
                x + (self.rubberBand_width / 2),
                y + (self.rubberBand_height / 2)),
            QgsPointXY(  # Right Down corner
                x + (self.rubberBand_width / 2),
                y - (self.rubberBand_height / 2)),
            QgsPointXY(  # Left Down corner
                x - (self.rubberBand_width / 2),
                y - (self.rubberBand_height / 2))
        ]]
        polygon = QgsGeometry.fromPolygonXY(points)
        polygon.rotate(self.rubberBand_angle, point)
        return polygon
Пример #28
0
class DeleteTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

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

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

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

        self.mouse_clicked = False
        self.snapper = None

        self.clicked_pt = None

        self.snap_results = None
        self.adj_links_fts = None

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

        self.adj_pipes_fts_d = {}

    def canvasPressEvent(self, event):

        # if self.snap_results is None:
        #     return

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

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

    def canvasMoveEvent(self, event):

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

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

        # Mouse not clicked
        if not self.mouse_clicked:

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

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

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

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

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

    def canvasReleaseEvent(self, event):

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

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

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

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

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

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

                self.rubber_band.reset()

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

            # Refresh
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.junctions_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.reservoirs_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.tanks_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.pipes_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.pumps_vlay)
            symbology.refresh_layer(self.iface.mapCanvas(),
                                    self.params.valves_vlay)

    def activate(self):

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

        layers = {
            self.params.junctions_vlay: QgsSnappingConfig.Vertex,
            self.params.reservoirs_vlay: QgsSnappingConfig.Vertex,
            self.params.tanks_vlay: QgsSnappingConfig.Vertex,
            self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment
        }
        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)
        self.snapper.toggleEnabled()

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

    def deactivate(self):
        self.data_dock.btn_delete_element.setChecked(False)
        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def show_rect(self, start_point, end_point):

        self.rubber_band.reset()
        if start_point.x() == end_point.x() or start_point.y() == end_point.y(
        ):
            return

        point1 = QgsPointXY(start_point.x(), start_point.y())
        point2 = QgsPointXY(start_point.x(), end_point.y())
        point3 = QgsPointXY(end_point.x(), end_point.y())
        point4 = QgsPointXY(end_point.x(), start_point.y())
        point5 = QgsPointXY(start_point.x(), start_point.y())

        self.rubber_band.addPoint(point1, False)
        self.rubber_band.addPoint(point2, False)
        self.rubber_band.addPoint(point3, False)
        self.rubber_band.addPoint(point4, False)
        self.rubber_band.closePoints(True)  # true to update canvas
        self.rubber_band.show()

    def delete_elements(self, layer, rectangle):

        try:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            feats = layer.getFeatures()
            for feat in feats:
                if rectangle.contains(feat.geometry().boundingBox()):
                    self.delete_element(layer, feat)

        finally:
            QApplication.restoreOverrideCursor()

    def delete_element(self, layer, feature):

        # If node
        if layer == self.params.junctions_vlay or \
                        layer == self.params.reservoirs_vlay or \
                        layer == self.params.tanks_vlay:

            # The node is a junction
            if layer == self.params.junctions_vlay:

                adj_links_fts = NetworkUtils.find_adjacent_links(
                    self.params, feature.geometry())

                # Only pipes adjacent to node: it's a simple junction
                if not adj_links_fts['pumps'] and not adj_links_fts['valves']:

                    # Delete node
                    NodeHandler.delete_node(self.params, layer, feature)

                    # Delete adjacent pipes
                    adj_pipes = NetworkUtils.find_adjacent_links(
                        self.params, feature.geometry())
                    for adj_pipe in adj_pipes['pipes']:
                        LinkHandler.delete_link(self.params.pipes_vlay,
                                                adj_pipe)

                # The node is part of a pump or valve
                else:

                    if adj_links_fts['pumps']:
                        LinkHandler.delete_link(self.params,
                                                self.params.pumps_vlay,
                                                feature)

                    elif adj_links_fts['valves']:
                        LinkHandler.delete_link(self.params,
                                                self.params.valves_vlay,
                                                feature)

            # The node is a reservoir or a tank
            elif layer == self.params.reservoirs_vlay or \
                            layer == self.params.tanks_vlay:

                adj_pipes = NetworkUtils.find_adjacent_links(
                    self.params, feature.geometry())['pipes']

                NodeHandler._delete_feature(self.params, layer, feature)

                for adj_pipe in adj_pipes:
                    LinkHandler.delete_link(self.params,
                                            self.params.pipes_vlay, adj_pipe)

        # If pipe
        elif layer == self.params.pipes_vlay:

            if self.snap_results is not None:
                vertex = feature.geometry().closestVertexWithContext(
                    self.snap_results.point())
                vertex_dist = vertex[0]
                if vertex_dist < self.params.min_dist:
                    # Delete vertex
                    LinkHandler.delete_vertex(self.params,
                                              self.params.pipes_vlay, feature,
                                              vertex[1])
                else:
                    # Delete whole feature
                    LinkHandler.delete_link(self.params, layer, feature)
            else:
                LinkHandler.delete_link(self.params, layer, feature)
Пример #29
0
class ArkMapToolInteractive(QgsMapTool):

    _active = False

    _dragging = False
    _panningEnabled = False

    _zoomingEnabled = False
    _zoomRubberBand = None  #QgsRubberBand()
    _zoomRect = None # QRect()

    _snappingEnabled = False
    _snapper = None  #QgsMapCanvasSnapper()
    _snappingMarker = None  # QgsVertexMarker()

    _showSnappableVertices = False
    _snappableVertices = []  # [QgsPoint()]
    _snappableMarkers = []  # [QgsVertexMarker()]

    def __init__(self, canvas, snappingEnabled=False, showSnappableVertices=False):
        super(ArkMapToolInteractive, self).__init__(canvas)
        self._snappingEnabled = snappingEnabled
        self._showSnappableVertices = showSnappableVertices

    def __del__(self):
        if self._active:
            self.deactivate()

    def isActive(self):
        return self._active

    def activate(self):
        super(ArkMapToolInteractive, self).activate()
        self._active = True
        self._startSnapping()

    def deactivate(self):
        self._active = False
        if self._snappingEnabled:
            self._stopSnapping()
        if (self._zoomRubberBand is not None):
            self.canvas().scene().removeItem(self._zoomRubberBand)
            self._zoomRubberBand = None
        super(ArkMapToolInteractive, self).deactivate()

    def setAction(self, action):
        super(ArkMapToolInteractive, self).setAction(action)
        self.action().triggered.connect(self._activate)

    def _activate(self):
        self.canvas().setMapTool(self)

    def panningEnabled(self):
        return self._panningEnabled

    def setPanningEnabled(self, enabled):
        self._panningEnabled = enabled

    def zoomingEnabled(self):
        return self._zoomingEnabled

    def setZoomingEnabled(self, enabled):
        self._zoomingEnabled = enabled

    def snappingEnabled(self):
        return self._snappingEnabled

    def setSnappingEnabled(self, enabled):
        if (self._snappingEnabled == enabled):
            return
        self._snappingEnabled = enabled
        if not self._active:
            return
        if enabled:
            self._startSnapping()
        else:
            self._stopSnapping()

    def _startSnapping(self):
        self._snapper = QgsMapCanvasSnapper()
        self._snapper.setMapCanvas(self.canvas())
        if self._showSnappableVertices:
            self._startSnappableVertices()

    def _stopSnapping(self):
        self._deleteSnappingMarker()
        self._snapper = None
        if self._showSnappableVertices:
            self._stopSnappableVertices()

    def showSnappableVertices(self):
        return self._showSnappableVertices

    def setShowSnappableVertices(self, show):
        if (self._showSnappableVertices == show):
            return
        self._showSnappableVertices = show
        if not self._active:
            return
        if show:
            self._startSnappableVertices()
        else:
            self._stopSnappableVertices()

    def _startSnappableVertices(self):
        self.canvas().layersChanged.connect(self._layersChanged)
        self.canvas().extentsChanged.connect(self._redrawSnappableMarkers)
        QgsProject.instance().snapSettingsChanged.connect(self._layersChanged)
        self._layersChanged()

    def _stopSnappableVertices(self):
        self._deleteSnappableMarkers()
        self._snappableLayers = []
        self.canvas().layersChanged.disconnect(self._layersChanged)
        self.canvas().extentsChanged.disconnect(self._redrawSnappableMarkers)
        QgsProject.instance().snapSettingsChanged.disconnect(self._layersChanged)

    def canvasMoveEvent(self, e):
        super(ArkMapToolInteractive, self).canvasMoveEvent(e)
        if not self._active:
            return
        e.ignore()
        if (self._panningEnabled and e.buttons() & Qt.LeftButton):
            # Pan map mode
            if not self._dragging:
                self._dragging = True
                self.setCursor(QCursor(Qt.ClosedHandCursor))
            self.canvas().panAction(e)
            e.accept()
        elif (self._zoomingEnabled and e.buttons() & Qt.RightButton):
            # Zoom map mode
            if not self._dragging:
                self._dragging = True
                self.setCursor(QCursor(Qt.ClosedHandCursor))
                self._zoomRubberBand = QgsRubberBand(self.canvas(), QGis.Polygon)
                color = QColor(Qt.blue)
                color.setAlpha(63)
                self._zoomRubberBand.setColor(color)
                self._zoomRect = QRect(0, 0, 0, 0)
                self._zoomRect.setTopLeft(e.pos())
            self._zoomRect.setBottomRight(e.pos())
            if self._zoomRubberBand is not None:
                self._zoomRubberBand.setToCanvasRectangle(self._zoomRect)
                self._zoomRubberBand.show()
            e.accept()
        elif self._snappingEnabled:
            mapPoint, snapped = self._snapCursorPoint(e.pos())
            if (snapped):
                self._createSnappingMarker(mapPoint)
            else:
                self._deleteSnappingMarker()

    def canvasReleaseEvent(self, e):
        super(ArkMapToolInteractive, self).canvasReleaseEvent(e)
        e.ignore()
        if (e.button() == Qt.LeftButton):
            if self._dragging:
                # Pan map mode
                self.canvas().panActionEnd(e.pos())
                self.setCursor(capture_point_cursor)
                self._dragging = False
                e.accept()
        elif (e.button() == Qt.RightButton):
            if self._dragging:
                # Zoom mode
                self._zoomRect.setBottomRight(e.pos())
                if (self._zoomRect.topLeft() != self._zoomRect.bottomRight()):
                    coordinateTransform = self.canvas().getCoordinateTransform()
                    ll = coordinateTransform.toMapCoordinates(self._zoomRect.left(), self._zoomRect.bottom())
                    ur = coordinateTransform.toMapCoordinates(self._zoomRect.right(), self._zoomRect.top())
                    r = QgsRectangle()
                    r.setXMinimum(ll.x())
                    r.setYMinimum(ll.y())
                    r.setXMaximum(ur.x())
                    r.setYMaximum(ur.y())
                    r.normalize()
                    if (r.width() != 0 and r.height() != 0):
                        self.canvas().setExtent(r)
                        self.canvas().refresh()
                self._dragging = False
                if (self._zoomRubberBand is not None):
                    self.canvas().scene().removeItem(self._zoomRubberBand)
                    self._zoomRubberBand = None
                e.accept()

    def keyPressEvent(self, e):
        super(ArkMapToolInteractive, self).keyPressEvent(e)
        if (e.key() == Qt.Key_Escape):
            self.canvas().unsetMapTool(self)
            e.accept()

    def _snapCursorPoint(self, cursorPoint):
        res, snapResults = self._snapper.snapToBackgroundLayers(cursorPoint)
        if (res != 0 or len(snapResults) < 1):
            return self.toMapCoordinates(cursorPoint), False
        else:
            # Take a copy as QGIS will delete the result!
            snappedVertex = QgsPoint(snapResults[0].snappedVertex)
            return snappedVertex, True

    def _createSnappingMarker(self, snapPoint):
        if (self._snappingMarker is None):
            self._snappingMarker = QgsVertexMarker(self.canvas())
            self._snappingMarker.setIconType(QgsVertexMarker.ICON_CROSS)
            self._snappingMarker.setColor(Qt.magenta)
            self._snappingMarker.setPenWidth(3)
        self._snappingMarker.setCenter(snapPoint)

    def _deleteSnappingMarker(self):
        if (self._snappingMarker is not None):
            self.canvas().scene().removeItem(self._snappingMarker)
            self._snappingMarker = None

    def _createSnappableMarkers(self):
        if (not self._showSnappableVertices or not self._snappingEnabled):
            return
        extent = self.canvas().extent()
        for vertex in self._snappableVertices.asMultiPoint():
            if (extent.contains(vertex)):
                marker = QgsVertexMarker(self.canvas())
                marker.setIconType(QgsVertexMarker.ICON_X)
                marker.setColor(Qt.gray)
                marker.setPenWidth(1)
                marker.setCenter(vertex)
                self._snappableMarkers.append(marker)

    def _deleteSnappableMarkers(self):
        for marker in self._snappableMarkers:
            self.canvas().scene().removeItem(marker)
        del self._snappableMarkers[:]

    def _layersChanged(self):
        if (not self._showSnappableVertices or not self._snappingEnabled):
            return
        self._buildSnappableLayers()
        self._deleteSnappableMarkers()
        self._createSnappableMarkers()

    def _redrawSnappableMarkers(self):
        if (not self._showSnappableVertices or not self._snappingEnabled):
            return
        self._deleteSnappableMarkers()
        self._createSnappableMarkers()

    def _buildSnappableLayers(self):
        if (not self._showSnappableVertices or not self._snappingEnabled):
            return
        vertices = []
        for layer in self.canvas().layers():
            ok, enabled, type, units, tolerance, avoid = QgsProject.instance().snapSettingsForLayer(layer.id())
            if (ok and enabled and not layer.isEditable()):
                for feature in layer.getFeatures():
                    geometry = feature.geometry()
                    if geometry is None:
                        pass
                    elif geometry.type() == QGis.Point:
                        vertices.extend([geometry.asPoint()])
                    elif geometry.type() == QGis.Line:
                        vertices.extend(geometry.asPolyline())
                    elif geometry.type() == QGis.Polygon:
                        lines = geometry.asPolygon()
                        for line in lines:
                            vertices.extend(line)
        self._snappableVertices = QgsGeometry.fromMultiPoint(vertices)
        self._snappableVertices.simplify(0)
Пример #30
0
class LineMapTool(MapTool, QgsMapToolEmitPoint):
    '''
    draw a line on the map (connected, multiple sections)

    Attributes
    ----------
    drawn : pyqtSignal
        emitted after double click or right click on the map canvas, emits the
        drawn line
    '''
    drawn = pyqtSignal(QgsGeometry)
    wkbtype = QgsWkbTypes.LineGeometry

    def __init__(self,
                 ui_element: QWidget,
                 canvas: QgsMapCanvas = None,
                 color: Union[str, int] = None,
                 draw_markers=False,
                 line_width: int = 2,
                 line_style: int = Qt.SolidLine,
                 snap_geometry: QgsGeometry = None,
                 target_epsg: int = 25832):
        '''
        Parameters
        ----------
        ui_element : QWidget
            clickable UI element, clicking it will activate/deactivate this
            tool
        canvas : QgsMapCanvas, optional
            the map canvas the tool will work on, defaults to the map canvas of
            the QGIS UI
        color : int or str, optional
            color description, sets color of line and markers while
            drawing, defaults to blue
        draw_markers : bool, optional
            draw markers between segments of the line, defaults to no markers
        line_width : int, optional
            width of drawn lines in pixels, defaults to 2 pixels
        line_style : int, optional
            style of drawn lines (e.g. Qt.DashDotLine), defaults to solid line
        snap_geometry : QgsGeometry, optional
            snap drawn lines to outline of given geometry, defaults to no
            snapping
        target_epsg : int, optional
            projection of emitted geometry after drawing as epsg code,
            defaults to 25832
        '''
        self.canvas = canvas
        MapTool.__init__(self, ui_element, self.canvas)
        QgsMapToolEmitPoint.__init__(self, canvas=self.canvas)
        self.rubberband = QgsRubberBand(self.canvas, self.wkbtype)
        self.color = QColor(color) if color else QColor(0, 0, 255)
        self.rubberband.setColor(self.color)
        self.color.setAlpha(100)
        self.rubberband.setFillColor(self.color)
        self.rubberband.setLineStyle(line_style)
        self.rubberband.setWidth(line_width)

        self.snap_geometry = self.set_snap_geometry(snap_geometry)
        self.draw_markers = draw_markers
        if self.draw_markers:
            # auto points on outline should but doesn't work:
            #self.drawing_lines.setIcon(QgsRubberBand.ICON_CIRCLE)
            #self.drawing_lines.setIconSize(8)

            # drawing markers manually instead
            self.markers = []

        self._drawing = False
        self._moving = False

        # marker for showing snapped point on move
        self._move_marker = QgsVertexMarker(self.canvas)
        self._move_marker.setColor(self.color)
        self._move_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self._move_marker.setIconSize(10)
        self._move_marker.setPenWidth(3)

        self.reset()

    def set_snap_geometry(self, geom: QgsGeometry):
        '''
        snap lines to outline of given geometry

        Parameters
        ----------
        snap_geometry : QgsGeometry
            geometry to snap lines to
        '''
        if not geom:
            return
        if SHAPELY_LOADED:
            self.snap_geometry = wkt.loads(geom.asWkt()).boundary
        # alternative for MacOS
        else:
            self.snap_geometry = QgsCurvePolygon()
            self.snap_geometry.fromWkt(geom.asWkt())

    def reset(self):
        '''
        reset drawing
        '''
        scene = self.canvas.scene()
        if self.draw_markers:
            for m in self.markers:
                scene.removeItem(m)
            self.markers = []
        self._moving = False
        self._drawing = False
        self.rubberband.reset(self.wkbtype)

    def canvasDoubleClickEvent(self, e):
        '''
        override, emit line on double click
        '''
        if self._moving:
            self.rubberband.removeLastPoint()
        geom = self.rubberband.asGeometry()
        self.drawn.emit(self.transform_from_map(geom))
        self.reset()

    def _snap(self, point: QgsPoint) -> QgsPointXY:
        '''
        snap point to snap-geometry
        '''
        point = self.transform_from_map(point)
        if SHAPELY_LOADED:
            p = geometry.Point(point.x(), point.y())
            np = nearest_points(self.snap_geometry, p)[0]
            p = QgsPointXY(np.x, np.y)
        # alternative for MacOS
        else:
            closest = QgsGeometryUtils.closestPoint(
                self.snap_geometry, QgsPoint(point.x(), point.y()))
            p = QgsPointXY(closest.x(), closest.y())
        p = self.transform_to_map(p)
        return p

    def canvasPressEvent(self, e):
        '''
        override, finish line segment when map is clicked
        '''
        if (e.button() == Qt.RightButton):
            if self._moving:
                self.rubberband.removeLastPoint()
            geom = self.rubberband.asGeometry()
            self.drawn.emit(self.transform_from_map(geom))
            self.reset()
            return
        self._moving = False
        self._drawing = True
        point = self.toMapCoordinates(e.pos())
        if self.snap_geometry:
            point = self._snap(point)
        self.rubberband.addPoint(point, True)
        if self.draw_markers:
            marker = QgsVertexMarker(self.canvas)
            marker.setCenter(point)
            marker.setColor(self.color)
            marker.setIconSize(8)
            marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            marker.setPenWidth(4)
            self.markers.append(marker)

    def canvasMoveEvent(self, e):
        '''
        override, draw connecting line to last segment when moving mouse
        '''
        if not self.snap_geometry and not self._drawing:
            return
        point = self.toMapCoordinates(e.pos())
        if self.snap_geometry:
            point = self._snap(point)
        if self.snap_geometry:
            self._move_marker.setCenter(point)
        if self._drawing:
            #self.rubberBand.removeLastPoint()
            if self._moving:
                self.rubberband.removeLastPoint()
            self.rubberband.addPoint(point, True)
            self._moving = True

    def disconnect(self, **kwargs):
        '''
        override, 'remove' marker
        '''
        if self._move_marker:
            #scene = self.canvas.scene()
            #scene.removeItem(self._move_marker)
            # workaround: if removed from scene marker won't appear any more
            # set it somewhere it can't be seen
            self._move_marker.setCenter(QgsPointXY(0, 0))
        super().disconnect(**kwargs)
class PdokServicesPlugin(object):

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # docked or dialog, defaults to dialog
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant):
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False))
        # else:
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        #
        # # Create the dialog and keep reference
        # if "True" == self.docked or "true" == self.docked or True is self.docked:
        #     self.dlg = PdokServicesPluginDockWidget()
        #     self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        # else:
        #     self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())

        self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + "/python/plugins/pdokservicesplugin"
        # initialize locale
        localePath = ""
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            locale = QSettings().value("locale/userLocale").value()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]

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

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None

    def getSettingsValue(self, key, default=''):
        if QSettings().contains(self.SETTINGS_SECTION + key):
            key = self.SETTINGS_SECTION + key
            if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8
                return str(QSettings().value(key).toString())
            else:
                return str(QSettings().value(key))
        else:
            return default

    def setSettingsValue(self, key, value):
        key = self.SETTINGS_SECTION + key
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue(key, QVariant(value))
        else:
            QSettings().setValue(key, value)

    def initGui(self):
        # Create action that will start plugin configuration
        self.run_action = QAction(QIcon(":/plugins/pdokservicesplugin/icon.png"), \
            u"Pdok Services Plugin", self.iface.mainWindow())

        self.servicesLoaded = False
        # connect the action to the run method
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if "True" == self.docked or "true" == self.docked or  True == self.docked:
        #     self.run_action.triggered.connect(self.showAndRaise)
        #     self.dlg.radioDocked.setChecked(True)
        #     # docked the dialog is immidiately visible, so should run NOW
        # else:
        #     self.run_action.triggered.connect(self.run)
        #     self.dlg.radioDocked.setChecked(False)
        #     self.setupfq()
        self.run_action.triggered.connect(self.run)
        #self.dlg.radioDocked.setChecked(False)
        self.setupfq()

        # Add toolbar button and menu item
        #self.iface.addToolBarIcon(self.action)

        self.toolbar = self.iface.addToolBar("PDOK services plugin")
        self.toolbar.setObjectName("PDOK services plugin")
        self.toolbar.addAction(self.run_action)
        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar)
        # address/point cleanup
        self.clean_action = QAction(QIcon(":/plugins/pdokservicesplugin/eraser.png"), \
            u"Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)

        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/help.png"), \
                            "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("Pdok Services Plugin About")
        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction)

        self.aboutAction.triggered.connect(self.about)
        self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService)

        self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress)

        self.dlg.geocoderSearch.textEdited.connect(self.searchAddress)
        self.dlg.geocoderSearch.setPlaceholderText("PDOK Locatieserver zoek, bv postcode of postcode huisnummer")

        self.dlg.geocoderResultSearch.textChanged.connect(self.filterGeocoderResult)
        self.dlg.geocoderResultSearch.setPlaceholderText("een of meer zoekwoorden uit resultaat")

        #self.dlg.radioDocked.toggled.connect(self.set_docked)

        self.dlg.btnCheckPdokJson.clicked.connect(self.checkPdokJson)
        #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged)

        ui = self.dlg.ui
        cbxs = [ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp]
        # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search
        for cbx in cbxs:
            cbx.stateChanged.connect(self.searchAddress)

        self.run(True)

    # for now hiding the pointer as soon as the extent changes
    #def extentsChanged(self):
    #    self.removePointer()

    def checkPdokJson(self):
        myversion = self.getSettingsValue('pdokversion', '1')
        msgtxt = ''
        msglvl = 0  # QgsMessageBar.INFO
        try:
            response = urllib.request.urlopen('http://www.qgis.nl/pdok.version')
            str_response = response.read().decode('utf-8')
            pdokversion = json.loads(str_response)
            if pdokversion > int(myversion):
                response = urllib.request.urlopen('http://www.qgis.nl/pdok.json')
                str_response = response.read().decode('utf-8')
                pdokjson = json.loads(str_response)
                with open(self.plugin_dir +'/pdok.json', 'w') as outfile:
                    json.dump(pdokjson, outfile)
                msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \
                    str(pdokversion) + ' (was ' + myversion +')'
                self.servicesLoaded = False # reset reading of json
                self.run()
                self.setSettingsValue('pdokversion', pdokversion)
            else:
                msgtxt = "Geen nieuwere versie beschikbaar dan " + str(pdokversion)
        except Exception as e:
            #print e
            msgtxt = "Fout bij ophalen van service info. Netwerk probleem?"
            msglvl = 2 # QgsMessageBar.CRITICAL
        # msg
        if hasattr(self.iface, 'messageBar'):
            self.iface.messageBar().pushMessage("PDOK services update", msgtxt, level=msglvl, duration=10)
        else: # 1.8
            QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin", msgtxt)

    # def set_docked(self, foo):
    #     self.setSettingsValue('docked', self.dlg.radioDocked.isChecked())
    #     #if Qgis.QGIS_VERSION_INT < 10900:
    #     #    # qgis <= 1.8
    #     #    QSettings().setValue("/pdokservicesplugin/docked", QVariant(self.dlg.radioDocked.isChecked()))
    #     #else:
    #     #    QSettings().setValue("/pdokservicesplugin/docked", self.dlg.radioDocked.isChecked())

    def showAndRaise(self):
        self.dlg.show()
        self.dlg.raise_()
        # also remove the pointer
        self.removePointer()

    def about(self):
        infoString =  "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - Zuidt - http://www.zuidt.nl\n"
        infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin"
        QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin About", infoString)

    def unload(self):
        self.removePointer()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(u"&Pdok Services Plugin",self.run_action)
        del self.toolbarSearch

    def showService(self, selectedIndexes):
        if len(selectedIndexes)==0:
            self.currentLayer = None
            self.dlg.ui.layerInfo.setHtml('')
            self.dlg.ui.comboSelectProj.clear()
            return
        # needed to scroll To the selected row incase of using the keyboard / arrows
        self.dlg.servicesView.scrollTo(self.dlg.servicesView.selectedIndexes()[0])
        # itemType holds the data (== column 1)
        self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data(Qt.UserRole)
        if isinstance(self.currentLayer, QVariant):
            self.currentLayer = self.currentLayer.toMap()
            # QGIS 1.8: QVariants
            currentLayer = {}
            for key in list(self.currentLayer.keys()):
                val = self.currentLayer[key]
                currentLayer[str(key)]=str(val.toString())
            self.currentLayer = currentLayer
        url = self.currentLayer['url']
        title = self.currentLayer['title']
        style = ''
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        servicetitle = self.currentLayer['servicetitle']
        layername = self.currentLayer['layers']
        abstract = self.currentLayer['abstract']
        stype = self.currentLayer['type'].upper()
        minscale =''
        if 'minscale' in self.currentLayer and self.currentLayer['minscale'] != None and self.currentLayer['minscale'] != '':
            minscale = "min. schaal 1:"+self.currentLayer['minscale']
        maxscale = ''
        if 'maxscale' in self.currentLayer and self.currentLayer['maxscale'] != None and self.currentLayer['maxscale'] != '':
            maxscale = "max. schaal 1:"+self.currentLayer['maxscale']
        self.dlg.ui.layerInfo.setText('')
        self.dlg.ui.btnLoadLayer.setEnabled(True)
        self.dlg.ui.layerInfo.setHtml('<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li>&nbsp;</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>' % (servicetitle, title, abstract, stype, url, layername, style, minscale, maxscale))
        self.dlg.ui.comboSelectProj.clear()
        if stype=="WMS":
            try:
                crs = self.currentLayer['crs']
            except KeyError:
                crs = 'EPSG:28992'
            crs = crs.split(',')
            self.dlg.ui.comboSelectProj.addItems(crs)
            for i in range(len(crs)):
                if crs[i] == 'EPSG:28992':
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)
        if stype=="WMTS":
            tilematrixsets = self.currentLayer['tilematrixsets'].split(',')
            self.dlg.ui.comboSelectProj.addItems(tilematrixsets)
            for i in range(len(tilematrixsets)):
                if tilematrixsets[i].startswith('EPSG:28992'):
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)

    def loadService(self):
        if self.currentLayer == None:
            return
        servicetype = self.currentLayer['type']
        url = self.currentLayer['url']
        # some services have an url with query parameters in it, we have to urlencode those:
        location,query = urllib.parse.splitquery(url)
        url = location
        if query != None and query != '':
            url +=('?'+urllib.parse.quote_plus(query))
        title = self.currentLayer['title']
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        else:
            style = '' # == default for this service
        layers = self.currentLayer['layers']
        # mmm, tricky: we take the first one while we can actually want png/gif or jpeg
        if servicetype == "wms":
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                crs = 'EPSG:28992'
            else:
                crs = self.dlg.ui.comboSelectProj.currentText()
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                uri = url
                self.iface.addRasterLayer(
                    uri, # service uri
                    title, # name for layer (as seen in QGIS)
                    "wms", # dataprovider key
                    [layers], # array of layername(s) for provider (id's)
                    [""], # array of stylename(s)  NOTE: ignoring styles here!!!
                    imgformat, # image format searchstring
                    crs) # crs code searchstring
            else:
                # qgis > 1.8
                uri = "crs="+crs+"&layers="+layers+"&styles="+style+"&format="+imgformat+"&url="+url;
                self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wmts":
            if Qgis.QGIS_VERSION_INT < 10900:
                QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
                return
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                tilematrixset = 'EPSG:28992'
            else:
                tilematrixset = self.dlg.ui.comboSelectProj.currentText()
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            # special case for luchtfoto
            #if layers=="luchtfoto":
            #    # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml
            #    # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'}
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url
            #else:
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url;
            #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            if tilematrixset.startswith('EPSG:'):
                crs=tilematrixset
                i = crs.find(':', 5)
                if i > -1:
                    crs=crs[:i]
            elif tilematrixset.startswith('OGC:1.0'):
                crs='EPSG:3857'
            uri = "tileMatrixSet="+tilematrixset+"&crs="+crs+"&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            #print "############ PDOK URI #################"
            #print uri
            self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wfs":
            location, query = urllib.parse.splitquery(url)
            #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992"
            #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992"
            # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time
            # QGIS will update the BBOX to the right value
            #uri += "&BBOX=-10000,310000,290000,650000"
            uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='"+layers+"' url='"+url+"' version='2.0.0' "
            self.iface.addVectorLayer(uri, title, "WFS")
        elif servicetype == "wcs":
            # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            uri = ''
            # cache=AlwaysCache
            # cache=PreferNetwork 
            # cache=AlwaysNetwork
            # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url
            # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32
            format = 'GEOTIFF_FLOAT32'
            # working for ahn25m is only image/tiff
            if layers=='ahn25m':
                format = 'image/tiff'
            # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32):
            if 'imgformats' in self.currentLayer:
                format = self.currentLayer['imgformats'].split(',')[0]
            uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&version=1.1.2&identifier=" + layers + "&url=" + url

            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url
            self.iface.addRasterLayer(uri, title, "wcs")
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
            return

    def filterGeocoderResult(self, string):
        #print "filtering geocoder results: %s" % string
        self.dlg.geocoderResultView.selectRow(0)
        self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.geocoderProxyModel.setFilterFixedString(string)

    def searchAddressFromToolbar(self):
        self.removePointer()
        self.geocoderSourceModel.clear()
        self.geocode()

    def searchAddress(self):
        self.removePointer()
        #print "search geocoder for: %s" % self.dlg.geocoderSearch.text()
        self.geocoderSourceModel.clear()
        #self.geocode(self.dlg.geocoderSearch.text())
        self.suggest()


    def eraseAddress(self):
        """
        clean the input and remove the pointer
        """
        self.removePointer()
        if self.geocoderSourceModel is not None:
            self.geocoderSourceModel.clear()
        if self.dlg.geocoderSearch is not None:
            self.dlg.geocoderSearch.clear()
        if self.toolbarSearch is not None:
            self.toolbarSearch.clear()

    def filterLayers(self, string):
        # remove selection if one row is selected
        self.dlg.servicesView.selectRow(0)
        #self.currentLayer = None
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setFilterFixedString(string)

    #def addSourceRow(self, service, layer):
    def addSourceRow(self, serviceLayer):
        # you can attache different "data's" to to an QStandarditem
        # default one is the visible one:
        itemType = QStandardItem("%s" % (serviceLayer["type"].upper()) )
        # userrole is a free form one:
        # only attach the data to the first item
        # service layer = a dict/object with all props of the layer
        itemType.setData( serviceLayer, Qt.UserRole )
        itemType.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        # only wms services have styles (sometimes)
        layername = serviceLayer["title"]
        if 'style' in serviceLayer:
            itemLayername = QStandardItem("%s [%s]" % (serviceLayer["title"], serviceLayer["style"]) )
            layername = "%s [%s]" % (serviceLayer["title"], serviceLayer["style"])
        else:
            itemLayername = QStandardItem("%s" % (serviceLayer["title"]))
        itemLayername.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["servicetitle"] ))
        # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here
        itemFilter = QStandardItem("%s %s %s %s" % (serviceLayer["type"], layername, serviceLayer["servicetitle"], serviceLayer["abstract"]) )
        itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"]))
        itemServicetitle.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        self.sourceModel.appendRow( [ itemLayername, itemType, itemServicetitle, itemFilter ] )

    # run method that performs all the real work
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value("/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".", "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            # 
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText("woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel().selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True;

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab", QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab", self.dlg.tabs.currentIndex())
        self.removePointer()

    def setupfq(self):
        """
        Setup the fq checkboxes in the gui, by looking into the settings for the
        'pdokservicesplugin/checkedfqs' key, which contains a list of type strings
        like ['weg','adres']
        """
        checked_fqs = self.getSettingsValue('checkedfqs', [])
        #self.info('setup fq: {}'.format(checked_fqs))
        if len(checked_fqs) > 0:  # else there is not saved state... take gui defaults
            self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs)
            self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs)
            self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs)
            self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs)
            self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs)
            self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs)
            self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs)

    def createfq(self):
        """
        This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver)
        Based on the checkboxes in the dialog.
        Defaults to ''
        Example: 'fq=+type:adres+type:gemeente'  (only gemeente AND addresses)
        :return:
        """
        fqlist = []
        if self.dlg.ui.cbx_gem.isChecked():
            fqlist.append('gemeente')
        if self.dlg.ui.cbx_wpl.isChecked():
            fqlist.append('woonplaats')
        if self.dlg.ui.cbx_weg.isChecked():
            fqlist.append('weg')
        if self.dlg.ui.cbx_pcd.isChecked():
            fqlist.append('postcode')
        if self.dlg.ui.cbx_adr.isChecked():
            fqlist.append('adres')
        if self.dlg.ui.cbx_pcl.isChecked():
            fqlist.append('perceel')
        if self.dlg.ui.cbx_hmp.isChecked():
            fqlist.append('hectometerpaal')
        self.setSettingsValue('checkedfqs', fqlist)
        #self.info(self.getSettingsValue('checkedfqs', ['leeg?']))
        fq = ''
        if len(fqlist) > 0:
            fq = '&fq=+type:' + '+type:'.join(fqlist)
        return fq

    def suggest(self):
        self.dlg.ui.lookupinfo.setHtml('')
        search_text = self.dlg.geocoderSearch.text()
        if len(search_text) <= 1:
            # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
            #     "meer input aub: {}".format(search_text)
            #     ), QMessageBox.Ok, QMessageBox.Ok)
            return
        # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
        #     "zoeken: {}".format(search_text)
        # ), QMessageBox.Ok, QMessageBox.Ok)
        results = self.pdokgeocoder.suggest(search_text, self.createfq())
        if len(results) == 0:
            # ignore, as we are suggesting, maybe more characters will reveal something...
            return
        for result in results:
            #print address
            adrestekst = QStandardItem("%s" % (result["adrestekst"]))
            adrestekst.setData(result, Qt.UserRole)
            type = QStandardItem("%s" % (result["type"]))
            id = QStandardItem("%s" % (result["id"]))
            score = QStandardItem("%s" % (result["score"]))
            adrestekst.setData(result, Qt.UserRole)
            self.geocoderSourceModel.appendRow([adrestekst, type])
        self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
        self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        self.dlg.geocoderResultView.resizeColumnsToContents()
        self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def geocode(self):
        self.dlg.geocoderSearch.setText(self.toolbarSearch.text())
        self.suggest()
        if self.dlg.geocoderResultView.model().rowCount()>0:
            self.dlg.geocoderResultView.selectRow(0)
            self.zoomToAddress()
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
                "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog."
                ), QMessageBox.Ok, QMessageBox.Ok)

    # def geocode(self):
    #     self.dlg.ui.lookupinfo.setHtml('')
    #     search_text = self.toolbarSearch.text()
    #     addresses = self.pdokgeocoder.search(search_text)
    #     if len(addresses) == 0:
    #         QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
    #             "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer."
    #             ), QMessageBox.Ok, QMessageBox.Ok)
    #         return
    #     for address in addresses:
    #         #print address
    #         adrestekst = QStandardItem("%s" % (address["adrestekst"]))
    #         adrestekst.setData(address, Qt.UserRole)
    #         straat = QStandardItem("%s" % (address["straat"]))
    #         nummer = QStandardItem("%s" % (address["nummer"]))
    #         postcode = QStandardItem("%s" % (address["postcode"]))
    #         plaats = QStandardItem("%s" % (address["plaats"]))
    #         gemeente = QStandardItem("%s" % (address["gemeente"]))
    #         provincie = QStandardItem("%s" % (address["provincie"]))
    #         self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie])
    #
    #     self.dlg.geocoderResultView.selectRow(0)
    #     self.zoomToAddress()
    #
    #     self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
    #     self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat")
    #     self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr")
    #     self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode")
    #     self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats")
    #     self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente")
    #     self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie")
    #
    #     self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft)
    #
    #     self.dlg.geocoderResultView.resizeColumnsToContents()
    #     self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def zoomToAddress(self):
        # get x,y from data of record
        self.removePointer()

        data = self.dlg.geocoderResultView.selectedIndexes()[0].data(Qt.UserRole)

        if 'centroide_rd' in data: # free OR lookup service
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
        else:
            # no centroid yet, probably only object id, retrieve it via lookup service
            id = data['id']
            data = self.pdokgeocoder.lookup(id)
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
            lookup_data= data['data']
            lis = ''
            for key in lookup_data.keys():
                lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key])
            self.dlg.ui.lookupinfo.setHtml(
                '<h4>{}</h4><lu>{}</lu>'.format(adrestekst, lis))

        # just always transform from 28992 to mapcanvas crs
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        crs28992 = QgsCoordinateReferenceSystem()
        crs28992.createFromId(28992)
        crsTransform = QgsCoordinateTransform(crs28992, crs, QgsProject.instance())
        z = 1587
        if adrestekst.lower().startswith('adres'):
            z = 794
        elif adrestekst.lower().startswith('perceel'):
            z = 794
        elif adrestekst.lower().startswith('hectometer'):
            z = 1587
        elif adrestekst.lower().startswith('straat'):
            z = 3175
        elif adrestekst.lower().startswith('postcode'):
            z = 6350
        elif adrestekst.lower().startswith('woonplaats'):
            z = 25398
        elif adrestekst.lower().startswith('gemeente'):
            z = 50797
        elif adrestekst.lower().startswith('provincie'):
            z = 812750
        geom.transform(crsTransform)
        center = geom.asPoint()
        self.setPointer(center)
        # zoom to with center is actually setting a point rectangle and then zoom
        rect = QgsRectangle(center, center)
        self.iface.mapCanvas().setExtent(rect)
        self.iface.mapCanvas().zoomScale(z)
        self.iface.mapCanvas().refresh()

    def setPointer(self, point):
        self.removePointer()
        self.pointer = QgsVertexMarker(self.iface.mapCanvas())
        self.pointer.setColor(QColor(255, 255, 0))
        self.pointer.setIconSize(10)
        self.pointer.setPenWidth(5)
        self.pointer.setCenter(point)

    def removePointer(self):
        if self.pointer is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin', Qgis.Info)
Пример #32
0
class ParentMapTool(QgsMapTool):


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

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.show_help = bool(int(self.settings.value('status/show_help', 1)))
        self.index_action = index_action
        self.layer_arc = None        
        self.layer_connec = None        
        self.layer_node = None   
        
        self.layer_arc_man = None        
        self.layer_connec_man = None        
        self.layer_node_man = None
        self.layer_gully_man = None 
            
        self.schema_name = None        
        self.controller = None        
        self.dao = None 
        
        # Call superclass constructor and set current action        
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Snapper
        self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper = QgsMapCanvasSnapper(self.canvas)
        
        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)

        # Get default cursor
        self.std_cursor = self.parent().cursor()    
        
        # Set default vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)  
                 
        # Set default rubber band
        color_selection = QColor(254, 178, 76, 63)
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Polygon)   
        self.rubber_band.setColor(color)
        self.rubber_band.setFillColor(color_selection)           
        self.rubber_band.setWidth(1)           
        self.reset()
        
        self.force_active_layer = True
        
        # Set default encoding 
        reload(sys)
        sys.setdefaultencoding('utf-8')   #@UndefinedVariable    
        
        
    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """
        
        path_folder = os.path.join(os.path.dirname(__file__), os.pardir) 
        path_cursor = os.path.join(path_folder, 'icons', '201.png')                
        if os.path.exists(path_cursor):      
            cursor = QCursor(QPixmap(path_cursor))    
        else:        
            cursor = QCursor(Qt.ArrowCursor)  
                
        return cursor
     

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


    def set_controller(self, controller):
        self.controller = controller
        self.schema_name = controller.schema_name
        self.plugin_dir = self.controller.plugin_dir 
        self.snapper_manager.controller = controller
        
        
    def deactivate(self):
        
        # Uncheck button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapper_manager.recover_snapping_options()

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

        # Remove highlight
        self.vertex_marker.hide()        


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

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')           
        icon_path = os.path.join(icons_folder, str(icon) + ".png")           
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)
            
    
    def set_action_pan(self):
        """ Set action 'Pan' """  
        try:
            self.iface.actionPan().trigger()     
        except Exception:          
            pass  


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

        # Selection
        self.snapped_feat = None      
        
    
    def cancel_map_tool(self):
        """ Executed if user press right button or escape key """
        
        # Reset rubber band
        self.reset()

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

    def remove_markers(self):
        """ Remove previous markers """
             
        vertex_items = [i for i in self.canvas.scene().items() if issubclass(type(i), QgsVertexMarker)]
        for ver in vertex_items:
            if ver in self.canvas.scene().items():
                self.canvas.scene().removeItem(ver)
        

    def refresh_map_canvas(self):
        """ Refresh all layers present in map canvas """
        
        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()     
           
           
    def open_dialog(self, dlg=None, dlg_name=None, maximize_button=True, stay_on_top=True): 
        """ Open dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
            
        # Manage i18n of the dialog                  
        if dlg_name:      
            self.controller.manage_translation(dlg_name, dlg)      
            
        # Manage stay on top and maximize button
        if maximize_button and stay_on_top:           
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint)       
        elif not maximize_button and stay_on_top:
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowStaysOnTopHint) 
        elif maximize_button and not stay_on_top:
            dlg.setWindowFlags(Qt.WindowMaximizeButtonHint)              

        # Open dialog
        dlg.open()    
                    

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


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

        if dialog is None:
            dialog = self.dlg

        try:
            x = self.controller.plugin_settings_value(dialog.objectName() + "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() + "_y")
            width = self.controller.plugin_settings_value(dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                screens = ctypes.windll.user32
                screen_x = screens.GetSystemMetrics(78)
                screen_y = screens.GetSystemMetrics(79)
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass
            
            
    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """   
                   
        if dialog is None:
            dialog = self.dlg
            
        try:             
            self.controller.plugin_settings_set_value(dialog.objectName() + "_width", dialog.property('width'))
            self.controller.plugin_settings_set_value(dialog.objectName() + "_height", dialog.property('height'))
            self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x())
            self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y())  
        except:
            pass                      
            
        
    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr is valid """
        
        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)      
            return (False, expr)
        return (True, expr)
    
        
    def canvasMoveEvent(self, event):
        
        # Make sure active layer is always 'v_edit_node'
        cur_layer = self.iface.activeLayer()
        if cur_layer != self.layer_node and self.force_active_layer:
            self.iface.setActiveLayer(self.layer_node) 
          
        # Hide highlight
        self.vertex_marker.hide()
  
        try:
            # Get current mouse coordinates
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)
        except(TypeError, KeyError):
            self.iface.actionPan().trigger()
            return

        # Snapping
        (retval, result) = self.snapper.snapToCurrentLayer(event_point, 2)  # @UnusedVariable
  
        # That's the snapped features
        if result:          
            # Get the point and add marker on it
            point = QgsPoint(result[0].snappedVertex)
            self.vertex_marker.setCenter(point)
            self.vertex_marker.show()           
                             
Пример #33
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 pipe_band_geom is None 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.',
                            QgsMessageBar.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.',
                                    QgsMessageBar.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.',
                                QgsMessageBar.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.',
                            QgsMessageBar.WARNING, 5)  # TODO: softcode

                return

            # There's a rubber band: create new pipe
            if pipe_band_geom is not None:
                # Finalize line
                rubberband_pts = pipe_band_geom.asPolyline()[:-1]
                rubberband_pts = self.remove_duplicated_point(rubberband_pts)

                if len(rubberband_pts) < 2:
                    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())
                    diameter = float(self.data_dock.txt_pipe_diameter.text())
                    loss = float(self.data_dock.txt_pipe_loss.text())
                    roughness = float(
                        self.data_dock.lbl_pipe_roughness_val_val.text())
                    status = self.data_dock.cbo_pipe_status.currentText()
                    material = self.data_dock.cbo_pipe_roughness.currentText()
                    pipe_desc = self.data_dock.txt_pipe_desc.text()
                    pipe_tag = self.data_dock.cbo_pipe_tag.currentText()

                    pipe_ft = LinkHandler.create_new_pipe(
                        self.params, pipe_eid, diameter, loss, roughness,
                        status, material,
                        rubberband_pts[junct_nrs[np]:junct_nrs[np + 1] + 1],
                        True, pipe_desc, pipe_tag)
                    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()

                # 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.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                    deltaz = float(self.data_dock.txt_junction_deltaz.text())
                    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,
                        j_demand, deltaz, pattern_id, emitter_coeff,
                        junction_desc, junction_tag)

                (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.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                    deltaz = float(self.data_dock.txt_junction_deltaz.text())

                    pattern = self.data_dock.cbo_junction_pattern.itemData(
                        self.data_dock.cbo_junction_pattern.currentIndex())
                    if pattern is not None:
                        pattern_id = pattern.id
                    else:
                        pattern_id = None
                    NodeHandler.create_new_junction(
                        self.params, new_end_junction, junction_eid, elev,
                        demand, deltaz, pattern_id, emitter_coeff,
                        junction_desc, junction_tag)

                # 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.fromPoint(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.fromPoint(new_end_junction)) < self.params.tolerance:
                            LinkHandler.split_pipe(self.params, pipe_ft,
                                                   new_end_junction)

        # 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(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: QgsPointLocator.Vertex,
            self.params.reservoirs_vlay: QgsPointLocator.Vertex,
            self.params.tanks_vlay: QgsPointLocator.Vertex,
            self.params.pipes_vlay: QgsPointLocator.All
        }

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

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
Пример #34
0
class CopyLatLonTool(QgsMapToolEmitPoint):
    '''Class to interact with the map canvas to capture the coordinate
    when the mouse button is pressed and to display the coordinate in
    in the status bar.'''
    captureStopped = pyqtSignal()

    def __init__(self, settings, iface):
        QgsMapToolEmitPoint.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.settings = settings
        self.marker = None
        self.vertex = None

    def activate(self):
        '''When activated set the cursor to a crosshair.'''
        self.canvas.setCursor(Qt.CrossCursor)
        self.snapcolor = QgsSettings().value("/qgis/digitizing/snap_color",
                                             QColor(Qt.magenta))

    def deactivate(self):
        self.removeMarker()
        self.removeVertexMarker()
        self.captureStopped.emit()

    def formatCoord(self, pt, delimiter):
        '''Format the coordinate string according to the settings from
        the settings dialog.'''
        if self.settings.captureProjIsWgs84():  # ProjectionTypeWgs84
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            lat = pt4326.y()
            lon = pt4326.x()
            if self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDMS:  # DMS
                msg = formatDmsString(lat, lon, 0, self.settings.dmsPrecision,
                                      self.settings.coordOrder, delimiter,
                                      settings.captureAddDmsSpace,
                                      settings.capturePadZeroes)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDDMMSS:  # DDMMSS
                msg = formatDmsString(lat, lon, 1, self.settings.dmsPrecision,
                                      self.settings.coordOrder, delimiter,
                                      settings.capturePadZeroes)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDMM:  # DM.MM
                msg = formatDmsString(lat, lon, 2,
                                      settings.captureDmmPrecision,
                                      self.settings.coordOrder, delimiter,
                                      settings.captureAddDmsSpace,
                                      settings.capturePadZeroes)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeWKT:  # WKT
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt4326.x(), pt4326.y(), prec=self.settings.decimalDigits)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeGeoJSON:  # GeoJSON
                msg = '{{"type": "Point","coordinates": [{:.{prec}f},{:.{prec}f}]}}'.format(
                    pt4326.x(), pt4326.y(), prec=self.settings.decimalDigits)
            else:  # decimal degrees
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt4326.y(),
                        delimiter,
                        pt4326.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt4326.x(),
                        delimiter,
                        pt4326.y(),
                        prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsProjectCRS():
            # Projection in the project CRS
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.y(),
                        delimiter,
                        pt.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.x(),
                        delimiter,
                        pt.y(),
                        prec=self.settings.decimalDigits)
            else:
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt.x(), pt.y(), prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsCustomCRS():
            # Projection is a custom CRS
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            customCRS = self.settings.captureCustomCRS()
            transform = QgsCoordinateTransform(canvasCRS, customCRS,
                                               QgsProject.instance())
            pt = transform.transform(pt.x(), pt.y())
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.y(),
                        delimiter,
                        pt.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.x(),
                        delimiter,
                        pt.y(),
                        prec=self.settings.decimalDigits)
            else:
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt.x(), pt.y(), prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsMGRS():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            try:
                msg = mgrs.toMgrs(pt4326.y(), pt4326.x())
            except Exception:
                # traceback.print_exc()
                msg = None
        elif self.settings.captureProjIsPlusCodes():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            try:
                msg = olc.encode(pt4326.y(), pt4326.x(),
                                 self.settings.plusCodesLength)
            except Exception:
                msg = None
        elif self.settings.captureProjIsUTM():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            msg = latLon2UtmString(pt4326.y(), pt4326.x(),
                                   settings.captureUtmPrecision)
            if msg == '':
                msg = None
        elif self.settings.captureProjIsGeohash():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            msg = geohash.encode(pt4326.y(), pt4326.x(),
                                 settings.captureGeohashPrecision)
            if msg == '':
                msg = None
        elif self.settings.captureProjIsMaidenhead():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            try:
                msg = maidenhead.toMaiden(
                    pt4326.y(),
                    pt4326.x(),
                    precision=settings.captureMaidenheadPrecision)
            except Exception:
                msg = None

        msg = '{}{}{}'.format(self.settings.capturePrefix, msg,
                              self.settings.captureSuffix)
        return msg

    def canvasMoveEvent(self, event):
        '''Capture the coordinate as the user moves the mouse over
        the canvas. Show it in the status bar.'''
        pt = self.snappoint(event.originalPixelPoint())  # input is QPoint
        try:
            msg = self.formatCoord(pt, ', ')
            formatString = self.coordFormatString()
            if msg is None:
                self.iface.statusBarIface().showMessage("")
            else:
                self.iface.statusBarIface().showMessage(
                    "{} - {}".format(msg, formatString), 4000)
        except Exception:
            self.iface.statusBarIface().showMessage("")

    def snappoint(self, qpoint):
        match = self.canvas.snappingUtils().snapToMap(qpoint)
        if match.isValid():
            if self.vertex is None:
                self.vertex = QgsVertexMarker(self.canvas)
                self.vertex.setIconSize(12)
                self.vertex.setPenWidth(2)
                self.vertex.setColor(self.snapcolor)
                self.vertex.setIconType(QgsVertexMarker.ICON_BOX)
            self.vertex.setCenter(match.point())
            return (match.point())  # Returns QgsPointXY
        else:
            self.removeVertexMarker()
            return self.toMapCoordinates(
                qpoint)  # QPoint input, returns QgsPointXY

    def coordFormatString(self):
        if self.settings.captureProjIsWgs84():
            if self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDecimal:
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = 'Lat Lon'
                else:
                    s = 'Lon Lat'
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeWKT:
                s = 'WKT'
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeGeoJSON:
                s = 'GeoJSON'
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDMM:
                s = 'DM.MM'
            else:
                s = 'DMS'
        elif self.settings.captureProjIsProjectCRS():
            crsID = self.canvas.mapSettings().destinationCrs().authid()
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = '{} - Y,X'.format(crsID)
                else:
                    s = '{} - X,Y'.format(crsID)
            else:  # WKT
                s = 'WKT'
        elif self.settings.captureProjIsMGRS():
            s = 'MGRS'
        elif self.settings.captureProjIsUTM():
            s = 'Standard UTM'
        elif self.settings.captureProjIsPlusCodes():
            s = 'Plus Codes'
        elif self.settings.captureProjIsGeohash():
            s = 'Geohash'
        elif self.settings.captureProjIsMaidenhead():
            s = 'Maidenhead Grid Locator'
        elif self.settings.captureProjIsCustomCRS():
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = '{} - Y,X'.format(self.settings.captureCustomCRSID())
                else:
                    s = '{} - X,Y'.format(self.settings.captureCustomCRSID())
            else:  # WKT
                s = 'WKT'
        else:  # Should never happen
            s = ''
        return s

    def canvasReleaseEvent(self, event):
        '''Capture the coordinate when the mouse button has been released,
        format it, and copy it to the clipboard. pt is QgsPointXY'''
        pt = self.snappoint(event.originalPixelPoint())
        self.removeVertexMarker()
        if settings.captureShowLocation:
            if self.marker is None:
                self.marker = QgsVertexMarker(self.canvas)
                self.marker.setIconSize(18)
                self.marker.setPenWidth(2)
                self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
            self.marker.setCenter(pt)
        else:
            self.removeMarker()

        try:
            msg = self.formatCoord(pt, self.settings.delimiter)
            formatString = self.coordFormatString()
            if msg is not None:
                clipboard = QApplication.clipboard()
                clipboard.setText(msg)
                self.iface.messageBar().pushMessage(
                    "",
                    "{} coordinate {} copied to the clipboard".format(
                        formatString, msg),
                    level=Qgis.Info,
                    duration=4)
        except Exception as e:
            self.iface.messageBar().pushMessage(
                "",
                "Invalid coordinate: {}".format(e),
                level=Qgis.Warning,
                duration=4)

    def removeMarker(self):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None

    def removeVertexMarker(self):
        if self.vertex is not None:
            self.canvas.scene().removeItem(self.vertex)
            self.vertex = None
Пример #35
0
class FeatureDragger(FeaturePicker):
    '''
    tool for moving features on the map canvas with drag & drop,
    does not change the geometry of the dragged feature but draws a marker
    at the new position and emits the geometry

    Attributes
    ----------
    feature_dragged : pyqtSignal
        emitted when a feature is dragged or clicked on the map canvas,
        (feature id, release position)
    drag_cursor : QCursor
        the appearance of the cursor while dragging a feature
    '''
    feature_dragged = pyqtSignal(int, QgsPointXY)
    drag_cursor = QCursor(Qt.DragMoveCursor)

    def __init__(self,
                 ui_element: QWidget,
                 layers: List[QgsVectorLayer] = [],
                 canvas: QgsMapCanvas = None,
                 target_epsg: int = 25832):
        '''
        Parameters
        ----------
        ui_element : QWidget
            clickable UI element, clicking on it will adctivate/deactivate this
            tool
        layers : list, optional
            the layers containing the features that can be picked,
            defaults to not setting any layers
        canvas : QgsMapCanvas, optional
            the map canvas the tool will work on, defaults to the map canvas of
            the QGIS UI
        target_epsg : int, optional
            projection of emitted geometry after drawing as epsg code,
            defaults to 25832
        '''
        super().__init__(ui_element, layers=layers, canvas=canvas)
        self._marker = None
        self._picked_feature = None
        self._dragging = False
        self.target_crs = QgsCoordinateReferenceSystem(target_epsg)

    def reset(self):
        '''
        reset the feature picker to it's initial state
        '''
        self.remove_marker()
        self._picked_feature = None

    def remove_marker(self):
        '''
        remove the marker from the map
        '''
        if not self._marker:
            return
        self.canvas.scene().removeItem(self._marker)
        self._marker = None

    def canvasPressEvent(self, e):
        '''
        override, remember feature on click and move marker (create one if not
        drawn yet)
        '''
        if self._picked_feature is None:
            features = QgsMapToolIdentify(self.canvas).identify(
                e.pos().x(),
                e.pos().y(), self._layers,
                QgsMapToolIdentify.TopDownStopAtFirst)
            if len(features) == 0:
                return
            feature = features[0].mFeature
            self._picked_feature = feature.id()
        # there is a feature -> drag it
        self._dragging = True
        self.canvas.setCursor(self.drag_cursor)
        # not marked yet -> mark position
        if not self._marker:
            color = QColor(0, 0, 255)
            color.setAlpha(100)
            self._marker = QgsVertexMarker(self.canvas)
            self._marker.setColor(color)
            self._marker.setIconSize(10)
            self._marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            self._marker.setPenWidth(10)
        point = self.toMapCoordinates(e.pos())
        self._marker.setCenter(point)

    def canvasMoveEvent(self, e):
        '''
        override, move marker if mouse dragging is active and mouse is moved
        '''
        if not self._marker or not self._dragging:
            return
        # update position of marker while dragging
        point = self.toMapCoordinates(e.pos())
        self._marker.setCenter(point)

    def canvasReleaseEvent(self, mouseEvent):
        '''
        override, emit geometry of position of marker on mouse release
        '''
        self._dragging = False
        if self._picked_feature is None:
            return
        self.canvas.setCursor(self.cursor)
        point = self.toMapCoordinates(self._marker.pos().toPoint())
        self.feature_dragged.emit(self._picked_feature,
                                  self.transform_from_map(point))
Пример #36
0
class MincutMapTool(ParentMapTool):
    ''' Button 26. User select one node or arc.
    Execute SQL function: 'gw_fct_mincut'
    This function fills 3 temporary tables with id's: node_id, arc_id and valve_id
    Returns and integer: error code
    Get these id's and select them in its corresponding layers '''    

    def __init__(self, iface, settings, action, index_action):  
        ''' Class constructor '''
        
        # Call ParentMapTool constructor     
        super(MincutMapTool, self).__init__(iface, settings, action, index_action)  

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



    ''' QgsMapTools inherited event functions '''

    def canvasMoveEvent(self, event):

        # Hide highlight
        self.vertexMarker.hide()

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

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

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

            # Check Arc or Node
            for snapPoint in result:

                if snapPoint.layer.name() == self.layer_node.name() or snapPoint.layer.name() == self.layer_arc.name():
                    
                    # Get the point
                    point = QgsPoint(result[0].snappedVertex)

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

                    # Data for function
                    self.current_layer = result[0].layer
                    self.snappFeat = next(result[0].layer.getFeatures(QgsFeatureRequest().setFilterFid(result[0].snappedAtGeometry)))

                    # Change symbol
                    if snapPoint.layer.name() == self.layer_node.name():
                        self.vertexMarker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                    else:
                        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX)

                    break


    def canvasReleaseEvent(self, event):
        ''' With left click the digitizing is finished '''
        
        if event.button() == Qt.LeftButton and self.current_layer is not None:

            # Get selected layer type: 'arc' or 'node'
            if self.current_layer.name() == self.layer_arc.name():
                elem_type = 'arc'
            elif self.current_layer.name() == self.layer_node.name():
                elem_type = 'node'
            else:
                message = "Current layer not valid"
                self.controller.show_warning(message, context_name='ui_message')
                return

            feature = self.snappFeat
            elem_id = feature.attribute(elem_type+'_id')

            # Execute SQL function
            function_name = "gw_fct_mincut"
            sql = "SELECT "+self.schema_name+"."+function_name+"('"+str(elem_id)+"', '"+elem_type+"');"
            result = self.controller.execute_sql(sql)
            print sql
            if result:
                # Get 'arc' and 'node' list and select them
                self.mg_flow_trace_select_features(self.layer_arc, 'arc')
                self.mg_flow_trace_select_features(self.layer_node, 'node')

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


    def mg_flow_trace_select_features(self, layer, elem_type):

        sql = "SELECT * FROM "+self.schema_name+".anl_mincut_"+elem_type+" ORDER BY "+elem_type+"_id"
        rows = self.controller.get_rows(sql)
        if rows:
    
            # Build an expression to select them
            aux = "\""+elem_type+"_id\" IN ("
            for elem in rows:
                aux += elem[0] + ", "
            aux = aux[:-2] + ")"
    
            # Get a featureIterator from this expression:
            expr = QgsExpression(aux)
            if expr.hasParserError():
                message = "Expression Error: " + str(expr.parserErrorString())
                self.controller.show_warning(message, context_name='ui_message')
                return
            it = layer.getFeatures(QgsFeatureRequest(expr))
    
            # Build a list of feature id's from the previous result
            id_list = [i.id() for i in it]
    
            # Select features with these id's
            layer.setSelectedFeatures(id_list)


    def activate(self):

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

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

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to arc and node
        self.snapperManager.snapToArc()
        self.snapperManager.snapToNode()

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

        # Show help message when action is activated
        if self.show_help:
            message = "Select a node or pipe and click on it, the valves minimum cut polygon is computed"
            self.controller.show_info(message, context_name='ui_message' )  
        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_arc)
        except:
            self.canvas.setCurrentLayer(self.layer_arc)


    def deactivate(self):

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

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

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

        # Remove highlight
        self.h = None
        
        
Пример #37
0
class AddValveTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

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

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

        self.diameter_dialog = None

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

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

    def canvasMoveEvent(self, event):

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

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

        if not self.mouse_clicked:

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

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

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

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

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

            else:

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

    def canvasReleaseEvent(self, event):

        if not self.mouse_clicked:
            return

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

            self.mouse_clicked = False

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

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

            # A pipe has been snapped
            else:

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

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

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

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

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

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

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

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

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

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

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

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

            self.mouse_clicked = False

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

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

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

                for valve_ft in adj_links['valves']:

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

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

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

                        if adj_pipes_fts:

                            for adj_pipe_ft in adj_pipes_fts['pipes']:

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

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

                    elif action == invert_action:

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

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

                                        geom = adj_link.geometry()

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

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

                                        self.iface.mapCanvas().refresh()

                                        break

    def activate(self):

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

        self.update_snapper()

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

    def deactivate(self):

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

        self.data_dock.btn_add_valve.setChecked(False)

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

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

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

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

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
Пример #38
0
class Interface(QtWidgets.QDockWidget, GUI):
    def __init__(self, canvas):
        super(Interface, self).__init__()
        self.setupUi(self)
        self.canvas = canvas
        self.initVariables()
        self.initSignals()
        self.dateTimeEdit.setDateTime(QDateTime.currentDateTime())
        self.layerCombo.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.outputFile.setFilter(".tif")
    
    def initVariables(self):
        self.myTool = QgsMapToolEmitPoint(self.canvas)
        self.currentTool = self.canvas.mapTool()
        self.clickedPoint = ''

    def createVertexMarker(self):
        self.clickedPoint = QgsVertexMarker(self.canvas)
        self.clickedPoint.setIconSize(15)
        self.clickedPoint.setPenWidth(3)
    
    def initSignals(self):
        self.ativarButton.toggled.connect(self.getPoint)
        self.myTool.canvasClicked.connect(self.doWork)
        self.canvas.mapToolSet.connect(self.verifyTool)        
        
    def verifyTool(self, tool):
        if tool != self.myTool:
            self.ativarButton.setChecked(False)
    
    def getPoint(self, state):
        if state:
            self.canvas.setMapTool(self.myTool)
            self.createVertexMarker()
        else:
            self.canvas.unsetMapTool(self.myTool)
            self.canvas.scene().removeItem(self.clickedPoint)
    
    def doWork(self, point, button):
        if button == QtCore.Qt.LeftButton:
            wgsPoint = self.getWGSPoint(point)
            now = self.dateTimeEdit.dateTime().toPyDateTime()
            az,zen = sunpos(now, wgsPoint.y(), wgsPoint.x(), 0)[:2]
            if not self.layerCombo.currentLayer():
                QMessageBox.critical(self, u"Erro", u"Nenhuma camada raster selecionada. Selecione uma camada.")
                return
            workingLayerFile = self.layerCombo.currentLayer().dataProvider().dataSourceUri()
            outputpath = self.outputFile.filePath()
            if not outputpath:
                QMessageBox.critical(self, u"Erro", u"Nenhum arquivo de saída definido. Escolha um arquivo de saída.")
                return
            if not outputpath.endswith(".tif"):
                outputpath = outputpath + '.tif'
            processing.run("gdal:hillshade", {'INPUT': workingLayerFile,
            'BAND': 1,
            'AZIMUTH': float(az),
            'ALTITUDE': 90 - float(zen),
            'OUTPUT': outputpath})
			
            shadedlayer = QgsRasterLayer(outputpath, "Raster sombreado")
            QgsProject.instance().addMapLayer(shadedlayer)
            self.clickedPoint.setCenter(point)
            
    def getWGSPoint(self, pt):
        crsSrc  = self.canvas.mapSettings().destinationCrs()
        crsDest = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        
        coordinateTransformer = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
        wgsPt = coordinateTransformer.transform(pt)
        return wgsPt
Пример #39
0
class MoveTool(QgsMapTool):

    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

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

        self.elev = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.mouse_clicked = False
        self.snapper = None

        self.clicked_pt = None

        self.snap_results = None

        self.selected_node_ft = None
        self.selected_node_ft_lay = None
        self.mouse_pt = None
        self.pump_valve_selected = False
        self.pump_or_valve = None
        self.pump_valve_ft = None
        self.adj_links_fts = None
        self.adj_junctions = None
        self.delta_vec = QgsVector(0, 0)
        self.adj_links_fts_d = {}

        # self.rubber_bands_d = {}
        # self.rubber_bands_geoms_d = {}

        self.rubber_band = None

        self.logger = logging.getLogger('Logger1')

    def canvasPressEvent(self, event):

        if self.snap_results is None:
            self.clicked_pt = None
            return

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

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

            self.mouse_clicked = True
            self.clicked_pt = self.snap_results.point()

            # Check if a node was snapped: it can be just one
            self.selected_node_ft = None
            self.adj_links_fts = None

            # Check if I snapped on a node
            snapped_layer_name = self.snap_results.layer().name()

            self.selected_node_ft = None

            pt_locator_ju = self.snapper.locatorForLayer(self.params.junctions_vlay)
            pt_locator_re = self.snapper.locatorForLayer(self.params.reservoirs_vlay)
            pt_locator_ta = self.snapper.locatorForLayer(self.params.tanks_vlay)
            match_ju = pt_locator_ju.nearestVertex(self.snap_results.point(), 1)
            match_re = pt_locator_re.nearestVertex(self.snap_results.point(), 1)
            match_ta = pt_locator_ta.nearestVertex(self.snap_results.point(), 1)

            if match_ju.isValid() or match_re.isValid() or match_ta.isValid():

                if match_ju.isValid():
                    node_feat_id = match_ju.featureId()
                    request = QgsFeatureRequest().setFilterFid(node_feat_id)
                    node = list(self.params.junctions_vlay.getFeatures(request))
                    self.selected_node_ft_lay = self.params.junctions_vlay

                if match_re.isValid():
                    node_feat_id = match_re.featureId()
                    request = QgsFeatureRequest().setFilterFid(node_feat_id)
                    node = list(self.params.reservoirs_vlay.getFeatures(request))
                    self.selected_node_ft_lay = self.params.reservoirs_vlay

                if match_ta.isValid():
                    node_feat_id = match_ta.featureId()
                    request = QgsFeatureRequest().setFilterFid(node_feat_id)
                    node = list(self.params.tanks_vlay.getFeatures(request))
                    self.selected_node_ft_lay = self.params.tanks_vlay

                self.selected_node_ft = QgsFeature(node[0])

                # self.selected_node_ft_lay = self.snap_results.layer()
                self.adj_links_fts = NetworkUtils.find_adjacent_links(self.params, self.selected_node_ft.geometry())

            # No selected nodes: it's just a vertex
            if self.selected_node_ft is None:

                snapped_ft = vector_utils.get_feats_by_id(self.snap_results.layer(), self.snap_results.featureId())[0]
                snapped_ft_geom = snapped_ft.geometry()

                points = []
                if self.snap_results.vertexIndex() - 1 >= 0 and self.snap_results.vertexIndex() - 1 < len(snapped_ft_geom.asPolyline()):
                    vertex_index = 1
                    vertex_before = snapped_ft_geom.vertexAt(self.snap_results.vertexIndex() - 1)
                    points.append(vertex_before)

                vertex_at = snapped_ft_geom.vertexAt(self.snap_results.vertexIndex())
                points.append(vertex_at)

                if self.snap_results.vertexIndex() + 1 >= 0 and self.snap_results.vertexIndex() + 1 < len(snapped_ft_geom.asPolyline()):
                    vertex_index = 0
                    vertex_after = snapped_ft_geom.vertexAt(self.snap_results.vertexIndex() + 1)
                    points.append(vertex_after)

                if self.snap_results.vertexIndex() > 0 and self.snap_results.vertexIndex() < len(snapped_ft_geom.asPolyline()) - 1:
                    vertex_index = 1

                # self.rubber_bands_d[0] = (self.build_rubber_band(points), [vertex_index], [vertex_at])
                self.rubber_band = self.build_rubber_band([self.snap_results.point(), self.snap_results.point()])

            # It's a node
            else:

                # It's an isolated node: no rubber band!
                if self.adj_links_fts is None or (not self.adj_links_fts['pipes'] and not self.adj_links_fts['pumps'] and not self.adj_links_fts['valves']):
                    # self.rubber_bands_d.clear()
                    self.rubber_band = self.build_rubber_band([self.snap_results.point(), self.snap_results.point()])
                    return

                # Adjacent links are neither pumps nor valves: find the two pipes adjacent to the node
                # OR node adjacent to pump or valve and NOT using block logic
                if (not self.adj_links_fts['pumps'] and not self.adj_links_fts['valves']) or not self.params.block_logic:

                    self.pump_valve_selected = False

                    rb_points = []

                    for adjacent_pipes_ft in self.adj_links_fts['pipes']:
                        closest = adjacent_pipes_ft.geometry().closestVertex(self.selected_node_ft.geometry().asPoint())
                        self.adj_links_fts_d[adjacent_pipes_ft] = (closest[1], self.params.pipes_vlay)
                        if closest[1] == 0:
                            next_vertext_id = closest[1] + 1
                        else:
                            next_vertext_id = closest[1] - 1
                        rb_points.append(adjacent_pipes_ft.geometry().vertexAt(next_vertext_id))

                    for adj_pumps_ft in self.adj_links_fts['pumps']:
                        closest = adj_pumps_ft.geometry().closestVertex(self.selected_node_ft.geometry().asPoint())
                        self.adj_links_fts_d[adj_pumps_ft] = (closest[1], self.params.pumps_vlay)
                        if closest[1] == 0:
                            next_vertext_id = closest[1] + 1
                        else:
                            next_vertext_id = closest[1] - 1
                        rb_points.append(adj_pumps_ft.geometry().vertexAt(next_vertext_id))

                    for adj_valves_ft in self.adj_links_fts['valves']:
                        closest = adj_valves_ft.geometry().closestVertex(self.selected_node_ft.geometry().asPoint())
                        self.adj_links_fts_d[adj_valves_ft] = (closest[1], self.params.valves_vlay)
                        if closest[1] == 0:
                            next_vertext_id = closest[1] + 1
                        else:
                            next_vertext_id = closest[1] - 1
                        rb_points.append(adj_valves_ft.geometry().vertexAt(next_vertext_id))

                    rb_points.insert(1, self.selected_node_ft.geometry().asPoint())
                    # self.rubber_bands_d[0] = (self.build_rubber_band(rb_points), [1], [self.selected_node_ft.geometry().asPoint()])
                    self.rubber_band = self.build_rubber_band([self.snap_results.point(), self.snap_results.point()])

                # Node adjacent to pump or valve and using block logic
                else:

                    self.pump_valve_selected = True

                    # Find the pipes adjacent to the pump/valve
                    if self.adj_links_fts['pumps']:
                        self.pump_valve_ft = self.adj_links_fts['pumps'][0]
                        self.pump_or_valve = 'pump'
                        adj_links = NetworkUtils.find_links_adjacent_to_link(self.params, self.params.pumps_vlay, self.pump_valve_ft, False, True, True)
                    elif self.adj_links_fts['valves']:
                        self.pump_valve_ft = self.adj_links_fts['valves'][0]
                        self.pump_or_valve = 'valve'
                        adj_links = NetworkUtils.find_links_adjacent_to_link(self.params, self.params.valves_vlay, self.pump_valve_ft, False, True, True)
                    else:
                        return

                    pump_valve_pts = self.pump_valve_ft.geometry().asPolyline()

                    # self.rubber_bands_d[0] = (self.build_rubber_band(pump_valve_pts), range(len(pump_valve_pts)), pump_valve_pts)
                    self.rubber_band = self.build_rubber_band([self.snap_results.point(), self.snap_results.point()])

                    rb_index = 1
                    if 'pipes' in adj_links:
                        for adj_link_ft in adj_links['pipes']:
                            self.process_adj(adj_link_ft, self.params.pipes_vlay, rb_index)
                            rb_index += 1
                    if 'pumps' in adj_links:
                        for adj_link_ft in adj_links['pumps']:
                            self.process_adj(adj_link_ft, self.params.pumps_vlay, rb_index)
                            rb_index += 1
                    if 'valves' in adj_links:
                        for adj_link_ft in adj_links['valves']:
                            self.process_adj(adj_link_ft, self.params.valves_vlay, rb_index)
                            rb_index += 1

                    # Find the nodes adjacent to the pump/valve
                    self.adj_junctions = NetworkUtils.find_start_end_nodes_w_layer(self.params, self.pump_valve_ft.geometry())

    def process_adj(self, adj_link_ft, layer, rb_index):
        adj_link_pts = adj_link_ft.geometry().asPolyline()
        pump_valve_pts = self.pump_valve_ft.geometry().asPolyline()

        if NetworkUtils.points_overlap(QgsGeometry.fromPoint(pump_valve_pts[0]), adj_link_pts[0], self.params.tolerance):
            self.adj_links_fts_d[adj_link_ft] = (0, layer)
            # rb_pts = [pump_valve_pts[0], adj_link_pts[1]]
            # self.rubber_bands_d[rb_index] = (self.build_rubber_band(rb_pts), [0], [pump_valve_pts[0]])

        if NetworkUtils.points_overlap(QgsGeometry.fromPoint(pump_valve_pts[-1]), adj_link_pts[0], self.params.tolerance):
            self.adj_links_fts_d[adj_link_ft] = (0, layer)
            # rb_pts = [pump_valve_pts[-1], adj_link_pts[1]]
            # self.rubber_bands_d[rb_index] = (self.build_rubber_band(rb_pts), [0], [pump_valve_pts[-1]])

        if NetworkUtils.points_overlap(QgsGeometry.fromPoint(pump_valve_pts[0]), adj_link_pts[-1], self.params.tolerance):
            self.adj_links_fts_d[adj_link_ft] = (len(adj_link_pts)-1, layer)
            # rb_pts = [pump_valve_pts[0], adj_link_pts[-2]]
            # self.rubber_bands_d[rb_index] = (self.build_rubber_band(rb_pts), [0], [pump_valve_pts[0]])

        if NetworkUtils.points_overlap(QgsGeometry.fromPoint(pump_valve_pts[-1]), adj_link_pts[-1], self.params.tolerance):
            self.adj_links_fts_d[adj_link_ft] = (len(adj_link_pts)-1, layer)
            # rb_pts = [pump_valve_pts[-1], adj_link_pts[-2]]
            # self.rubber_bands_d[rb_index] = (self.build_rubber_band(rb_pts), [0], [pump_valve_pts[-1]])

    def canvasMoveEvent(self, event):

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

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

        # Mouse not clicked
        if not self.mouse_clicked:

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

                self.snap_results = match
                # snapped_pt = self.snap_results[0].snappedVertex
                snapped_vertex = match.point()

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

        # Mouse clicked
        else:

            # Update rubber band
            if self.snap_results is not None and self.rubber_band:

                snapped_pt = self.snap_results.point()

                # In 2.16+: self.delta_vec = QgsVector(self.mouse_pt - snapped_pt)
                self.delta_vec = QgsVector(self.mouse_pt.x() - snapped_pt.x(),
                                           self.mouse_pt.y() - snapped_pt.y())

                self.move_rubber_band_pt(self.rubber_band)

                # if self.adj_links_fts is None or (not self.adj_links_fts['pipes'] and not self.adj_links_fts['pumps'] and not self.adj_links_fts['valves']):
                #     # There are no adjacent links
                #     self.move_rubber_band_pt(self.rubber_bands_d[0])
                # else:
                #
                #     # It's just a junction
                #     if not self.pump_valve_selected:
                #         for key, value in self.rubber_bands_d.iteritems():
                #             self.move_rubber_band_pt(self.rubber_bands_d[key])
                #
                #     # It's a pump/valve
                #     else:
                #
                #         # Adjacent links are neither pumps nor valves: find the two pipes adjacent to the node
                #         # Or node adjacent to pump or valve and NOT using block logic
                #         if (not self.adj_links_fts['pumps'] and not self.adj_links_fts['valves']) or not self.params.block_logic:
                #
                #             for key, value in self.rubber_bands_d.iteritems():
                #                 self.move_rubber_band_pt(self.rubber_bands_d[key])
                #                 # in 2.16: self.rubber_bands_d[key].movePoint(1, snapped_pt + self.delta_vec)
                #                 # self.rubber_bands_d[key].movePoint(2, QgsPoint(snapped_pt.x() + self.delta_vec.x(), snapped_pt.y() + self.delta_vec.y()))
                #
                #         # Node adjacent to pump or valve and using block logic
                #         else:
                #             for key, value in self.rubber_bands_d.iteritems():
                #                 self.move_rubber_band_pt(self.rubber_bands_d[key])

    def move_rubber_band_pt(self, rubber_band_v):
        # rubber_band = rubber_band_v[0]
        # pt_indices = rubber_band_v[1]
        # start_pts = rubber_band_v[2]

        # for i in range(len(pt_indices)):
        #     rubber_band.movePoint(pt_indices[i], QgsPoint(start_pts[i].x() + self.delta_vec.x(), start_pts[i].y() + self.delta_vec.y()))

        rubber_band_v.movePoint(1, QgsPoint(self.clicked_pt.x() + self.delta_vec.x(), self.clicked_pt.y() + self.delta_vec.y()))

    def canvasReleaseEvent(self, event):

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

        if not self.mouse_clicked:
            return

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

            if self.snap_results is not None:

                snap_results = self.snap_results
                selected_node_ft = self.selected_node_ft
                selected_node_ft_lay = self.selected_node_ft_lay

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

                # It's just a pipe vertex
                if selected_node_ft is None:

                    feat = vector_utils.get_feats_by_id(snap_results.layer(), snap_results.featureId())
                    vertex_id = QgsVertexId(0, 0, snap_results.vertexIndex(), QgsVertexId.SegmentVertex)
                    vertex_v2 = feat[0].geometry().geometry().vertexAt(vertex_id)
                    new_pos_pt_v2 = QgsPointV2(mouse_pt.x(), mouse_pt.y())
                    new_pos_pt_v2.addZValue(vertex_v2.z())
                    LinkHandler.move_link_vertex(self.params, self.params.pipes_vlay, feat[0], new_pos_pt_v2,
                                                 snap_results.vertexIndex())

                # There are adjacent links: it's a node
                else:

                    # Not pump or valve: plain junction
                    if not self.pump_valve_selected:

                        # Update junction geometry
                        NodeHandler.move_element(
                            selected_node_ft_lay,
                            self.params.dem_rlay,
                            selected_node_ft,
                            mouse_pt)

                        # Update pipes
                        for feat, (vertex_index, layer) in self.adj_links_fts_d.iteritems():

                            vertex_id = QgsVertexId(0, 0, vertex_index, QgsVertexId.SegmentVertex)
                            vertex_v2 = feat.geometry().geometry().vertexAt(vertex_id)
                            new_pos_pt_v2 = QgsPointV2(mouse_pt.x(), mouse_pt.y())
                            new_pos_pt_v2.addZValue(vertex_v2.z())

                            LinkHandler.move_link_vertex(self.params, layer, feat, new_pos_pt_v2, vertex_index)

                    # Pump or valve
                    else:

                        # Update junctions geometry
                        NodeHandler.move_element(self.adj_junctions[0][1],
                                                 self.params.dem_rlay,
                                                 self.adj_junctions[0][0],
                                                 QgsPoint(
                                                    self.adj_junctions[0][0].geometry().asPoint().x() + self.delta_vec.x(),
                                                    self.adj_junctions[0][0].geometry().asPoint().y() + self.delta_vec.y()))

                        NodeHandler.move_element(self.adj_junctions[1][1],
                                                 self.params.dem_rlay,
                                                 self.adj_junctions[1][0],
                                                 QgsPoint(
                                                     self.adj_junctions[1][0].geometry().asPoint().x() + self.delta_vec.x(),
                                                     self.adj_junctions[1][0].geometry().asPoint().y() + self.delta_vec.y()))

                        # in 2.16: NodeHandler.move_element(Parameters.junctions_vlay, self.adj_links_fts[0], self.adj_links_fts[0].geometry().asPoint() + self.delta_vec)

                        if self.pump_or_valve == 'pump':
                            lay = self.params.pumps_vlay
                        elif self.pump_or_valve == 'valve':
                            lay = self.params.valves_vlay

                        # Move the pump/valve
                        LinkHandler.move_pump_valve(lay, self.pump_valve_ft, self.delta_vec)

                        # Move the adjacent pipes' vertices
                        for feat, (vertex_index, layer) in self.adj_links_fts_d.iteritems():

                            vertex_id = QgsVertexId(0, 0, vertex_index, QgsVertexId.SegmentVertex)
                            vertex_v2 = feat.geometry().geometry().vertexAt(vertex_id)
                            new_pos_pt_v2 = QgsPointV2(
                                feat.geometry().vertexAt(vertex_index).x() + self.delta_vec.x(),
                                feat.geometry().vertexAt(vertex_index).y() + self.delta_vec.y())
                            new_pos_pt_v2.addZValue(vertex_v2.z())

                            LinkHandler.move_link_vertex(self.params, layer, feat, new_pos_pt_v2, vertex_index)
                            # In 2.16: LinkHandler.move_pipe_vertex(feat, feat.geometry().vertexAt(vertex_index) + self.delta_vec, vertex_index)

                    self.adj_links_fts_d.clear()

                symbology.refresh_layer(self.iface.mapCanvas(), self.params.junctions_vlay)
                symbology.refresh_layer(self.iface.mapCanvas(), self.params.reservoirs_vlay)
                symbology.refresh_layer(self.iface.mapCanvas(), self.params.tanks_vlay)
                symbology.refresh_layer(self.iface.mapCanvas(), self.params.pipes_vlay)
                symbology.refresh_layer(self.iface.mapCanvas(), self.params.pumps_vlay)
                symbology.refresh_layer(self.iface.mapCanvas(), self.params.valves_vlay)

            # Remove vertex marker and rubber band
            self.vertex_marker.hide()
            self.iface.mapCanvas().scene().removeItem(self.rubber_band)

    def activate(self):

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

        # Snapping
        layers = {
            self.params.junctions_vlay: QgsPointLocator.Vertex,
            self.params.reservoirs_vlay: QgsPointLocator.Vertex,
            self.params.tanks_vlay: QgsPointLocator.Vertex,
            self.params.pipes_vlay: QgsPointLocator.Vertex}
        self.snapper = NetworkUtils.set_up_snapper(layers, self.iface.mapCanvas(), self.params.snap_tolerance)

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

    def deactivate(self):
        # self.rubber_bands.clear()
        self.canvas().scene().removeItem(self.vertex_marker)
        self.dock_widget.btn_move_element.setChecked(False)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def build_rubber_band(self, points):
        rubber_band = QgsRubberBand(self.canvas(), False)  # False = not a polygon
        rubber_band.setToGeometry(QgsGeometry.fromPolyline(points), None)
        # for point in points:
        #     rubber_band.addPoint(point)
        rubber_band.setColor(QColor(255, 128, 128))
        rubber_band.setWidth(1)
        rubber_band.setBrushStyle(Qt.Dense4Pattern)
        return rubber_band
Пример #40
0
class MoveNodeMapTool(ParentMapTool):
    ''' Button 16. Move node
    Execute SQL function: 'gw_fct_node2arc' '''        

    def __init__(self, iface, settings, action, index_action, controller, srid):
        ''' Class constructor '''        
        
        # Call ParentMapTool constructor     
        super(MoveNodeMapTool, self).__init__(iface, settings, action, index_action)  
        self.srid = srid  

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


    def reset(self):
                
        # Clear selected features 
        layer = self.canvas.currentLayer()
        if layer is not None:
            layer.removeSelection()

        # Graphic elements
        self.rubberBand.reset()
          
            
    def move_node(self, node_id, point):
        ''' Move selected node to the current point '''  
           
        if self.srid is None:
            self.srid = self.settings.value('db/srid')  
        if self.schema_name is None:
            self.schema_name = self.settings.value('db/schema_name')               
                   
        # Update node geometry
        the_geom = "ST_GeomFromText('POINT("+str(point.x())+" "+str(point.y())+")', "+str(self.srid)+")";
        sql = "UPDATE "+self.schema_name+".node SET the_geom = "+the_geom
        sql+= " WHERE node_id = '"+node_id+"'"
        status = self.controller.execute_sql(sql) 
        if status:
            # Execute SQL function and show result to the user
            function_name = "gw_fct_node2arc"
            sql = "SELECT "+self.schema_name+"."+function_name+"('"+str(node_id)+"');"
            self.controller.execute_sql(sql)
        else:
            message = "Move node: Error updating geometry"
            self.controller.show_warning(message, context_name='ui_message')
            
        # Refresh map canvas
        self.canvas.currentLayer().triggerRepaint()  

                
    
    ''' QgsMapTool inherited event functions '''    
       
    def activate(self):
        ''' Called when set as currently active map tool '''

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

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

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to node
        self.snapperManager.snapToNode()
        self.snapperManager.snapToArc()

        # Change pointer
        cursor = QCursor()
        cursor.setShape(Qt.CrossCursor)

        # Get default cursor        
        self.stdCursor = self.parent().cursor()   
 
        # And finally we set the mapTool's parent cursor
        self.parent().setCursor(cursor)

        # Reset
        self.reset()

        # Show help message when action is activated
        if self.show_help:
            message = "Select the disconnected node by clicking on it, move the pointer to desired location inside a pipe and click again"
            self.controller.show_info(message, context_name='ui_message' )

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


    def deactivate(self):
        ''' Called when map tool is being deactivated '''

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

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

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

        try:
            self.rubberBand.reset(QGis.Line)
        except AttributeError:
            pass


    def canvasMoveEvent(self, event):
        ''' Mouse movement event '''      
                        
        # Hide highlight
        self.vertexMarker.hide()
            
        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        eventPoint = QPoint(x,y)

        # Node layer
        layer = self.canvas.currentLayer()
        if layer is None:
            return

        # Select node or arc
        if layer.selectedFeatureCount() == 0:

            # Snap to node
            (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
            # That's the snapped point
            if result <> [] and (result[0].layer.name() == self.layer_node.name()):

                point = QgsPoint(result[0].snappedVertex)

                # Add marker    
                self.vertexMarker.setColor(QColor(0, 255, 0))
                self.vertexMarker.setCenter(point)
                self.vertexMarker.show()
                
                # Set a new point to go on with
                #self.appendPoint(point)
                self.rubberBand.movePoint(point)

            else:
                point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(),  x, y)
                self.rubberBand.movePoint(point)

        else:
                
            # Snap to arc
            result = []
            (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
            # That's the snapped point
            if (result <> []) and (result[0].layer.name() == self.layer_arc.name()) and (result[0].snappedVertexNr == -1):
            
                point = QgsPoint(result[0].snappedVertex)

                # Add marker
                self.vertexMarker.setColor(QColor(255, 0, 0))
                self.vertexMarker.setCenter(point)
                self.vertexMarker.show()
                
                # Select the arc
                self.layer_arc.removeSelection()
                self.layer_arc.select([result[0].snappedAtGeometry])

                # Bring the rubberband to the cursor i.e. the clicked point
                self.rubberBand.movePoint(point)
        
            else:
                
                # Bring the rubberband to the cursor i.e. the clicked point
                point = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(),  x, y)
                self.rubberBand.movePoint(point)


    def canvasReleaseEvent(self, event):
        ''' Mouse release event '''         
        
        if event.button() == Qt.LeftButton:
            
            # Get the click
            x = event.pos().x()
            y = event.pos().y()
            eventPoint = QPoint(x,y)

            # Node layer
            layer = self.canvas.currentLayer()

            # Select node or arc
            if layer.selectedFeatureCount() == 0:

                # Snap to node
                (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
                # That's the snapped point
                if result <> [] and (result[0].layer.name() == self.layer_node.name()):
            
                    point = QgsPoint(result[0].snappedVertex)

                    layer.select([result[0].snappedAtGeometry])
        
                    # Hide highlight
                    self.vertexMarker.hide()
                    
                    # Set a new point to go on with
                    self.rubberBand.addPoint(point)

            else:
                
                # Snap to arc
                (retval,result) = self.snapper.snapToBackgroundLayers(eventPoint)   #@UnusedVariable
            
                # That's the snapped point
                if (result <> []) and (result[0].layer.name() == self.layer_arc.name()):
            
                    point = QgsPoint(result[0].snappedVertex)
                    
                    # Get selected feature (at this moment it will have one and only one)           
                    feature = layer.selectedFeatures()[0]
                    node_id = feature.attribute('node_id') 
        
                    # Move selected node to the released point
                    self.move_node(node_id, point)       
            
                    # Rubberband reset
                    self.reset()                    
            
                    # Refresh map canvas
                    self.iface.mapCanvas().refresh()               
        
        elif event.button() == Qt.RightButton:
            self.reset()
Пример #41
0
class QGISRedMoveVertexsTool(QgsMapTool):
    ownMainLayers = ["Pipes", "Valves", "Pumps"]

    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.mouseClicked = False
        self.clickedPoint = None
        self.objectSnapped = 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(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 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:
            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:
                                        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
                                        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:
            # # 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):
        mousePoint = self.toMapCoordinates(event.pos())
        if self.mouseClicked:
            if event.button() == 1:
                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.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()
Пример #42
0
class KPTool(QgsMapToolEmitPoint):
    """Class to interact with the map canvas to capture the coordinate
    when the mouse button is pressed and to display the coordinate in
    in the status bar.
    It will take all the things from Class QgsMapToolEmitPoint and
    overwrite some of the functions, activate, etc..
    Other functions here do the measurements
    """
    captureStopped = pyqtSignal()
    epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326")
    geod = Geodesic.WGS84

    def __init__(self, iface, linelayer=None):
        QgsMapToolEmitPoint.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.marker = None
        self.vertex = None
        self.linelayer = linelayer  #import a line layer from the main function
        self.proj_crs = iface.mapCanvas().mapSettings().destinationCrs()

    def __str__(self, linelayer):
        return linelayer.name()

    def activate(self):
        '''When activated set the cursor to a crosshair.'''
        self.canvas.setCursor(Qt.CrossCursor)
        self.snapcolor = QgsSettings().value("/qgis/digitizing/snap_color",
                                             QColor(Qt.magenta))

    def deactivate(self):
        self.removeMarker()
        self.removeVertexMarker()
        self.captureStopped.emit()

    def canvasMoveEvent(self, event):
        '''Capture the coordinate as the user moves the mouse over
        the canvas. Show it in the status bar. Currently not used'''
        pt = self.snappoint(
            event.originalPixelPoint())  # input is QPoint, cursor snaps

    def snappoint(self, qpoint):
        match = self.canvas.snappingUtils().snapToMap(qpoint)
        if match.isValid():
            if self.vertex is None:
                self.vertex = QgsVertexMarker(self.canvas)
                self.vertex.setIconSize(12)
                self.vertex.setPenWidth(2)
                self.vertex.setColor(self.snapcolor)
                self.vertex.setIconType(QgsVertexMarker.ICON_BOX)
            self.vertex.setCenter(match.point())
            return (match.point())  # Returns QgsPointXY
        else:
            self.removeVertexMarker()
            return self.toMapCoordinates(
                qpoint)  # QPoint input, returns QgsPointXY

    def canvasReleaseEvent(self, event):
        """Capture the coordinate when the mouse button has been released,
        format it, and copy it to the clipboard. pt is QgsPointXY"""
        pt = self.snappoint(event.originalPixelPoint())
        self.removeVertexMarker()
        # if we enable this we will get some vertex markers:
        # if self.marker is None:
        #     self.marker = QgsVertexMarker(self.canvas)
        #     self.marker.setIconSize(18)
        #     self.marker.setPenWidth(2)
        #     self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        # self.marker.setCenter(pt)
        if self.geodetic_use == 0:
            # use cartesian
            line_length = self.measureLine(self.linelayer, pt, False)
            whole_line_length = self.measureWholeLine(self.linelayer, False)
            dist_off_Line = self.closestPt(
                self.linelayer, pt, True,
                False)[1]  #second False means we use Cartesian distance
        elif self.geodetic_use == 2:
            # use geodetic
            line_length = self.measureLine(self.linelayer, pt, True)
            whole_line_length = self.measureWholeLine(self.linelayer, True)
            dist_off_Line = self.closestPt(self.linelayer, pt, True, True)[1]
        if self.reversekp_status == 0:
            LL_message = '{:.{prec}f}'.format(
                line_length + self.offset,
                prec=self.kpdec)  #round to specified decimal
        elif self.reversekp_status == 2:
            LL_message = '{:.{prec}f}'.format(
                whole_line_length - line_length + self.offset,
                prec=self.kpdec)  #round to specified decimal
        DT_message = '{:.{prec}f}'.format(
            dist_off_Line, prec=self.dccdec)  #round to specified decimal
        # check for output format below:
        if self.out_format == KpFindDialogInteractive.KP_out:  # KP
            msg = 'KP ' + str(LL_message)
        elif self.out_format == KpFindDialogInteractive.KP_DCC_Out:  # KP and DCC
            msg = 'KP ' + str(LL_message) + ' , DOL : ' + str(
                DT_message) + ' m'
        elif self.out_format == KpFindDialogInteractive.DMS_out:  # Lat Lon and KP
            msg = self.formatCoord(pt)[0] + ', ' + self.formatCoord(
                pt)[1] + ' (KP ' + str(LL_message) + ')'
        if msg is not None:
            clipboard = QApplication.clipboard()
            clipboard.setText(msg)
            self.iface.messageBar().pushMessage(msg + ' on layer ' +
                                                str(self.linelayer.name()) +
                                                ' copied to clipboard',
                                                level=Qgis.Info,
                                                duration=2)
        else:
            self.iface.messageBar().pushMessage(
                'Something went wrong with the coordinate composition',
                level=Qgis.Info,
                duration=2)

    def removeMarker(self):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None

    def removeVertexMarker(self):
        if self.vertex is not None:
            self.canvas.scene().removeItem(self.vertex)
            self.vertex = None

    def name_collision_checker(self, new_names, old_layer):
        #check for name collisions in attribute fields
        fields_ptLayer = old_layer.dataProvider().fields()
        old_fields_names = [
        ]  #we will use this later to compare for collisions
        for f in fields_ptLayer:  #iterate over all field names and add to new provider
            old_fields_names.append(f.name())  #create the collision test list
        trynumber = 1
        num_suffix = ''
        max_num = 1
        for name in new_names:
            collision = True
            while collision:  # Iterate until there are no collissions
                collision = False
                if name + num_suffix in old_fields_names:
                    collision = True
                    num_suffix = '_' + str(trynumber)
                    if trynumber > max_num + 1:
                        max_num = trynumber
                        num_suffix = '_' + str(max_num)
                    trynumber = trynumber + 1
        new_list = [item + num_suffix
                    for item in new_names]  #add same suffix to all fields
        return new_list

    def closestPt(self,
                  linelayer,
                  clicked_point,
                  extend_line=False,
                  give_geod=True):  # get the linelayer and QgsPointXY
        """This will take a point and a line layer and find the closest point
        along a perpendicular line from the point to the line layer. It takes
        the first feature in that line layer. It will also extend the first and
        last line segments. Cartesian and geodetic distance possible"""
        if linelayer.getFeature(0).geometry().isMultipart():
            line_feat = linelayer.getFeature(0)
            linear_geom = line_feat.geometry()
        else:
            line_feat = linelayer.getFeature(
                1)  #for some reason linestring feature 0 is NULL
            linear_geom = line_feat.geometry()
            linear_geom.convertToMultiType()

        if extend_line == True:
            linear_geom = linear_geom.extendLine(
                1000000,
                10000000)  # extend fist and last seg by 1000km, bit of a fudge
        _, mindistpt, _, leftoff = linear_geom.closestSegmentWithContext(
            clicked_point)  # get min distance point to line
        projected_point = QgsPointXY(
            mindistpt[0], mindistpt[1])  # create projected point on line
        distance_cart = QgsDistanceArea().measureLine(
            clicked_point, projected_point)  #cartesian distance
        srcCRS = linelayer.sourceCrs()  # get CRS from line
        wgs84 = KPTool.epsg4326  # define EPSG 4326
        if srcCRS != wgs84:
            geomTo4326 = QgsCoordinateTransform(
                srcCRS, wgs84, QgsProject.instance())  #convert if needed
            ptCP84 = geomTo4326.transform(clicked_point)
            ptPP84 = geomTo4326.transform(projected_point)
        else:
            ptCP84 = clicked_point
            ptPP84 = projected_point
        geod_ds = KPTool.geod.Inverse(ptCP84.y(), ptCP84.x(), ptPP84.y(),
                                      ptPP84.x())  # use geographiclib
        distance_geod = geod_ds['s12']
        if leftoff < 0:
            distance_cart = -distance_cart  #planar distance
            distance_geod = -distance_geod  #return the geographiclib distance
        #if abs(distance_cart)>1000000 or abs(distance_geod)>1000000:
        #self.iface.messageBar().pushMessage('Line extended more than 1000 km, possible errors',level=Qgis.Warning) #warn user if they click more than 1000 km away from end of line
        if give_geod is True:
            return projected_point, distance_geod
        else:
            return projected_point, distance_cart

    def measureLine(self, linetoMeasure, clicked_pt, geodetic_measure=True):
        """This will take a line segment and the clicked point and return the
        length up till that point for the segment in km. Inspired by shape tools and closest point plugins"""
        srcCRS = linetoMeasure.sourceCrs()  #get CRS from line
        feature = linetoMeasure.getFeature(0)  #get first feature from line
        wgs84 = KPTool.epsg4326  #define EPSG 4326
        projected_point_raw, dist_ext = self.closestPt(
            linetoMeasure, clicked_pt, True
        )  #we'll need that point later to compare with projected points of subsegments
        projected_point_on_line_raw, dist_nonext = self.closestPt(
            linetoMeasure, clicked_pt,
            False)  #get proj point on non-extended line
        if srcCRS != wgs84:
            geomTo4326 = QgsCoordinateTransform(
                srcCRS, wgs84, QgsProject.instance())  #convert if needed
        if feature.geometry().isMultipart():
            # get nodes out of data
            ptdata = [feature.geometry().asMultiPolyline()]
        else:
            feature = linetoMeasure.getFeature(
                1)  #for some reason singleline first feature is NULL
            ptdata = [[feature.geometry().asPolyline()]]
        for seg in ptdata:
            if len(seg) < 1:
                # should never happen
                self.iface.messageBar().pushMessage(
                    'Something is strange with your line file',
                    level=Qgis.Critical,
                    duration=2)
                continue
            for pts in seg:
                # now we get all nodes from start to end of segment line
                numpoints = len(pts)
                if numpoints < 2:
                    # should never happen
                    self.iface.messageBar().pushMessage(
                        'Something is strange with your line file',
                        level=Qgis.Critical,
                        duration=2)
                    continue
                ptStart_raw = QgsPointXY(pts[0].x(),
                                         pts[0].y())  #get initial point coords
                # Calculate the total distance of this line segment
                distance = 0.0
                for x in range(1, numpoints):
                    # from point one (since we preextend segment) start measuring distance cumulative
                    ptEnd_raw = QgsPointXY(
                        pts[x].x(), pts[x].y())  # coordinates of next point
                    P1 = QgsPoint(ptStart_raw.x(), ptStart_raw.y())
                    P2 = QgsPoint(ptEnd_raw.x(), ptEnd_raw.y())
                    seg_geom = QgsGeometry.fromPolyline(
                        (P1, P2))  # generate geometry for current subsegment
                    _, mindistpt, _, _ = seg_geom.closestSegmentWithContext(
                        projected_point_raw)
                    TestPoint = QgsPointXY(
                        mindistpt[0],
                        mindistpt[1])  #create projected point on subsegment
                    ptStart = ptStart_raw
                    ptEnd = ptEnd_raw
                    projected_point = projected_point_raw
                    projected_point_on_line = projected_point_on_line_raw
                    if geodetic_measure == True:
                        if srcCRS != wgs84:
                            # Convert to 4326 - just to be safe when using geodetic measure
                            ptStart = geomTo4326.transform(ptStart_raw)
                            ptEnd = geomTo4326.transform(ptEnd_raw)
                            projected_point = geomTo4326.transform(
                                projected_point_raw)
                            projected_point_on_line = geomTo4326.transform(
                                projected_point_on_line_raw)
                            TestPoint = geomTo4326.transform(TestPoint)
                        d_to_click = KPTool.geod.Inverse(
                            ptStart.y(), ptStart.x(),
                            projected_point_on_line.y(),
                            projected_point_on_line.x())['s12']
                        len_subsegment = KPTool.geod.Inverse(
                            ptStart.y(), ptStart.x(), ptEnd.y(), ptEnd.x()
                        )['s12']  # geodetic distance between begin and end of subsegment
                        test_distance = KPTool.geod.Inverse(
                            projected_point_on_line.y(),
                            projected_point_on_line.x(), TestPoint.y(),
                            TestPoint.x()
                        )['s12']  # check distance between two on-subsegment-points

                    else:
                        d_to_click = QgsDistanceArea().measureLine(
                            ptStart, projected_point_on_line)
                        len_subsegment = QgsDistanceArea().measureLine(
                            ptStart, ptEnd
                        )  # cartesian distance between begin and end point
                        test_distance = QgsDistanceArea().measureLine(
                            projected_point_on_line, TestPoint
                        )  # check distance between two on-subsegment-points
                    round_test_distance = round(
                        test_distance, 6
                    )  # round so we can get zero, otherwise it will be a small fraction
                    if round_test_distance != 0:
                        # not yet the last segment to be measured
                        distance += len_subsegment  #add to comulative
                    else:
                        # this is the segment, where we have to stop measuring
                        distance += d_to_click
                        break  # break loop and give distance so far
                    ptStart_raw = ptEnd_raw  # make ready for next pair of points
                if QgsPoint(projected_point) != QgsPoint(
                        projected_point_on_line):
                    # if our point on the extended line is different, the projected point is before start or after end of line layer
                    if geodetic_measure == True:
                        extra_dist = KPTool.geod.Inverse(
                            projected_point.y(), projected_point.x(),
                            projected_point_on_line.y(),
                            projected_point_on_line.x())['s12']
                    else:
                        extra_dist = QgsDistanceArea().measureLine(
                            projected_point, projected_point_on_line)
                    if round(distance, 6) == 0:
                        # we are at the start of the line layer, the for loops hasn't done anything, so negative distance to starting node
                        distance = -extra_dist
                    else:
                        # we are at the end of the line segment, so need to add more distance
                        distance = distance + extra_dist
                out = distance / 1000  # Distance converted to KM
        return out

    def kpIteratePts(self, linetoMeasurekp4p, ptLayer):
        """will iterate over all points in a layer, finding distance to and along line.
        Outputs a new layer."""
        new_pt_layer = QgsVectorLayer(
            'Point', 'KPed_' + str(ptLayer.name()),
            'memory')  # define new layer we will return
        new_pt_layer.setCrs(ptLayer.crs())  # get crs from input layer
        prov_old = ptLayer.dataProvider(
        )  # provider to get the attribute field names and type
        provider_ptLayer = new_pt_layer.dataProvider(
        )  # provider for new layer to add the features to
        fields_ptLayer = prov_old.fields()
        for f in fields_ptLayer:
            # iterate over all field names and add to new provider
            znameField = f.name()
            type_field = str(f.typeName())
            if type_field == 'Integer':
                provider_ptLayer.addAttributes(
                    [QgsField(znameField, QVariant.Int)])
            if type_field == 'Real':
                provider_ptLayer.addAttributes(
                    [QgsField(znameField, QVariant.Double)])
            if type_field == 'String':
                provider_ptLayer.addAttributes(
                    [QgsField(znameField, QVariant.String)])
            else:
                provider_ptLayer.addAttributes(
                    [QgsField(znameField, QVariant.String)])

        iterate_names_list = ["KP", "DOL", "Latitude", "Longitude"]
        new_attr_names = self.name_collision_checker(
            iterate_names_list,
            ptLayer)  # check if the new names we add already exist
        provider_ptLayer.addAttributes([
            QgsField(new_attr_names[0], QVariant.Double),
            QgsField(new_attr_names[1], QVariant.Double),
            QgsField(new_attr_names[2], QVariant.String),
            QgsField(new_attr_names[3], QVariant.String)
        ])  # four new fields we are calculating
        new_pt_layer.startEditing()
        for old_feat in ptLayer.getFeatures():
            # iterate over all point features
            geom_of = old_feat.geometry()
            point_of = geom_of.asPoint()  # get point object
            new_feat = QgsFeature()
            new_feat.setGeometry(
                geom_of)  # create and set geometry from old feature
            attributes_nf = old_feat.attributes(
            )  # copy of old feat attributes

            if self.geodetic_usekp4p == 0:
                # we measure Cartesian coords
                line_length = self.measureLine(self.linelayer, point_of,
                                               False) + self.offsetkp4p
                whole_line_length = self.measureWholeLine(
                    self.linelayer, False)
                dcc_dist = self.closestPt(
                    linetoMeasurekp4p, point_of, True,
                    False)[1]  # second False means we use Cartesian distance
            elif self.geodetic_usekp4p == 2:
                # we measure geodetic coords
                line_length = self.measureLine(linetoMeasurekp4p, point_of,
                                               True) + self.offsetkp4p
                whole_line_length = self.measureWholeLine(self.linelayer, True)
                dcc_dist = self.closestPt(linetoMeasurekp4p, point_of, True,
                                          True)[1]
            if self.reversekp_statuskp4p == 0:
                kp_dist = line_length
            elif self.reversekp_statuskp4p == 2:
                kp_dist = whole_line_length - line_length

            attributes_nf.append(round(
                kp_dist, self.kpdeckp4p))  # round with precision values
            attributes_nf.append(round(
                dcc_dist, self.dccdeckp4p))  # round with precision values
            attributes_nf.append(
                self.formatCoord(point_of)[0])  # insert latitude
            attributes_nf.append(
                self.formatCoord(point_of)[1])  # insert longitude
            new_feat.setAttributes(
                attributes_nf)  # set new attributes to new feat
            provider_ptLayer.addFeatures([new_feat
                                          ])  # add new feature to provider

        new_pt_layer.commitChanges()  # finish editing layer
        return new_pt_layer  # return the new layer with new features with new attributes

    def formatCoord(self, pt):
        canvasCRS = self.canvas.mapSettings().destinationCrs()
        epsg4326 = QgsCoordinateReferenceSystem('EPSG:4326')
        # convert point to wgs84 for conversion
        if canvasCRS == epsg4326:
            pt4326 = pt
        else:
            transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                               QgsProject.instance())
            pt4326 = transform.transform(pt.x(), pt.y())
        lat = self.convertDD2DM(pt4326.y(), True, 4)
        lon = self.convertDD2DM(pt4326.x(), False, 4)
        return [lat, lon]

    def convertDD2DM(self, coord, islat, prec):
        """Convert decimal degrees to DM - taken from latlontools plugin"""
        if islat:
            if coord < 0:
                unit = 'S'
            else:
                unit = 'N'
        else:
            if coord > 0:
                unit = 'E'
            else:
                unit = 'W'
        dmsSpace = ' '  # put some spaces in there
        zeroes = 1  # this will be used for padding
        coord = math.fabs(coord)
        deg = math.floor(coord)
        dmin = (coord - deg) * 60.0
        min = math.floor(dmin)
        sec = (dmin - min) * 60.0
        s = ""
        # Properly handle rounding based on the digit precision
        d = "{:.{prec}f}".format(dmin, prec=prec)
        if float(d) == 60:
            deg += 1
            dmin = 0
        if islat:
            s = '{:0{}.0f}\xB0{}{:0{}.0{prec}f}\'{}{}'.format(deg,
                                                              zeroes * 2,
                                                              dmsSpace,
                                                              dmin,
                                                              prec +
                                                              zeroes * 3,
                                                              dmsSpace,
                                                              unit,
                                                              prec=prec)
        else:
            s = '{:0{}.0f}\xB0{}{:0{}.0{prec}f}\'{}{}'.format(deg,
                                                              zeroes * 3,
                                                              dmsSpace,
                                                              dmin,
                                                              prec +
                                                              zeroes * 3,
                                                              dmsSpace,
                                                              unit,
                                                              prec=prec)
        return (s)

    def measureWholeLine(self, linetoMeasure, geodetic_measure=True):
        """This will take a line segment and return its geodetic length"""
        srcCRS = linetoMeasure.sourceCrs()  #get CRS from line
        feature = linetoMeasure.getFeature(0)  #get first feature from line
        wgs84 = KPTool.epsg4326  #define EPSG 43226
        if feature.geometry().isMultipart():  #get nodes out of data
            ptdata = [feature.geometry().asMultiPolyline()]
        else:
            feature = linetoMeasure.getFeature(1)
            ptdata = [[feature.geometry().asPolyline()]]
        for seg in ptdata:
            if len(seg) < 1:  #should never happen
                self.iface.messageBar().pushMessage(
                    'Something is strange with your line file',
                    level=Qgis.Critical,
                    duration=2)
                continue
            for pts in seg:  # now we get all nodes from start to end of line
                numpoints = len(pts)

                if numpoints < 2:  # should never happen
                    self.iface.messageBar().pushMessage(
                        'Something is strange with your line file',
                        level=Qgis.Critical,
                        duration=2)
                    continue
                ptStart_raw = QgsPointXY(
                    pts[0].x(), pts[0].y())  # get initial point coords
                # Calculate the total distance of this line segment
                distance = 0.0
                for x in range(1, numpoints):
                    # from point one (since we preextend segment), cumulative
                    ptEnd_raw = QgsPointXY(
                        pts[x].x(), pts[x].y())  # coordinates of next point
                    if geodetic_measure == True:
                        if srcCRS != wgs84:
                            # Convert to 4326 - just to be safe when using geodetic measure
                            geomTo4326 = QgsCoordinateTransform(
                                srcCRS, wgs84,
                                QgsProject.instance())  # convert if needed
                            ptStart = geomTo4326.transform(ptStart_raw)
                            ptEnd = geomTo4326.transform(ptEnd_raw)
                        length = KPTool.geod.Inverse(
                            ptStart.y(), ptStart.x(), ptEnd.y(), ptEnd.x()
                        )['s12']  # geodetic distance between begin and end of subsegment
                    else:
                        length = QgsDistanceArea().measureLine(
                            ptStart_raw, ptEnd_raw)
                    distance += length  # add to cumulative
                    ptStart_raw = ptEnd_raw  # make ready for next pair of points
                out = distance / 1000  # Distance converted KM
        return out

    def putKPPointsAlongLine(self, source, maxseglen):
        "We travel along the line and test if each consecutive segment should contain KPs and how many"
        layercrs = source.sourceCrs()
        if layercrs != KPTool.epsg4326:
            transto4326 = QgsCoordinateTransform(layercrs, KPTool.epsg4326,
                                                 QgsProject.instance())
            transfrom4326 = QgsCoordinateTransform(KPTool.epsg4326, layercrs,
                                                   QgsProject.instance())

        new_pt_layer = QgsVectorLayer(
            'Point', 'KP_points_' + str(source.name()),
            'memory')  # define new layer we will return
        new_pt_layer.setCrs(source.crs())  # get crs from input layer
        new_pt_layer.startEditing()
        provider_ptLayer = new_pt_layer.dataProvider(
        )  # provider for new layer to add the features to
        provider_ptLayer.addAttributes([QgsField('KP', QVariant.Double)])
        iterator = source.getFeatures()
        KP_label_count = 0

        for cnt, feature in enumerate(iterator):
            if feature.geometry().isMultipart():
                seg = feature.geometry().asMultiPolyline()
            else:
                seg = [feature.geometry().asPolyline()]
            numseg = len(seg)
            if numseg < 1 or len(seg[0]) < 2:
                self.iface.messageBar().pushMessage(
                    'Less than one segment in line layer',
                    level=Qgis.Critical,
                    duration=2)
                continue
            for line in seg:
                numpoints = len(line)
                if self.Reverse_KP_points == 2:  #reverse point order for reverse KP
                    _ = line.reverse()
                ptStart = QgsPointXY(line[0][0], line[0][1])
                new_kp_point = self.createFeatureFromPoint(
                    ptStart, KP_label_count)
                provider_ptLayer.addFeatures([new_kp_point])
                remaining_dist = 0.0  #remaining distance to next point
                if layercrs != KPTool.epsg4326:  # Convert to 4326
                    ptStart = transto4326.transform(ptStart)
                for x in range(1, numpoints):
                    ptEnd = QgsPointXY(line[x][0], line[x][1])
                    if layercrs != KPTool.epsg4326:  # Convert to 4326
                        ptEnd = transto4326.transform(ptEnd)
                    gline = KPTool.geod.InverseLine(ptStart.y(), ptStart.x(),
                                                    ptEnd.y(), ptEnd.x())
                    if remaining_dist + gline.s13 > maxseglen:  #we have to place at least one KP
                        s = maxseglen - remaining_dist
                        g = gline.Position(
                            s, Geodesic.LATITUDE | Geodesic.LONGITUDE
                            | Geodesic.LONG_UNROLL)
                        ptKP = QgsPointXY(g['lon2'], g['lat2'])
                        if layercrs != KPTool.epsg4326:
                            ptKP = transfrom4326.transform(ptKP)
                        KP_label_count = KP_label_count + maxseglen
                        remaining_dist = remaining_dist + gline.s13 - maxseglen
                        new_kp_point = self.createFeatureFromPoint(
                            ptKP, KP_label_count)
                        provider_ptLayer.addFeatures([new_kp_point])
                        if remaining_dist > maxseglen:  #we need to place more KP pts
                            extra_from_start = s
                            n = int(remaining_dist / maxseglen)
                            for i in range(0, n):
                                s = maxseglen * (i + 1) + extra_from_start
                                g = gline.Position(
                                    s, Geodesic.LATITUDE | Geodesic.LONGITUDE
                                    | Geodesic.LONG_UNROLL)
                                ptKP = QgsPointXY(g['lon2'], g['lat2'])
                                if layercrs != KPTool.epsg4326:  # Convert each point back to the output CRS
                                    ptKP = transfrom4326.transform(ptKP)
                                KP_label_count = KP_label_count + maxseglen
                                remaining_dist = remaining_dist - maxseglen
                                new_kp_point = self.createFeatureFromPoint(
                                    ptKP, KP_label_count)
                                provider_ptLayer.addFeatures([new_kp_point])
                    else:  #no KPs placed in this segment, keep the cumulative distance
                        remaining_dist = remaining_dist + gline.s13
                    ptStart = ptEnd
        new_pt_layer.commitChanges()
        return new_pt_layer

    def putKPPointsAlongLineCart(self, source, maxseglen):
        "this uses the .interpolate method from the QgsGeometry class, which works well in Cartesian coordinates"
        new_pt_layer = QgsVectorLayer(
            'Point', 'KP_points_' + str(source.name()),
            'memory')  # define new layer we will return
        new_pt_layer.setCrs(source.crs())  # get crs from input layer
        new_pt_layer.startEditing()
        provider_ptLayer = new_pt_layer.dataProvider(
        )  # provider for new layer to add the features to
        provider_ptLayer.addAttributes([QgsField('KP', QVariant.Double)])
        iterator = source.getFeatures()
        for cnt, feature in enumerate(iterator):
            if feature.geometry().isMultipart():
                seg = feature.geometry()
            else:
                seg = feature.geometry()
                seg.convertToMultiType()
            if self.Reverse_KP_points == 2:  #reverse point order for reverse KP
                seg = self.reverseLineDirection(seg)
            n = int(seg.length() / maxseglen)
            KP_label_count = -maxseglen  # so we get zero with first interp point
            for i in range(0, n + 1):
                ptKP = seg.interpolate(i * maxseglen)
                ptKP = ptKP.asPoint()
                KP_label_count = KP_label_count + maxseglen
                new_kp_point = self.createFeatureFromPoint(
                    ptKP, KP_label_count)
                provider_ptLayer.addFeatures([new_kp_point])
        new_pt_layer.commitChanges()
        return new_pt_layer

    def createFeatureFromPoint(self, point, attributes):
        "takes an QgsPointXY and makes it a feature, adds attributes"
        new_feat = QgsFeature()
        new_feat.setGeometry(QgsGeometry.fromPointXY(
            point))  # create and set geometry from old feature
        new_feat.setAttributes([round(attributes, 3)])
        return new_feat

    def reverseLineDirection(self, line_geom):
        mls1 = line_geom.get()
        mls2 = QgsMultiLineString()
        # For each reversed linestring, visited in reverse order
        for i in [QgsLineString([*i][::-1]) for i in [*mls1][::-1]]:
            _ = mls2.addGeometry(i)  # add it to new geometry
        new_geometry = QgsGeometry(mls2)
        return new_geometry
Пример #43
0
class W3WCoordInputDialog(QDockWidget):
    def __init__(self, canvas, parent):
        self.canvas = canvas
        self.marker = None
        QDockWidget.__init__(self, parent)
        self.setAllowedAreas(Qt.TopDockWidgetArea)
        self.initGui()

    def setApiKey(self, apikey):
        self.w3w = what3words(apikey=apikey)

    def initGui(self):
        self.setWindowTitle("Zoom to 3 word address")
        self.label = QLabel('3 Word Address')
        self.coordBox = QLineEdit()
        '''
        When the button is pressed, we try to zoom to the coordinate entered
        by the user. That is done in the zoomToPressed method, but since this 
        is a method that might take a while to be executed (it connects 
        the w3w API), we use the 'execute' function in the qgiscommons 
        library, which will take care of changing the mouse pointer to an 
        hourglass until the method execution is finished.
        '''
        self.coordBox.returnPressed.connect(
            lambda: execute(self.zoomToPressed))
        self.zoomToButton = QPushButton("Zoom to")
        self.zoomToButton.clicked.connect(self.zoomToPressed)
        self.removeMarkerButton = QPushButton("Remove marker")
        self.removeMarkerButton.clicked.connect(self.removeMarker)
        self.removeMarkerButton.setDisabled(True)
        self.hlayout = QHBoxLayout()
        self.hlayout.setSpacing(6)
        self.hlayout.setMargin(9)
        self.hlayout.addWidget(self.label)
        self.hlayout.addWidget(self.coordBox)
        self.hlayout.addWidget(self.zoomToButton)
        self.hlayout.addWidget(self.removeMarkerButton)
        self.dockWidgetContents = QWidget()
        self.dockWidgetContents.setLayout(self.hlayout)
        self.setWidget(self.dockWidgetContents)

    def zoomToPressed(self):
        try:
            '''We convert the w3w address into a EPSG:4326 coord'''
            w3wCoord = str(self.coordBox.text()).replace(" ", "")
            json = self.w3w.forwardGeocode(w3wCoord)
            lat = float(json["geometry"]["lat"])
            lon = float(json["geometry"]["lng"])
            '''
            We convert the 4326 coord into a coord in the CRS of the canvas
            '''
            canvasCrs = self.canvas.mapSettings().destinationCrs()
            epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326")
            transform4326 = QgsCoordinateTransform(epsg4326, canvasCrs)
            center = transform4326.transform(lon, lat)
            '''We zoom to that coord and set a marker'''
            self.canvas.zoomByFactor(1, center)
            self.canvas.refresh()
            if self.marker is None:
                self.marker = QgsVertexMarker(self.canvas)
            self.marker.setCenter(center)
            self.marker.setIconSize(8)
            self.marker.setPenWidth(4)
            '''Allow user to remove marker'''
            self.removeMarkerButton.setDisabled(False)

            self.coordBox.setStyleSheet("QLineEdit{background: white}")
        except Exception as e:
            self.coordBox.setStyleSheet("QLineEdit{background: yellow}")

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

    def closeEvent(self, evt):
        '''Remove marker when closing widget'''
        if self.marker is not None:
            self.removeMarker()
Пример #44
0
class QgepMapToolAddReach(QgepMapToolAddFeature):
    """
    Create a new reach with the mouse.
    Will snap to wastewater nodes for the first and last point and auto-connect
    these.
    """
    first_snapping_match = None
    last_snapping_match = None
    last_feature_attributes = None

    def __init__(self, iface: QgisInterface, layer):
        QgepMapToolAddFeature.__init__(self, iface, layer)
        self.snapping_marker = None
        self.node_layer = QgepLayerManager.layer('vw_wastewater_node')
        assert self.node_layer is not None
        self.reach_layer = QgepLayerManager.layer('vw_qgep_reach')
        assert self.reach_layer is not None
        self.setAdvancedDigitizingAllowed(True)
        self.setAutoSnapEnabled(True)

        layer_snapping_configs = [{
            'layer': self.node_layer,
            'mode': QgsSnappingConfig.Vertex
        }, {
            'layer': self.reach_layer,
            'mode': QgsSnappingConfig.VertexAndSegment
        }]
        self.snapping_configs = []
        self.snapping_utils = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())

        for lsc in layer_snapping_configs:
            config = QgsSnappingConfig()
            config.setMode(QgsSnappingConfig.AdvancedConfiguration)
            config.setEnabled(True)
            settings = QgsSnappingConfig.IndividualLayerSettings(
                True, lsc['mode'], 10, QgsTolerance.Pixels)
            config.setIndividualLayerSettings(lsc['layer'], settings)
            self.snapping_configs.append(config)

    def left_clicked(self, event):
        """
        The mouse is clicked: snap to neary points which are on the wastewater node layer
        and update the rubberband
        :param event: The coordinates etc.
        """
        point3d, match = self.snap(event)
        if self.rubberband.numberOfVertices() == 0:
            self.first_snapping_match = match
        self.last_snapping_match = match
        self.rubberband.addPoint3D(point3d)
        self.temp_rubberband.reset()
        self.temp_rubberband.addPoint(QgsPointXY(point3d.x(), point3d.y()))

        if self.snapping_marker is not None:
            self.iface.mapCanvas().scene().removeItem(self.snapping_marker)
            self.snapping_marker = None

    def mouse_move(self, event):
        _, match = self.snap(event)
        # snap indicator
        if not match.isValid():
            if self.snapping_marker is not None:
                self.iface.mapCanvas().scene().removeItem(self.snapping_marker)
                self.snapping_marker = None
            return

        # TODO QGIS 3: see if vertices can be removed

        # we have a valid match
        if self.snapping_marker is None:
            self.snapping_marker = QgsVertexMarker(self.iface.mapCanvas())
            self.snapping_marker.setPenWidth(3)
            self.snapping_marker.setColor(QColor(Qt.magenta))

        if match.hasVertex():
            if match.layer():
                icon_type = QgsVertexMarker.ICON_BOX  # vertex snap
            else:
                icon_type = QgsVertexMarker.ICON_X  # intersection snap
        else:
            icon_type = QgsVertexMarker.ICON_DOUBLE_TRIANGLE  # must be segment snap
        self.snapping_marker.setIconType(icon_type)
        self.snapping_marker.setCenter(match.point())

    def snap(self, event):
        """
        Snap to nearby points on the wastewater node layer which may be used as connection
        points for this reach.
        :param event: The mouse event
        :return: The snapped position in map coordinates
        """

        for config in self.snapping_configs:
            self.snapping_utils.setConfig(config)
            match = self.snapping_utils.snapToMap(
                QgsPointXY(event.originalMapPoint()))
            if match.isValid():
                return QgsPoint(match.point()), match

        # if no match, snap to all layers (according to map settings) and try to grab Z
        match = self.iface.mapCanvas().snappingUtils().snapToMap(
            QgsPointXY(event.originalMapPoint()))
        if match.isValid() and match.hasVertex():
            if match.layer():
                req = QgsFeatureRequest(match.featureId())
                f = next(match.layer().getFeatures(req))
                assert f.isValid()
                if match.layer().geometryType() == QgsWkbTypes.PointGeometry:
                    point = QgsPoint(f.geometry().constGet())
                else:
                    (ok, vertex_id) = f.geometry().vertexIdFromVertexNr(
                        match.vertexIndex())
                    assert ok
                    point = f.geometry().constGet().vertexAt(vertex_id)
                assert type(point) == QgsPoint
                return point, match
            else:
                return QgsPoint(match.point()), match

        return QgsPoint(event.originalMapPoint()), match

    def right_clicked(self, _):
        """
        The party is over, the reach digitized. Create a feature from the rubberband and
        show the feature form.
        """
        self.temp_rubberband.reset()

        if self.snapping_marker is not None:
            self.iface.mapCanvas().scene().removeItem(self.snapping_marker)
            self.snapping_marker = None

        if len(self.rubberband.points) >= 2:

            fields = self.layer.fields()
            f = QgsFeature(fields)
            if not self.last_feature_attributes:
                self.last_feature_attributes = [None] * fields.count()
            for idx, field in enumerate(fields):
                if field.name() in [
                        'clear_height', 'material', 'ch_usage_current',
                        'ch_function_hierarchic', 'ch_function_hydraulic',
                        'horizontal_positioning', 'ws_status',
                        'ws_year_of_construction', 'ws_fk_owner',
                        'ws_fk_operator', 'inside_coating', 'fk_pipe_profile',
                        'remark'
                ]:
                    f.setAttribute(idx, self.last_feature_attributes[idx])
                else:
                    # try client side default value first
                    v = self.layer.defaultValue(idx, f)
                    if v != NULL:
                        f.setAttribute(idx, v)
                    else:
                        f.setAttribute(
                            idx,
                            self.layer.dataProvider().defaultValue(idx))

            f.setGeometry(self.rubberband.asGeometry3D())

            snapping_results = {
                'from': self.first_snapping_match,
                'to': self.last_snapping_match
            }
            for dest, match in list(snapping_results.items()):
                level_field_index = self.layer.fields().indexFromName(
                    'rp_{dest}_level'.format(dest=dest))
                pt_idx = 0 if dest == 'from' else -1
                if match.isValid() and match.layer() in (self.node_layer,
                                                         self.reach_layer):
                    request = QgsFeatureRequest(match.featureId())
                    network_element = next(match.layer().getFeatures(request))
                    assert network_element.isValid()
                    # set the related network element
                    field = self.layer.fields().indexFromName(
                        'rp_{dest}_fk_wastewater_networkelement'.format(
                            dest=dest))
                    f.setAttribute(field, network_element.attribute('obj_id'))
                    # assign level if the match is a node or if we have 3D from snapping
                    if match.layer() == self.node_layer:
                        level = network_element['bottom_level']
                        f.setAttribute(level_field_index, level)
                elif self.rubberband.points[pt_idx].z() != 0:
                    level = self.rubberband.points[pt_idx].z()
                    level = level if not math.isnan(level) else NULL
                    f.setAttribute(level_field_index, level)

            dlg = self.iface.getFeatureForm(self.layer, f)
            dlg.setMode(QgsAttributeEditorContext.AddFeatureMode)
            dlg.exec_()
            self.last_feature_attributes = dlg.feature().attributes()

        self.rubberband.reset3D()
Пример #45
0
class geopunt4QgisElevationDialog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self, None)
        self.setWindowFlags( self.windowFlags() & ~Qt.WindowContextHelpButtonHint )

        self.iface = iface
    
        # initialize locale
        locale = QSettings().value("locale/userLocale", "en")
        if not locale: locale == 'en'
        else: locale = locale[0:2]
        localePath = os.path.join(os.path.dirname(__file__), 'i18n', 'geopunt4qgis_{}.qm'.format(locale))
        if os.path.exists(localePath):
            self.translator = QTranslator()
            self.translator.load(localePath)
            QCoreApplication.installTranslator(self.translator)
    
        self._initGui()

    def _initGui(self):
        """setup the user interface"""
        self.ui = Ui_elevationDlg()
        self.ui.setupUi(self)
                
        #get settings
        self.s = QSettings()
        self.loadSettings()

        self.gh = geometryHelper( self.iface )
        self.eh = elevationHelper( self.iface, self.startDir)
        
        #setup a message bar
        self.bar = QgsMessageBar() 
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
        self.ui.verticalLayout.addWidget(self.bar)
        
        self.ui.buttonBox.addButton(QPushButton("Sluiten"), QDialogButtonBox.RejectRole )
        for btn in self.ui.buttonBox.buttons():
            btn.setAutoDefault(0)
                  
        ##graph global vars
        self.Rubberline =  None
        self.profile = None
        self.pt = None
        self.ax = None
        self.ano = None
        self.anoLbl = None
        self.counter = 0
        self.xscaleUnit = (1, "m")
        
        # a figure instance to plot on
        self.figure = Figure()

        #create the Canvas widget and toolbar and set graphWgt as parent
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)

        ###
        #self.ui.toolbar.layout().insertWidget(0, self.toolbar)
        self.ui.graphWgt.layout().addWidget(self.canvas)
        self.createCanvasToolbar()
        
        #events
        self.ui.drawBtn.clicked.connect(self.drawBtnClicked)
        self.figure.canvas.mpl_connect('motion_notify_event', self.showGraphMotion)
        self.ui.saveLineBtn.clicked.connect(self.saveLineClicked)
        self.ui.savePntBtn.clicked.connect(self.savePntClicked)
        self.ui.addDHMbtn.clicked.connect(self.addDHMasWMS) 
        self.ui.refreshBtn.clicked.connect( self.onRefresh )
        self.ui.buttonBox.helpRequested.connect(self.openHelp)
        
        self.rejected.connect(self.clean )

    def createCanvasToolbar (self):
        '''
        1 Reset original view
        2 Back to  previous view
        3 Forward to next view
        4 Pan axes with left mouse, zoom with right
        5 Zoom to rectangle
        6 Save the figure
        7 Edit curves line and axes parameters
        '''
        self.toolbar.setVisible(False)
        toolbarBtns = self.ui.toolbar.findChildren(QToolButton)
        self.ui.toolbar.setStyleSheet("""QToolButton {border-width: 2px; border-style: outset; 
                                                      border-color: #fbd837; border-radius: 5px ; background-color: white }
                                         QToolButton:pressed { border-style: inset;   background-color: grey } """)
        toolbarBtns[0].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Keer terug naar overzicht"))
        toolbarBtns[0].setIcon( QIcon(":/plugins/geopunt4Qgis/images/full_extent.png"))
        toolbarBtns[0].clicked.connect( self.toolbar.home )
        toolbarBtns[1].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Vorige"))
        toolbarBtns[1].setIcon( QIcon(":/plugins/geopunt4Qgis/images/previous.png")) 
        toolbarBtns[1].clicked.connect( self.toolbar.back )
        toolbarBtns[2].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Volgende"))
        toolbarBtns[2].setIcon( QIcon(":/plugins/geopunt4Qgis/images/next.png"))
        toolbarBtns[2].clicked.connect( self.toolbar.forward )
        toolbarBtns[3].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Pannen"))
        toolbarBtns[3].setIcon( QIcon(":/plugins/geopunt4Qgis/images/pan.png")) 
        toolbarBtns[3].clicked.connect( self.toolbar.pan )
        toolbarBtns[4].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Zoom naar rechthoek"))
        toolbarBtns[4].setIcon( QIcon(":/plugins/geopunt4Qgis/images/rectangleZoom.png"))  
        toolbarBtns[4].clicked.connect( self.toolbar.zoom )
        toolbarBtns[5].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Opslaan als afbeelding"))
        toolbarBtns[5].setIcon( QIcon(":/plugins/geopunt4Qgis/images/save.png"))
        toolbarBtns[5].clicked.connect( self.save_fig ) #semf.toolbar.save_figure
        toolbarBtns[6].setToolTip(QCoreApplication.translate("geopunt4QgisElevationDialog", "Vorm grafiek aanpassen"))
        toolbarBtns[6].setIcon( QIcon(":/plugins/geopunt4Qgis/images/wrench.png")) 
        toolbarBtns[6].clicked.connect( self.toolbar.edit_parameters)
        toolbarBtns[7].setIcon( QIcon(":/plugins/geopunt4Qgis/images/fill.png"))
        toolbarBtns[7].setToolTip( QCoreApplication.translate("geopunt4QgisElevationDialog", "Kies de vulkleur"))
        toolbarBtns[7].clicked.connect( self.setFill)
        
    def loadSettings(self):
        self.timeout =  int( self.s.value("geopunt4qgis/timeout" ,15))
        if settings().proxyUrl:
            self.proxy = settings().proxyUrl
        else:
            self.proxy = ""
        self.samplesSavetoFile = int( self.s.value("geopunt4qgis/samplesSavetoFile" , 1))
        sampleLayer = self.s.value("geopunt4qgis/sampleLayerTxt", "")
        if sampleLayer:  
           self.sampleLayerTxt = sampleLayer
        self.profileLineSavetoFile = int( self.s.value("geopunt4qgis/profileLineSavetoFile" , 1))
        profileLineLayer= self.s.value("geopunt4qgis/profileLineLayerTxt", "")
        if profileLineLayer:
           self.profileLineLayerTxt = profileLineLayer
        self.startDir = self.s.value("geopunt4qgis/startDir", os.path.expanduser("~"))        
        self.elevation = elevation(self.timeout, self.proxy )

    def resizeEvent(self, event):
        QDialog.resizeEvent(self, event)
        if self.ax: self.figure.tight_layout()

    #eventhandlers
    def save_fig(self):
        formats = (
        "Joint Photographic Experts Group (*.jpg) (*.jpg);;Scalable Vector Grapics (*.svg) (*.svg);;"+
        "Portable Document Format (*.pdf) (*.pdf);;Tagged Image File Format (*.tif) (*.tif)"+
        ";;Encapsulated Postscript (*.eps) (*.eps)")
      
        if not(sys.platform == 'win32'):
           formats += ";;Portable Network Graphics  (*.png) (*.png)"
      
        fileName, __ = QFileDialog.getSaveFileName( self , "Save File", self.startDir, formats);
        self.figure.savefig(fileName)
    
    def onRefresh(self):
        if self.ano: 
            self.ano.remove()
            self.ano = None
        if self.anoLbl: 
            self.anoLbl.remove()
            self.anoLbl = None
        self.plot()
    
    def onResize(self, event):
        self.figure.tight_layout()
    
    def openHelp(self):
        webbrowser.open_new_tab("http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/hoogteprofiel")
    
    def drawBtnClicked(self):
        self.clean()
        #self.reSetFigure()
        self.tool = lineTool(self.iface, self.callBack )  
        self.iface.mapCanvas().setMapTool(self.tool)
        self.showMinimized()
        self.counter += 1
             
    def showGraphMotion(self, event):
        if self.ax == None: return
        
        if event.xdata != None and event.ydata != None:
          if self.ano != None: 
             self.ano.remove()
             self.ano = None
          if self.anoLbl != None: 
             self.anoLbl.remove()
             self.anoLbl = None
            
          xdata = np.array( [n[0] for n in self.profile ] ) * self.xscaleUnit[0]
          ydata = np.array( [n[3] for n in self.profile ] )# if n[3] > -9999 ]
          zx = np.interp( event.xdata, xdata, ydata )
          xmax = np.max( xdata ) 
          xmin = np.min( xdata )
          zmax = np.max( ydata )
          zmin = np.max( [n[3] for n in self.profile if n[3] > -9999 ] )
           
          if event.xdata <= xmax and event.xdata >= xmin  :
              self.ano = self.ax.arrow( event.xdata , -9999, 0, zx + 9999, fc="k", ec="k" )
              
              box_props = dict(boxstyle="Round,pad=0.3", fc="cyan", ec="b", lw=2)
              self.anoLbl = self.ax.annotate( str( round(zx, 2)) + " m",  xy= (event.xdata, zx ) , 
                          xytext= (event.xdata , zx + (0.2 * ( zmax - zmin )) ),
                          bbox=box_props )
              self.setMapPt( event.xdata / self.xscaleUnit[0] )
          else:
              self.setMapPt()
              
          event.canvas.draw()
        
    def saveLineClicked(self):
        if not hasattr(self, 'profileLineLayerTxt'):
           layerName, accept = QInputDialog.getText(None,
              QCoreApplication.translate("geopunt4Qgis", 'Laag toevoegen'),
              QCoreApplication.translate("geopunt4Qgis", 'Geef een naam voor de laag op:') )
           if accept == False: 
              return
           else:  
              self.profileLineLayerTxt = layerName
           
        if self.profile != None and self.Rubberline != None:
           title = self.ax.get_title()
           self.eh.save_profile( self.Rubberline.asGeometry(), self.profile, title,
                              self.profileLineLayerTxt, self.profileLineSavetoFile, sender=self )
        
    def savePntClicked(self):
        if not hasattr(self, 'sampleLayerTxt'):
           layerName, accept = QInputDialog.getText(None,
              QCoreApplication.translate("geopunt4Qgis", 'Laag toevoegen'),
              QCoreApplication.translate("geopunt4Qgis", 'Geef een naam voor de laag op:') )
           if accept == False: 
              return
           else:  
              self.sampleLayerTxt = layerName
      
        if self.profile != None:
           title = self.ax.get_title()
           self.eh.save_sample_points( self.profile, title, 
                                   self.sampleLayerTxt, self.samplesSavetoFile, sender=self )
    
    def setFill( self ):
        if self.profile == None: return
        if self.ax == None: return
        
        clr = QColorDialog.getColor( Qt.white, self, QCoreApplication.translate(
                  "geopunt4QgisElevationDialog", "Kies de vulkleur") )
        if clr.isValid():
          xdata = np.array( [n[0] for n in self.profile ] ) * self.xscaleUnit[0]
          ydata = np.array( [n[3] for n in self.profile ] )
          self.ax.fill_between( xdata, ydata, -9999, color=clr.name() )
    
    def addDHMasWMS(self):
        crs = self.gh.getGetMapCrs(self.iface).authid()
        if crs != 'EPSG:31370' or  crs != 'EPSG:3857' or  crs != 'EPSG:3043':
           crs = 'EPSG:31370' 
        dhmUrl =  "url=https://geoservices.informatievlaanderen.be/raadpleegdiensten/DHMV/wms&layers=DHMVII_DTM_1m&&format=image/png&styles=default&crs="+ crs

        try:
            rlayer = QgsRasterLayer(dhmUrl, 'Hoogtemodel', 'wms') 
            if rlayer.isValid():
               rlayer.renderer().setOpacity(0.8)
               QgsProject.instance().addMapLayer(rlayer)
            else: self.bar.pushMessage("Error", 
                QCoreApplication.translate("geopunt4QgisElevationDialog", "Kan WMS niet laden"), 
                level=Qgis.Critical, duration=10) 
        except: 
            self.bar.pushMessage("Error", str( sys.exc_info()[1] ), level=Qgis.Critical, duration=10)
            return 
        
    def plot(self):
        if self.Rubberline == None: return
      
        wgsLine = self.gh.prjLineFromMapCrs( self.Rubberline.asGeometry() )
        lineString = [ list(n) for n in wgsLine.asPolyline()]
        nrSamples = self.ui.nrOfSampleSpin.value()
        #try:
        self.profile = self.elevation.fetchElevaton( lineString, 4326, nrSamples)
        #except geopuntError as ge: 
        #    self.bar.pushMessage("Error", ge.message, level=Qgis.Critical, duration=10)
        #    return 
        
        if np.max( [n[0] for n in self.profile ] ) > 1000: self.xscaleUnit = (0.001 , "km" )
        else: self.xscaleUnit = (1 , "m" )
        
        xdata = np.array( [n[0] for n in self.profile ] ) * self.xscaleUnit[0]
        ydata = np.array( [n[3] for n in self.profile ] )
        
        #need at least 3 values
        if len(xdata) <= 2 or len([n for n in self.profile if n[3] > -9999 ]) <= 2:
           self.bar.pushMessage("Error", 
                QCoreApplication.translate(
                  "geopunt4QgisElevationDialog", "Er werd geen of onvoldoende data gevonden"),
                level=Qgis.Warning, duration=5)
           self.profile = None
           return 
        
        ymin = np.min( [n[3] for n in self.profile if n[3] > -9999 ] )
        ymax = np.max( ydata )
     
        # create an axis
        self.ax = self.figure.add_subplot(111)
        
        # discards the old graph
        self.ax.hold(False)

        # plot data
        self.ax.plot( xdata, ydata,'r*')
        self.ax.fill_between(xdata, ydata, -9999, color='#F8E6E0' )
        self.ax.set_ylim([ymin , ymax])
        self.ax.set_xlim([0 , None ])
        self.ax.set_ylabel("hoogte (m)")
        self.ax.set_xlabel("afstand (%s)" % self.xscaleUnit[1] )
        self.ax.set_title("Hoogteprofiel " + str( self.counter) )

        # refresh canvas
        self.figure.tight_layout()
        self.canvas.draw()
        
    def callBack(self, geom):
        self.iface.mapCanvas().unsetMapTool(self.tool)
        self.Rubberline = geom
        self.showNormal()
        self.activateWindow()
        self.plot()
        self.ui.saveWgt.setEnabled(True)

    def setMapPt(self, dist=None ):
        if self.pt: self.iface.mapCanvas().scene().removeItem(self.pt)
           
        if dist==None: return
        
        if self.Rubberline == None: return 

        # dist is measured in lambert 72 in meters
        lb72Line = self.gh.prjLineFromMapCrs( self.Rubberline.asGeometry() , 31370 )
        lb72pt = lb72Line.interpolate(dist).asPoint()
        pt = self.gh.prjPtToMapCrs(lb72pt, 31370)
        
        self.pt = QgsVertexMarker(self.iface.mapCanvas())
        self.pt.setCenter( pt )
        self.pt.setColor(QColor(0,255,250))
        self.pt.setIconSize(5)
        self.pt.setIconType(QgsVertexMarker.ICON_BOX ) # or ICON_CROSS, ICON_X
        self.pt.setPenWidth(7)
        
        if self.xscaleUnit[0] != 1:
           msg= "lengte= %s %s" %  (round( dist * self.xscaleUnit[0], 2) , self.xscaleUnit[1])
        else:
           msg= "lengte= %s %s" %  (int( dist * self.xscaleUnit[0]) , self.xscaleUnit[1])
        
        self.ui.mgsLbl.setText( msg )    
        
    def clean(self):
        if self.pt:
           self.iface.mapCanvas().scene().removeItem(self.pt)
        if self.Rubberline:
           self.iface.mapCanvas().scene().removeItem(self.Rubberline)
           
        if self.ano: 
           self.ano.remove()
           self.ano = None
        if self.anoLbl: 
           self.anoLbl.remove()
           self.anoLbl = None 
        if self.ax:  
           self.ax.hold(False)
           self.ax.clear()
           self.ax = None
        
        self.figure.clf()
              
        self.canvas.draw()
        self.ui.saveWgt.setEnabled(False)
        self.profile = None
        self.Rubberline = None
        self.ui.mgsLbl.setText("")
Пример #46
0
class QGISRedCreatePipeTool(QgsMapTool):
    def __init__(self, button, iface, projectDirectory, netwName, method):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.ProjectDirectory = projectDirectory
        self.NetworkName = netwName
        self.method = method
        self.setAction(button)

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

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

        self.snapper = None
        self.rubberBand1 = None
        self.rubberBand2 = None
        self.resetProperties()

    def activate(self):
        QgsMapTool.activate(self)

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

    def deactivate(self):
        self.resetProperties()
        QgsMapTool.deactivate(self)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    """Methods"""

    def resetProperties(self):
        # self.toolbarButton.setChecked(False)
        if self.rubberBand1 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand1)
        if self.rubberBand2 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand2)
        self.startMarker.hide()
        self.endMarker.hide()

        self.mousePoints = []
        self.firstClicked = False
        self.objectSnapped = None

        self.rubberBand1 = None
        self.rubberBand2 = None

    def createRubberBand(self, points):
        myPoints1 = []
        for p in points:
            myPoints1.append(QgsPoint(p.x(), p.y()))
        myPoints1.remove(myPoints1[-1])
        if self.rubberBand1 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand1)
        self.rubberBand1 = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand1.setToGeometry(QgsGeometry.fromPolyline(myPoints1),
                                       None)
        self.rubberBand1.setColor(QColor(240, 40, 40))
        self.rubberBand1.setWidth(1)
        self.rubberBand1.setLineStyle(Qt.SolidLine)

        myPoints2 = []
        myPoints2.append(QgsPoint(points[-2].x(), points[-2].y()))
        myPoints2.append(QgsPoint(points[-1].x(), points[-1].y()))
        if self.rubberBand2 is not None:
            self.iface.mapCanvas().scene().removeItem(self.rubberBand2)
        self.rubberBand2 = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand2.setToGeometry(QgsGeometry.fromPolyline(myPoints2),
                                       None)
        self.rubberBand2.setColor(QColor(240, 40, 40))
        self.rubberBand2.setWidth(1)
        self.rubberBand2.setLineStyle(Qt.DashLine)

    """Events"""

    def canvasPressEvent(self, event):
        if event.button() == Qt.LeftButton:
            if not self.firstClicked:
                self.firstClicked = True
                point = self.toMapCoordinates(event.pos())
                if self.objectSnapped is not None:
                    point = self.objectSnapped.point()
                self.mousePoints.append(point)
                self.mousePoints.append(point)
            else:
                self.mousePoints.append(self.mousePoints[-1])
            self.createRubberBand(self.mousePoints)

        if event.button() == Qt.RightButton:
            self.mousePoints.remove(self.mousePoints[-1])
            if self.firstClicked:
                if (len(self.mousePoints) == 2
                        and self.mousePoints[0] == self.mousePoints[1]):
                    createdPipe = False
                elif len(self.mousePoints) < 2:
                    createdPipe = False
                else:
                    createdPipe = True
            if createdPipe:
                self.method(self.mousePoints)
            self.resetProperties()

    def canvasMoveEvent(self, event):
        # Mouse not clicked
        if not self.firstClicked:
            match = self.snapper.snapToMap(self.toMapCoordinates(event.pos()))
            if match.isValid():
                self.objectSnapped = match
                self.startMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.startMarker.show()
            else:
                self.objectSnapped = None
                self.startMarker.hide()
        # Mouse clicked
        else:
            point = self.toMapCoordinates(event.pos())
            match = self.snapper.snapToMap(point)
            if match.isValid():
                self.objectSnapped = match
                self.endMarker.setCenter(
                    QgsPointXY(match.point().x(),
                               match.point().y()))
                self.endMarker.show()
                self.mousePoints[-1] = match.point()
            else:
                self.objectSnapped = None
                self.endMarker.hide()
                self.mousePoints[-1] = point
            self.createRubberBand(self.mousePoints)
Пример #47
0
class ReverseGeocodeTool(QgsMapTool):
    def __init__(self, iface, settings):
        self.canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, self.canvas)
        self.iface = iface
        self.settings = settings
        self.reverseGeoCodeDialog = ReverseGeocodeDialog(
            self, self.iface, self.iface.mainWindow())
        self.iface.addDockWidget(Qt.TopDockWidgetArea,
                                 self.reverseGeoCodeDialog)
        self.reverseGeoCodeDialog.hide()
        self.epsg4326 = QgsCoordinateReferenceSystem('EPSG:4326')
        self.marker = None

        # Set up a polygon/line rubber band
        self.rubber = QgsRubberBand(self.canvas)
        self.rubber.setColor(QColor(255, 70, 0, 200))
        self.rubber.setWidth(5)
        self.rubber.setBrushStyle(Qt.NoBrush)

    def activate(self):
        '''When activated set the cursor to a crosshair.'''
        self.canvas.setCursor(Qt.CrossCursor)
        self.show()

    def unload(self):
        self.iface.removeDockWidget(self.reverseGeoCodeDialog)
        self.reverseGeoCodeDialog = None
        if self.rubber:
            self.canvas.scene().removeItem(self.rubber)
            del self.rubber
        self.removeMarker()

    def addMarker(self, lat, lon):
        if self.marker:
            self.removeMarker()
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(self.epsg4326, canvasCrs,
                                           QgsProject.instance())
        center = transform.transform(lon, lat)
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.setCenter(center)
        self.marker.setColor(QColor(255, 70, 0))
        self.marker.setIconSize(15)
        self.marker.setIconType(QgsVertexMarker.ICON_X)
        self.marker.setPenWidth(3)
        self.marker.show()

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

    def clearSelection(self):
        self.removeMarker()
        self.rubber.reset()

    def transform_geom(self, geometry):
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        geom = QgsGeometry(geometry)
        geom.transform(
            QgsCoordinateTransform(self.epsg4326, canvasCrs,
                                   QgsProject.instance()))
        return geom

    def show(self):
        self.reverseGeoCodeDialog.show()

    def request(self, url):
        fetcher = QgsNetworkContentFetcher()
        fetcher.fetchContent(QUrl(url))
        evloop = QEventLoop()
        fetcher.finished.connect(evloop.quit)
        evloop.exec_(QEventLoop.ExcludeUserInputEvents)
        fetcher.finished.disconnect(evloop.quit)
        return fetcher.contentAsString()

    def canvasReleaseEvent(self, event):
        # Make sure the point is transfored to 4326
        self.clearSelection()
        pt = self.toMapCoordinates(event.pos())
        canvasCRS = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(canvasCRS, self.epsg4326,
                                           QgsProject.instance())
        pt = transform.transform(pt.x(), pt.y())
        url = '{}?format=json&lat={:f}&lon={:f}&zoom={:d}&addressdetails=0&polygon_text=1'.format(
            self.settings.reverseURL(), pt.y(), pt.x(),
            self.settings.levelOfDetail)
        # print( url )
        jsondata = self.request(url)

        try:
            jd = json.loads(jsondata)
            try:
                display_name = jd['display_name']
                self.setText(display_name)
            except KeyError:
                self.setText("[Could not find address]")
            try:
                wkt = jd['geotext']
                geometry = QgsGeometry.fromWkt(wkt)
                if geometry.wkbType() == QgsWkbTypes.Point:
                    pt = geometry.asPoint()
                    lon = pt.x()
                    lat = pt.y()
                    self.addMarker(lat, lon)
                else:
                    geometry = self.transform_geom(geometry)
                    self.rubber.addGeometry(geometry, None)
                    self.rubber.show()
            except KeyError:
                try:
                    lon = float(jd['lon'])
                    lat = float(jd['lat'])
                    self.addMarker(lat, lon)
                except:
                    pass
        except Exception:
            self.setText("Error: " + jsondata)

        if not self.reverseGeoCodeDialog.isVisible():
            self.show()

    def setText(self, text):
        self.reverseGeoCodeDialog.addressLineEdit.setText(text)
Пример #48
0
class mapillary_cursor():

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

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

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

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

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

    def checkForTemplateFields(self, layer):

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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

            self.parentInstance.viewer.addMarkers(markersDef)
Пример #49
0
class ShowOnMapTool(QgsMapToolEmitPoint):
    '''Class to interact with the map canvas to capture the coordinate
    when the mouse button is pressed and to display the coordinate in
    in the status bar.'''
    def __init__(self, iface):
        QgsMapToolEmitPoint.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.canvasClicked.connect(self.clicked)
        self.marker = None
        
    def activate(self):
        '''When activated set the cursor to a crosshair.'''
        self.canvas.setCursor(Qt.CrossCursor)
    
    def deactivate(self):
        self.removeMarker()
    
    def clicked(self, pt, b):
        '''Capture the coordinate when the mouse button has been released,
        format it, and copy it to the clipboard.'''
        if settings.externalMapShowLocation:
            if self.marker is None:
                self.marker = QgsVertexMarker(self.canvas)
                self.marker.setIconSize(18)
                self.marker.setPenWidth(2)
                self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
            self.marker.setCenter(pt)
        else:
            self.removeMarker();
            
        canvasCRS = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(canvasCRS, epsg4326, QgsProject.instance())
        pt4326 = transform.transform(pt.x(), pt.y())
        lat = pt4326.y()
        lon = pt4326.x()
        if settings.googleEarthMapProvider():
            f = tempfile.NamedTemporaryFile(mode='w', suffix=".kml", delete=False)
            f.write('<?xml version="1.0" encoding="UTF-8"?>')
            f.write('<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">')
            f.write('<Document>')
            f.write('   <name>QGIS Location</name>')
            f.write('   <description>{:.8f}, {:.8f}</description>'.format(lon, lat))
            f.write('   <Placemark>')
            f.write('       <name>QGIS Location</name>')
            f.write('       <Point>')
            f.write('           <coordinates>{:.8f},{:.8f},0</coordinates>'.format(lon, lat))
            f.write('       </Point>')
            f.write('   </Placemark>')
            f.write('</Document>')
            f.write('</kml>')
            f.close()
            if platform.system() == 'Windows':
                os.startfile(f.name)
            else:
                webbrowser.open(f.name)
            self.iface.messageBar().pushMessage("", "Viewing Coordinate %f,%f in Google Earth" % (lat, lon), level=Qgis.Info, duration=3)
        else:
            mapprovider = settings.getMapProviderString(lat, lon)
            url = QUrl(mapprovider).toString()
            webbrowser.open(url, new=2)
            self.iface.messageBar().pushMessage("", "Viewing Coordinate %f,%f in external map" % (lat, lon), level=Qgis.Info, duration=3)
    
    def removeMarker(self):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None
Пример #50
0
class DeleteNodeMapTool(ParentMapTool):
    ''' Button 17. User select one node.
    Execute SQL function: 'gw_fct_delete_node' '''

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

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

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

    ''' QgsMapTools inherited event functions '''

    def canvasMoveEvent(self, event):

        # Hide highlight
        self.vertexMarker.hide()

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

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

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

            # Check Arc or Node
            for snapPoint in result:

                if snapPoint.layer.name() == self.layer_node.name():
                    # Get the point
                    point = QgsPoint(result[0].snappedVertex)

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

                    break

    def canvasReleaseEvent(self, event):

        # With left click the digitizing is finished
        if event.button() == Qt.LeftButton:

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

            snappFeat = None

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

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

                # Check Arc or Node
                for snapPoint in result:

                    if snapPoint.layer.name() == self.layer_node.name():
                        # Get the point
                        point = QgsPoint(result[0].snappedVertex)

                        snappFeat = next(
                            result[0].layer.getFeatures(QgsFeatureRequest().setFilterFid(result[0].snappedAtGeometry)))

                        break

            if snappFeat is not None:

                # Get selected features and layer type: 'node'
                feature = snappFeat
                node_id = feature.attribute('node_id')

                # Execute SQL function and show result to the user
                function_name = "gw_fct_delete_node"
                sql = "SELECT " + self.schema_name + "." + function_name + "('" + str(node_id) + "');"
                status = self.controller.execute_sql(sql)
                if status:
                    message = "Node deleted successfully"
                    self.controller.show_warning(message, context_name='ui_message' )  

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

    def activate(self):

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

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

        # Clear snapping
        self.snapperManager.clearSnapping()

        # Set snapping to node
        self.snapperManager.snapToNode()

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

        # Show help message when action is activated
        if self.show_help:
            message = "Select the node inside a pipe by clicking on it and it will be removed"
            self.controller.show_warning(message, context_name='ui_message')
               
        # Control current layer (due to QGIS bug in snapping system)
        try:
            if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer:
                self.canvas.setCurrentLayer(self.layer_node)
        except:
            self.canvas.setCurrentLayer(self.layer_node)

    def deactivate(self):

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

        # Restore previous snapping
        self.snapperManager.recoverSnappingOptions()

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

        # Removehighlight
        self.h = None
class gazetteerSearch:
    def __init__(self, iface):
        self.dock = None
        self.results = []
        # Save reference to the QGIS interface
        self.iface = iface
        self.iface.newProjectCreated.connect(self._hideMarker)
        self.iface.projectRead.connect(self._hideMarker)
        self.canvas = self.iface.mapCanvas()
        self.marker = QgsVertexMarker(self.iface.mapCanvas())
        self.marker.setIconSize(20)
        self.marker.setPenWidth(3)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.marker.hide()

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

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

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

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

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/gazetteersearch/icon.png"), \
            u"Gazetteer Search", self.iface.mainWindow())
        # connect the action to the run method
        self.action.triggered.connect(self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(u"&Gazetteer Search", self.action)

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

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

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

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

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

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

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

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

        common.search(url, callback)

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

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

    def zoomTo(self, name):
        for res in self.results:
            if unicode(res.description) == unicode(name):
                dest_crs = self.canvas.mapRenderer().destinationCrs()
                if QGis.QGIS_VERSION_INT < 10900:
                    src_crs = QgsCoordinateReferenceSystem()
                    src_crs.createFromEpsg(res.epsg)
                else:
                    src_crs = QgsCoordinateReferenceSystem(res.epsg, QgsCoordinateReferenceSystem.EpsgCrsId)
                transform = QgsCoordinateTransform(src_crs, dest_crs)
                new_point = transform.transform(res.x, res.y)
                x = new_point.x()
                y = new_point.y()
                self.canvas.setExtent(QgsRectangle(x,y,x,y))
                self.canvas.zoomScale(res.zoom)
                self.canvas.refresh()
                self.marker.setCenter(new_point)
                self.marker.show()
                return
Пример #52
0
class rmVertexTool(QgsMapTool):
    def __init__(self, canvas, layer, iface, action):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.layer = layer
        self.iface = iface
        self.action = action
        self.rb = None
        self.vx = None
        self.threshold = float(QSettings().value('ale/threshold'))

    def canvasPressEvent(self, event):
        pass

    def canvasMoveEvent(self, event):
        if self.rb:
            self.canvas.scene().removeItem(self.rb)
        if self.vx:
            self.canvas.scene().removeItem(self.vx)
        layerPoint = self.toLayerCoordinates(self.layer, event.pos())
        (closestPointID,
         closestFeature) = finder.closestpoint(self.layer, layerPoint)
        polyline = closestFeature.geometry().asPolyline()
        shortestDistance = QgsGeometry.fromPointXY(
            polyline[closestPointID]).distance(
                QgsGeometry.fromPointXY(layerPoint))

        if closestPointID and shortestDistance < self.threshold:
            self.rb = QgsRubberBand(self.canvas, False)
            linePart = polyline[closestPointID - 1:closestPointID + 2]
            self.rb.setToGeometry(QgsGeometry.fromPolylineXY(linePart), None)
            self.rb.setColor(QColor(0, 0, 255))
            self.rb.setWidth(3)
            self.vx = QgsVertexMarker(self.canvas)
            self.vx.setCenter(QgsPointXY(polyline[closestPointID]))
            self.vx.setColor(QColor(0, 255, 0))
            self.vx.setIconSize(5)
            self.vx.setIconType(
                QgsVertexMarker.ICON_X)  # or ICON_CROSS, ICON_BOX
            self.vx.setPenWidth(3)

    def canvasReleaseEvent(self, event):
        layerPoint = self.toLayerCoordinates(self.layer, event.pos())
        (closestPointID,
         closestFeature) = finder.closestpoint(self.layer, layerPoint)
        polyline = closestFeature.geometry().asPolyline()
        shortestDistance = QgsGeometry.fromPointXY(
            polyline[closestPointID]).distance(
                QgsGeometry.fromPointXY(layerPoint))
        if closestPointID and shortestDistance < self.threshold:
            ftNew = QgsFeature()
            ptsNew = polyline[closestPointID + 1:]
            if len(ptsNew) > 1:  # can be a linestring
                plNew = QgsGeometry.fromPolylineXY(ptsNew)
                ftNew.setGeometry(plNew)
                pr = self.layer.dataProvider()
                pr.addFeatures([ftNew])
            ptsOld = polyline[:closestPointID]
            if len(ptsOld) > 1:  # can be a linestring
                plOld = QgsGeometry.fromPolylineXY(ptsOld)
                self.layer.changeGeometry(closestFeature.id(), plOld)
            else:
                self.layer.deleteFeature(closestFeature.id())

        if self.rb:
            self.canvas.scene().removeItem(self.rb)
        if self.vx:
            self.canvas.scene().removeItem(self.vx)
        self.iface.mapCanvas().refresh()

    def activate(self):
        self.action.setChecked(True)

    def deactivate(self):
        if self.rb:
            self.canvas.scene().removeItem(self.rb)
        if self.vx:
            self.canvas.scene().removeItem(self.vx)
        self.action.setChecked(False)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True
Пример #53
0
class gazetteerSearch:
    def __init__(self, iface):
        self.dock = None
        self.results = []
        # Save reference to the QGIS interface
        self.iface = iface
        self.iface.newProjectCreated.connect(self._hideMarker)
        self.iface.projectRead.connect(self._hideMarker)
        self.canvas = self.iface.mapCanvas()
        self.marker = QgsVertexMarker(self.iface.mapCanvas())
        self.marker.setIconSize(20)
        self.marker.setPenWidth(3)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.marker.hide()

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

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

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

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

    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/gazetteersearch/icon.png"), \
            u"Gazetteer Search", self.iface.mainWindow())
        # connect the action to the run method
        self.action.triggered.connect(self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(u"&Gazetteer Search", self.action)

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

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

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

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

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

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

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

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

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

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

    def zoomTo(self, name):
        for res in self.results:
            if unicode(res.description) == unicode(name):
                dest_crs = self.canvas.mapRenderer().destinationCrs()
                src_crs = QgsCoordinateReferenceSystem()
                src_crs.createFromEpsg(res.epsg)
                transform = QgsCoordinateTransform(src_crs, dest_crs)
                new_point = transform.transform(res.x, res.y)
                x = new_point.x()
                y = new_point.y()
                self.canvas.setExtent(QgsRectangle(x, y, x, y))
                self.canvas.zoomScale(res.zoom)
                self.canvas.refresh()
                self.marker.setCenter(new_point)
                self.marker.show()
                return
Пример #54
0
class W3WCoordInputDialog(QDockWidget):
    def __init__(self, canvas, parent):
        self.canvas = canvas
        self.marker = None
        QDockWidget.__init__(self, parent)
        self.setAllowedAreas(Qt.TopDockWidgetArea)
        self.initGui()

    def setApiKey(self, apikey):
        self.w3w = what3words(apikey=apikey)

    def initGui(self):
        self.setWindowTitle("Zoom to 3 word address")
        self.label = QLabel('3 Word Address')
        self.coordBox = QLineEdit()
        self.coordBox.returnPressed.connect(self.zoomToPressed)
        self.zoomToButton = QPushButton("Zoom to")
        self.zoomToButton.clicked.connect(self.zoomToPressed)
        self.removeMarkerButton = QPushButton("Remove marker")
        self.removeMarkerButton.clicked.connect(self.removeMarker)
        self.removeMarkerButton.setDisabled(True)
        self.hlayout = QHBoxLayout()
        self.hlayout.setSpacing(6)
        self.hlayout.setMargin(9)
        self.hlayout.addWidget(self.label)
        self.hlayout.addWidget(self.coordBox)
        self.hlayout.addWidget(self.zoomToButton)
        self.hlayout.addWidget(self.removeMarkerButton)
        self.dockWidgetContents = QWidget()
        self.dockWidgetContents.setLayout(self.hlayout)
        self.setWidget(self.dockWidgetContents)

    def zoomToPressed(self):
        try:
            w3wCoord = str(self.coordBox.text()).replace(" ", "")
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            json = self.w3w.forwardGeocode(w3wCoord)
            lat = float(json["geometry"]["lat"])
            lon = float(json["geometry"]["lng"])
            canvasCrs = self.canvas.mapSettings().destinationCrs()
            epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326")
            transform4326 = QgsCoordinateTransform(epsg4326, canvasCrs, QgsProject.instance())
            center = transform4326.transform(lon, lat)
            self.canvas.zoomByFactor(1, center)
            self.canvas.refresh()
            if self.marker is None:
                self.marker = QgsVertexMarker(self.canvas)
            self.marker.setCenter(center)
            self.marker.setIconSize(8)
            self.marker.setPenWidth(4)
            self.removeMarkerButton.setDisabled(False)
            self.coordBox.setStyleSheet("QLineEdit{background: white}")
        except Exception as e:
            raise
            self.coordBox.setStyleSheet("QLineEdit{background: yellow}")
        finally:
            QApplication.restoreOverrideCursor()

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

    def closeEvent(self, evt):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None
Пример #55
0
class MultipleSnapping(QgsMapTool):

    canvasClicked = pyqtSignal()

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

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

        self.controller = controller
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Polygon)
        mFillColor = QColor(254, 178, 76, 63)
        self.rubber_band.setColor(mFillColor)
        self.rubber_band.setWidth(1)
        self.reset()
        self.snapper = QgsMapCanvasSnapper(self.canvas)
        self.selected_features = []

        # Vertex marker
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setColor(QColor(255, 0, 255))
        self.vertex_marker.setIconSize(11)
        self.vertex_marker.setIconType(
            QgsVertexMarker.ICON_CROSS)  # or ICON_CROSS, ICON_X, ICON_BOX
        self.vertex_marker.setPenWidth(3)

    def reset(self):
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):

        if e.button() == Qt.LeftButton:
            self.start_point = self.toMapCoordinates(e.pos())
            self.end_point = self.start_point
            self.is_emitting_point = True
            self.show_rect(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):

        self.is_emitting_point = False
        r = self.rectangle()

        # Use CTRL button to unselect features
        key = QApplication.keyboardModifiers()

        number_features = 0
        if e.button() == Qt.LeftButton:
            for layer in self.group_pointers:
                # Check number of selections
                #number_features = layer.selectedFeatureCount()
                if r is not None:
                    # Selection by rectange
                    lRect = self.canvas.mapSettings().mapToLayerCoordinates(
                        layer, r)
                    layer.select(lRect,
                                 True)  # True for leave previous selection
                    # if CTRL pressed : unselect features
                    if key == Qt.ControlModifier:
                        layer.selectByRect(lRect, layer.RemoveFromSelection)
                else:
                    # Selection one by one
                    x = e.pos().x()
                    y = e.pos().y()
                    eventPoint = QPoint(x, y)
                    (retval,
                     result) = self.snapper.snapToBackgroundLayers(eventPoint)
                    if result:
                        # Check feature
                        for snap_point in result:
                            # Get the point
                            #point = QgsPoint(snap_point.snappedVertex)
                            snapp_feat = next(
                                snap_point.layer.getFeatures(
                                    QgsFeatureRequest().setFilterFid(
                                        snap_point.snappedAtGeometry)))
                            # LEAVE SELECTION
                            snap_point.layer.select(
                                [snap_point.snappedAtGeometry])

            self.rubber_band.hide()

    def canvasMoveEvent(self, e):

        if not self.is_emitting_point:
            return
        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rect(self.start_point, self.end_point)

    def show_rect(self, start_point, end_point):

        self.rubber_band.reset(QGis.Polygon)
        if start_point.x() == end_point.x() or start_point.y() == end_point.y(
        ):
            return
        point1 = QgsPoint(start_point.x(), start_point.y())
        point2 = QgsPoint(start_point.x(), end_point.y())
        point3 = QgsPoint(end_point.x(), end_point.y())
        point4 = QgsPoint(end_point.x(), start_point.y())

        self.rubber_band.addPoint(point1, False)
        self.rubber_band.addPoint(point2, False)
        self.rubber_band.addPoint(point3, False)
        self.rubber_band.addPoint(point4, True)  # true to update canvas
        self.rubber_band.show()

    def rectangle(self):

        if self.start_point is None or self.end_point is None:
            return None
        elif self.start_point.x() == self.end_point.x() or self.start_point.y(
        ) == self.end_point.y():
            return None

        return QgsRectangle(self.start_point, self.end_point)

    def deactivate(self):
        self.rubber_band.hide()
        QgsMapTool.deactivate(self)

    def activate(self):

        self.group_layers = ["Wjoin", "Fountain", "Greentap", "Tap"]
        self.group_pointers = []
        for layer_name in self.group_layers:
            layer = QgsMapLayerRegistry.instance().mapLayersByName(layer_name)
            if layer:
                layer = layer[0]
                self.group_pointers.append(layer)

        # Set active layer
        self.layer_connec = None
        self.layer_connec = QgsMapLayerRegistry.instance().mapLayersByName(
            "Edit connec")[0]
        self.iface.setActiveLayer(self.layer_connec)

        self.canvas.connect(self.canvas,
                            SIGNAL("xyCoordinates(const QgsPoint&)"),
                            self.mouse_move)

    def mouse_move(self, p):

        map_point = self.canvas.getCoordinateTransform().transform(p)
        x = map_point.x()
        y = map_point.y()
        event_point = QPoint(x, y)

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

        # That's the snapped point
        if result:
            # Check feature
            for snapPoint in result:
                #self.controller.log_info(str(snapPoint))
                if snapPoint.layer.name() == 'Edit connec':
                    point = QgsPoint(snapPoint.snappedVertex)
                    # Add marker
                    self.vertex_marker.setCenter(point)
                    self.vertex_marker.show()
        else:
            self.vertex_marker.hide()
class PdokServicesPlugin(object):

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # docked or dialog, defaults to dialog
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant):
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False))
        # else:
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        #
        # # Create the dialog and keep reference
        # if "True" == self.docked or "true" == self.docked or True is self.docked:
        #     self.dlg = PdokServicesPluginDockWidget()
        #     self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        # else:
        #     self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())

        self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + "/python/plugins/pdokservicesplugin"
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None

    def getSettingsValue(self, key, default=''):
        if QSettings().contains(self.SETTINGS_SECTION + key):
            key = self.SETTINGS_SECTION + key
            if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8
                return str(QSettings().value(key).toString())
            else:
                return str(QSettings().value(key))
        else:
            return default

    def setSettingsValue(self, key, value):
        key = self.SETTINGS_SECTION + key
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue(key, QVariant(value))
        else:
            QSettings().setValue(key, value)

    def initGui(self):
        # Create action that will start plugin configuration
        runIcon = QIcon(os.path.join(self.plugin_dir, 'icon_add_service.svg'))
        self.run_action = QAction(runIcon, \
            "PDOK Services plugin", self.iface.mainWindow())

        self.servicesLoaded = False
        # connect the action to the run method
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if "True" == self.docked or "true" == self.docked or  True == self.docked:
        #     self.run_action.triggered.connect(self.showAndRaise)
        #     self.dlg.radioDocked.setChecked(True)
        #     # docked the dialog is immidiately visible, so should run NOW
        # else:
        #     self.run_action.triggered.connect(self.run)
        #     self.dlg.radioDocked.setChecked(False)
        #     self.setupfq()
        self.run_action.triggered.connect(self.run)
        #self.dlg.radioDocked.setChecked(False)
        self.setupfq()

        # Add toolbar button and menu item
        #self.iface.addToolBarIcon(self.action)

        self.toolbar = self.iface.addToolBar("PDOK services plugin")
        self.toolbar.setObjectName("PDOK services plugin")
        self.toolbar.addAction(self.run_action)
        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar)
        # address/point cleanup
        eraserIcon = QIcon(os.path.join(self.plugin_dir, 'icon_remove_cross.svg'))
        self.clean_action = QAction(eraserIcon, \
            "Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)
        self.clean_action.setEnabled(False)

        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/icon_help.png"), \
                            "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("Pdok Services Plugin About")
        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction)

        self.aboutAction.triggered.connect(self.about)
        self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService)

        self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress)

        self.dlg.geocoderSearch.textEdited.connect(self.searchAddress)
        self.dlg.geocoderSearch.setPlaceholderText("PDOK Locatieserver zoek, bv postcode of postcode huisnummer")

        self.dlg.geocoderResultSearch.textChanged.connect(self.filterGeocoderResult)
        self.dlg.geocoderResultSearch.setPlaceholderText("een of meer zoekwoorden uit resultaat")

        #self.dlg.radioDocked.toggled.connect(self.set_docked)

        self.dlg.btnCheckPdokJson.clicked.connect(self.checkPdokJson)
        #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged)

        ui = self.dlg.ui
        cbxs = [ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp]
        # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search
        for cbx in cbxs:
            cbx.stateChanged.connect(self.searchAddress)

        self.run(True)

    # for now hiding the pointer as soon as the extent changes
    #def extentsChanged(self):
    #    self.removePointer()

    def checkPdokJson(self):
        myversion = self.getSettingsValue('pdokversion', '1')
        msgtxt = ''
        msglvl = 0  # QgsMessageBar.INFO
        try:
            response = urllib.request.urlopen('http://www.qgis.nl/pdok.version')
            str_response = response.read().decode('utf-8')
            pdokversion = json.loads(str_response)
            if pdokversion > int(myversion):
                response = urllib.request.urlopen('http://www.qgis.nl/pdok.json')
                str_response = response.read().decode('utf-8')
                pdokjson = json.loads(str_response)
                with open(self.plugin_dir +'/pdok.json', 'w') as outfile:
                    json.dump(pdokjson, outfile)
                msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \
                    str(pdokversion) + ' (was ' + myversion +')'
                self.servicesLoaded = False # reset reading of json
                self.run()
                self.setSettingsValue('pdokversion', pdokversion)
            else:
                msgtxt = "Geen nieuwere versie beschikbaar dan " + str(pdokversion)
        except Exception as e:
            #print e
            msgtxt = "Fout bij ophalen van service info. Netwerk probleem?"
            msglvl = 2 # QgsMessageBar.CRITICAL
        # msg
        if hasattr(self.iface, 'messageBar'):
            self.iface.messageBar().pushMessage("PDOK services update", msgtxt, level=msglvl, duration=10)
        else: # 1.8
            QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin", msgtxt)

    # def set_docked(self, foo):
    #     self.setSettingsValue('docked', self.dlg.radioDocked.isChecked())
    #     #if Qgis.QGIS_VERSION_INT < 10900:
    #     #    # qgis <= 1.8
    #     #    QSettings().setValue("/pdokservicesplugin/docked", QVariant(self.dlg.radioDocked.isChecked()))
    #     #else:
    #     #    QSettings().setValue("/pdokservicesplugin/docked", self.dlg.radioDocked.isChecked())

    def showAndRaise(self):
        self.dlg.show()
        self.dlg.raise_()
        # also remove the pointer
        self.removePointer()

    def about(self):
        infoString =  "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - Zuidt - http://www.zuidt.nl\n"
        infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin"
        QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin About", infoString)

    def unload(self):
        self.removePointer()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu("&Pdok Services Plugin", self.run_action)
        self.iface.removePluginMenu("&Pdok Services Plugin", self.aboutAction)
        del self.toolbarSearch
        del self.run_action
        del self.aboutAction

    def showService(self, selectedIndexes):
        if len(selectedIndexes)==0:
            self.currentLayer = None
            self.dlg.ui.layerInfo.setHtml('')
            self.dlg.ui.comboSelectProj.clear()
            return
        # needed to scroll To the selected row incase of using the keyboard / arrows
        self.dlg.servicesView.scrollTo(self.dlg.servicesView.selectedIndexes()[0])
        # itemType holds the data (== column 1)
        self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data(Qt.UserRole)
        if isinstance(self.currentLayer, QVariant):
            self.currentLayer = self.currentLayer.toMap()
            # QGIS 1.8: QVariants
            currentLayer = {}
            for key in list(self.currentLayer.keys()):
                val = self.currentLayer[key]
                currentLayer[str(key)]=str(val.toString())
            self.currentLayer = currentLayer
        url = self.currentLayer['url']
        title = self.currentLayer['title']
        style = ''
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        servicetitle = self.currentLayer['servicetitle']
        layername = self.currentLayer['layers']
        abstract = self.currentLayer['abstract']
        stype = self.currentLayer['type'].upper()
        minscale =''
        if 'minscale' in self.currentLayer and self.currentLayer['minscale'] != None and self.currentLayer['minscale'] != '':
            minscale = "min. schaal 1:"+self.currentLayer['minscale']
        maxscale = ''
        if 'maxscale' in self.currentLayer and self.currentLayer['maxscale'] != None and self.currentLayer['maxscale'] != '':
            maxscale = "max. schaal 1:"+self.currentLayer['maxscale']
        self.dlg.ui.layerInfo.setText('')
        self.dlg.ui.btnLoadLayer.setEnabled(True)
        self.dlg.ui.layerInfo.setHtml('<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li>&nbsp;</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>' % (servicetitle, title, abstract, stype, url, layername, style, minscale, maxscale))
        self.dlg.ui.comboSelectProj.clear()
        if stype=="WMS":
            try:
                crs = self.currentLayer['crs']
            except KeyError:
                crs = 'EPSG:28992'
            crs = crs.split(',')
            self.dlg.ui.comboSelectProj.addItems(crs)
            for i in range(len(crs)):
                if crs[i] == 'EPSG:28992':
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)
        if stype=="WMTS":
            tilematrixsets = self.currentLayer['tilematrixsets'].split(',')
            self.dlg.ui.comboSelectProj.addItems(tilematrixsets)
            for i in range(len(tilematrixsets)):
                if tilematrixsets[i].startswith('EPSG:28992'):
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)

    def loadService(self):
        if self.currentLayer == None:
            return
        servicetype = self.currentLayer['type']
        url = self.currentLayer['url']
        # some services have an url with query parameters in it, we have to urlencode those:
        location,query = urllib.parse.splitquery(url)
        url = location
        # RD: 20200820: lijkt of het quoten van de query problemen geeft bij WFS, is/was dit nodig???
        #if query != None and query != '':
        #    url +=('?'+urllib.parse.quote_plus(query))
        title = self.currentLayer['title']
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        else:
            style = '' # == default for this service
        layers = self.currentLayer['layers']
        # mmm, tricky: we take the first one while we can actually want png/gif or jpeg
        if servicetype == "wms":
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                crs = 'EPSG:28992'
            else:
                crs = self.dlg.ui.comboSelectProj.currentText()
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                uri = url
                self.iface.addRasterLayer(
                    uri, # service uri
                    title, # name for layer (as seen in QGIS)
                    "wms", # dataprovider key
                    [layers], # array of layername(s) for provider (id's)
                    [""], # array of stylename(s)  NOTE: ignoring styles here!!!
                    imgformat, # image format searchstring
                    crs) # crs code searchstring
            else:
                # qgis > 1.8
                uri = "crs="+crs+"&layers="+layers+"&styles="+style+"&format="+imgformat+"&url="+url;
                self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wmts":
            if Qgis.QGIS_VERSION_INT < 10900:
                QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
                return
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                tilematrixset = 'EPSG:28992'
            else:
                tilematrixset = self.dlg.ui.comboSelectProj.currentText()
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            # special case for luchtfoto
            #if layers=="luchtfoto":
            #    # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml
            #    # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'}
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url
            #else:
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url;
            #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            if tilematrixset.startswith('EPSG:'):
                crs=tilematrixset
                i = crs.find(':', 5)
                if i > -1:
                    crs=crs[:i]
            elif tilematrixset.startswith('OGC:1.0'):
                crs='EPSG:3857'
            uri = "tileMatrixSet="+tilematrixset+"&crs="+crs+"&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            #print "############ PDOK URI #################"
            #print uri
            self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wfs":
            location, query = urllib.parse.splitquery(url)
            #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992"
            #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992"
            # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time
            # QGIS will update the BBOX to the right value
            #uri += "&BBOX=-10000,310000,290000,650000"
            uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='"+layers+"' url='"+url+"' version='2.0.0' "
            self.iface.addVectorLayer(uri, title, "WFS")
        elif servicetype == "wcs":
            # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            uri = ''
            # cache=AlwaysCache
            # cache=PreferNetwork
            # cache=AlwaysNetwork
            # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url
            # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32
            format = 'GEOTIFF_FLOAT32'
            # working for ahn25m is only image/tiff
            if layers=='ahn25m':
                format = 'image/tiff'
            # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32):
            if 'imgformats' in self.currentLayer:
                format = self.currentLayer['imgformats'].split(',')[0]
            uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&identifier=" + layers + "&url=" + url
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&version=1.1.2&identifier=" + layers + "&url=" + url
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url
            self.iface.addRasterLayer(uri, title, "wcs")
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
            return

    def filterGeocoderResult(self, string):
        #print "filtering geocoder results: %s" % string
        self.dlg.geocoderResultView.selectRow(0)
        self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.geocoderProxyModel.setFilterFixedString(string)

    def searchAddressFromToolbar(self):
        self.removePointer()
        self.geocoderSourceModel.clear()
        self.geocode()

    def searchAddress(self):
        self.removePointer()
        #print "search geocoder for: %s" % self.dlg.geocoderSearch.text()
        self.geocoderSourceModel.clear()
        #self.geocode(self.dlg.geocoderSearch.text())
        self.suggest()


    def eraseAddress(self):
        """
        clean the input and remove the pointer
        """
        self.removePointer()
        if self.geocoderSourceModel is not None:
            self.geocoderSourceModel.clear()
        if self.dlg.geocoderSearch is not None:
            self.dlg.geocoderSearch.clear()
        if self.toolbarSearch is not None:
            self.toolbarSearch.clear()

    def filterLayers(self, string):
        # remove selection if one row is selected
        self.dlg.servicesView.selectRow(0)
        #self.currentLayer = None
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setFilterFixedString(string)

    #def addSourceRow(self, service, layer):
    def addSourceRow(self, serviceLayer):
        # you can attache different "data's" to to an QStandarditem
        # default one is the visible one:
        itemType = QStandardItem("%s" % (serviceLayer["type"].upper()) )
        # userrole is a free form one:
        # only attach the data to the first item
        # service layer = a dict/object with all props of the layer
        itemType.setData( serviceLayer, Qt.UserRole )
        itemType.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        # only wms services have styles (sometimes)
        layername = serviceLayer["title"]
        if 'style' in serviceLayer:
            itemLayername = QStandardItem("%s [%s]" % (serviceLayer["title"], serviceLayer["style"]) )
            layername = "%s [%s]" % (serviceLayer["title"], serviceLayer["style"])
        else:
            itemLayername = QStandardItem("%s" % (serviceLayer["title"]))
        itemLayername.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["servicetitle"] ))
        # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here
        itemFilter = QStandardItem("%s %s %s %s" % (serviceLayer["type"], layername, serviceLayer["servicetitle"], serviceLayer["abstract"]) )
        itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"]))
        itemServicetitle.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        self.sourceModel.appendRow( [ itemLayername, itemType, itemServicetitle, itemFilter ] )

    # run method that performs all the real work
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value("/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".", "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            #
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText("woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel().selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True;

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab", QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab", self.dlg.tabs.currentIndex())
        self.removePointer()

    def setupfq(self):
        """
        Setup the fq checkboxes in the gui, by looking into the settings for the
        'pdokservicesplugin/checkedfqs' key, which contains a list of type strings
        like ['weg','adres']
        """
        checked_fqs = self.getSettingsValue('checkedfqs', [])
        #self.info('setup fq: {}'.format(checked_fqs))
        if len(checked_fqs) > 0:  # else there is not saved state... take gui defaults
            self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs)
            self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs)
            self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs)
            self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs)
            self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs)
            self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs)
            self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs)

    def createfq(self):
        """
        This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver)
        Based on the checkboxes in the dialog.
        Defaults to ''
        Example: 'fq=+type:adres+type:gemeente'  (only gemeente AND addresses)
        :return:
        """
        fqlist = []
        if self.dlg.ui.cbx_gem.isChecked():
            fqlist.append('gemeente')
        if self.dlg.ui.cbx_wpl.isChecked():
            fqlist.append('woonplaats')
        if self.dlg.ui.cbx_weg.isChecked():
            fqlist.append('weg')
        if self.dlg.ui.cbx_pcd.isChecked():
            fqlist.append('postcode')
        if self.dlg.ui.cbx_adr.isChecked():
            fqlist.append('adres')
        if self.dlg.ui.cbx_pcl.isChecked():
            fqlist.append('perceel')
        if self.dlg.ui.cbx_hmp.isChecked():
            fqlist.append('hectometerpaal')
        self.setSettingsValue('checkedfqs', fqlist)
        #self.info(self.getSettingsValue('checkedfqs', ['leeg?']))
        fq = ''
        if len(fqlist) > 0:
            fq = '&fq=+type:' + '+type:'.join(fqlist)
        return fq

    def suggest(self):
        self.dlg.ui.lookupinfo.setHtml('')
        search_text = self.dlg.geocoderSearch.text()
        if len(search_text) <= 1:
            # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
            #     "meer input aub: {}".format(search_text)
            #     ), QMessageBox.Ok, QMessageBox.Ok)
            return
        # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
        #     "zoeken: {}".format(search_text)
        # ), QMessageBox.Ok, QMessageBox.Ok)
        results = self.pdokgeocoder.suggest(search_text, self.createfq())
        if len(results) == 0:
            # ignore, as we are suggesting, maybe more characters will reveal something...
            return
        for result in results:
            #print address
            adrestekst = QStandardItem("%s" % (result["adrestekst"]))
            adrestekst.setData(result, Qt.UserRole)
            type = QStandardItem("%s" % (result["type"]))
            id = QStandardItem("%s" % (result["id"]))
            score = QStandardItem("%s" % (result["score"]))
            adrestekst.setData(result, Qt.UserRole)
            self.geocoderSourceModel.appendRow([adrestekst, type])
        self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
        self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        self.dlg.geocoderResultView.resizeColumnsToContents()
        self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def geocode(self):
        self.dlg.geocoderSearch.setText(self.toolbarSearch.text())
        self.suggest()
        if self.dlg.geocoderResultView.model().rowCount()>0:
            self.dlg.geocoderResultView.selectRow(0)
            self.zoomToAddress()
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
                "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog."
                ), QMessageBox.Ok, QMessageBox.Ok)

    # def geocode(self):
    #     self.dlg.ui.lookupinfo.setHtml('')
    #     search_text = self.toolbarSearch.text()
    #     addresses = self.pdokgeocoder.search(search_text)
    #     if len(addresses) == 0:
    #         QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
    #             "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer."
    #             ), QMessageBox.Ok, QMessageBox.Ok)
    #         return
    #     for address in addresses:
    #         #print address
    #         adrestekst = QStandardItem("%s" % (address["adrestekst"]))
    #         adrestekst.setData(address, Qt.UserRole)
    #         straat = QStandardItem("%s" % (address["straat"]))
    #         nummer = QStandardItem("%s" % (address["nummer"]))
    #         postcode = QStandardItem("%s" % (address["postcode"]))
    #         plaats = QStandardItem("%s" % (address["plaats"]))
    #         gemeente = QStandardItem("%s" % (address["gemeente"]))
    #         provincie = QStandardItem("%s" % (address["provincie"]))
    #         self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie])
    #
    #     self.dlg.geocoderResultView.selectRow(0)
    #     self.zoomToAddress()
    #
    #     self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
    #     self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat")
    #     self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr")
    #     self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode")
    #     self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats")
    #     self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente")
    #     self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie")
    #
    #     self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft)
    #
    #     self.dlg.geocoderResultView.resizeColumnsToContents()
    #     self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def zoomToAddress(self):
        # get x,y from data of record
        self.removePointer()

        data = self.dlg.geocoderResultView.selectedIndexes()[0].data(Qt.UserRole)

        if 'centroide_rd' in data: # free OR lookup service
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
        else:
            # no centroid yet, probably only object id, retrieve it via lookup service
            id = data['id']
            data = self.pdokgeocoder.lookup(id)
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
            lookup_data= data['data']
            lis = ''
            for key in lookup_data.keys():
                lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key])
            self.dlg.ui.lookupinfo.setHtml(
                '<h4>{}</h4><lu>{}</lu>'.format(adrestekst, lis))

        # just always transform from 28992 to mapcanvas crs
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        crs28992 = QgsCoordinateReferenceSystem()
        crs28992.createFromId(28992)
        crsTransform = QgsCoordinateTransform(crs28992, crs, QgsProject.instance())
        z = 1587
        if adrestekst.lower().startswith('adres'):
            z = 794
        elif adrestekst.lower().startswith('perceel'):
            z = 794
        elif adrestekst.lower().startswith('hectometer'):
            z = 1587
        elif adrestekst.lower().startswith('straat'):
            z = 3175
        elif adrestekst.lower().startswith('postcode'):
            z = 6350
        elif adrestekst.lower().startswith('woonplaats'):
            z = 25398
        elif adrestekst.lower().startswith('gemeente'):
            z = 50797
        elif adrestekst.lower().startswith('provincie'):
            z = 812750
        geom.transform(crsTransform)
        center = geom.asPoint()
        self.setPointer(center)
        # zoom to with center is actually setting a point rectangle and then zoom
        rect = QgsRectangle(center, center)
        self.iface.mapCanvas().setExtent(rect)
        self.iface.mapCanvas().zoomScale(z)
        self.iface.mapCanvas().refresh()

    def setPointer(self, point):
        self.removePointer()
        self.pointer = QgsVertexMarker(self.iface.mapCanvas())
        self.pointer.setColor(QColor(255, 255, 0))
        self.pointer.setIconSize(10)
        self.pointer.setPenWidth(5)
        self.pointer.setCenter(point)
        self.clean_action.setEnabled(True)

    def removePointer(self):
        if self.pointer is not None and self.pointer.scene() is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)
            self.pointer = None
            self.clean_action.setEnabled(False)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin', Qgis.Info)
class CopyLatLonTool(QgsMapToolEmitPoint):
    '''Class to interact with the map canvas to capture the coordinate
    when the mouse button is pressed and to display the coordinate in
    in the status bar.'''
    capturesig = pyqtSignal(QgsPointXY)

    def __init__(self, settings, iface):
        QgsMapToolEmitPoint.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.settings = settings
        self.capture4326 = False
        self.canvasClicked.connect(self.clicked)
        self.marker = None

    def activate(self):
        '''When activated set the cursor to a crosshair.'''
        self.canvas.setCursor(Qt.CrossCursor)

    def deactivate(self):
        self.removeMarker()

    def formatCoord(self, pt, delimiter):
        '''Format the coordinate string according to the settings from
        the settings dialog.'''
        if self.settings.captureProjIsWgs84():  # ProjectionTypeWgs84
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            lat = pt4326.y()
            lon = pt4326.x()
            if self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDMS:  # DMS
                msg = formatDmsString(lat, lon, True,
                                      self.settings.dmsPrecision,
                                      self.settings.coordOrder, delimiter)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDDMMSS:  # DDMMSS
                msg = formatDmsString(lat, lon, False,
                                      self.settings.dmsPrecision,
                                      self.settings.coordOrder, delimiter)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeWKT:  # WKT
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt4326.x(), pt4326.y(), prec=self.settings.decimalDigits)
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeGeoJSON:  # GeoJSON
                msg = '{{"type": "Point","coordinates": [{:.{prec}f},{:.{prec}f}]}}'.format(
                    pt4326.x(), pt4326.y(), prec=self.settings.decimalDigits)
            else:  # decimal degrees
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt4326.y(),
                        delimiter,
                        pt4326.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt4326.x(),
                        delimiter,
                        pt4326.y(),
                        prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsProjectCRS():
            # Projection in the project CRS
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.y(),
                        delimiter,
                        pt.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.x(),
                        delimiter,
                        pt.y(),
                        prec=self.settings.decimalDigits)
            else:
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt.x(), pt.y(), prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsCustomCRS():
            # Projection is a custom CRS
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            customCRS = self.settings.captureCustomCRS()
            transform = QgsCoordinateTransform(canvasCRS, customCRS,
                                               QgsProject.instance())
            pt = transform.transform(pt.x(), pt.y())
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.y(),
                        delimiter,
                        pt.x(),
                        prec=self.settings.decimalDigits)
                else:
                    msg = '{:.{prec}f}{}{:.{prec}f}'.format(
                        pt.x(),
                        delimiter,
                        pt.y(),
                        prec=self.settings.decimalDigits)
            else:
                msg = 'POINT({:.{prec}f} {:.{prec}f})'.format(
                    pt.x(), pt.y(), prec=self.settings.decimalDigits)
        elif self.settings.captureProjIsMGRS():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            try:
                msg = mgrs.toMgrs(pt4326.y(), pt4326.x())
            except:
                msg = None
        elif self.settings.captureProjIsPlusCodes():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            try:
                msg = olc.encode(pt4326.y(), pt4326.x(),
                                 self.settings.plusCodesLength)
            except:
                msg = None
        elif self.settings.captureProjIsUTM():
            # Make sure the coordinate is transformed to EPSG:4326
            canvasCRS = self.canvas.mapSettings().destinationCrs()
            if canvasCRS == epsg4326:
                pt4326 = pt
            else:
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
            msg = latLon2UtmString(pt4326.y(), pt4326.x(),
                                   self.settings.dmsPrecision)
            if msg == '':
                msg = None

        msg = '{}{}{}'.format(self.settings.capturePrefix, msg,
                              self.settings.captureSuffix)
        return msg

    def canvasMoveEvent(self, event):
        '''Capture the coordinate as the user moves the mouse over
        the canvas. Show it in the status bar.'''
        try:
            pt = self.toMapCoordinates(event.pos())
            msg = self.formatCoord(pt, ', ')
            formatString = self.coordFormatString()
            if msg == None:
                self.iface.statusBarIface().showMessage("")
            else:
                self.iface.statusBarIface().showMessage(
                    "{} - {}".format(msg, formatString), 4000)
        except:
            self.iface.statusBarIface().showMessage("")

    def coordFormatString(self):
        if self.settings.captureProjIsWgs84():
            if self.settings.wgs84NumberFormat == self.settings.Wgs84TypeDecimal:
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = 'Lat Lon'
                else:
                    s = 'Lon Lat'
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeWKT:
                s = 'WKT'
            elif self.settings.wgs84NumberFormat == self.settings.Wgs84TypeGeoJSON:
                s = 'GeoJSON'
            else:
                s = 'DMS'
        elif self.settings.captureProjIsProjectCRS():
            crsID = self.canvas.mapSettings().destinationCrs().authid()
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = '{} - Y,X'.format(crsID)
                else:
                    s = '{} - X,Y'.format(crsID)
            else:  # WKT
                s = 'WKT'
        elif self.settings.captureProjIsMGRS():
            s = 'MGRS'
        elif self.settings.captureProjIsUTM():
            s = 'Standard UTM'
        elif self.settings.captureProjIsPlusCodes():
            s = 'Plus Codes'
        elif self.settings.captureProjIsCustomCRS():
            if self.settings.otherNumberFormat == 0:  # Numerical
                if self.settings.coordOrder == self.settings.OrderYX:
                    s = '{} - Y,X'.format(self.settings.captureCustomCRSID())
                else:
                    s = '{} - X,Y'.format(self.settings.captureCustomCRSID())
            else:  # WKT
                s = 'WKT'
        else:  # Should never happen
            s = ''
        return s

    def clicked(self, pt, b):
        '''Capture the coordinate when the mouse button has been released,
        format it, and copy it to the clipboard.'''
        if settings.captureShowLocation:
            if self.marker is None:
                self.marker = QgsVertexMarker(self.canvas)
                self.marker.setIconSize(18)
                self.marker.setPenWidth(2)
                self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
            self.marker.setCenter(pt)
        else:
            self.removeMarker()

        try:
            if self.capture4326:
                canvasCRS = self.canvas.mapSettings().destinationCrs()
                transform = QgsCoordinateTransform(canvasCRS, epsg4326,
                                                   QgsProject.instance())
                pt4326 = transform.transform(pt.x(), pt.y())
                self.capturesig.emit(pt4326)
                return
            msg = self.formatCoord(pt, self.settings.delimiter)
            formatString = self.coordFormatString()
            if msg != None:
                clipboard = QApplication.clipboard()
                clipboard.setText(msg)
                self.iface.messageBar().pushMessage(
                    "",
                    "{} coordinate {} copied to the clipboard".format(
                        formatString, msg),
                    level=Qgis.Info,
                    duration=4)
        except Exception as e:
            self.iface.messageBar().pushMessage(
                "",
                "Invalid coordinate: {}".format(e),
                level=Qgis.Warning,
                duration=4)

    def removeMarker(self):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None
class captureGPSFeatures(FieldRestrictionTypeUtilsMixin):

    def __init__(self, iface, featuresWithGPSToolbar):

        TOMsMessageLog.logMessage("In captureGPSFeatures::init", level=Qgis.Info)

        FieldRestrictionTypeUtilsMixin.__init__(self, iface)

        # Save reference to the QGIS interface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        self.featuresWithGPSToolbar = featuresWithGPSToolbar
        self.gpsMapTool = False
        self.marker = None

        # This will set up the items on the toolbar
        # Create actions

        self.gnssToolGroup = QActionGroup(featuresWithGPSToolbar)
        self.actionCreateRestriction = QAction(QIcon(":/plugins/featureswithgps/resources/mActionAddTrack.svg"),
                               QCoreApplication.translate("MyPlugin", "Create Restriction"),
                               self.iface.mainWindow())
        self.actionCreateRestriction.setCheckable(True)

        self.actionAddGPSLocation = QAction(QIcon(":/plugins/featureswithgps/resources/greendot3.png"),
                               QCoreApplication.translate("MyPlugin", "Add vertex from gnss"),
                               self.iface.mainWindow())
        #self.actionAddGPSLocation.setCheckable(True)

        self.actionRemoveRestriction = QAction(QIcon(":plugins/featureswithgps/resources/mActionDeleteTrack.svg"),
                                        QCoreApplication.translate("MyPlugin", "Remove Restriction"),
                                        self.iface.mainWindow())
        self.actionRemoveRestriction.setCheckable(True)

        self.actionRestrictionDetails = QAction(QIcon(":/plugins/featureswithgps/resources/mActionGetInfo.svg"),
                                         QCoreApplication.translate("MyPlugin", "Get Restriction Details"),
                                         self.iface.mainWindow())
        self.actionRestrictionDetails.setCheckable(True)
        self.gnssToolGroup.addAction(self.actionRestrictionDetails)

        self.actionCreateSign = QAction(QIcon(":/plugins/featureswithgps/resources/mActionSetEndPoint.svg"),
                                                    QCoreApplication.translate("MyPlugin", "Create sign from gnss"),
                                                    self.iface.mainWindow())
        self.actionCreateSign.setCheckable(True)

        self.actionCreateMTR = QAction(QIcon(":/plugins/featureswithgps/resources/UK_traffic_sign_606F.svg"),
                                                    QCoreApplication.translate("MyPlugin", "Create moving traffic restriction"),
                                                    self.iface.mainWindow())
        self.actionCreateMTR.setCheckable(True)

        self.actionMoveFeatureToDifferentLayer = QAction(QIcon(""),
                                         QCoreApplication.translate("MyPlugin", "Move feature to different layer"),
                                         self.iface.mainWindow())
        self.actionMoveFeatureToDifferentLayer.setCheckable(True)
        self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer)

        # Add actions to the toolbar

        self.featuresWithGPSToolbar.addAction(self.actionCreateRestriction)
        self.featuresWithGPSToolbar.addAction(self.actionAddGPSLocation)
        self.featuresWithGPSToolbar.addAction(self.actionRestrictionDetails)
        #self.featuresWithGPSToolbar.addAction(self.actionRemoveRestriction)
        self.featuresWithGPSToolbar.addAction(self.actionCreateSign)
        #self.featuresWithGPSToolbar.addAction(self.actionCreateMTR)
        self.featuresWithGPSToolbar.addAction(self.actionMoveFeatureToDifferentLayer)

        self.gnssToolGroup.addAction(self.actionCreateRestriction)
        #self.gnssToolGroup.addAction(self.actionAddGPSLocation)
        #self.gnssToolGroup.addAction(self.actionRemoveRestriction)
        self.gnssToolGroup.addAction(self.actionRestrictionDetails)
        #self.gnssToolGroup.addAction(self.actionCreateSign)
        #self.gnssToolGroup.addAction(self.actionCreateMTR)
        self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer)

        self.gnssToolGroup.setExclusive(True)
        self.gnssToolGroup.triggered.connect(self.onGroupTriggered)

        # Connect action signals to slots

        self.actionCreateRestriction.triggered.connect(self.doCreateRestriction)
        self.actionAddGPSLocation.triggered.connect(self.doAddGPSLocation)
        self.actionRestrictionDetails.triggered.connect(self.doRestrictionDetails)
        #self.actionRemoveRestriction.triggered.connect(self.doRemoveRestriction)
        self.actionCreateSign.triggered.connect(self.doCreateSign)
        #self.actionCreateMTR.triggered.connect(self.doCreateMTR)
        self.actionMoveFeatureToDifferentLayer.triggered.connect(self.doMoveFeatureToDifferentLayer)

        self.actionCreateRestriction.setEnabled(False)
        self.actionAddGPSLocation.setEnabled(False)
        self.actionRestrictionDetails.setEnabled(False)
        #self.actionRemoveRestriction.setEnabled(False)
        self.actionCreateSign.setEnabled(False)
        #self.actionCreateMTR.setEnabled(False)
        self.actionMoveFeatureToDifferentLayer.setEnabled(False)

        self.searchBar = searchBar(self.iface, self.featuresWithGPSToolbar)
        self.searchBar.disableSearchBar()

        self.mapTool = None
        self.currGnssAction = None
        self.gpsConnection = None
        self.createMapToolDict = {}

    def enableFeaturesWithGPSToolbarItems(self):

        TOMsMessageLog.logMessage("In enablefeaturesWithGPSToolbarItems", level=Qgis.Warning)
        self.gpsAvailable = False
        self.closeTOMs = False

        self.tableNames = TOMsLayers(self.iface)
        self.params = gpsParams()

        self.tableNames.TOMsLayersNotFound.connect(self.setCloseTOMsFlag)
        #self.tableNames.gpsLayersNotFound.connect(self.setCloseCaptureGPSFeaturesFlag)
        self.params.TOMsParamsNotFound.connect(self.setCloseCaptureGPSFeaturesFlag)

        self.TOMsConfigFileObject = TOMsConfigFile()
        self.TOMsConfigFileObject.TOMsConfigFileNotFound.connect(self.setCloseTOMsFlag)
        self.TOMsConfigFileObject.initialiseTOMsConfigFile()

        self.tableNames.getLayers(self.TOMsConfigFileObject)

        self.prj = QgsProject().instance()
        self.dest_crs = self.prj.crs()
        TOMsMessageLog.logMessage("In captureGPSFeatures::init project CRS is " + self.dest_crs.description(),
                                 level=Qgis.Warning)
        self.transformation = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4326"), self.dest_crs,
                                                     self.prj)

        self.params.getParams()

        if self.closeTOMs:
            QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start editing tool ..."))
            #self.actionProposalsPanel.setChecked(False)
            return   # TODO: allow function to continue without GPS enabled ...

        # Now check to see if the port is set. If not assume that just normal tools

        gpsPort = self.params.setParam("gpsPort")
        TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems: GPS port is: {}".format(gpsPort), level=Qgis.Warning)
        self.gpsConnection = None

        if gpsPort:
            self.gpsAvailable = True

        if self.gpsAvailable == True:
            self.curr_gps_location = None
            self.curr_gps_info = None

            TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - GPS port is specified ",
                                     level=Qgis.Info)
            self.gps_thread = GPS_Thread(self.dest_crs, gpsPort)
            thread = QThread()
            self.gps_thread.moveToThread(thread)
            self.gps_thread.gpsActivated.connect(self.gpsStarted)
            self.gps_thread.gpsPosition.connect(self.gpsPositionProvided)
            self.gps_thread.gpsDeactivated.connect(functools.partial(self.gpsStopped))
            self.gps_thread.gpsError.connect(self.gpsErrorEncountered)
            #self.gps_thread.progress.connect(progressBar.setValue)
            thread.started.connect(self.gps_thread.startGPS)
            #thread.finished.connect(functools.partial(self.gpsStopped, thread))
            thread.start()
            self.thread = thread

            TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - attempting connection ",
                                     level=Qgis.Info)

            time.sleep(1.0)

            try:
                self.roamDistance = float(self.params.setParam("roamDistance"))
            except Exception as e:
                TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems:init: roamDistance issue: {}".format(e), level=Qgis.Warning)
                self.roamDistance = 5.0

        self.enableToolbarItems()

        self.createMapToolDict = {}

    def enableToolbarItems(self):
        TOMsMessageLog.logMessage("In enableToolbarItems", level=Qgis.Warning)
        self.actionCreateRestriction.setEnabled(True)
        self.actionRestrictionDetails.setEnabled(True)
        #self.actionRemoveRestriction.setEnabled(True)
        #self.actionCreateSign.setEnabled(True)
        #self.actionCreateMTR.setEnabled(True)
        self.actionMoveFeatureToDifferentLayer.setEnabled(True)

        self.searchBar.enableSearchBar()

        self.currMapTool = None
        self.theCurrentMapTool = None

        self.iface.currentLayerChanged.connect(self.changeCurrLayer2)
        self.canvas.mapToolSet.connect(self.changeMapTool2)
        self.canvas.extentsChanged.connect(self.changeExtents)

        # transaction for move ...
        self.localTransaction = MoveLayerTransaction(self.iface)

    def enableGnssToolbarItem(self):
        if self.gpsConnection:
            self.actionAddGPSLocation.setEnabled(True)
            self.actionCreateSign.setEnabled(True)
            self.lastCentre = QgsPointXY(0,0)

    def disableGnssToolbarItem(self):
        self.actionAddGPSLocation.setEnabled(False)
        self.actionCreateSign.setEnabled(False)

    def disableToolbarItems(self):

        self.actionCreateRestriction.setEnabled(False)
        self.actionRestrictionDetails.setEnabled(False)
        self.actionRemoveRestriction.setEnabled(False)
        self.actionCreateSign.setEnabled(False)
        #self.actionCreateMTR.setEnabled(False)
        self.actionMoveFeatureToDifferentLayer.setEnabled(False)

        self.searchBar.disableSearchBar()

        """if self.gpsConnection:
            self.actionAddGPSLocation.setEnabled(False)"""

    def setCloseTOMsFlag(self):
        self.closeTOMs = True
        QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Now closing TOMs ..."))

    def disableFeaturesWithGPSToolbarItems(self):

        TOMsMessageLog.logMessage("In disablefeaturesWithGPSToolbarItems", level=Qgis.Warning)
        if self.gpsConnection and not self.closeTOMs:
            self.gps_thread.endGPS()

        self.disableToolbarItems()

        # TODO: Need to delete any tools ...
        for layer, mapTool in self.createMapToolDict.items  ():
            try:
                status = layer.rollBack()
            except Exception as e:
                None
                """reply = QMessageBox.information(None, "Information",
                                                    "Problem rolling back changes" + str(self.currLayer.commitErrors()),
                                                    QMessageBox.Ok)"""
            del mapTool

        self.createMapToolDict = {}

        try:
            self.iface.currentLayerChanged.disconnect(self.changeCurrLayer2)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for currentLayerChanged {}".format(e),
                level=Qgis.Warning)

        try:
            self.canvas.mapToolSet.disconnect(self.changeMapTool2)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for mapToolSet {}".format(
                    e),
                level=Qgis.Warning)

        try:
            self.canvas.extentsChanged.disconnect(self.changeExtents)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for extentsChanged {}".format(
                    e),
                level=Qgis.Warning)

        self.tableNames.removePathFromLayerForms()

    def setCloseCaptureGPSFeaturesFlag(self):
        self.closeCaptureGPSFeatures = True
        self.gpsAvailable = True

    def onGroupTriggered(self, action):
        # hold the current action
        self.currGnssAction = action
        TOMsMessageLog.logMessage("In onGroupTriggered: curr action is {}".format(action.text()), level=Qgis.Info)

    """ 
        Using signals for ChangeTool and ChangeLayer to manage the tools - with the following functions
    """
    def isGnssTool(self, mapTool):

        if (isinstance(mapTool, CreateRestrictionTool) or
           isinstance(mapTool, GeometryInfoMapTool) or
           isinstance(mapTool, RemoveRestrictionTool)):
            return True

        return False

    def changeMapTool2(self):
        TOMsMessageLog.logMessage(
            "In changeMapTool2 ...", level=Qgis.Info)

        currMapTool = self.iface.mapCanvas().mapTool()

        if not self.isGnssTool(currMapTool):
            TOMsMessageLog.logMessage(
                "In changeMapTool2. Unchecking action ...", level=Qgis.Info)
            if self.currGnssAction:
                self.currGnssAction.setChecked(False)
        else:
            TOMsMessageLog.logMessage(
            "In changeMapTool2. No action for gnssTools.", level=Qgis.Info)

        TOMsMessageLog.logMessage(
            "In changeMapTool2. finished.", level=Qgis.Info)
        #print('tool unset')

    def changeCurrLayer2(self):
        TOMsMessageLog.logMessage("In changeLayer2 ... ", level=Qgis.Info)

        try:
            currMapTool = self.iface.mapCanvas().mapTool()
            self.currGnssAction.setChecked(False)
        except Exception as e:
            None

        """if self.isGnssTool(currMapTool):
            TOMsMessageLog.logMessage("In changeLayer2. Action triggered ... ", level=Qgis.Info)
            self.currGnssAction.trigger()  # assumption is that there is an action associated with the tool
        else:
            TOMsMessageLog.logMessage(
            "In changeLayer2. No action for currentMapTool.", level=Qgis.Info)"""

        TOMsMessageLog.logMessage(
            "In changeLayer2. finished.", level=Qgis.Info)
        print('layer changed')


    def doCreateRestriction(self):

        TOMsMessageLog.logMessage("In doCreateRestriction", level=Qgis.Info)

        self.currLayer = self.iface.activeLayer()
        if not self.currLayer:
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        # TODO: Check that this is a restriction layer

        if self.actionCreateRestriction.isChecked():

            TOMsMessageLog.logMessage("In doCreateRestriction - tool activated", level=Qgis.Info)
            TOMsMessageLog.logMessage(
                "In doCreateRestriction: current map tool {}".format(type(self.iface.mapCanvas().mapTool()).__name__),
                level=Qgis.Info)

            self.createRestrictionMapTool = self.createMapToolDict.get(self.currLayer)

            if not self.createRestrictionMapTool:
                TOMsMessageLog.logMessage("In doCreateRestriction. creating new map tool", level=Qgis.Info)
                self.createRestrictionMapTool = CreateRestrictionTool(self.iface, self.currLayer)
                self.createMapToolDict[self.currLayer] = self.createRestrictionMapTool

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 1", level=Qgis.Info)

            self.iface.mapCanvas().setMapTool(self.createRestrictionMapTool)

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 2", level=Qgis.Info)

            if not self.createRestrictionMapTool.isCapturing():
                if self.currLayer.isEditable() == True:
                    if self.currLayer.commitChanges() == False:
                        reply = QMessageBox.information(None, "Information",
                                                        "Problem committing changes" + str(self.currLayer.commitErrors()),
                                                        QMessageBox.Ok)
                    else:
                        TOMsMessageLog.logMessage("In doCreateRestriction: changes committed", level=Qgis.Info)

                if self.currLayer.readOnly() == True:
                    TOMsMessageLog.logMessage("In doCreateRestriction - Not able to start transaction ...",
                                             level=Qgis.Info)
                else:
                    if self.currLayer.startEditing() == False:
                        reply = QMessageBox.information(None, "Information",
                                                        "Could not start transaction on " + self.currLayer.name(),
                                                        QMessageBox.Ok)
                        return

            TOMsMessageLog.logMessage("In doCreateRestriction. Here 3", level=Qgis.Info)

        else:

            TOMsMessageLog.logMessage("In doCreateRestriction - tool deactivated", level=Qgis.Info)

            if self.createRestrictionMapTool:
                self.iface.mapCanvas().unsetMapTool(self.createRestrictionMapTool)

            self.currMapTool = None
            self.currentlySelectedLayer = None

            self.actionCreateRestriction.setChecked(False)

            # TODO: stop editting on layers??

        TOMsMessageLog.logMessage("In doCreateRestriction. Here 4", level=Qgis.Info)



    # -- end of tools for signals

    def changeExtents(self):
        TOMsMessageLog.logMessage("In changeExtents ... ", level=Qgis.Info)

    def doAddGPSLocation(self):

        # need to have a addPointFromGPS function within each tool

        TOMsMessageLog.logMessage("In doAddGPSLocation", level=Qgis.Info)

        if self.gpsConnection:

            if self.curr_gps_location:
                try:
                    status = self.createRestrictionMapTool.addPointFromGPS(self.curr_gps_location, self.curr_gps_info)
                except Exception as e:
                    TOMsMessageLog.logMessage("In doAddGPSLocation: Problem adding gnss location: {}".format(e), level=Qgis.Warning)
                    reply = QMessageBox.information(self.iface.mainWindow(), "Error",
                                                    "Problem adding gnss location ... ",
                                                    QMessageBox.Ok)
            else:
                reply = QMessageBox.information(self.iface.mainWindow(), "Information",
                                                "No position found ...",
                                                QMessageBox.Ok)
        else:

            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "You need to activate the tool first ...",
                                            QMessageBox.Ok)

    def doRestrictionDetails(self):
        """
            Select point and then display details. Assume that there is only one of these map tools in existence at any one time ??
        """
        TOMsMessageLog.logMessage("In doRestrictionDetails", level=Qgis.Info)

        # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools

        if not self.iface.activeLayer():
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.actionRestrictionDetails.isChecked():

            TOMsMessageLog.logMessage("In doRestrictionDetails - tool activated", level=Qgis.Warning)

            self.showRestrictionMapTool = GeometryInfoMapTool(self.iface)
            self.iface.mapCanvas().setMapTool(self.showRestrictionMapTool)
            self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails)

        else:

            TOMsMessageLog.logMessage("In doRestrictionDetails - tool deactivated", level=Qgis.Warning)

            if self.showRestrictionMapTool:
                self.iface.mapCanvas().unsetMapTool(self.showRestrictionMapTool)

            self.actionRestrictionDetails.setChecked(False)

    #@pyqtSlot(str)
    def showRestrictionDetails(self, closestLayer, closestFeature):

        TOMsMessageLog.logMessage(
            "In showRestrictionDetails ... Layer: " + str(closestLayer.name()),
            level=Qgis.Info)

        self.showRestrictionMapTool.notifyFeatureFound.disconnect(self.showRestrictionDetails)

        # TODO: could improve ... basically check to see if transaction in progress ...
        if closestLayer.isEditable() == True:
            reply = QMessageBox.question(None, "Information",
                                            "There is a transaction in progress on this layer. This action will rollback back any changes. Do you want to continue?",
                                            QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.No:
                return
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Problem committing changes" + str(closestLayer.commitErrors()),
                                                QMessageBox.Ok)
            else:
                TOMsMessageLog.logMessage("In showRestrictionDetails: changes committed", level=Qgis.Info)

        """if self.iface.activeLayer().readOnly() == True:
            TOMsMessageLog.logMessage("In showSignDetails - Not able to start transaction ...",
                                     level=Qgis.Info)
        else:
            if self.iface.activeLayer().startEditing() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Could not start transaction on " + self.currLayer.name(),
                                                QMessageBox.Ok)
                return"""

        self.dialog = self.iface.getFeatureForm(closestLayer, closestFeature)
        #self.TOMsUtils.setupRestrictionDialog(self.dialog, closestLayer, closestFeature)
        self.setupFieldRestrictionDialog(self.dialog, closestLayer, closestFeature)

        self.dialog.show()

    """
        Decided that it is best to use the QGIS select/delete tools to manage removals. So these functions are not used
    """
    def doRemoveRestriction(self):

        TOMsMessageLog.logMessage("In doRemoveRestriction", level=Qgis.Info)

        self.currLayer = self.iface.activeLayer()

        if not self.currLayer:
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.currLayer.readOnly() == True:
            """reply = QMessageBox.information(None, "Information",
                                            "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok)"""
            TOMsMessageLog.logMessage("In doRemoveRestriction - Not able to start transaction ...", level=Qgis.Info)
            self.actionRemoveRestriction.setChecked(False)
            return

        if self.actionRemoveRestriction.isChecked():

            TOMsMessageLog.logMessage("In doRemoveRestriction - tool activated", level=Qgis.Warning)

            """self.mapTool = self.deleteMapToolDict.get(self.currLayer)

            if not self.mapTool:
                self.mapTool = RemoveRestrictionTool(self.iface)
                self.deleteMapToolDict[self.currLayer] =  self.mapTool"""

            self.mapTool = RemoveRestrictionTool(self.iface)
            #self.removeRestrictionMapTool.setAction(self.actionRemoveRestriction)
            self.iface.mapCanvas().setMapTool(self.removeRestrictionMapTool)
            #self.gpsMapTool = True
            #self.removeRestrictionMapTool.deactivated.connect(functools.partial(self.deactivateAction, self.actionRemoveRestriction))
            #self.iface.currentLayerChanged.connect(self.changeCurrLayer)
            #self.canvas.mapToolSet.connect(self.changeMapTool)

            self.removeRestrictionMapTool.notifyFeatureFound.connect(self.removeRestriction)

        else:

            TOMsMessageLog.logMessage("In doRemoveRestriction - tool deactivated", level=Qgis.Warning)

            self.removeRestrictionMapTool.notifyFeatureFound.disconnect(self.removeRestriction)

            #self.canvas.mapToolSet.disconnect(self.changeMapTool)
            #self.iface.currentLayerChanged.disconnect(self.changeCurrLayer)

            self.iface.mapCanvas().unsetMapTool(self.removeRestrictionMapTool)
            #self.removeRestrictionMapTool.deactivate()
            #self.mapTool = None
            self.actionRemoveRestriction.setChecked(False)

    #@pyqtSlot(str)
    def removeRestriction(self, closestLayer, closestFeature):

        TOMsMessageLog.logMessage(
            "In removeRestriction ... Layer: " + str(closestLayer.name()),
            level=Qgis.Info)

        if closestLayer.isEditable() == True:
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(None, "Information",
                                                "Problem committing changes" + str(closestLayer.commitErrors()),
                                                QMessageBox.Ok)
            else:
                TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info)

        if self.currLayer.startEditing() == False:
            reply = QMessageBox.information(None, "Information",
                                            "Could not start transaction on " + self.currLayer.name(),
                                            QMessageBox.Ok)
            return

        # TODO: Sort out this for UPDATE
        # self.setDefaultRestrictionDetails(closestFeature, closestLayer)

        closestLayer.deleteFeature(closestFeature.id())

        if closestLayer.commitChanges() == False:
            reply = QMessageBox.information(None, "Information",
                                            "Problem committing changes" + str(closestLayer.commitErrors()),
                                            QMessageBox.Ok)
        else:
            TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info)

    """
        This is a tool for adding a point feature. currently only used for signs, but could be used for any point
    """
    def doCreateSign(self):

        TOMsMessageLog.logMessage("In doCreateSign", level=Qgis.Info)

        if self.actionCreateSign.isChecked():

            self.currMapTool = self.canvas.mapTool()
            self.currentlySelectedLayer = self.iface.activeLayer()
            self.signsLayer = self.tableNames.setLayer("Signs")

            self.iface.setActiveLayer(self.signsLayer)

            self.createPointMapTool = CreatePointTool(self.iface, self.signsLayer)

            TOMsMessageLog.logMessage("In doCreateSign - tool activated", level=Qgis.Info)

            self.signsLayer.editingStopped.connect(self.reinstateMapTool)

            self.actionCreateSign.setChecked(False)

            self.iface.mapCanvas().setMapTool(self.createPointMapTool)

            """ add the point from the gnss """
            try:
                status = self.canvas.mapTool().addPointFromGPS(self.curr_gps_location, self.curr_gps_info)
            except Exception as e:
                TOMsMessageLog.logMessage("In doCreateSign: Problem adding gnss location: {}".format(e),
                                          level=Qgis.Warning)
                reply = QMessageBox.information(self.iface.mainWindow(), "Error",
                                                "Problem adding gnss location ... ",
                                                QMessageBox.Ok)

    """
        Not currently used, but want to develop ...
    """
    def doCreateMTR(self):

        TOMsMessageLog.logMessage("In doCreateMTR", level=Qgis.Info)

        if self.actionCreateMTR.isChecked():

            TOMsMessageLog.logMessage("In doCreateMTR - tool activated", level=Qgis.Info)

            # Open MTR form ...

            try:
                self.thisMtrForm
            except AttributeError:
                self.thisMtrForm = mtrForm(self.iface)

            #res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog)
            #self.mtrTypeCB = self.dialog.findChild(QComboBox, "cmb_MTR_list")
            #self.mtrTypeCB.activated[str].connect(self.onLocalChanged)
            #self.currDialog.findChild(QComboBox, "cmb_MTR_list").activated[str].connect(self.onChanged)


            """ Need to setup dialog:
                a. create drop down
                b. link structure of form to different options from drop down, e.g., Access Restriction needs ?? attributes and one point, Turn Restriction needs ?? attributes and two points
                c. link getPoint actions to buttons
            """
            status = self.thisMtrForm.show()
            # Run the dialog event loop
            result = self.thisMtrForm.exec_()
            #

        else:

            TOMsMessageLog.logMessage("In doCreateMTR - tool deactivated", level=Qgis.Info)

            #self.iface.mapCanvas().unsetMapTool(self.mapTool)
            #self.mapTool = None
            self.actionCreateMTR.setChecked(False)
            self.gpsMapTool = False

    def onLocalChanged(self, text):
        TOMsMessageLog.logMessage(
            "In generateFirstStageForm::selectionchange.  " + text, level=Qgis.Info)
        res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog, text)

    """
        Used with the createSign tool to reinstate the last used maptool, i.e., to allow the interupt of feature creation
    """

    def reinstateMapTool(self):

        TOMsMessageLog.logMessage("In reinstateMapTool ... ", level=Qgis.Info)
        self.iface.activeLayer().editingStopped.disconnect(self.reinstateMapTool)

        if self.currMapTool:

            TOMsMessageLog.logMessage(
                "In reinstateMapTool. layer to be reinstated {} using tool {}".format(self.currentlySelectedLayer.name(), self.currMapTool.toolName()),
                level=Qgis.Warning)
            # now reinstate
            if self.currentlySelectedLayer:
                self.iface.setActiveLayer(self.currentlySelectedLayer)

            self.iface.mapCanvas().setMapTool(self.currMapTool)


    def doMoveFeatureToDifferentLayer(self):
        """
            Select point and then display details. Assume that there is only one of these map tools in existence at any one time ??
        """
        TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer", level=Qgis.Info)

        # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools

        if not self.iface.activeLayer():
            reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...",
                                            QMessageBox.Ok)
            return

        if self.actionMoveFeatureToDifferentLayer.isChecked():

            TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool activated", level=Qgis.Warning)

            self.moveFeatureToDifferentLayerMapTool = ChangeLayerMapTool(self.iface, self.localTransaction)
            self.iface.mapCanvas().setMapTool(self.moveFeatureToDifferentLayerMapTool)
            #self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails)

        else:

            TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool deactivated", level=Qgis.Warning)

            if self.moveFeatureToDifferentLayerMapTool:
                self.iface.mapCanvas().unsetMapTool(self.moveFeatureToDifferentLayerMapTool)

            self.actionMoveFeatureToDifferentLayer.setChecked(False)


    #@pyqtSlot(QgsGpsConnection)
    def gpsStarted(self, connection):
        TOMsMessageLog.logMessage("In enableTools - GPS connection found ",
                                     level=Qgis.Info)

        self.gpsConnection = connection

        # marker
        self.marker = QgsVertexMarker(self.canvas)
        self.marker.setColor(QColor(255, 0, 0))  # (R,G,B)
        self.marker.setIconSize(10)
        self.marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.marker.setPenWidth(3)

        self.enableGnssToolbarItem()
        reply = QMessageBox.information(None, "Information",
                                            "Connection found",
                                            QMessageBox.Ok)

    #@pyqtSlot()
    def gpsStopped(self):
        TOMsMessageLog.logMessage("In enableTools - GPS connection stopped ",
                                     level=Qgis.Warning)

        self.gps_thread.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()

        if self.gpsConnection:
            if self.canvas is not None:
                self.marker.hide()
                self.canvas.scene().removeItem(self.marker)

        self.gpsConnection = None
        self.disableGnssToolbarItem()

    #@pyqtSlot()
    def gpsPositionProvided(self, mapPointXY, gpsInfo):
        """reply = QMessageBox.information(None, "Information",
                                            "Position provided",
                                            QMessageBox.Ok)"""
        TOMsMessageLog.logMessage("In enableTools - ******** initial GPS location provided " + mapPointXY.asWkt(),
                                     level=Qgis.Info)

        self.curr_gps_location = mapPointXY
        self.curr_gps_info = gpsInfo

        wgs84_pointXY = QgsPointXY(gpsInfo.longitude, gpsInfo.latitude)
        wgs84_point = QgsPoint(wgs84_pointXY)
        wgs84_point.transform(self.transformation)
        x = wgs84_point.x()
        y = wgs84_point.y()
        new_mapPointXY = QgsPointXY(x, y)

        TOMsMessageLog.logMessage("In enableTools - ******** transformed GPS location provided " + str(gpsInfo.longitude) + ":" + str(gpsInfo.latitude) + "; " + new_mapPointXY.asWkt(),
                                     level=Qgis.Info)

        if gpsInfo.pdop >= 1:  # gps ok
            self.marker.setColor(QColor(0, 200, 0))
        else:
            self.marker.setColor(QColor(255, 0, 0))
        self.marker.setCenter(mapPointXY)
        self.marker.show()
        #self.canvas.setCenter(mapPointXY)

        """TOMsMessageLog.logMessage("In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)),
                                     level=Qgis.Info)"""
        if self.lastCentre.distance(mapPointXY) > self.roamDistance:
            self.lastCentre = mapPointXY
            self.canvas.setCenter(mapPointXY)
            TOMsMessageLog.logMessage(
                "In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)),
                level=Qgis.Warning)
            self.canvas.refresh()

        # TODO: populate message bar with details about satellites, etc

    #@pyqtSlot(Exception, str)
    def gpsErrorEncountered(self, e):
        TOMsMessageLog.logMessage("In enableTools - GPS connection has error {}".format(e),
                                     level=Qgis.Warning)
        """self.actionCreateRestriction.setEnabled(False)
        self.actionAddGPSLocation.setEnabled(False)"""
        self.disableGnssToolbarItem()
Пример #59
0
class SplineTool(QgsMapToolEdit):
    def __init__(self, iface):
        super(SplineTool, self).__init__(iface.mapCanvas())
        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.snap_marker = QgsVertexMarker(self.canvas)
        self.snapping_utils = self.canvas.snappingUtils()

        self.points = []  # digitized, not yet interpolated points
        self.type = QgsWkbTypes.LineGeometry  # layer geometry type
        self.tolerance = None
        self.tightness = None
        self.is_polygon = None

        self.cursor = QCursor(
            QPixmap([
                "16 16 3 1",
                "      c None",
                ".     c #FF0000",
                "+     c #FFFFFF",
                "                ",
                "       +.+      ",
                "      ++.++     ",
                "     +.....+    ",
                "    +.     .+   ",
                "   +.   .   .+  ",
                "  +.    .    .+ ",
                " ++.    .    .++",
                " ... ...+... ...",
                " ++.    .    .++",
                "  +.    .    .+ ",
                "   +.   .   .+  ",
                "   ++.     .+   ",
                "    ++.....+    ",
                "      ++.++     ",
                "       +.+      ",
            ]))

        s = QgsSettings()
        self.snap_col = s.value("/qgis/digitizing/snap_color",
                                QColor("#ff00ff"))

    def canvasMoveEvent(self, event):
        color = QColor(255, 0, 0, 100)
        self.rb.setColor(color)
        self.rb.setWidth(1)
        point = self.toMapCoordinates(event.pos())

        # try to snap to a feature
        result = self.snapping_utils.snapToMap(point)
        if result.isValid():
            point = result.point()
            self.update_snap_marker(snapped_pt=point)
        else:
            self.update_snap_marker()

        points = list(self.points)
        points.append(QgsPoint(point))
        points = interpolate(points)
        self.set_rubber_band_points(points)

    def canvasReleaseEvent(self, event):
        color = QColor(255, 0, 0, 100)
        self.rb.setColor(color)
        self.rb.setWidth(1)
        point = self.toMapCoordinates(event.pos())

        if event.button() == Qt.LeftButton:
            # try to snap to a feature
            result = self.snapping_utils.snapToMap(point)
            if result.isValid():
                point = result.point()
            self.points.append(QgsPoint(point))
            points = interpolate(self.points)
            self.set_rubber_band_points(points)
        else:
            if len(self.points) >= 2:
                # refresh without last point
                self.refresh()
                self.create_feature()
            self.reset_points()
            self.reset_rubber_band()
            self.canvas.refresh()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.deactivate()
            self.activate()
        elif e.key() == Qt.Key_Backspace:
            if self.points:
                self.points.pop()
            points = interpolate(self.points)
            self.set_rubber_band_points(points)
            self.canvas.refresh()

    def reset_points(self):
        self.points = []

    # Create feature from digitized points, i.e. without the last moving point
    # where right click happened. This the same way how core QGIS Add Feature works.
    def create_feature(self):
        layer = self.iface.activeLayer()
        provider = layer.dataProvider()
        fields = provider.fields()
        f = QgsFeature(fields)
        coords = [QgsPointXY(pt) for pt in interpolate(self.points)]

        proj = QgsProject.instance()
        if layer.crs() != proj.crs():
            trans_context = proj.transformContext()
            transf = QgsCoordinateTransform(proj.crs(), layer.crs(),
                                            trans_context)
            coords_tmp = coords[:]
            coords = []
            for point in coords_tmp:
                transformed_pt = transf.transform(point)
                coords.append(transformed_pt)

        # Add geometry to feature
        if self.is_polygon:
            g = QgsGeometry.fromPolygonXY([coords])
        else:
            g = QgsGeometry.fromPolylineXY(coords)
        f.setGeometry(g)

        # Add attribute fields to feature
        for field in fields.toList():
            ix = fields.indexFromName(field.name())
            f[field.name()] = provider.defaultValue(ix)

        layer.beginEditCommand("Feature added")

        settings = QSettings()
        disable_attributes = settings.value(
            "/qgis/digitizing/disable_enter_attribute_values_dialog",
            False,
            type=bool)
        layer.addFeature(f)
        if disable_attributes:
            layer.endEditCommand()
        else:
            dlg = self.iface.getFeatureForm(layer, f)
            if dlg.exec_():
                layer.endEditCommand()
            else:
                layer.destroyEditCommand()

    def refresh(self):
        if self.points:
            points = interpolate(self.points)
            self.set_rubber_band_points(points)

    def canvasPressEvent(self, event):
        pass

    def showSettingsWarning(self):
        pass

    def activate(self):
        self.canvas.setCursor(self.cursor)
        layer = self.iface.activeLayer()
        self.type = layer.geometryType()
        self.is_polygon = False
        if self.type == QgsWkbTypes.PolygonGeometry:
            self.is_polygon = True

    def reset_rubber_band(self):
        self.rb.reset(self.type)

    def set_rubber_band_points(self, points):
        self.reset_rubber_band()
        for point in points:
            update = point is points[-1]
            if isinstance(point, QgsPoint):
                point = QgsPointXY(point)
            self.rb.addPoint(point, update)

    def update_snap_marker(self, snapped_pt=None):
        self.canvas.scene().removeItem(self.snap_marker)
        if snapped_pt is None:
            return
        self.snap_marker = QgsVertexMarker(self.canvas)
        self.snap_marker.setCenter(snapped_pt)
        self.snap_marker.setIconSize(16)
        self.snap_marker.setIconType(QgsVertexMarker.ICON_BOX)
        self.snap_marker.setPenWidth(3)
        self.snap_marker.setColor(self.snap_col)

    def deactivate(self):
        self.reset_points()
        self.update_snap_marker()
        self.reset_rubber_band()
        QgsMapToolEdit.deactivate(self)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True
Пример #60
0
class ZoomToLatLon(QDockWidget, FORM_CLASS):
    def __init__(self, lltools, iface, parent):
        super(ZoomToLatLon, self).__init__(parent)
        self.setupUi(self)
        self.canvas = iface.mapCanvas()
        self.marker = None
        self.zoomToolButton.setIcon(
            QIcon(':/images/themes/default/mActionZoomIn.svg'))
        self.clearToolButton.setIcon(
            QIcon(':/images/themes/default/mIconClearText.svg'))
        self.zoomToolButton.clicked.connect(self.zoomToPressed)
        self.clearToolButton.clicked.connect(self.removeMarker)
        self.lltools = lltools
        self.settings = lltools.settingsDialog
        self.iface = iface
        self.coordTxt.returnPressed.connect(self.zoomToPressed)
        self.canvas.destinationCrsChanged.connect(self.crsChanged)
        self.configure()

    def showEvent(self, e):
        self.configure()

    def closeEvent(self, event):
        self.removeMarker()
        event.accept()

    def crsChanged(self):
        if self.isVisible():
            self.configure()

    def is_number(self, s):
        try:
            float(s)
            return True
        except ValueError:
            return False

    def configure(self):
        self.coordTxt.setText("")
        self.removeMarker()

        if self.settings.zoomToProjIsMGRS():
            # This is an MGRS coordinate
            self.label.setText("Enter MGRS Coordinate")
        elif self.settings.zoomToProjIsPlusCodes():
            self.label.setText("Enter Plus Codes")
        elif self.settings.zoomToProjIsStandardUtm():
            self.label.setText("Enter Standard UTM")
        elif self.settings.zoomToProjIsWgs84():
            if self.settings.zoomToCoordOrder == 0:
                self.label.setText("Enter 'Latitude, Longitude'")
            else:
                self.label.setText("Enter 'Longitude, Latitude'")
        elif self.settings.zoomToProjIsProjectCRS():
            crsID = self.canvas.mapSettings().destinationCrs().authid()
            if self.settings.zoomToCoordOrder == 0:
                self.label.setText("Enter {} Y,X".format(crsID))
            else:
                self.label.setText("Enter {} X,Y".format(crsID))
        else:  # Default to custom CRS
            crsID = self.settings.zoomToCustomCrsId()
            if self.settings.zoomToCoordOrder == 0:
                self.label.setText("Enter {} Y,X".format(crsID))
            else:
                self.label.setText("Enter {} X,Y".format(crsID))

    def convertCoordinate(self, text):
        try:
            if self.settings.zoomToProjIsMGRS():
                # An MGRS coordinate only format has been specified. This will result in an exception
                # if it is not a valid MGRS coordinate
                text2 = re.sub(r'\s+', '', str(text))  # Remove all white space
                lat, lon = mgrs.toWgs(text2)
                return (lat, lon, epsg4326)

            if self.settings.zoomToProjIsPlusCodes():
                # A Plus Codes coordinate has been selected. This will result in an exception
                # if it is not a valid plus codes coordinate.
                coord = olc.decode(text)
                lat = coord.latitudeCenter
                lon = coord.longitudeCenter
                return (lat, lon, epsg4326)

            if self.settings.zoomToProjIsStandardUtm():
                # A Standard UTM coordinate has been selected. This will result in an exception
                # if it is not a valid utm coordinate.
                pt = utmString2Crs(text)
                return (pt.y(), pt.x(), epsg4326)

            # Check for other formats
            if text[0] == '{':  # This may be a GeoJSON point
                codec = QTextCodec.codecForName("UTF-8")
                fields = QgsJsonUtils.stringToFields(text, codec)
                fet = QgsJsonUtils.stringToFeatureList(text, fields, codec)
                if (len(fet) == 0) or not fet[0].isValid():
                    raise ValueError('Invalid Coordinates')

                geom = fet[0].geometry()
                if geom.isEmpty() or (geom.wkbType() != QgsWkbTypes.Point):
                    raise ValueError('Invalid GeoJSON Geometry')
                pt = geom.asPoint()
                return (pt.y(), pt.x(), epsg4326)

            # Check to see if it is standard UTM
            if isUtm(text):
                pt = utmString2Crs(text)
                return (pt.y(), pt.x(), epsg4326)

            # Check to see if it is an MGRS coordinate
            try:
                text2 = re.sub(r'\s+', '', str(text))
                lat, lon = mgrs.toWgs(text2)
                return (lat, lon, epsg4326)
            except Exception:
                pass

            # Check to see if it is a plus codes string
            try:
                coord = olc.decode(text)
                lat = coord.latitudeCenter
                lon = coord.longitudeCenter
                return (lat, lon, epsg4326)
            except Exception:
                pass

            # Check to see if it is a WKT POINT format
            if re.search(r'POINT\(', text) is not None:
                m = re.findall(
                    r'POINT\(\s*([+-]?\d*\.?\d*)\s+([+-]?\d*\.?\d*)', text)
                if len(m) != 1:
                    raise ValueError('Invalid Coordinates')
                lon = float(m[0][0])
                lat = float(m[0][1])
                if self.settings.zoomToProjIsWgs84():
                    srcCrs = epsg4326
                elif self.settings.zoomToProjIsProjectCRS():
                    srcCrs = self.canvas.mapSettings().destinationCrs()
                else:
                    srcCrs = self.settings.zoomToCustomCRS()
                return (lat, lon, srcCrs)

            # We are left with either DMS or decimal degrees in one of the projections
            if self.settings.zoomToProjIsWgs84():
                lat, lon = parseDMSString(text, self.settings.zoomToCoordOrder)
                return (lat, lon, epsg4326)

            # We are left with a non WGS 84 decimal projection
            coords = re.split(r'[\s,;:]+', text, 1)
            if len(coords) < 2:
                raise ValueError('Invalid Coordinates')
            if self.settings.zoomToCoordOrder == self.settings.OrderYX:
                lat = float(coords[0])
                lon = float(coords[1])
            else:
                lon = float(coords[0])
                lat = float(coords[1])
            if self.settings.zoomToProjIsProjectCRS():
                srcCrs = self.canvas.mapSettings().destinationCrs()
            else:
                srcCrs = self.settings.zoomToCustomCRS()
            return (lat, lon, srcCrs)

        except Exception:
            raise ValueError('Invalid Coordinates')

    def zoomToPressed(self):
        try:
            text = self.coordTxt.text().strip()
            (lat, lon, srcCrs) = self.convertCoordinate(text)
            pt = self.lltools.zoomTo(srcCrs, lat, lon)
            if self.settings.persistentMarker:
                if self.marker is None:
                    self.marker = QgsVertexMarker(self.canvas)
                self.marker.setCenter(pt)
                self.marker.setIconSize(18)
                self.marker.setPenWidth(2)
                self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
            elif self.marker is not None:
                self.removeMarker()
        except Exception:
            # traceback.print_exc()
            self.iface.messageBar().pushMessage("",
                                                "Invalid Coordinate",
                                                level=Qgis.Warning,
                                                duration=2)
            return

    def removeMarker(self):
        if self.marker is not None:
            self.canvas.scene().removeItem(self.marker)
            self.marker = None
            self.coordTxt.clear()