class LineDrawer(QgsMapToolEmitPoint):

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

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

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


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

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

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

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

            # we are drawing now
            self.isDrawing = True

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

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

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

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

    def geometry(self):
        return self.rubberBand.asGeometry()
class PlaceMarkerMapTool(QgsMapToolEmitPoint):
    '''
    classdocs
    '''

    def __init__(self, canvas):
        '''
        Constructor
        '''
        self.canvas = canvas
        super(PlaceMarkerMapTool, self).__init__(self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.rubberBand.reset(QGis.Polygon)

    def canvasReleaseEvent(self, e):
        p1 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() - 2)
        p2 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() - 2)
        p3 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() + 2)
        p4 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() + 2)
        self.reset()

        self.rubberBand.addPoint(p1, False)
        self.rubberBand.addPoint(p2, False)
        self.rubberBand.addPoint(p3, False)
        self.rubberBand.addPoint(p4, True)
        self.rubberBand.show()

    def deactivate(self):
        self.reset()
        super(PlaceMarkerMapTool, self).deactivate()
class GetPointMapTool(QgsMapToolEmitPoint):

    coordCaptured = ""

    def __init__(self, canvas, iface, dockwidget, currentMapTool):
        self.canvas = canvas
        self.iface = iface
        self.currentMapTool = currentMapTool
        self.dockwidget = dockwidget
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Point)
        self.rubberBand.setColor(QColor(255,5,5))
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        self.point = self.toMapCoordinates(e.pos())
        self.isEmittingPoint = True
        self.showPoint(self.point)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        self.coordCaptured = self.pointdef()
        if self.coordCaptured is not None:
            print "Point:", self.coordCaptured
            self.coordCaptured = str(self.coordCaptured).strip("(")
            self.coordCaptured = str(self.coordCaptured).strip(")")
            self.dockwidget.munLineEdit.setText(self.coordCaptured)


        self.iface.mapCanvas().setMapTool(self.currentMapTool)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
       # self.showRect(self.startPoint, self.endPoint)

    def showPoint(self, point):
        self.rubberBand.reset(QGis.Polygon)


        point1 = QgsPoint(point.x(), point.y())


        self.rubberBand.addPoint(point1, False)

        self.rubberBand.show()

    def pointdef(self):

        return QgsPoint(self.point)
Example #4
0
class CurrentSelection(QgsRubberBand):
    """
    Position marker for the current location in the viewer.
    """

    class AniObject(QObject):
        def __init__(self, band):
            super(CurrentSelection.AniObject, self).__init__()
            self.color = QColor()

        @pyqtProperty(int)
        def alpha(self):
            return self.color.alpha()

        @alpha.setter
        def alpha(self, value):
            self.color.setAlpha(value)

    def __init__(self, canvas):
        super(CurrentSelection, self).__init__(canvas)
        self.outline = QgsRubberBand(canvas)
        self.outline.setBrushStyle(Qt.NoBrush)
        self.outline.setWidth(5)
        self.outline.setIconSize(30)
        self.aniobject = CurrentSelection.AniObject(self)
        self.anim = QPropertyAnimation(self.aniobject, "alpha")
        self.anim.setDuration(500)
        self.anim.setStartValue(50)
        self.anim.setEndValue(100)
        self.anim.valueChanged.connect(self.value_changed)

    def setOutlineColour(self, color):
        self.outline.setColor(color)

    def setToGeometry(self, geom, layer):
        super(CurrentSelection, self).setToGeometry(geom, layer)
        self.outline.setToGeometry(geom, layer)
        self.anim.stop()
        self.anim.start()

    def reset(self, geomtype=QGis.Line):
        super(CurrentSelection, self).reset(geomtype)
        self.outline.reset(geomtype)
        self.anim.stop()

    def value_changed(self, value):
        self.setColor(self.aniobject.color)
        self.update()

    def setColor(self, color):
        self.aniobject.color = color
        super(CurrentSelection, self).setColor(color)
Example #5
0
class SelectPoint(QgsMapTool):
    select = pyqtSignal()
    selectionDone = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(couleur)
        self.rbSelect = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        return None

    def canvasReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() - 5, e.pos().y() - 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() + 5, e.pos().y() - 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() + 5, e.pos().y() + 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() - 5, e.pos().y() + 5))
            self.rbSelect.addPoint(cp)
            self.select.emit()
        else:
            self.selectionDone.emit()
        return None

    def reset(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)

    def deactivate(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)
        QgsMapTool.deactivate(self)
Example #6
0
class RubberBandResultRenderer():

    def __init__(self, iface, color = QColor('magenta'), size = 12):
        self.iface = iface
        self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rb.setColor(color)
        self.rb.setIconSize(size)

        self.srs_wgs84 = QgsCoordinateReferenceSystem(4326)
        self.transformation = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84)

    def show_point(self, point, center=False):
        #check srs
        if self.need_transform():
            point = self.transform_point(point)

        self.rb.addPoint(point)
        if center:
            self.center_to_point(point)

    def clear(self):
        self.rb.reset(QGis.Point)

    def need_transform(self):
        return self.iface.mapCanvas().mapRenderer().destinationCrs().postgisSrid() != 4326

    def transform_point(self, point):
        dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
        self.transformation.setDestCRSID(dest_srs_id)
        try:
            return self.transformation.transform(point)
        except:
            print 'Error on transform!'  # DEBUG! need message???
            return

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

    def isZoomTool(self):
        return False
    
    def isTransient(self):
        return False
      
    def isEditTool(self):
        return False
 def highlight(self,geometry):
     def processEvents():
         try:
             qApp.processEvents()
         except:
             QApplication.processEvents()
             
     highlight = QgsRubberBand(self.canvas, geometry.type())
     highlight.setColor(QColor("#36AF6C"))
     highlight.setFillColor(QColor("#36AF6C"))
     highlight.setWidth(2)
     highlight.setToGeometry(geometry,self.canvas.currentLayer())
     processEvents()
     sleep(.1)
     highlight.hide()
     processEvents()
     sleep(.1)
     highlight.show()
     processEvents()
     sleep(.1)
     highlight.reset()
     processEvents()
Example #9
0
class DrawPoint(QgsMapTool):
    selectionDone = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.rb.setColor(couleur)
        self.rb.setWidth(3)

    def canvasReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.rb.addPoint(self.toMapCoordinates(e.pos()))
            self.selectionDone.emit()

    def reset(self):
        self.rb.reset(QgsWkbTypes.PointGeometry)

    def deactivate(self):
        self.rb.reset(QgsWkbTypes.PointGeometry)
        QgsMapTool.deactivate(self)
Example #10
0
class QgepMapToolAddFeature( QgsMapTool ):
    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas() )
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() )
        self.rubberband.setColor( QColor( "#ee5555" ) )
        self.rubberband.setWidth( 2 )
        self.tempRubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() )
        self.tempRubberband.setColor( QColor( "#ee5555" ) )
        self.tempRubberband.setWidth( 2 )
        self.tempRubberband.setLineStyle(Qt.DotLine)

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

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

    def isZoomTool( self ):
        return False

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

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

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

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

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

    def mouseMoved(self, event):
        mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() )
        self.tempRubberband.movePoint( mousePos )
Example #11
0
class DrawPolygon(QgsMapTool):
    '''Outil de sélection par polygone, tiré de selectPlusFr'''

    selectionDone = pyqtSignal()
    move = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.status = 0
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(couleur)
        return None

    def keyPressEvent(self, e):
        if e.matches(QKeySequence.Undo):
            if self.rb.numberOfVertices() > 1:
                self.rb.removeLastPoint()

    def canvasPressEvent(self, e):
        if e.button() == Qt.LeftButton:
            if self.status == 0:
                self.rb.reset(QgsWkbTypes.PolygonGeometry)
                self.status = 1
            self.rb.addPoint(self.toMapCoordinates(e.pos()))
        else:
            if self.rb.numberOfVertices() > 2:
                self.status = 0
                self.selectionDone.emit()
            else:
                self.reset()
        return None

    def canvasMoveEvent(self, e):
        if self.rb.numberOfVertices() > 0 and self.status == 1:
            self.rb.removeLastPoint(0)
            self.rb.addPoint(self.toMapCoordinates(e.pos()))
        self.move.emit()
        return None

    def reset(self):
        self.status = 0
        self.rb.reset(True)

    def deactivate(self):
        self.rb.reset(True)
        QgsMapTool.deactivate(self)
Example #12
0
class DistanceDialog(QDialog, Ui_place_distance):
    def __init__(self, distance, canvas):
        QDialog.__init__(self)
        self.setupUi(self)
        self.settings = MySettings()

        # this is a reference, distance observation is modified in outer class
        self.distance = distance

        self.rubber = QgsRubberBand(canvas)
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.rubber.setIconSize(self.settings.value("rubberSize"))

        self.x.setText("%.3f" % distance.point.x())
        self.y.setText("%.3f" % distance.point.y())
        self.observation.setValue(distance.observation)
        self.precision.setValue(distance.precision)
        self.observation.selectAll()

    @pyqtSignature("on_observation_valueChanged(double)")
    def on_observation_valueChanged(self, v):
        self.distance.observation = v
        self.rubber.setToGeometry(self.distance.geometry(), None)

    @pyqtSignature("on_precision_valueChanged(double)")
    def on_precision_valueChanged(self, v):
        self.distance.precision = v

    def accept(self):
        self.rubber.reset()
        QDialog.accept(self)

    def reject(self):
        self.rubber.reset()
        QDialog.reject(self)

    def closeEvent(self, e):
        self.rubber.reset()
class SimpleIntersectionMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        QgsMapTool.__init__(self, self.mapCanvas)
        self.settings = MySettings()
        self.rubber = QgsRubberBand(self.mapCanvas, QGis.Point)

    def deactivate(self):
        self.rubber.reset()
        QgsMapTool.deactivate(self)

    def activate(self):
        QgsMapTool.activate(self)
        self.rubber.setWidth(self.settings.value("rubberWidth"))
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.checkLayer()

    def canvasMoveEvent(self, mouseEvent):
        # put the observations within tolerance in the rubber band
        self.rubber.reset(QGis.Point)
        match = self.snap_to_intersection(mouseEvent.pos())
        if match.type() == QgsPointLocator.Vertex and match.layer() is None:
            self.rubber.addPoint(match.point())

    def canvasPressEvent(self, mouseEvent):
        self.rubber.reset()
        match = self.snap_to_intersection(mouseEvent.pos())
        if match.type() != QgsPointLocator.Vertex or match.layer() is not None:
            return

        layer = self.checkLayer()
        if layer is None:
            return
        f = QgsFeature()
        initFields = layer.dataProvider().fields()
        f.setFields(initFields)
        f.initAttributes(initFields.size())
        f.setGeometry(QgsGeometry().fromPoint(match.point()))
        layer.editBuffer().addFeature(f)
        layer.triggerRepaint()

    def snap_to_intersection(self, pos):
        """ Temporarily override snapping config and snap to vertices and edges
         of any editable vector layer, to allow selection of node for editing
         (if snapped to edge, it would offer creation of a new vertex there).
        """
        map_point = self.toMapCoordinates(pos)
        tol = QgsTolerance.vertexSearchRadius(self.canvas().mapSettings())
        snap_type = QgsPointLocator.Type(QgsPointLocator.Edge)

        snap_layers = []
        for layer in self.canvas().layers():
            if not isinstance(layer, QgsVectorLayer):
                continue
            snap_layers.append(QgsSnappingUtils.LayerConfig(
                layer, snap_type, tol, QgsTolerance.ProjectUnits))

        snap_util = self.canvas().snappingUtils()
        old_layers = snap_util.layers()
        old_mode = snap_util.snapToMapMode()
        old_inter = snap_util.snapOnIntersections()
        snap_util.setLayers(snap_layers)
        snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)
        snap_util.setSnapOnIntersections(True)
        m = snap_util.snapToMap(map_point)
        snap_util.setLayers(old_layers)
        snap_util.setSnapToMapMode(old_mode)
        snap_util.setSnapOnIntersections(old_inter)
        return m

    def checkLayer(self):
        # check output layer is defined
        layerid = self.settings.value("simpleIntersectionLayer")
        layer = QgsMapLayerRegistry.instance().mapLayer(layerid)
        if not self.settings.value("simpleIntersectionWritePoint") or layer is None:
            self.iface.messageBar().pushMessage("Intersect It",
                                                "You must define an output layer for simple intersections",
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        if not layer.isEditable():
            self.iface.messageBar().pushMessage("Intersect It",
                                                "The output layer <b>%s must be editable</b>" % layer.name(),
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        return layer
Example #14
0
class MetaSearchDialog(QDialog, BASE_CLASS):
    """main dialogue"""
    def __init__(self, iface):
        """init window"""

        QDialog.__init__(self)
        self.setupUi(self)

        self.iface = iface
        self.map = iface.mapCanvas()
        self.settings = QgsSettings()
        self.catalog = None
        self.catalog_url = None
        self.catalog_username = None
        self.catalog_password = None
        self.context = StaticContext()

        version = self.context.metadata.get('general', 'version')
        self.setWindowTitle(self.tr('MetaSearch {0}').format(version))

        self.rubber_band = QgsRubberBand(self.map, True)  # True = a polygon
        self.rubber_band.setColor(QColor(255, 0, 0, 75))
        self.rubber_band.setWidth(5)

        # form inputs
        self.startfrom = 0
        self.maxrecords = 10
        self.timeout = 10
        self.constraints = []

        # Servers tab
        self.cmbConnectionsServices.activated.connect(self.save_connection)
        self.cmbConnectionsSearch.activated.connect(self.save_connection)
        self.btnServerInfo.clicked.connect(self.connection_info)
        self.btnAddDefault.clicked.connect(self.add_default_connections)
        self.btnCapabilities.clicked.connect(self.show_xml)
        self.tabWidget.currentChanged.connect(self.populate_connection_list)

        # server management buttons
        self.btnNew.clicked.connect(self.add_connection)
        self.btnEdit.clicked.connect(self.edit_connection)
        self.btnDelete.clicked.connect(self.delete_connection)
        self.btnLoad.clicked.connect(self.load_connections)
        self.btnSave.clicked.connect(save_connections)

        # Search tab
        self.treeRecords.itemSelectionChanged.connect(self.record_clicked)
        self.treeRecords.itemDoubleClicked.connect(self.show_metadata)
        self.btnSearch.clicked.connect(self.search)
        self.leKeywords.returnPressed.connect(self.search)
        # prevent dialog from closing upon pressing enter
        self.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False)
        # launch help from button
        self.buttonBox.helpRequested.connect(self.help)
        self.btnCanvasBbox.setAutoDefault(False)
        self.btnCanvasBbox.clicked.connect(self.set_bbox_from_map)
        self.btnGlobalBbox.clicked.connect(self.set_bbox_global)

        # navigation buttons
        self.btnFirst.clicked.connect(self.navigate)
        self.btnPrev.clicked.connect(self.navigate)
        self.btnNext.clicked.connect(self.navigate)
        self.btnLast.clicked.connect(self.navigate)

        self.mActionAddWms.triggered.connect(self.add_to_ows)
        self.mActionAddWfs.triggered.connect(self.add_to_ows)
        self.mActionAddWcs.triggered.connect(self.add_to_ows)
        self.btnShowXml.clicked.connect(self.show_xml)

        # settings
        self.radioTitleAsk.clicked.connect(self.set_ows_save_title_ask)
        self.radioTitleNoAsk.clicked.connect(self.set_ows_save_title_no_ask)
        self.radioTempName.clicked.connect(self.set_ows_save_temp_name)

        self.manageGui()

    def manageGui(self):
        """open window"""

        self.tabWidget.setCurrentIndex(0)
        self.populate_connection_list()
        self.btnCapabilities.setEnabled(False)
        self.spnRecords.setValue(
            int(self.settings.value('/MetaSearch/returnRecords', 10)))

        key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText()
        self.catalog_url = self.settings.value('%s/url' % key)
        self.catalog_username = self.settings.value('%s/username' % key)
        self.catalog_password = self.settings.value('%s/password' % key)

        self.set_bbox_global()

        self.reset_buttons()

        # get preferred connection save strategy from settings and set it
        save_strategy = self.settings.value('/MetaSearch/ows_save_strategy',
                                            'title_ask')
        if save_strategy == 'temp_name':
            self.radioTempName.setChecked(True)
        elif save_strategy == 'title_no_ask':
            self.radioTitleNoAsk.setChecked(True)
        else:
            self.radioTitleAsk.setChecked(True)

        # install proxy handler if specified in QGIS settings
        self.install_proxy()

    # Servers tab

    def populate_connection_list(self):
        """populate select box with connections"""

        self.settings.beginGroup('/MetaSearch/')
        self.cmbConnectionsServices.clear()
        self.cmbConnectionsServices.addItems(self.settings.childGroups())
        self.cmbConnectionsSearch.clear()
        self.cmbConnectionsSearch.addItems(self.settings.childGroups())
        self.settings.endGroup()

        self.set_connection_list_position()

        if self.cmbConnectionsServices.count() == 0:
            # no connections - disable various buttons
            state_disabled = False
            self.btnSave.setEnabled(state_disabled)
            # and start with connection tab open
            self.tabWidget.setCurrentIndex(1)
            # tell the user to add services
            msg = self.tr('No services/connections defined. To get '
                          'started with MetaSearch, create a new '
                          'connection by clicking \'New\' or click '
                          '\'Add default services\'.')
            self.textMetadata.setHtml('<p><h3>%s</h3></p>' % msg)
        else:
            # connections - enable various buttons
            state_disabled = True

        self.btnServerInfo.setEnabled(state_disabled)
        self.btnEdit.setEnabled(state_disabled)
        self.btnDelete.setEnabled(state_disabled)

    def set_connection_list_position(self):
        """set the current index to the selected connection"""
        to_select = self.settings.value('/MetaSearch/selected')
        conn_count = self.cmbConnectionsServices.count()

        if conn_count == 0:
            self.btnDelete.setEnabled(False)
            self.btnServerInfo.setEnabled(False)
            self.btnEdit.setEnabled(False)

        # does to_select exist in cmbConnectionsServices?
        exists = False
        for i in range(conn_count):
            if self.cmbConnectionsServices.itemText(i) == to_select:
                self.cmbConnectionsServices.setCurrentIndex(i)
                self.cmbConnectionsSearch.setCurrentIndex(i)
                exists = True
                break

        # If we couldn't find the stored item, but there are some, default
        # to the last item (this makes some sense when deleting items as it
        # allows the user to repeatidly click on delete to remove a whole
        # lot of items)
        if not exists and conn_count > 0:
            # If to_select is null, then the selected connection wasn't found
            # by QgsSettings, which probably means that this is the first time
            # the user has used CSWClient, so default to the first in the list
            # of connetions. Otherwise default to the last.
            if not to_select:
                current_index = 0
            else:
                current_index = conn_count - 1

            self.cmbConnectionsServices.setCurrentIndex(current_index)
            self.cmbConnectionsSearch.setCurrentIndex(current_index)

    def save_connection(self):
        """save connection"""

        caller = self.sender().objectName()

        if caller == 'cmbConnectionsServices':  # servers tab
            current_text = self.cmbConnectionsServices.currentText()
        elif caller == 'cmbConnectionsSearch':  # search tab
            current_text = self.cmbConnectionsSearch.currentText()

        self.settings.setValue('/MetaSearch/selected', current_text)
        key = '/MetaSearch/%s' % current_text

        if caller == 'cmbConnectionsSearch':  # bind to service in search tab
            self.catalog_url = self.settings.value('%s/url' % key)
            self.catalog_username = self.settings.value('%s/username' % key)
            self.catalog_password = self.settings.value('%s/password' % key)

        if caller == 'cmbConnectionsServices':  # clear server metadata
            self.textMetadata.clear()

        self.btnCapabilities.setEnabled(False)

    def connection_info(self):
        """show connection info"""

        current_text = self.cmbConnectionsServices.currentText()
        key = '/MetaSearch/%s' % current_text
        self.catalog_url = self.settings.value('%s/url' % key)
        self.catalog_username = self.settings.value('%s/username' % key)
        self.catalog_password = self.settings.value('%s/password' % key)

        # connect to the server
        if not self._get_csw():
            return

        QApplication.restoreOverrideCursor()

        if self.catalog:  # display service metadata
            self.btnCapabilities.setEnabled(True)
            metadata = render_template('en', self.context, self.catalog,
                                       'service_metadata.html')
            style = QgsApplication.reportStyleSheet()
            self.textMetadata.clear()
            self.textMetadata.document().setDefaultStyleSheet(style)
            self.textMetadata.setHtml(metadata)

    def add_connection(self):
        """add new service"""

        conn_new = NewConnectionDialog()
        conn_new.setWindowTitle(self.tr('New Catalogue service'))
        if conn_new.exec_() == QDialog.Accepted:  # add to service list
            self.populate_connection_list()
        self.textMetadata.clear()

    def edit_connection(self):
        """modify existing connection"""

        current_text = self.cmbConnectionsServices.currentText()

        url = self.settings.value('/MetaSearch/%s/url' % current_text)

        conn_edit = NewConnectionDialog(current_text)
        conn_edit.setWindowTitle(self.tr('Edit Catalogue service'))
        conn_edit.leName.setText(current_text)
        conn_edit.leURL.setText(url)
        conn_edit.leUsername.setText(
            self.settings.value('/MetaSearch/%s/username' % current_text))
        conn_edit.lePassword.setText(
            self.settings.value('/MetaSearch/%s/password' % current_text))

        if conn_edit.exec_() == QDialog.Accepted:  # update service list
            self.populate_connection_list()

    def delete_connection(self):
        """delete connection"""

        current_text = self.cmbConnectionsServices.currentText()

        key = '/MetaSearch/%s' % current_text

        msg = self.tr('Remove service {0}?').format(current_text)

        result = QMessageBox.information(self, self.tr('Confirm delete'), msg,
                                         QMessageBox.Ok | QMessageBox.Cancel)
        if result == QMessageBox.Ok:  # remove service from list
            self.settings.remove(key)
            index_to_delete = self.cmbConnectionsServices.currentIndex()
            self.cmbConnectionsServices.removeItem(index_to_delete)
            self.cmbConnectionsSearch.removeItem(index_to_delete)
            self.set_connection_list_position()

    def load_connections(self):
        """load services from list"""

        ManageConnectionsDialog(1).exec_()
        self.populate_connection_list()

    def add_default_connections(self):
        """add default connections"""

        filename = os.path.join(self.context.ppath, 'resources',
                                'connections-default.xml')
        doc = get_connections_from_file(self, filename)
        if doc is None:
            return

        self.settings.beginGroup('/MetaSearch/')
        keys = self.settings.childGroups()
        self.settings.endGroup()

        for server in doc.findall('csw'):
            name = server.attrib.get('name')
            # check for duplicates
            if name in keys:
                msg = self.tr('{0} exists.  Overwrite?').format(name)
                res = QMessageBox.warning(self, self.tr('Loading connections'),
                                          msg,
                                          QMessageBox.Yes | QMessageBox.No)
                if res != QMessageBox.Yes:
                    continue

            # no dups detected or overwrite is allowed
            key = '/MetaSearch/%s' % name
            self.settings.setValue('%s/url' % key, server.attrib.get('url'))

        self.populate_connection_list()

    # Settings tab

    def set_ows_save_title_ask(self):
        """save ows save strategy as save ows title, ask if duplicate"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask')

    def set_ows_save_title_no_ask(self):
        """save ows save strategy as save ows title, do NOT ask if duplicate"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask')

    def set_ows_save_temp_name(self):
        """save ows save strategy as save with a temporary name"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name')

    # Search tab

    def set_bbox_from_map(self):
        """set bounding box from map extent"""

        crs = self.map.mapSettings().destinationCrs()
        crsid = int(crs.authid().split(':')[1])

        extent = self.map.extent()

        if crsid != 4326:  # reproject to EPSG:4326
            src = QgsCoordinateReferenceSystem(crsid)
            dest = QgsCoordinateReferenceSystem(4326)
            xform = QgsCoordinateTransform(src, dest)
            minxy = xform.transform(
                QgsPoint(extent.xMinimum(), extent.yMinimum()))
            maxxy = xform.transform(
                QgsPoint(extent.xMaximum(), extent.yMaximum()))
            minx, miny = minxy
            maxx, maxy = maxxy
        else:  # 4326
            minx = extent.xMinimum()
            miny = extent.yMinimum()
            maxx = extent.xMaximum()
            maxy = extent.yMaximum()

        self.leNorth.setText(str(maxy)[0:9])
        self.leSouth.setText(str(miny)[0:9])
        self.leWest.setText(str(minx)[0:9])
        self.leEast.setText(str(maxx)[0:9])

    def set_bbox_global(self):
        """set global bounding box"""
        self.leNorth.setText('90')
        self.leSouth.setText('-90')
        self.leWest.setText('-180')
        self.leEast.setText('180')

    def search(self):
        """execute search"""

        self.catalog = None
        self.constraints = []

        # clear all fields and disable buttons
        self.lblResults.clear()
        self.treeRecords.clear()

        self.reset_buttons()

        # save some settings
        self.settings.setValue('/MetaSearch/returnRecords',
                               self.spnRecords.cleanText())

        # set current catalogue
        current_text = self.cmbConnectionsSearch.currentText()
        key = '/MetaSearch/%s' % current_text
        self.catalog_url = self.settings.value('%s/url' % key)
        self.catalog_username = self.settings.value('%s/username' % key)
        self.catalog_password = self.settings.value('%s/password' % key)

        # start position and number of records to return
        self.startfrom = 0
        self.maxrecords = self.spnRecords.value()

        # set timeout
        self.timeout = self.spnTimeout.value()

        # bbox
        minx = self.leWest.text()
        miny = self.leSouth.text()
        maxx = self.leEast.text()
        maxy = self.leNorth.text()
        bbox = [minx, miny, maxx, maxy]

        # only apply spatial filter if bbox is not global
        # even for a global bbox, if a spatial filter is applied, then
        # the CSW server will skip records without a bbox
        if bbox != ['-180', '-90', '180', '90']:
            self.constraints.append(BBox(bbox))

        # keywords
        if self.leKeywords.text():
            # TODO: handle multiple word searches
            keywords = self.leKeywords.text()
            self.constraints.append(PropertyIsLike('csw:AnyText', keywords))

        if len(self.constraints) > 1:  # exclusive search (a && b)
            self.constraints = [self.constraints]

        # build request
        if not self._get_csw():
            return

        # TODO: allow users to select resources types
        # to find ('service', 'dataset', etc.)
        try:
            self.catalog.getrecords2(constraints=self.constraints,
                                     maxrecords=self.maxrecords,
                                     esn='full')
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Search error'),
                                self.tr('Search error: {0}').format(err))
            return
        except Exception as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Connection error'),
                                self.tr('Connection error: {0}').format(err))
            return

        if self.catalog.results['matches'] == 0:
            QApplication.restoreOverrideCursor()
            self.lblResults.setText(self.tr('0 results'))
            return

        QApplication.restoreOverrideCursor()
        self.display_results()

    def display_results(self):
        """display search results"""

        self.treeRecords.clear()

        position = self.catalog.results['returned'] + self.startfrom

        msg = self.tr('Showing {0} - {1} of %n result(s)', 'number of results',
                      self.catalog.results['matches']).format(
                          self.startfrom + 1, position)

        self.lblResults.setText(msg)

        for rec in self.catalog.records:
            item = QTreeWidgetItem(self.treeRecords)
            if self.catalog.records[rec].type:
                item.setText(0, normalize_text(self.catalog.records[rec].type))
            else:
                item.setText(0, 'unknown')
            if self.catalog.records[rec].title:
                item.setText(1,
                             normalize_text(self.catalog.records[rec].title))
            if self.catalog.records[rec].identifier:
                set_item_data(item, 'identifier',
                              self.catalog.records[rec].identifier)

        self.btnShowXml.setEnabled(True)

        if self.catalog.results["matches"] < self.maxrecords:
            disabled = False
        else:
            disabled = True

        self.btnFirst.setEnabled(disabled)
        self.btnPrev.setEnabled(disabled)
        self.btnNext.setEnabled(disabled)
        self.btnLast.setEnabled(disabled)

    def record_clicked(self):
        """record clicked signal"""

        # disable only service buttons
        self.reset_buttons(True, False, False)

        if not self.treeRecords.selectedItems():
            return

        item = self.treeRecords.currentItem()
        if not item:
            return

        identifier = get_item_data(item, 'identifier')
        try:
            record = self.catalog.records[identifier]
        except KeyError as err:
            QMessageBox.warning(self, self.tr('Record parsing error'),
                                'Unable to locate record identifier')
            return

        # if the record has a bbox, show a footprint on the map
        if record.bbox is not None:
            points = bbox_to_polygon(record.bbox)
            if points is not None:
                src = QgsCoordinateReferenceSystem(4326)
                dst = self.map.mapSettings().destinationCrs()
                geom = QgsGeometry.fromPolygon(points)
                if src.postgisSrid() != dst.postgisSrid():
                    ctr = QgsCoordinateTransform(src, dst)
                    try:
                        geom.transform(ctr)
                    except Exception as err:
                        QMessageBox.warning(
                            self, self.tr('Coordinate Transformation Error'),
                            str(err))
                self.rubber_band.setToGeometry(geom, None)

        # figure out if the data is interactive and can be operated on
        self.find_services(record, item)

    def find_services(self, record, item):
        """scan record for WMS/WMTS|WFS|WCS endpoints"""

        links = record.uris + record.references

        services = {}
        for link in links:

            if 'scheme' in link:
                link_type = link['scheme']
            elif 'protocol' in link:
                link_type = link['protocol']
            else:
                link_type = None

            if link_type is not None:
                link_type = link_type.upper()

            wmswmst_link_types = list(
                map(str.upper, link_types.WMSWMST_LINK_TYPES))
            wfs_link_types = list(map(str.upper, link_types.WFS_LINK_TYPES))
            wcs_link_types = list(map(str.upper, link_types.WCS_LINK_TYPES))

            # if the link type exists, and it is one of the acceptable
            # interactive link types, then set
            if all([
                    link_type is not None, link_type
                    in wmswmst_link_types + wfs_link_types + wcs_link_types
            ]):
                if link_type in wmswmst_link_types:
                    services['wms'] = link['url']
                    self.mActionAddWms.setEnabled(True)
                if link_type in wfs_link_types:
                    services['wfs'] = link['url']
                    self.mActionAddWfs.setEnabled(True)
                if link_type in wcs_link_types:
                    services['wcs'] = link['url']
                    self.mActionAddWcs.setEnabled(True)
                self.tbAddData.setEnabled(True)

            set_item_data(item, 'link', json.dumps(services))

    def navigate(self):
        """manage navigation / paging"""

        caller = self.sender().objectName()

        if caller == 'btnFirst':
            self.startfrom = 0
        elif caller == 'btnLast':
            self.startfrom = self.catalog.results['matches'] - self.maxrecords
        elif caller == 'btnNext':
            self.startfrom += self.maxrecords
            if self.startfrom >= self.catalog.results["matches"]:
                msg = self.tr('End of results. Go to start?')
                res = QMessageBox.information(
                    self, self.tr('Navigation'), msg,
                    (QMessageBox.Ok | QMessageBox.Cancel))
                if res == QMessageBox.Ok:
                    self.startfrom = 0
                else:
                    return
        elif caller == "btnPrev":
            self.startfrom -= self.maxrecords
            if self.startfrom <= 0:
                msg = self.tr('Start of results. Go to end?')
                res = QMessageBox.information(
                    self, self.tr('Navigation'), msg,
                    (QMessageBox.Ok | QMessageBox.Cancel))
                if res == QMessageBox.Ok:
                    self.startfrom = (self.catalog.results['matches'] -
                                      self.maxrecords)
                else:
                    return

        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

        try:
            self.catalog.getrecords2(constraints=self.constraints,
                                     maxrecords=self.maxrecords,
                                     startposition=self.startfrom,
                                     esn='full')
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Search error'),
                                self.tr('Search error: {0}').format(err))
            return
        except Exception as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Connection error'),
                                self.tr('Connection error: {0}').format(err))
            return

        QApplication.restoreOverrideCursor()

        self.display_results()

    def add_to_ows(self):
        """add to OWS provider connection list"""

        conn_name_matches = []

        item = self.treeRecords.currentItem()

        if not item:
            return

        item_data = json.loads(get_item_data(item, 'link'))

        caller = self.sender().objectName()

        # stype = human name,/Qgis/connections-%s,providername
        if caller == 'mActionAddWms':
            stype = ['OGC:WMS/OGC:WMTS', 'wms', 'wms']
            data_url = item_data['wms']
        elif caller == 'mActionAddWfs':
            stype = ['OGC:WFS', 'wfs', 'WFS']
            data_url = item_data['wfs']
        elif caller == 'mActionAddWcs':
            stype = ['OGC:WCS', 'wcs', 'wcs']
            data_url = item_data['wcs']

        QApplication.restoreOverrideCursor()

        sname = '%s from MetaSearch' % stype[1]

        # store connection
        # check if there is a connection with same name
        self.settings.beginGroup('/Qgis/connections-%s' % stype[1])
        keys = self.settings.childGroups()
        self.settings.endGroup()

        for key in keys:
            if key.startswith(sname):
                conn_name_matches.append(key)
        if conn_name_matches:
            sname = conn_name_matches[-1]

        # check for duplicates
        if sname in keys:  # duplicate found
            if self.radioTitleAsk.isChecked():  # ask to overwrite
                msg = self.tr('Connection {0} exists. Overwrite?').format(
                    sname)
                res = QMessageBox.warning(self, self.tr('Saving server'), msg,
                                          QMessageBox.Yes | QMessageBox.No)
                if res != QMessageBox.Yes:  # assign new name with serial
                    sname = serialize_string(sname)
            elif self.radioTitleNoAsk.isChecked():  # don't ask to overwrite
                pass
            elif self.radioTempName.isChecked():  # use temp name
                sname = serialize_string(sname)

        # no dups detected or overwrite is allowed
        self.settings.beginGroup('/Qgis/connections-%s' % stype[1])
        self.settings.setValue('/%s/url' % sname, clean_ows_url(data_url))
        self.settings.endGroup()

        # open provider window
        ows_provider = QgsProviderRegistry.instance().selectWidget(
            stype[2], self)

        service_type = stype[0]

        # connect dialog signals to iface slots
        if service_type == 'OGC:WMS/OGC:WMTS':
            ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
            connect = 'on_btnConnect_clicked'
        elif service_type == 'OGC:WFS':
            ows_provider.addWfsLayer.connect(
                self.iface.mainWindow().addWfsLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
            connect = 'connectToServer'
        elif service_type == 'OGC:WCS':
            ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox')
            connect = 'on_mConnectButton_clicked'
        ows_provider.setModal(False)
        ows_provider.show()

        # open provider dialogue against added OWS
        index = conn_cmb.findText(sname)
        if index > -1:
            conn_cmb.setCurrentIndex(index)
            # only for wfs
            if service_type == 'OGC:WFS':
                ows_provider.on_cmbConnections_activated(index)
        getattr(ows_provider, connect)()

    def show_metadata(self):
        """show record metadata"""

        if not self.treeRecords.selectedItems():
            return

        item = self.treeRecords.currentItem()
        if not item:
            return

        identifier = get_item_data(item, 'identifier')

        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            cat = CatalogueServiceWeb(self.catalog_url,
                                      timeout=self.timeout,
                                      username=self.catalog_username,
                                      password=self.catalog_password)
            cat.getrecordbyid([self.catalog.records[identifier].identifier])
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(
                self, self.tr('GetRecords error'),
                self.tr('Error getting response: {0}').format(err))
            return
        except KeyError as err:
            QMessageBox.warning(self, self.tr('Record parsing error'),
                                self.tr('Unable to locate record identifier'))
            QApplication.restoreOverrideCursor()
            return

        QApplication.restoreOverrideCursor()

        record = cat.records[identifier]
        record.xml_url = cat.request

        crd = RecordDialog()
        metadata = render_template('en', self.context, record,
                                   'record_metadata_dc.html')

        style = QgsApplication.reportStyleSheet()
        crd.textMetadata.document().setDefaultStyleSheet(style)
        crd.textMetadata.setHtml(metadata)
        crd.exec_()

    def show_xml(self):
        """show XML request / response"""

        crd = XMLDialog()
        request_html = highlight_xml(self.context, self.catalog.request)
        response_html = highlight_xml(self.context, self.catalog.response)
        style = QgsApplication.reportStyleSheet()
        crd.txtbrXMLRequest.clear()
        crd.txtbrXMLResponse.clear()
        crd.txtbrXMLRequest.document().setDefaultStyleSheet(style)
        crd.txtbrXMLResponse.document().setDefaultStyleSheet(style)
        crd.txtbrXMLRequest.setHtml(request_html)
        crd.txtbrXMLResponse.setHtml(response_html)
        crd.exec_()

    def reset_buttons(self, services=True, xml=True, navigation=True):
        """Convenience function to disable WMS/WMTS|WFS|WCS buttons"""

        if services:
            self.tbAddData.setEnabled(False)
            self.mActionAddWms.setEnabled(False)
            self.mActionAddWfs.setEnabled(False)
            self.mActionAddWcs.setEnabled(False)

        if xml:
            self.btnShowXml.setEnabled(False)

        if navigation:
            self.btnFirst.setEnabled(False)
            self.btnPrev.setEnabled(False)
            self.btnNext.setEnabled(False)
            self.btnLast.setEnabled(False)

    def help(self):
        """launch help"""

        open_url(get_help_url())

    def reject(self):
        """back out of dialogue"""

        QDialog.reject(self)
        self.rubber_band.reset()

    def _get_csw(self):
        """convenience function to init owslib.csw.CatalogueServiceWeb"""

        # connect to the server
        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            self.catalog = CatalogueServiceWeb(self.catalog_url,
                                               timeout=self.timeout,
                                               username=self.catalog_username,
                                               password=self.catalog_password)
            return True
        except ExceptionReport as err:
            msg = self.tr('Error connecting to service: {0}').format(err)
        except ValueError as err:
            msg = self.tr('Value Error: {0}').format(err)
        except Exception as err:
            msg = self.tr('Unknown Error: {0}').format(err)

        QApplication.restoreOverrideCursor()
        QMessageBox.warning(self, self.tr('CSW Connection error'), msg)
        return False

    def install_proxy(self):
        """set proxy if one is set in QGIS network settings"""

        # initially support HTTP for now
        if self.settings.value('/proxy/proxyEnabled') == 'true':
            if self.settings.value('/proxy/proxyType') == 'HttpProxy':
                ptype = 'http'
            else:
                return

            user = self.settings.value('/proxy/proxyUser')
            password = self.settings.value('/proxy/proxyPassword')
            host = self.settings.value('/proxy/proxyHost')
            port = self.settings.value('/proxy/proxyPort')

            proxy_up = ''
            proxy_port = ''

            if all([user != '', password != '']):
                proxy_up = '%s:%s@' % (user, password)

            if port != '':
                proxy_port = ':%s' % port

            conn = '%s://%s%s%s' % (ptype, proxy_up, host, proxy_port)
            install_opener(build_opener(ProxyHandler({ptype: conn})))
class SimpleIntersectionMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        QgsMapTool.__init__(self, self.mapCanvas)
        self.settings = MySettings()
        self.rubber = QgsRubberBand(self.mapCanvas)

    def deactivate(self):
        self.rubber.reset()
        self.mapCanvas.layersChanged.disconnect(self.updateSnapperList)
        self.mapCanvas.scaleChanged.disconnect(self.updateSnapperList)
        QgsMapTool.deactivate(self)

    def activate(self):
        QgsMapTool.activate(self)
        self.rubber.setWidth(self.settings.value("rubberWidth"))
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.updateSnapperList()
        self.mapCanvas.layersChanged.connect(self.updateSnapperList)
        self.mapCanvas.scaleChanged.connect(self.updateSnapperList)
        self.checkLayer()

    def updateSnapperList(self, dummy=None):
        # make a snapper list of all line and polygons layers
        self.snapperList = []
        scale = self.iface.mapCanvas().mapRenderer().scale()
        for layer in self.mapCanvas.layers():
            if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType():
                if layer.geometryType() in (QGis.Line, QGis.Polygon):
                    if not layer.hasScaleBasedVisibility() or layer.minimumScale() < scale <= layer.maximumScale():
                        snapLayer = QgsSnapper.SnapLayer()
                        snapLayer.mLayer = layer
                        snapLayer.mSnapTo = QgsSnapper.SnapToVertexAndSegment
                        snapLayer.mTolerance = self.settings.value("selectTolerance")
                        if self.settings.value("selectUnits") == "map":
                            snapLayer.mUnitType = QgsTolerance.MapUnits
                        else:
                            snapLayer.mUnitType = QgsTolerance.Pixels
                        self.snapperList.append(snapLayer)

    def canvasMoveEvent(self, mouseEvent):
        # put the observations within tolerance in the rubber band
        self.rubber.reset()
        for f in self.getFeatures(mouseEvent.pos()):
            self.rubber.addGeometry(f.geometry(), None)

    def canvasPressEvent(self, mouseEvent):
        self.rubber.reset()
        pos = mouseEvent.pos()
        features = self.getFeatures(pos)
        nFeat = len(features)
        if nFeat < 2:
            layerNames = " , ".join([feature.layer.name() for feature in features])
            self.iface.messageBar().pushMessage("Intersect It", "You need 2 features to proceed a simple intersection."
                                                " %u given (%s)" % (nFeat, layerNames), QgsMessageBar.WARNING, 3)
            return
        intersectionP = self.intersection(features, pos)
        if intersectionP == QgsPoint(0,0):
            self.iface.messageBar().pushMessage("Intersect It", "Objects do not intersect.", QgsMessageBar.WARNING, 2)
            return

        layer = self.checkLayer()
        if layer is None:
            return
        f = QgsFeature()
        initFields = layer.dataProvider().fields()
        f.setFields(initFields)
        f.initAttributes(initFields.size())
        f.setGeometry(QgsGeometry().fromPoint(intersectionP))
        layer.editBuffer().addFeature(f)
        layer.triggerRepaint()

    def getFeatures(self, pixPoint):
        # do the snapping
        snapper = QgsSnapper(self.mapCanvas.mapRenderer())
        snapper.setSnapLayers(self.snapperList)
        snapper.setSnapMode(QgsSnapper.SnapWithResultsWithinTolerances)
        ok, snappingResults = snapper.snapPoint(pixPoint, [])
        # output snapped features
        features = []
        alreadyGot = []
        for result in snappingResults:
            featureId = result.snappedAtGeometry
            f = QgsFeature()
            if (result.layer.id(), featureId) not in alreadyGot:
                if result.layer.getFeatures(QgsFeatureRequest().setFilterFid(featureId)).nextFeature(f) is False:
                    continue
                if not isFeatureRendered(self.mapCanvas, result.layer, f):
                    continue
                features.append(QgsFeature(f))
                features[-1].layer = result.layer
                alreadyGot.append((result.layer.id(), featureId))
        return features

    def intersection(self, features, pos):
        # try all the combinations
        nFeat = len(features)
        intersections = []
        for i in range(nFeat-1):
            for j in range(i+1,nFeat):
                intersection = features[i].geometry().intersection(features[j].geometry())
                intersectionMP = intersection.asMultiPoint()
                intersectionP = intersection.asPoint()
                if len(intersectionMP) == 0:
                    intersectionMP = intersection.asPolyline()
                if len(intersectionMP) == 0 and intersectionP == QgsPoint(0, 0):
                    continue
                if len(intersectionMP) > 1:
                    mousePoint = self.toMapCoordinates(pos)
                    intersectionP = intersectionMP[0]
                    for point in intersectionMP[1:]:
                        if mousePoint.sqrDist(point) < mousePoint.sqrDist(intersectionP):
                            intersectionP = QgsPoint(point.x(), point.y())
                if intersectionP != QgsPoint(0,0):
                    intersections.append(intersectionP)
        if len(intersections) == 0:
            return QgsPoint(0,0)
        intersectionP = intersections[0]
        for point in intersections[1:]:
            if mousePoint.sqrDist(point) < mousePoint.sqrDist(intersectionP):
                intersectionP = QgsPoint(point.x(), point.y())
        return intersectionP

    def checkLayer(self):
        # check output layer is defined
        layerid = self.settings.value("simpleIntersectionLayer")
        layer = QgsMapLayerRegistry.instance().mapLayer(layerid)
        if not self.settings.value("simpleIntersectionWritePoint") or layer is None:
            self.iface.messageBar().pushMessage("Intersect It",
                                                "You must define an output layer for simple intersections",
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        if not layer.isEditable():
            self.iface.messageBar().pushMessage("Intersect It",
                                                "The output layer <b>%s must be editable</b>" % layer.name(),
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        return layer
Example #16
0
class GeorefRasterBy2PointsMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.firstPoint = None

        self.rubberBandOrigin = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.PointGeometry)
        self.rubberBandOrigin.setColor(Qt.red)
        self.rubberBandOrigin.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubberBandOrigin.setIconSize(7)
        self.rubberBandOrigin.setWidth(2)

        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(2)

        self.isLayerVisible = True

        self.reset()

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.startPoint = self.endPoint = self.firstPoint = None
        self.isEmittingPoint = False
        self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def deactivate(self):
        QgsMapToolEmitPoint.deactivate(self)
        self.reset()

    def canvasPressEvent(self, e):
        if self.firstPoint is None:
            self.startPoint = self.toMapCoordinates(e.pos())
            self.endPoint = self.startPoint
            self.isEmittingPoint = True
            self.originalCenter = self.layer.center
            # this tool do the displacement itself TODO update so it is done by
            # transformed coordinates + new center)
            self.originalCornerPoints = \
                self.layer.transformedCornerCoordinates(
                    *self.layer.transformParameters())

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            self.showDisplacement(self.startPoint, self.endPoint)
            self.layer.history.append({
                "action": "2pointsA",
                "center": self.layer.center
            })
        else:
            self.startPoint = self.toMapCoordinates(e.pos())
            self.endPoint = self.startPoint

            self.startY = e.pos().y()
            self.endY = self.startY
            self.isEmittingPoint = True
            self.height = self.canvas.height()

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.showRotationScale(rotation, xScale, yScale)
            self.layer.history.append({
                "action": "2pointsB",
                "center": self.layer.center,
                "xScale": self.layer.xScale,
                "yScale": self.layer.yScale,
                "rotation": None
            })

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

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        if self.firstPoint is None:
            x = (self.originalCenter.x() + self.endPoint.x() -
                 self.startPoint.x())
            y = (self.originalCenter.y() + self.endPoint.y() -
                 self.startPoint.y())
            self.layer.setCenter(QgsPointXY(x, y))
            self.firstPoint = self.endPoint

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)
            self.layer.repaint()

            self.layer.commitTransformParameters()
        else:
            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.layer.moveCenterFromPointRotate(self.firstPoint, rotation,
                                                 xScale, yScale)
            self.layer.setScale(self.layer.xScale * xScale,
                                self.layer.yScale * yScale)
            val = self.layer.rotation + rotation
            if val > 180:
                val = val - 360
            self.iface.mainWindow().findChild(
                QDoubleSpinBox,
                'FreehandRasterGeoreferencer_spinbox').setValue(val)

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)

            self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
            self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
            self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
            self.rasterShadow.reset()

            self.firstPoint = None
            self.startPoint = self.endPoint = None

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())

        if self.firstPoint is None:
            self.showDisplacement(self.startPoint, self.endPoint)
        else:
            self.endY = e.pos().y()
            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.showRotationScale(rotation, xScale, yScale)

    def computeRotation(self):
        # The angle is the difference between angle
        # horizontal/endPoint-firstPoint and horizontal/startPoint-firstPoint.
        dX0 = self.startPoint.x() - self.firstPoint.x()
        dY0 = self.startPoint.y() - self.firstPoint.y()
        dX = self.endPoint.x() - self.firstPoint.x()
        dY = self.endPoint.y() - self.firstPoint.y()
        return math.degrees(math.atan2(-dY, dX) - math.atan2(-dY0, dX0))

    def computeScale(self):
        # The scale is the ratio between endPoint-firstPoint and
        # startPoint-firstPoint.
        dX0 = self.startPoint.x() - self.firstPoint.x()
        dY0 = self.startPoint.y() - self.firstPoint.y()
        dX = self.endPoint.x() - self.firstPoint.x()
        dY = self.endPoint.y() - self.firstPoint.y()
        return math.sqrt((dX * dX + dY * dY) / (dX0 * dX0 + dY0 * dY0))

    def showRotationScale(self, rotation, xScale, yScale):
        center, _, _, _ = self.layer.transformParameters()
        # newRotation = rotation + originalRotation
        cornerPoints = self.layer.transformedCornerCoordinatesFromPoint(
            self.firstPoint, rotation, xScale, yScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        # Calculate the displacement of the center due to the rotation from
        # another point.
        newCenterDX = (cornerPoints[0].x() +
                       cornerPoints[2].x()) / 2 - center.x()
        newCenterDY = (cornerPoints[0].y() +
                       cornerPoints[2].y()) / 2 - center.y()
        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(newCenterDX, newCenterDY, False)
        self.rasterShadow.setDeltaScale(xScale, yScale, False)
        self.rasterShadow.setDeltaRotation(rotation, True)
        self.rasterShadow.show()

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point0 = QgsPointXY(self.startPoint.x(), self.startPoint.y())
        point1 = QgsPointXY(self.firstPoint.x(), self.firstPoint.y())
        point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y())
        self.rubberBandDisplacement.addPoint(point0, False)
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

    def showDisplacement(self, startPoint, endPoint):
        self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
        self.rubberBandOrigin.addPoint(endPoint, True)
        self.rubberBandOrigin.show()

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(endPoint.x(), endPoint.y())
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in self.originalCornerPoints:
            self._addDisplacementToPoint(self.rubberBandExtent, point, False)
        # for closing
        self._addDisplacementToPoint(self.rubberBandExtent,
                                     self.originalCornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(
            self.endPoint.x() - self.startPoint.x(),
            self.endPoint.y() - self.startPoint.y(), True)
        self.rasterShadow.show()

    def _addDisplacementToPoint(self, rubberBand, point, doUpdate):
        x = point.x() + self.endPoint.x() - self.startPoint.x()
        y = point.y() + self.endPoint.y() - self.startPoint.y()
        self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
Example #17
0
class ShapeTool(QgsMapTool):
    #signal emitted when the mouse is clicked. This indicates that the tool finished its job
    toolFinished = pyqtSignal()
    def __init__(self, canvas, geometryType, param, type, color = QColor( 254, 178, 76, 63 )):
        """
        Constructor
        """
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.active = False
        self.geometryType = self.tr(geometryType)
        self.param=param
        self.type=type       
        self.cursor=None
        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)     
        self.setColor(color)
        self.reset()
        self.rotAngle = 0
        self.currentCentroid = None
        self.rotate = False
    
    def setColor(self, mFillColor):
        """
        Adjusting the color to create the rubber band
        """
    
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(1)
    
    def reset(self):
        """
        Resetting the rubber band
        """
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        try:
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        except:
            pass

    def rotateRect(self, centroid, e):
        """
        Calculates the angle for the rotation.
        """
        item_position = self.canvas.mapToGlobal(e.pos())
        c = self.toCanvasCoordinates(centroid)
        c = self.canvas.mapToGlobal(c)
        rotAngle = pi - atan2(
            item_position.y() - c.y(), item_position.x() - c.x())
        return rotAngle

    def canvasPressEvent(self, e):
        """
        When the canvas is pressed the tool finishes its job
        """
        # enforce mouse restoring if clicked right after rotation 
        QApplication.restoreOverrideCursor()
        self.canvas.unsetMapTool(self)
        self.toolFinished.emit()

    def _baseDistanceInMeters(self):
        """
        Calculates the distance in meters of 2 points 1 unit map away on
        current canvas CRS.
        :return: (float) distance in meters between two points 1 map unit apart
                 from each other.
        """
        source_crs = self.canvas.mapSettings().destinationCrs()
        dest_crs = QgsCoordinateReferenceSystem(3857)
        tr = QgsCoordinateTransform(
            source_crs, dest_crs, QgsCoordinateTransformContext())
        p1t = QgsGeometry().fromPointXY(QgsPointXY(1, 0))
        p1t.transform(tr)
        p2t = QgsGeometry().fromPointXY(QgsPointXY(0, 0))
        p2t.transform(tr)
        return QgsDistanceArea().measureLine(p1t.asPoint(), p2t.asPoint())

    def getAdjustedSize(self, size):
        """
        If map unit is not metric, the figure to be drawn needs to have its
        size adjusted. This is necessary because input parameters are designed
        to be meters on tool's GUI.
        :param size: (float) tool's radius/length reference size in meters.
        :return: (float)  
        """
        source_crs = self.canvas.mapSettings().destinationCrs()
        if source_crs.mapUnits() != QgsUnitTypes.DistanceMeters:
            return size / self._baseDistanceInMeters()
        return size

    def canvasMoveEvent(self, e):
        """
        Deals with mouse move event to update the rubber band position in the canvas
        """
        ctrlIsHeld = QApplication.keyboardModifiers() == Qt2.ControlModifier
        if e.button() != None and not ctrlIsHeld:
            if self.rotate:
                # change rotate status
                self.rotate = False
            QApplication.restoreOverrideCursor()
            self.endPoint = self.toMapCoordinates( e.pos() )
        elif e.button() != None and ctrlIsHeld \
            and self.geometryType == self.tr(u"Square"):
            # calculate angle between mouse and last rubberband centroid before holding control
            self.rotAngle = self.rotateRect(self.currentCentroid, e)
            if not self.rotate:
                # only override mouse if it is not overriden already
                QApplication.setOverrideCursor(QCursor(Qt2.BlankCursor))
                self.rotate = True
        if self.geometryType == self.tr(u"Circle"):
                self.showCircle(self.endPoint)
        elif self.geometryType == self.tr(u"Square"):
            self.showRect(self.endPoint, sqrt(self.param)/2, self.rotAngle)
    
    def showCircle(self, startPoint):
        """
        Draws a circle in the canvas
        """
        nPoints = 50
        x = startPoint.x()
        y = startPoint.y()
        if self.type == self.tr('distance'):
            r = self.getAdjustedSize(self.param)
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
            for itheta in range(nPoints+1):
                theta = itheta*(2.0*pi/nPoints)
                self.rubberBand.addPoint(QgsPointXY(x+r*cos(theta), y+r*sin(theta)))
            self.rubberBand.show()
        else:
            r = self.getAdjustedSize(sqrt(self.param/pi))
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
            for itheta in range(nPoints+1):
                theta = itheta*(2.0*pi/nPoints)
                self.rubberBand.addPoint(QgsPointXY(x+r*cos(theta), y+r*sin(theta)))
            self.rubberBand.show()

    def showRect(self, startPoint, param, rotAngle=0):
        """
        Draws a rectangle in the canvas
        """  
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        x = startPoint.x() # center point x
        y = startPoint.y() # center point y
        # rotation angle is always applied in reference to center point
        # to avoid unnecessary calculations
        c = cos(rotAngle)
        s = sin(rotAngle)
        # translating coordinate system to rubberband centroid
        param = self.getAdjustedSize(param)
        for posx, posy in ((-1, -1), (-1, 1), (1, 1), (1, -1)):
            px = posx * param
            py = posy * param
            pnt = QgsPointXY(px * c - py * s + x, py * c + px * s + y)
            self.rubberBand.addPoint(pnt, False)
        self.rubberBand.setVisible(True)
        self.rubberBand.updateRect()
        self.rubberBand.update()
        self.rubberBand.show()
        self.currentCentroid = startPoint
        
    def deactivate(self):
        """
        Deactivates the tool and hides the rubber band
        """
        self.rubberBand.hide()
        QgsMapTool.deactivate(self)
        # restore mouse in case tool is disabled right after rotation
        QApplication.restoreOverrideCursor()
        
    def activate(self):
        """
        Activates the tool
        """
        QgsMapTool.activate(self)
Example #18
0
class RectangleMapTool(QgsMapToolEmitPoint):

    boxCreated = pyqtSignal(QgsRectangle)

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        #self.rubberBand.setBorderColor(Qt.red)
        self.rubberBand.setBrushStyle(Qt.Dense6Pattern)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.reset()

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

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        r = self.rectangle()
        if r is not None:
            self.boxCreated.emit(r)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

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

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

        return QgsRectangle(self.startPoint, self.endPoint)
Example #19
0
class InfoTool(TouchMapTool):
    infoResults = pyqtSignal(dict)

    def __init__(self, canvas, snapradius = 2):
        super(InfoTool, self).__init__(canvas)
        self.radius = snapradius

        self.band = QgsRubberBand(self.canvas)
        self.band.setColor(QColor.fromRgb(224,162,16))
        self.band.setWidth(3)

        self.selectband = None
        self.selectrect = QRect()
        self.dragging = False
        self.selectionlayers = []

    def getFeatures(self, rect, firstonly=False):
        self.band.reset()
        for layer in self.selectionlayers.itervalues():
            if (not layer.type() == QgsMapLayer.VectorLayer
                or layer.geometryType() == QGis.NoGeometry):
                continue

            rect = self.toLayerCoordinates(layer, rect)
            rq = QgsFeatureRequest().setFilterRect(rect)\
                                    .setFlags(QgsFeatureRequest.ExactIntersect)\
                                    .setSubsetOfAttributes([])
            features = []
            if firstonly:
                try:
                    feature = layer.getFeatures(rq).next()
                    if feature.isValid():
                        features.append(feature)
                except StopIteration:
                    continue
            else:
                for feature in layer.getFeatures(rq):
                    if feature.isValid():
                        features.append(feature)

            yield layer, features

    def toSearchRect(self, point):
        point = self.toMapCoordinates(point)
        rect = QgsRectangle(point.x(), point.y(), point.x() + 10, point.y() + 10)
        return rect

    def canvasPressEvent(self, event):
        if self.pinching:
            return

        self.dragging = False
        self.selectrect.setRect(0, 0, 0, 0)

        self.selectband = QgsRubberBand(self.canvas, QGis.Polygon )
        self.selectband.setColor(QColor.fromRgb(0,0,255, 65))
        self.selectband.setWidth(5)

    def canvasMoveEvent(self, event):
        if self.pinching:
            return

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

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

        maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband)

    def canvasReleaseEvent(self, event):
        if self.pinching:
            return

        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()
            firstonly = False
        else:
            firstonly = True
            rect = self.toSearchRect(event.pos())

        self.dragging = False
        self.selectband.reset()

        results = OrderedDict((l,f) for l, f in self.getFeatures(rect))
        self.infoResults.emit(results)
Example #20
0
class FinderBox(QComboBox):

    running = False
    to_finish = 0

    search_started = pyqtSignal()
    search_finished = pyqtSignal()

    def __init__(self, finders, iface, parent=None):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        self.marker = None
        self.rubber = QgsRubberBand(self.mapCanvas)
        self.rubber.setColor(QColor(255, 255, 50, 200))
        self.rubber.setIcon(self.rubber.ICON_CIRCLE)
        self.rubber.setIconSize(15)
        self.rubber.setWidth(4)
        self.rubber.setBrushStyle(Qt.NoBrush)

        QComboBox.__init__(self, parent)
        self.setEditable(True)
        self.setInsertPolicy(QComboBox.InsertAtTop)
        self.setMinimumHeight(27)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        self.insertSeparator(0)
        self.lineEdit().returnPressed.connect(self.search)

        self.result_view = QTreeView()
        self.result_view.setHeaderHidden(True)
        self.result_view.setMinimumHeight(300)
        self.result_view.activated.connect(self.itemActivated)
        self.result_view.pressed.connect(self.itemPressed)
        self.setView(self.result_view)

        self.result_model = ResultModel(self)
        self.setModel(self.result_model)

        self.finders = finders
        for finder in list(self.finders.values()):
            finder.result_found.connect(self.result_found)
            finder.limit_reached.connect(self.limit_reached)
            finder.finished.connect(self.finished)

        self.clearButton = QPushButton(self)
        self.clearButton.setIcon(
            QIcon(":/plugins/quickfinder/icons/draft.svg"))
        self.clearButton.setText('')
        self.clearButton.setFlat(True)
        self.clearButton.setCursor(QCursor(Qt.ArrowCursor))
        self.clearButton.setStyleSheet('border: 0px; padding: 0px;')
        self.clearButton.clicked.connect(self.clear)

        layout = QHBoxLayout(self)
        self.setLayout(layout)
        layout.addStretch()
        layout.addWidget(self.clearButton)
        layout.addSpacing(20)

        button_size = self.clearButton.sizeHint()
        # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
        padding = button_size.width()  # + frameWidth + 1
        self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' %
                                      padding)

    def __del__(self):
        if self.rubber:
            self.iface.mapCanvas().scene().removeItem(self.rubber)
            del self.rubber

    #clear marker that the lonlat seted
    def clearMarker(self):
        self.mapCanvas.scene().removeItem(self.marker)
        self.marker = None

    def clearSelection(self):
        self.result_model.setSelected(None, self.result_view.palette())
        self.rubber.reset()
        #self.clearMarker()

    def clear(self):
        self.clearSelection()
        self.result_model.clearResults()
        self.lineEdit().setText('')

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.clearSelection()
            self.clearMarker()
        QComboBox.keyPressEvent(self, event)

    def lnglatFinder(self, to_find):
        import re
        m = re.match(r'(?P<lon>-?\d*(.\d+))\s+(?P<lat>-?\d*(.\d+))', to_find)
        if not m:
            return False
        x = float(m.group('lon'))
        y = float(m.group('lat'))
        return self.zoomLnglat(x, y)

    def zoomLnglat(self, lng, lat):
        x, y = lng, lat

        canvas = self.mapCanvas
        currExt = canvas.extent()
        canvasCenter = currExt.center()
        dx = float(x) - canvasCenter.x()
        dy = float(y) - canvasCenter.y()

        xMin = currExt.xMinimum() + dx
        xMax = currExt.xMaximum() + dx
        yMin = currExt.yMinimum() + dy
        yMax = currExt.yMaximum() + dy

        rect = QgsRectangle(xMin, yMin, xMax, yMax)
        canvas.setExtent(rect)
        pt = QgsPointXY(float(x), float(y))
        self.marker = QgsVertexMarker(canvas)
        self.marker.setCenter(pt)
        self.marker.setIconSize(18)
        self.marker.setPenWidth(2)
        self.marker.setIconType(QgsVertexMarker.ICON_CROSS)
        canvas.refresh()
        return True

#    def geocodeFinder(self, to_finder):
#        print(to_finder[:2])
#        if not to_finder[:2] == 'b:':
#            return False
#
#        address = to_finder[2:]
#        url = MySettings().value("baiduUrl")
#        url = url + parse.quote(address)
#
#        response = request.urlopen(url)
#        content = response.read()
#        data = json.loads(content)
#        print(data)
#        lng, lat = (data['result']['location']['lng'], data['result']['location']['lat'])
#        from .cood_trans import bd09_to_wgs84
#        lng, lat = bd09_to_wgs84(lng, lat)
#        print(f'{lng}-{lat}')
#        return self.zoomLnglat(lng, lat)

    def search(self):
        #  self.geocode()
        if self.running:
            return

        to_find = self.lineEdit().text()
        if not to_find or to_find == '':
            return
#        if not (self.lnglatFinder(to_find) or self.geocodeFinder(to_find)):
        if not self.lnglatFinder(to_find):
            self.showPopup()

        self.running = True
        self.search_started.emit()

        self.clearSelection()
        self.result_model.clearResults()
        self.result_model.truncateHistory(MySettings().value("historyLength"))
        self.result_model.setLoading(True)

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

        self.finders_to_start = []
        for finder in list(self.finders.values()):
            if finder.activated():
                self.finders_to_start.append(finder)

        bbox = self.mapCanvas.fullExtent()

        while len(self.finders_to_start) > 0:
            finder = self.finders_to_start[0]
            self.finders_to_start.remove(finder)
            self.result_model.addResult(finder.name)
            finder.start(to_find, bbox=bbox)

        # For case there is no finder activated
        self.finished(None)

    def stop(self):
        self.finders_to_start = []
        for finder in list(self.finders.values()):
            if finder.is_running():
                finder.stop()
        self.finished(None)

    def result_found(self, finder, layername, value, geometry, srid):
        self.result_model.addResult(finder.name, layername, value, geometry,
                                    srid)
        self.result_view.expandAll()

    def limit_reached(self, finder, layername):
        self.result_model.addEllipsys(finder.name, layername)

    def finished(self, finder):
        if len(self.finders_to_start) > 0:
            return
        for finder in list(self.finders.values()):
            if finder.is_running():
                return

        self.running = False
        self.search_finished.emit()

        self.result_model.setLoading(False)

        QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

    def itemActivated(self, index):
        item = self.result_model.itemFromIndex(index)
        self.showItem(item)

    def itemPressed(self, index):
        item = self.result_model.itemFromIndex(index)
        if QApplication.mouseButtons() == Qt.LeftButton:
            self.showItem(item)

    def showItem(self, item):
        if isinstance(item, ResultItem):
            self.result_model.setSelected(item, self.result_view.palette())
            geometry = self.transform_geom(item)
            self.rubber.reset(geometry.type())
            self.rubber.setToGeometry(geometry, None)
            self.zoom_to_rubberband()
            return

        if isinstance(item, GroupItem):
            child = item.child(0)
            if isinstance(child, ResultItem):
                self.result_model.setSelected(item, self.result_view.palette())
                self.rubber.reset(child.geometry.type())
                for i in range(0, item.rowCount()):
                    geometry = self.transform_geom(item.child(i))
                    self.rubber.addGeometry(geometry, None)
                self.zoom_to_rubberband()
            return

        if item.__class__.__name__ == 'QStandardItem':
            self.clearSelection()

    def transform_geom(self, item):
        src_crs = QgsCoordinateReferenceSystem()
        src_crs.createFromSrid(item.srid)
        dest_crs = self.mapCanvas.mapSettings().destinationCrs()
        geom = QgsGeometry(item.geometry)
        geom.transform(
            QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance()))
        return geom

    def zoom_to_rubberband(self):
        geom = self.rubber.asGeometry()
        if geom:
            rect = geom.boundingBox()
            rect.scale(1.5)
            self.mapCanvas.setExtent(rect)
            self.mapCanvas.refresh()
Example #21
0
class RectByFixedExtentTool(QgsMapTool):
    msgbar = pyqtSignal(str)
    rbFinished = pyqtSignal(object)
    rb_reset_signal = pyqtSignal()

    def __init__(self, canvas, x_length, y_length):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.nbPoints = 0
        self.rb = None
        self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3, self.x_p4, self.y_p4 = None, None, None, None, None, None, None, None
        self.distance = QgsDistanceArea()
        self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326),
                                   QgsProject.instance().transformContext())
        self.distance.setEllipsoid('WGS84')
        self.fixed_p2, self.fixed_p3 = QgsPointXY(0, 0), QgsPointXY(0, 0)
        self.length = 0
        self.mCtrl = None
        self.x_length = x_length
        self.y_length = y_length
        self.bearing = 0.0
        # our own fancy cursor
        self.cursor = QCursor(
            QPixmap([
                "16 16 3 1", "      c None", ".     c #FF0000",
                "+     c #1210f3", "                ", "       +.+      ",
                "      ++.++     ", "     +.....+    ", "    +.     .+   ",
                "   +.   .   .+  ", "  +.    .    .+ ", " ++.    .    .++",
                " ... ...+... ...", " ++.    .    .++", "  +.    .    .+ ",
                "   +.   .   .+  ", "   ++.     .+   ", "    ++.....+    ",
                "      ++.++     ", "       +.+      "
            ]))
        self.rectangle = Rectangle()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = True

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = False
        if event.key() == Qt.Key_Escape:
            self.nbPoints = 0
            self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None
            self.fixed_p2, self.fixed_p3 = None, None
            if self.rb:
                self.rb.reset(True)
            self.rb = None

            self.canvas.refresh()
            self.rb_reset_signal.emit()
            return

    def canvasPressEvent(self, event):
        layer = self.canvas.currentLayer()
        if self.nbPoints == 0:
            color = QColor(255, 0, 0, 128)
            if self.rb:
                self.rb.reset()
                self.rb = None
            self.rb = QgsRubberBand(self.canvas, True)
            self.rb.setColor(color)
            self.rb.setWidth(1)
            self.msgbar.emit("Define bearing along track")
            self.rb_reset_signal.emit()

        elif self.nbPoints == 2:
            self.canvas.refresh()

        point = self.toLayerCoordinates(layer, event.pos())
        point_map = self.toMapCoordinates(layer, point)

        if self.nbPoints == 0:
            self.x_p1 = point_map.x()
            self.y_p1 = point_map.y()

        elif self.nbPoints == 1:
            self.x_p2 = point_map.x()
            self.y_p2 = point_map.y()
            self.bearing = self.distance.bearing(
                QgsPointXY(self.x_p1, self.y_p1),
                QgsPointXY(self.x_p2, self.y_p2))
            self.msgbar.emit("Define across track direction")
        else:
            self.x_p3 = point_map.x()
            self.y_p3 = point_map.y()

        self.nbPoints += 1

        if self.nbPoints == 3:
            geom = self.rectangle.get_rect_by3_points(
                QgsPointXY(self.x_p1, self.y_p1), self.fixed_p2, self.fixed_p3,
                self.y_length)
            self.rb.setToGeometry(geom, None)

            self.nbPoints = 0
            self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None
            self.fixed_p2, self.fixed_p3 = None, None
            self.msgbar.emit("")
            self.rbFinished.emit(geom)

        if self.rb: return

    def canvasMoveEvent(self, event):

        if not self.rb: return
        currpoint = self.toMapCoordinates(event.pos())

        if self.nbPoints == 1:
            self.bearing = self.distance.bearing(
                QgsPointXY(self.x_p1, self.y_p1), currpoint)
            self.fixed_p2 = self.distance.computeSpheroidProject(
                QgsPointXY(self.x_p1, self.y_p1), self.x_length, self.bearing)

            self.rb.setToGeometry(
                QgsGeometry.fromPolyline(
                    [QgsPoint(self.x_p1, self.y_p1),
                     QgsPoint(self.fixed_p2)]), None)
            curr_bearing = degrees(self.bearing)
            if curr_bearing < 0.0:
                curr_bearing = 360 + curr_bearing
            self.msgbar.emit(
                "Current distance: {:.3F} m, Current bearing: {:.3F} degrees".
                format(self.x_length, curr_bearing))
        if self.nbPoints >= 2:
            # test if currpoint is left or right of the line defined by p1 and p2
            side = calc_is_collinear(QgsPointXY(self.x_p1, self.y_p1),
                                     self.fixed_p2, currpoint)

            if side == 0:
                return None
            self.fixed_p3 = self.distance.computeSpheroidProject(
                QgsPointXY(self.x_p2, self.y_p2), self.y_length,
                self.bearing + radians(90) * side)

            geom = self.rectangle.get_rect_by3_points(
                QgsPointXY(self.x_p1, self.y_p1), self.fixed_p2, self.fixed_p3,
                self.y_length)
            self.rb.setToGeometry(geom, None)

            curr_bearing = degrees(self.bearing + radians(90) * side)
            if curr_bearing < 0.0:
                curr_bearing = 360 + curr_bearing
            self.msgbar.emit(
                "Current distance: {:.3F} m, Current bearing: {:.3F} degrees".
                format(self.y_length, curr_bearing))

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

    def deactivate(self):
        self.nbPoints = 0
        self.x_p1, self.y_p1, self.x_p2, self.y_p2, self.x_p3, self.y_p3 = None, None, None, None, None, None
        self.fixed_p2, self.fixed_p3 = None, None
        if self.rb:
            self.rb.reset(True)
            self.rb.hide()
        self.rb = None

        self.canvas.refresh()

    def is_zoom_tool(self):
        return False

    def is_transient(self):
        return False

    def is_edit_tool(self):
        return True
Example #22
0
class run(QObject):
    def __init__(self, id, gtotool, config, debug):
        super(run, self).__init__()
        self.debug = debug
        self.gtotool = gtotool
        self.gtomain = gtotool.gtomain
        self.info = gtotool.info
        self.iface = self.gtotool.iface
        self.act = self.sender()
        self.act.setCheckable(True)
        self.sourcefeat = None
        self.rubbers = []
        try:
            # create rubberband
            self.rubber = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry)
            self.rubber.setColor(QColor(Qt.blue))
            self.rubber.setLineStyle(Qt.PenStyle(Qt.DashDotLine))
            self.rubber.setWidth(2)

            # get metadata
            self.sourcelayer = QgsProject.instance().mapLayersByName(config["sourcelayer"])[0]
            self.targetlayer = QgsProject.instance().mapLayersByName(config['targetlayer'])[0]
            self.iface.setActiveLayer(self.targetlayer)
            # start edit
            if not self.targetlayer.isEditable(): self.targetlayer.startEditing()
            if not self.sourcelayer.isEditable(): self.sourcelayer.startEditing()
            # mouse move
            self.canvas = self.iface.mapCanvas()
            self.canvas.xyCoordinates.connect(self.mouse_move)
            # set maptool
            self.mapTool = QgsMapToolIdentifyFeature(self.canvas)
            self.mapTool.setLayer(self.sourcelayer)
            self.canvas.setMapTool(self.mapTool)
            self.mapTool.featureIdentified.connect(self.feature_Identified)
            self.mapTool.deactivated.connect(self.reset_tool)
            self.act.setChecked(True)
        except Exception as e:
            self.info.err(e)

    def mouse_move(self, pointXY):
        try:
            if self.sourcefeat is not None:
                if self.rubber.numberOfVertices() > 1:
                    self.rubber.removeLastPoint()
                self.rubber.addPoint(pointXY)
        except Exception as e:
            self.info.err(e)

    def feature_Identified(self, feature):
        try:
            if self.sourcefeat is None:
                self.sourcefeat = feature
                self.mapTool.setLayer(self.targetlayer)
            else:
                # transform
                geo = self.sourcefeat.geometry()
                sourceCrs = self.sourcelayer.crs()
                destCrs = self.targetlayer.crs()
                tr = QgsCoordinateTransform(sourceCrs, destCrs, QgsProject.instance())
                geo.transform(tr)
                # change geometry
                self.targetlayer.beginEditCommand("New feature")
                self.targetlayer.changeGeometry(feature.id(), geo)
                self.targetlayer.endEditCommand()
                # cleanup
                self.rubber.reset()
                self.iface.mapCanvas().refresh()
                self.mapTool.setLayer(self.sourcelayer)
                self.sourcefeat = None
            print("feature selected : " + str(feature.id()))
        except Exception as e:
            self.info.err(e)

    def reset_tool(self):
        try:
            self.act.setChecked(False)
            self.iface.mapCanvas().scene().removeItem(self.rubber)
        except Exception as e:
            self.info.err(e)
Example #23
0
class DiscoveryPlugin:

    def __init__(self, _iface):
        # Save reference to the QGIS interface
        self.iface = _iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # Variables to facilitate delayed queries and database connection management
        self.db_timer = QTimer()
        self.line_edit_timer = QTimer()
        self.line_edit_timer.setSingleShot(True)
        self.line_edit_timer.timeout.connect(self.reset_line_edit_after_move)
        self.next_query_time = None
        self.last_query_time = time.time()
        self.db_conn = None
        self.search_delay = 0.5  # s
        self.query_sql = ''
        self.query_text = ''
        self.query_dict = {}
        self.db_idle_time = 60.0  # s
        self.display_time = 5000  # ms
        self.bar_info_time = 30  # s

        self.search_results = []
        self.limit_results = 1000
        self.tool_bar = None
        self.search_line_edit = None
        self.completer = None
        self.conn_info = {}

        self.marker = QgsVertexMarker(iface.mapCanvas())
        self.marker.setIconSize(15)
        self.marker.setPenWidth(2)
        self.marker.setColor(QColor(226, 27, 28))  #51,160,44))
        self.marker.setZValue(11)
        self.marker.setVisible(False)
        self.marker2 = QgsVertexMarker(iface.mapCanvas())
        self.marker2.setIconSize(16)
        self.marker2.setPenWidth(4)
        self.marker2.setColor(QColor(255, 255, 255, 200))
        self.marker2.setZValue(10)
        self.marker2.setVisible(False)
        self.is_displayed = False

        self.rubber_band = QgsRubberBand(iface.mapCanvas(), False)
        self.rubber_band.setVisible(False)
        self.rubber_band.setWidth(3)
        self.rubber_band.setStrokeColor(QColor(226, 27, 28))
        self.rubber_band.setFillColor(QColor(226, 27, 28, 63))

    def initGui(self):

        # Create a new toolbar
        self.tool_bar = self.iface.addToolBar('Discovery')
        self.tool_bar.setObjectName('Discovery_Plugin')

        # Create action that will start plugin configuration
        self.action_config = QAction(
             QIcon(os.path.join(self.plugin_dir, "discovery_logo.png")),
             u"Configure Discovery", self.tool_bar)
        self.action_config.triggered.connect(self.show_config_dialog)
        self.tool_bar.addAction(self.action_config)

        # Add combobox for configs
        self.config_combo = QComboBox()
        settings = QgsSettings()
        settings.beginGroup("/Discovery")
        config_list = settings.value("config_list")

        if config_list:
            for conf in config_list:
                self.config_combo.addItem(conf)
        elif settings.childGroups():
            # support for prev version
            key = "Config1"
            config_list = []
            config_list.append(key)
            settings.setValue("config_list", config_list)
            self.config_combo.addItem(key)

            settings.setValue(key + "data_type", settings.value("data_type"))
            settings.setValue(key + "file", settings.value("file"))
            settings.setValue(key + "connection", settings.value("connection"))
            settings.setValue(key + "schema", settings.value("schema"))
            settings.setValue(key + "table", settings.value("table"))
            settings.setValue(key + "search_column", settings.value("search_column"))
            settings.setValue(key + "escape_spec_chars", settings.value("escape_spec_chars"))
            settings.setValue(key + "echo_search_column", settings.value("echo_search_column"))
            settings.setValue(key + "display_columns", settings.value("display_columns"))
            settings.setValue(key + "geom_column", settings.value("geom_column"))
            settings.setValue(key + "scale_expr", settings.value("scale_expr"))
            settings.setValue(key + "bbox_expr", settings.value("bbox_expr"))

            delete_config_from_settings("", settings)
        self.tool_bar.addWidget(self.config_combo)

        # Add search edit box
        self.search_line_edit = QgsFilterLineEdit()
        self.search_line_edit.setPlaceholderText('Search for...')
        self.search_line_edit.setMaximumWidth(768)
        self.tool_bar.addWidget(self.search_line_edit)

        self.config_combo.currentIndexChanged.connect(self.change_configuration)

        # Set up the completer
        self.completer = QCompleter([])  # Initialise with en empty list
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setMaxVisibleItems(1000)
        self.completer.setModelSorting(QCompleter.UnsortedModel)  # Sorting done in PostGIS
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)  # Show all fetched possibilities
        self.completer.activated[QModelIndex].connect(self.on_result_selected)
        self.completer.highlighted[QModelIndex].connect(self.on_result_highlighted)
        self.search_line_edit.setCompleter(self.completer)

        # Connect any signals
        self.search_line_edit.textEdited.connect(self.on_search_text_changed)

        # Search results
        self.search_results = []

        # Set up a timer to periodically perform db queries as required
        self.db_timer.timeout.connect(self.do_db_operations)
        self.db_timer.start(100)

        # Read config
        self.read_config(config_list[0] if config_list else "")

        self.locator_filter = locator_filter.DiscoveryLocatorFilter(self)
        self.iface.registerLocatorFilter(self.locator_filter)

        # Debug
        # import pydevd; pydevd.settrace('localhost', port=5678)

    def unload(self):
        # Stop timer
        self.db_timer.stop()
        # Disconnect any signals
        self.db_timer.timeout.disconnect(self.do_db_operations)
        self.completer.highlighted[QModelIndex].disconnect(self.on_result_highlighted)
        self.completer.activated[QModelIndex].disconnect(self.on_result_selected)
        self.search_line_edit.textEdited.disconnect(self.on_search_text_changed)
        # Remove the new toolbar
        self.tool_bar.clear()  # Clear all actions
        self.iface.mainWindow().removeToolBar(self.tool_bar)

        self.iface.deregisterLocatorFilter(self.locator_filter)
        self.locator_filter = None

    def clear_suggestions(self):
        model = self.completer.model()
        model.setStringList([])

    def on_search_text_changed(self, new_search_text):
        """
        This function is called whenever the user modified the search text

        1. Open a database connection
        2. Make the query
        3. Update the QStringListModel with these results
        4. Store the other details in self.search_results
        """

        self.query_text = new_search_text

        if len(new_search_text) < 3:
            # Clear any previous suggestions in case the user is 'backspacing'
            self.clear_suggestions()
            return

        if self.data_type == "postgres":
            query_text, query_dict = dbutils.get_search_sql(
                new_search_text,
                self.postgisgeomcolumn,
                self.postgissearchcolumn,
                self.echosearchcolumn,
                self.postgisdisplaycolumn,
                self.extra_expr_columns,
                self.postgisschema,
                self.postgistable,
                self.escapespecchars,
                self.limit_results
            )
            self.schedule_search(query_text, query_dict)

        elif self.data_type == "gpkg":
            query_text = (
                new_search_text,
                self.postgissearchcolumn,
                self.echosearchcolumn,
                self.postgisdisplaycolumn.split(","),
                self.extra_expr_columns,
                self.layer,
                self.limit_results
            )
            self.schedule_search(query_text, None)

        elif self.data_type == "mssql":
            query_text = mssql_utils.get_search_sql(
                new_search_text,
                self.postgisgeomcolumn,
                self.postgissearchcolumn,
                self.echosearchcolumn,
                self.postgisdisplaycolumn,
                self.extra_expr_columns,
                self.postgisschema,
                self.postgistable,
                self.limit_results
            )
            self.schedule_search(query_text, None)

    def do_db_operations(self):
        if self.next_query_time is not None and self.next_query_time < time.time():
            # It's time to run a query
            self.next_query_time = None  # Prevent this query from being repeated
            self.last_query_time = time.time()
            self.perform_search()
        else:
            # We're not performing a query, close the db connection if it's been open for > 60s
            if time.time() > self.last_query_time + self.db_idle_time:
                self.db_conn = None

    def perform_search(self):
        db = self.get_db()
        self.search_results = []
        suggestions = []
        if self.data_type == "postgres":
            cur = db.cursor()
            try:
                cur.execute(self.query_sql, self.query_dict)
            except psycopg2.Error as e:
                err_info = "Failed to execute the search query. Please, check your settings. Error message:\n\n"
                err_info += f"{e.pgerror}"
                QMessageBox.critical(None, "Discovery", err_info)
                return
            result_set = cur.fetchall()
        elif self.data_type == "mssql":
            result_set = mssql_utils.execute(db, self.query_sql)
        elif self.data_type == "gpkg":
            result_set = gpkg_utils.search_gpkg(*self.query_sql)

        for row in result_set:
            geom, epsg, suggestion_text = row[0], row[1], row[2]
            extra_data = {}
            for idx, extra_col in enumerate(self.extra_expr_columns):
                extra_data[extra_col] = row[3+idx]
            self.search_results.append((geom, epsg, suggestion_text, extra_data))
            suggestions.append(suggestion_text)
        model = self.completer.model()
        model.setStringList(suggestions)
        self.completer.complete()

    def schedule_search(self, query_text, query_dict):
        # Update the search text and the time after which the query should be executed
        self.query_sql = query_text
        self.query_dict = query_dict
        self.next_query_time = time.time() + self.search_delay

    def show_bar_info(self, info_text):
        """Optional show info bar message with selected result information"""
        self.iface.messageBar().clearWidgets()
        if self.bar_info_time:
            self.iface.messageBar().pushMessage("Discovery", info_text, level=Qgis.Info, duration=self.bar_info_time)

    def on_result_selected(self, result_index):
        # What to do when the user makes a selection
        self.select_result(self.search_results[result_index.row()])

    def select_result(self, result_data):
        geometry_text, src_epsg, suggestion_text, extra_data = result_data
        location_geom = QgsGeometry.fromWkt(geometry_text)
        canvas = self.iface.mapCanvas()
        dst_srid = canvas.mapSettings().destinationCrs().authid()
        transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(src_epsg),
                                           QgsCoordinateReferenceSystem(dst_srid),
                                           canvas.mapSettings().transformContext())
        # Ensure the geometry from the DB is reprojected to the same SRID as the map canvas
        location_geom.transform(transform)
        location_centroid = location_geom.centroid().asPoint()

        # show temporary marker
        if location_geom.type() == QgsWkbTypes.PointGeometry:
            self.show_marker(location_centroid)
        elif location_geom.type() == QgsWkbTypes.LineGeometry or \
            location_geom.type() == QgsWkbTypes.PolygonGeometry:
            self.show_line_rubber_band(location_geom)
        else:
            #unsupported geometry type
            pass

        # Adjust map canvas extent
        zoom_method = 'Move and Zoom'
        if zoom_method == 'Move and Zoom':
            # with higher priority try to use exact bounding box to zoom to features (if provided)
            bbox_str = eval_expression(self.bbox_expr, extra_data)
            rect = bbox_str_to_rectangle(bbox_str)
            if rect is not None:
                # transform the rectangle in case of OTF projection
                rect = transform.transformBoundingBox(rect)
            else:
                # bbox is not available - so let's just use defined scale
                # compute target scale. If the result is 2000 this means the target scale is 1:2000
                rect = location_geom.boundingBox()
                if rect.isEmpty():
                    scale_denom = eval_expression(self.scale_expr, extra_data, default=2000.)
                    rect = canvas.mapSettings().extent()
                    rect.scale(scale_denom / canvas.scale(), location_centroid)
                else:
                    # enlarge geom bbox to have some margin
                    rect.scale(1.2)
            canvas.setExtent(rect)
        elif zoom_method == 'Move':
            current_extent = QgsGeometry.fromRect(self.iface.mapCanvas().extent())
            dx = location_centroid.x() - location_centroid.x()
            dy = location_centroid.y() - location_centroid.y()
            current_extent.translate(dx, dy)
            canvas.setExtent(current_extent.boundingBox())
        canvas.refresh()
        self.line_edit_timer.start(0)
        if self.info_to_clipboard:
            QApplication.clipboard().setText(suggestion_text)
            suggestion_text += ' (copied to clipboard)'
        self.show_bar_info(suggestion_text)

    def on_result_highlighted(self, result_idx):
        self.line_edit_timer.start(0)

    def reset_line_edit_after_move(self):
        self.search_line_edit.setText(self.query_text)

    def get_db(self):
        # Create a new new connection if required
        if self.db_conn is None:
            if self.data_type == "postgres":
                self.db_conn = dbutils.get_connection(self.conn_info)
            elif self.data_type == "mssql":
                self.db_conn = mssql_utils.get_mssql_conn(self.conn_info)
        return self.db_conn

    def change_configuration(self):
        self.search_line_edit.setText("")
        self.line_edit_timer.start(0)
        self.read_config(self.config_combo.currentText())

    def read_config(self, key=""):
        # the following code reads the configuration file which setups the plugin to search in the correct database,
        # table and method

        settings = QgsSettings()
        settings.beginGroup("/Discovery")

        connection = settings.value(key + "connection", "", type=str)
        self.data_type = settings.value(key + "data_type", "", type=str)
        self.file = settings.value(key + "file", "", type=str)
        self.postgisschema = settings.value(key + "schema", "", type=str)
        self.postgistable = settings.value(key + "table", "", type=str)
        self.postgissearchcolumn = settings.value(key + "search_column", "", type=str)
        self.escapespecchars = settings.value(key + "escape_spec_chars", False, type=bool)
        self.echosearchcolumn = settings.value(key + "echo_search_column", True, type=bool)
        self.postgisdisplaycolumn = settings.value(key + "display_columns", "", type=str)
        self.postgisgeomcolumn = settings.value(key + "geom_column", "", type=str)
        if settings.value("marker_time_enabled", True, type=bool):
            self.display_time = settings.value("marker_time", 5000, type=int)
        else:
            self.display_time = -1
        if settings.value("bar_info_time_enabled", True, type=bool):
            self.bar_info_time = settings.value("bar_info_time", 30, type=int)
        else:
             self.bar_info_time = 0
        self.limit_results = settings.value("limit_results", 1000, type=int)
        self.info_to_clipboard = settings.value("info_to_clipboard", True, type=bool)

        scale_expr = settings.value(key + "scale_expr", "", type=str)
        bbox_expr = settings.value(key + "bbox_expr", "", type=str)

        if self.is_displayed:
            self.hide_marker()
            self.hide_rubber_band()
            self.is_displayed = False

        self.make_enabled(False)   # assume the config is invalid first

        self.db_conn = None
        if self.data_type == "postgres":
            self.conn_info = dbutils.get_postgres_conn_info(connection)
            self.layer = None

            if len(connection) == 0 or len(self.postgisschema) == 0 or len(self.postgistable) == 0 or \
                    len(self.postgissearchcolumn) == 0 or len(self.postgisgeomcolumn) == 0:
                return

            if len(self.conn_info) == 0:
                iface.messageBar().pushMessage("Discovery", "The database connection '%s' does not exist!" % connection,
                                               level=Qgis.Critical)
                return
        if self.data_type == "mssql":
            self.conn_info = mssql_utils.get_mssql_conn_info(connection)
            self.layer = None

            if len(connection) == 0 or len(self.postgisschema) == 0 or len(self.postgistable) == 0 or \
                    len(self.postgissearchcolumn) == 0 or len(self.postgisgeomcolumn) == 0:
                return

            if len(self.conn_info) == 0:
                iface.messageBar().pushMessage("Discovery", "The database connection '%s' does not exist!" % connection,
                                               level=Qgis.Critical)
                return
        elif self.data_type == "gpkg":
            self.layer = QgsVectorLayer(self.file + '|layername=' + self.postgistable, self.postgistable, 'ogr')
            self.conn_info = None
        self.extra_expr_columns = []
        self.scale_expr = None
        self.bbox_expr = None

        self.make_enabled(True)

        # optional scale expression when zooming in to results
        if len(scale_expr) != 0:
            expr = QgsExpression(scale_expr)
            if expr.hasParserError():
                iface.messageBar().pushMessage("Discovery", "Invalid scale expression: " + expr.parserErrorString(),
                                               level=Qgis.Warning)
            else:
                self.scale_expr = scale_expr
                self.extra_expr_columns += expr.referencedColumns()

        # optional bbox expression when zooming in to results
        if len(bbox_expr) != 0:
            expr = QgsExpression(bbox_expr)
            if expr.hasParserError():
                iface.messageBar().pushMessage("Discovery", "Invalid bbox expression: " + expr.parserErrorString(),
                                               level=Qgis.Warning)
            else:
                self.bbox_expr = bbox_expr
                self.extra_expr_columns += expr.referencedColumns()

    def show_config_dialog(self):
        dlg = config_dialog.ConfigDialog()
        if (self.config_combo.currentIndex() >= 0):
            dlg.configOptions.setCurrentIndex(self.config_combo.currentIndex())

        if dlg.exec_():
            dlg.write_config()
            self.config_combo.clear()
            for key in [dlg.configOptions.itemText(i) for i in range(dlg.configOptions.count())]:
                self.config_combo.addItem(key)

            self.config_combo.setCurrentIndex(dlg.configOptions.currentIndex())
            self.change_configuration()

    def make_enabled(self, enabled):
        self.search_line_edit.setEnabled(enabled)
        self.search_line_edit.setPlaceholderText("Search for..." if enabled else "Search disabled: check configuration")

    def show_marker(self, point):
        for m in [self.marker, self.marker2]:
            m.setCenter(point)
            m.setOpacity(1.0)
            m.setVisible(True)
        if self.display_time == -1:
            self.is_displayed = True
        else:
            QTimer.singleShot(self.display_time, self.hide_marker)

    def hide_marker(self):
        opacity = self.marker.opacity()
        if opacity > 0.:
            # produce a fade out effect
            opacity -= 0.1
            self.marker.setOpacity(opacity)
            self.marker2.setOpacity(opacity)
            QTimer.singleShot(100, self.hide_marker)
        else:
            self.marker.setVisible(False)
            self.marker2.setVisible(False)

    def show_line_rubber_band(self, geom):
        self.rubber_band.reset(geom.type())
        self.rubber_band.setToGeometry(geom, None)
        self.rubber_band.setVisible(True)
        self.rubber_band.setOpacity(1.0)
        self.rubber_band.show()
        if self.display_time == -1:
            self.is_displayed = True
        else:
            QTimer.singleShot(self.display_time, self.hide_rubber_band)
        pass

    def hide_rubber_band(self):
        opacity = self.rubber_band.opacity()
        if opacity > 0.:
            # produce a fade out effect
            opacity -= 0.1
            self.rubber_band.setOpacity(opacity)
            QTimer.singleShot(100, self.hide_rubber_band)
        else:
            self.rubber_band.setVisible(False)
            self.rubber_band.hide()
Example #24
0
class LineMapTool(QgsMapToolEmitPoint):
    """ Class implements rubberband line tool for polygon division
    """
    def __init__(self, iface):
        """ initialize rubberband line drawing
            :param iface: interface to QGIS
        """
        self.iface = iface
        self.layer = None
        self.canvas = self.iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Line)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.startPoint = None
        self.endPoint = None
        self.reset()

    def reset(self):
        """ reset rubberband line tool to original state
        """
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Line)

    def canvasPressEvent(self, e):
        """ handler to handle left button down, start rubberband line

            :param e: event
        """
        al = self.iface.activeLayer()
        if al is None or al.type() != QgsMapLayer.VectorLayer or \
            al.geometryType() != 2:
            QMessageBox.warning(self.iface.mainWindow(), tr("Warning"),
                                tr("Actual layer contains no polygons"))
            return
        if len(al.selectedFeatures()) != 1:
            QMessageBox.warning(
                self.iface.mainWindow(), tr("Warning"),
                tr("Not a single polygon is selected in active layer"))
            return
        self.layer = al
        self.startPoint = self.toMapCoordinates(e.pos())
        # snap to point on active layer
        line_tolerance = float(QSettings().value(
            "SurveyingCalculation/line_tolerance", config.line_tolerance))
        self.layer.snapPoint(self.startPoint, line_tolerance)
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showLine()

    def canvasReleaseEvent(self, e):
        """ Handler to handle left button up, end rubberband line

            :param e: event
        """
        self.isEmittingPoint = False
        if self.startPoint.x() == self.endPoint.x() or \
            self.startPoint.y() == self.endPoint.y():
            return
        self.divide()

    def canvasMoveEvent(self, e):
        """ handler to handle mouse move event

            :param e: event
        """
        if not self.isEmittingPoint:
            return

        line_tolerance = float(QSettings().value(
            "SurveyingCalculation/line_tolerance", config.line_tolerance))

        self.endPoint = self.toMapCoordinates(e.pos())
        self.layer.snapPoint(self.endPoint, line_tolerance)
        self.showLine()

    def showLine(self):
        """ Draw rubberband line
        """
        self.rubberBand.reset(QGis.Line)
        if self.startPoint.x() == self.endPoint.x() or \
            self.startPoint.y() == self.endPoint.y():
            return
        self.rubberBand.addPoint(self.startPoint, False)
        self.rubberBand.addPoint(self.endPoint, True)
        self.rubberBand.show()

    def deactivate(self):
        """ deactivate line tool
        """
        try:
            self.rubberBand.reset(QGis.Line)  # erase rubberband line
        except:
            pass
        super(LineMapTool, self).deactivate()
        self.emit(SIGNAL("deactivated()"))

    def divide(self):
        """ Divide the selected polygon.

            :param area: area to divide (float)
            :param rotate: rotate/offset True/False (bool)
        """
        selection = self.layer.selectedFeatures()
        if len(selection) != 1:
            QMessageBox.warning(
                self.iface.mainWindow(), tr("Warning"),
                tr("Not a single polygon is selected in active layer"))
            return
        feat = selection[0]  # feature to divide
        geom = feat.geometry()
        if geom is None:
            return
        save_geom = QgsGeometry(geom)  # save original geometry
        # change to layer coordinates
        point1 = self.toLayerCoordinates(
            self.layer, QgsPoint(self.startPoint.x(), self.startPoint.y()))
        point2 = self.toLayerCoordinates(
            self.layer, QgsPoint(self.endPoint.x(), self.endPoint.y()))
        # show coordinates to change
        coord_dlg = CoordDialog(point1, point2)
        if not coord_dlg.exec_():
            return

        point1 = QgsPoint(float(coord_dlg.ui.StartEast.text()), \
                          float(coord_dlg.ui.StartNorth.text()))
        point2 = QgsPoint(float(coord_dlg.ui.EndEast.text()), \
                          float(coord_dlg.ui.EndNorth.text()))
        # center of rotation
        point0 = point1
        rotate = True
        while geom.contains(point1):
            # extend line outside polygon
            point1 = QgsPoint(point1.x() - (point2.x() - point1.x()) * 10, \
                point1.y() - (point2.y() - point1.y()) * 10)
        while geom.contains(point2):
            # extend line outside polygon
            point2 = QgsPoint(point2.x() + (point2.x() - point1.x()) * 10, \
                point2.y() + (point2.y() - point1.y()) * 10)
        geom_line = QgsGeometry.fromPolyline([point1, point2])  # divider
        if not geom.intersects(geom_line):
            if QMessageBox.question(self.iface.mainWindow(), \
                tr("Question"), tr("Line does not intersects polygon, line will be shifted into the polygon. Do you want to continue?"), \
                QMessageBox.Yes, QMessageBox.No) == QMessageBox.No:
                return
            # find an internal point
            if QGis.QGIS_VERSION > '2.4':
                cp = geom.pointOnSurface().vertexAt(0)
            else:
                cp = geom.centroid().vertexAt(0)
            # offset line to go through cp
            dx = point2.x() - point1.x()
            dy = point2.y() - point1.y()
            point0 = QgsPoint(cp.x(), cp.y())
            point1 = QgsPoint(cp.x() - 1000.0 * dx, cp.y() - 1000.0 * dy)
            point2 = QgsPoint(cp.x() + 1000.0 * dx, cp.y() + 1000.0 * dy)
            rotate = False
        # divide polygon
        result, new_geoms, test_points = geom.splitGeometry([point1, point2],
                                                            True)
        if result != 0:
            QMessageBox.warning(self.iface.mainWindow(), tr("Warning"),
                                tr("Area division failed ") + str(result))
            return
        # open modal dialog
        area_dlg = AreaDialog(save_geom.area(), geom.area(), rotate)
        if not area_dlg.exec_():
            return
        area = float(area_dlg.ui.AreaLineEdit.text())
        rotate = area_dlg.ui.OnePointRadio.isChecked()
        if save_geom.area() <= area:
            QMessageBox.warning(
                self.iface.mainWindow(), tr("Warning"),
                tr("Area of polygon is smaller then requested area"))
            return

        area_tolerance = float(QSettings().value(
            "SurveyingCalculation/area_tolerance", config.area_tolerance))
        max_iteration = int(QSettings().value(
            "SurveyingCalculation/max_iteration", config.max_iteration))

        i = 0
        #l = ((point2.x() - point1.x())**2 + (point2.y() - point1.y())**2)**0.5
        while True:
            da = geom.area() - area
            if fabs(da) <= area_tolerance:
                break
                # area OK exit loop
            # length of intersection
            geom_line = QgsGeometry.fromPolyline([point1, point2])
            section = save_geom.intersection(geom_line)
            l = section.length()  # section length
            dir = atan2(point2.x() - point0.x(), point2.y() - point0.y())
            if rotate:  # change line direction
                b = da * 2.0 / l
                dir += atan(b / l)
                point1 = QgsPoint(point0.x() + sin(dir + pi) * 1000.0, \
                    point0.y() + cos(dir + pi) * 1000.0)
                point2 = QgsPoint(point0.x() + sin(dir) * 1000.0, \
                    point0.y() + cos(dir) * 1000.0)
            else:  # offset line
                # perpendicular direction to line
                b = da / l  # approximate offset
                dir += pi / 2.0  # perpendicular dir
                point1 = QgsPoint(point1.x() + sin(dir) * b, \
                    point1.y() + cos(dir) * b)
                point2 = QgsPoint(point2.x() + sin(dir) * b, \
                    point2.y() + cos(dir) * b)
            i += 1
            if i > max_iteration:
                QMessageBox.warning(
                    self.iface.mainWindow(), tr("Warning"),
                    tr("Area division not finished after max iteration") +
                    str(result))
                return
            geom = QgsGeometry(save_geom)  # continue from original geomerty
            while geom.contains(point1):
                # extend line outside polygon
                point1 = QgsPoint(point1.x() - (point2.x() - point1.x()) * 10, \
                    point1.y() - (point2.y() - point1.y()) * 10)
            while geom.contains(point2):
                # extend line outside polygon
                point2 = QgsPoint(point2.x() + (point2.x() - point1.x()) * 10, \
                    point2.y() + (point2.y() - point1.y()) * 10)
            result, new_geoms, test_points = geom.splitGeometry(
                [point1, point2], True)
        # refresh old geometry
        fid = feat.id()
        self.layer.dataProvider().changeGeometryValues({fid: geom})
        # add new feature
        feat_new = QgsFeature()
        fields = self.layer.dataProvider().fields()
        feat_new.setFields(fields, True)
        # combine new_geoms to single geometry
        new_geom = QgsGeometry(new_geoms[0])
        for new_g in new_geoms[1:]:
            new_geom = QgsGeometry(new_geom.combine(new_g))
        feat_new.setGeometry(new_geom)
        self.layer.dataProvider().addFeatures([feat_new])
        # refresh canvas
        self.canvas.refresh()
Example #25
0
class InterpolateTool(QgsMapToolAdvancedDigitizing):
    """
    Map tool class to interpolate an elevation in the middle of a segment
    """
    def __init__(self, iface):
        """
        Constructor
        :param iface: interface
        """
        QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(),
                                              iface.cadDockWidget())
        self.__iface = iface
        self.icon_path = ':/plugins/VDLTools/icons/interpolate_icon.png'
        self.text = QCoreApplication.translate(
            "VDLTools",
            "Interpolate the elevation of a vertex and a point in the middle of a line"
        )
        self.__layer = None
        self.setCursor(Qt.ArrowCursor)
        self.__isEditing = False
        self.__lastFeatureId = None
        self.__layerList = None
        self.__lastLayer = None
        self.__confDlg = None
        self.__mapPoint = None
        self.__rubber = None
        self.__selectedFeature = None
        self.__findVertex = False

    def setTool(self):
        """
        To set the current tool as this one
        """
        self.canvas().setMapTool(self)

    def activate(self):
        """
        When the action is selected
        """
        QgsMapToolAdvancedDigitizing.activate(self)
        self.__updateList()
        self.__rubber = QgsRubberBand(self.canvas(), QGis.Point)
        color = QColor("red")
        color.setAlphaF(0.78)
        self.__rubber.setColor(color)
        self.__rubber.setIcon(4)
        self.__rubber.setWidth(2)
        self.__rubber.setIconSize(20)
        self.canvas().layersChanged.connect(self.__updateList)
        self.canvas().scaleChanged.connect(self.__updateList)
        self.setMode(self.CaptureLine)

    def deactivate(self):
        """
        When the action is deselected
        """
        self.__done()
        self.__cancel()
        self.__rubber = None
        Signal.safelyDisconnect(self.canvas().layersChanged, self.__updateList)
        Signal.safelyDisconnect(self.canvas().scaleChanged, self.__updateList)
        QgsMapToolAdvancedDigitizing.deactivate(self)

    def startEditing(self):
        """
        To set the action as enable, as the layer is editable
        """
        self.action().setEnabled(True)
        Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing)
        self.__layer.editingStopped.connect(self.stopEditing)

    def stopEditing(self):
        """
        To set the action as disable, as the layer is not editable
        """
        self.action().setEnabled(False)
        Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing)
        self.__layer.editingStarted.connect(self.startEditing)
        if self.canvas().mapTool() == self:
            self.__iface.actionPan().trigger()

    def __done(self):
        """
        When the edition is finished
        """
        self.__isEditing = False
        self.__confDlg = None
        self.__mapPoint = None

    def __cancel(self):
        """
        To cancel used variables
        """
        self.__findVertex = False
        if self.__lastLayer is not None:
            self.__lastLayer.removeSelection()
            self.__lastLayer = None
        if self.__rubber is not None:
            self.__rubber.reset()
        self.__lastFeatureId = None
        self.__selectedFeature = None

    def __removeLayer(self):
        """
        To remove the current working layer
        """
        if self.__layer is not None:
            if self.__layer.isEditable():
                Signal.safelyDisconnect(self.__layer.editingStopped,
                                        self.stopEditing)
            else:
                Signal.safelyDisconnect(self.__layer.editingStarted,
                                        self.startEditing)
            self.__layer = None

    def setEnable(self, layer):
        """
        To check if we can enable the action for the selected layer
        :param layer: selected layer
        """
        if layer is not None and layer.type(
        ) == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point:
            if layer == self.__layer:
                return

            if self.__layer is not None:
                if self.__layer.isEditable():
                    Signal.safelyDisconnect(self.__layer.editingStopped,
                                            self.stopEditing)
                else:
                    Signal.safelyDisconnect(self.__layer.editingStarted,
                                            self.startEditing)
            self.__layer = layer
            if self.__layer.isEditable():
                self.action().setEnabled(True)
                self.__layer.editingStopped.connect(self.stopEditing)
            else:
                self.action().setEnabled(False)
                self.__layer.editingStarted.connect(self.startEditing)
                if self.canvas().mapTool() == self:
                    self.__iface.actionPan().trigger()
            return
        if self.canvas().mapTool() == self:
            self.__iface.actionPan().trigger()
        self.action().setEnabled(False)
        self.__removeLayer()

    def __updateList(self):
        """
        To update the line layers list that we can use for interpolation
        """
        self.__layerList = []
        for layer in self.canvas().layers():
            if layer.type() == QgsMapLayer.VectorLayer and layer.hasGeometryType() \
                    and layer.geometryType() == QGis.Line:
                self.__layerList.append(
                    QgsSnappingUtils.LayerConfig(layer, QgsPointLocator.All,
                                                 10, QgsTolerance.Pixels))

    def keyReleaseEvent(self, event):
        """
        When keyboard is pressed
        :param event: keyboard event
        """
        if event.key() == Qt.Key_Escape:
            self.__done()
            self.__cancel()

    def cadCanvasMoveEvent(self, event):
        """
        When the mouse is moved
        :param event: mouse event
        """

        if type(event) == QMoveEvent:
            map_point = self.toMapCoordinates(event.pos())
        else:
            map_point = event.mapPoint()

        if not self.__isEditing and not self.__findVertex and self.__layerList is not None:
            f_l = Finder.findClosestFeatureAt(map_point, self.canvas(),
                                              self.__layerList)

            if f_l is not None and self.__lastFeatureId != f_l[0].id():
                f = f_l[0]
                self.__lastFeatureId = f.id()
                if self.__lastLayer is not None:
                    self.__lastLayer.removeSelection()
                self.__lastLayer = f_l[1]
                self.__lastLayer.setSelectedFeatures([f.id()])
            if f_l is None and self.__lastLayer is not None:
                self.__lastLayer.removeSelection()
                self.__lastFeatureId = None
        elif self.__findVertex:
            self.__rubber.reset()
            snap_layers = Finder.getLayersSettings(self.canvas(),
                                                   [QGis.Line, QGis.Polygon],
                                                   QgsPointLocator.All)
            match = Finder.snap(map_point, self.canvas(), snap_layers)
            if match.hasVertex() or match.hasEdge():
                point = match.point()
                if match.hasVertex():
                    if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \
                            and match.layer().id() == self.__lastLayer.id():
                        self.__rubber.setIcon(4)
                        self.__rubber.setToGeometry(
                            QgsGeometry().fromPoint(point), None)
                    else:
                        intersection = Finder.snapCurvedIntersections(
                            point, self.canvas(), self,
                            self.__selectedFeature.id())
                        if intersection is not None:
                            self.__rubber.setIcon(1)
                            self.__rubber.setToGeometry(
                                QgsGeometry().fromPoint(intersection), None)
                if match.hasEdge():
                    intersection = Finder.snapCurvedIntersections(
                        point, self.canvas(), self,
                        self.__selectedFeature.id())
                    if intersection is not None:
                        self.__rubber.setIcon(1)
                        self.__rubber.setToGeometry(
                            QgsGeometry().fromPoint(intersection), None)
                    elif self.__selectedFeature.id() == match.featureId() \
                            and match.layer().id() == self.__lastLayer.id():
                        self.__rubber.setIcon(3)
                        self.__rubber.setToGeometry(
                            QgsGeometry().fromPoint(point), None)

    def cadCanvasReleaseEvent(self, event):
        """
        When the mouse is clicked
        :param event: mouse event
        """
        if self.__lastLayer is not None and not self.__findVertex:
            found_features = self.__lastLayer.selectedFeatures()
            if len(found_features) > 0:
                if len(found_features) > 1:
                    self.__iface.messageBar().pushMessage(
                        QCoreApplication.translate("VDLTools",
                                                   "One feature at a time"),
                        level=QgsMessageBar.INFO)
                    return
                self.__selectedFeature = found_features[0]

                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate(
                        "VDLTools",
                        "Select the position for interpolation (ESC to undo)"),
                    level=QgsMessageBar.INFO,
                    duration=3)
                self.setMode(self.CaptureNone)
                self.__findVertex = True
        elif self.__findVertex:
            self.__rubber.reset()
            snap_layers = Finder.getLayersSettings(self.canvas(),
                                                   [QGis.Line, QGis.Polygon],
                                                   QgsPointLocator.All)
            match = Finder.snap(event.mapPoint(), self.canvas(), snap_layers)
            if match.hasVertex() or match.hasEdge():
                point = match.point()
                ok = False
                noVertex = False
                if match.hasVertex():
                    if match.layer() is not None and self.__selectedFeature.id() == match.featureId() \
                            and match.layer().id() == self.__lastLayer.id():

                        ok = True
                        noVertex = True
                    else:
                        intersection = Finder.snapCurvedIntersections(
                            point, self.canvas(), self,
                            self.__selectedFeature.id())
                        if intersection is not None:
                            point = intersection
                            ok = True
                if match.hasEdge():
                    intersection = Finder.snapCurvedIntersections(
                        point, self.canvas(), self,
                        self.__selectedFeature.id())
                    if intersection is not None:
                        point = intersection
                        ok = True
                    elif self.__selectedFeature.id() == match.featureId() \
                            and match.layer().id() == self.__lastLayer.id():
                        ok = True
                if ok:
                    self.__isEditing = True
                    self.__findVertex = False
                    self.__mapPoint = point
                    if noVertex:
                        self.__ok(False, True)
                    else:
                        self.__confDlg = InterpolateConfirmDialog()
                        if self.__lastLayer.isEditable():
                            self.__confDlg.setMainLabel(
                                QCoreApplication.translate(
                                    "VDLTools", "What do you want to do ?"))
                            self.__confDlg.setAllLabel(
                                QCoreApplication.translate(
                                    "VDLTools", "Create point and new vertex"))
                            self.__confDlg.setVtLabel(
                                QCoreApplication.translate(
                                    "VDLTools", "Create only the vertex"))
                        self.__confDlg.rejected.connect(self.__done)
                        self.__confDlg.okButton().clicked.connect(
                            self.__onConfirmOk)
                        self.__confDlg.cancelButton().clicked.connect(
                            self.__onConfirmCancel)
                        self.__confDlg.show()
            else:
                self.__done()
                self.__cancel()

    def __onConfirmCancel(self):
        """
        When the Cancel button in Interpolate Confirm Dialog is pushed
        """
        self.__confDlg.reject()

    def __onConfirmOk(self):
        """
        When the Ok button in Interpolate Confirm Dialog is pushed
        """
        checkedId = self.__confDlg.getCheckedId()
        self.__confDlg.accept()

        withVertex = True
        withPoint = True
        if checkedId == 1:
            withVertex = False
        else:
            if not self.__lastLayer.isEditable():
                self.__lastLayer.startEditing()
        if checkedId == 2:
            withPoint = False

        self.__ok(withVertex, withPoint)

    def __ok(self, withVertex, withPoint):
        """
        To realize the interpolation
        :param withVertex: if we want a new interpolated vertex
        :param withPoint: if we want a new interpolated point
        """
        line_v2, curved = GeometryV2.asLineV2(
            self.__selectedFeature.geometry(), self.__iface)
        vertex_v2 = QgsPointV2()
        vertex_id = QgsVertexId()
        line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2,
                               vertex_id, 0)

        x0 = line_v2.xAt(vertex_id.vertex - 1)
        y0 = line_v2.yAt(vertex_id.vertex - 1)
        d0 = Finder.sqrDistForCoords(x0, vertex_v2.x(), y0, vertex_v2.y())
        x1 = line_v2.xAt(vertex_id.vertex)
        y1 = line_v2.yAt(vertex_id.vertex)
        d1 = Finder.sqrDistForCoords(x1, vertex_v2.x(), y1, vertex_v2.y())
        z0 = line_v2.zAt(vertex_id.vertex - 1)
        z1 = line_v2.zAt(vertex_id.vertex)
        vertex_v2.addZValue(old_div((d0 * z1 + d1 * z0), (d0 + d1)))

        if withPoint:
            pt_feat = QgsFeature(self.__layer.pendingFields())
            pt_feat.setGeometry(QgsGeometry(vertex_v2))
            for i in range(len(self.__layer.pendingFields())):
                # default = self.__layer.defaultValue(i, pt_feat)
                # if default is not None:
                #     print(pt_feat.fields().at(i).name(), pt_feat.fields().at(i).defaultValueExpression(), default)
                #     print(self.__layer.defaultValueExpression(i), self.__layer.expressionField(i))

                e = QgsExpression(self.__layer.defaultValueExpression(i))
                default = e.evaluate(pt_feat)
                pt_feat.setAttribute(i, default)

            if self.__layer.editFormConfig().suppress(
            ) == QgsEditFormConfig.SuppressOn:
                self.__layer.addFeature(pt_feat)
            else:
                self.__iface.openFeatureForm(self.__layer, pt_feat)

        if withVertex:
            line_v2.insertVertex(vertex_id, vertex_v2)
            self.__lastLayer.changeGeometry(self.__selectedFeature.id(),
                                            QgsGeometry(line_v2))

            found_features = self.__lastLayer.selectedFeatures()
            if len(found_features) > 0:
                if len(found_features) > 1:
                    self.__iface.messageBar().pushMessage(
                        QCoreApplication.translate("VDLTools",
                                                   "One feature at a time"),
                        level=QgsMessageBar.INFO)
                else:
                    self.__selectedFeature = found_features[0]
            else:
                self.__iface.messageBar().pushMessage(
                    QCoreApplication.translate("VDLTools",
                                               "No more feature selected"),
                    level=QgsMessageBar.INFO)

        self.__iface.mapCanvas().refresh()

        self.__done()
        self.__findVertex = True
Example #26
0
class AttributePainterClass:
    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # Source feature rubberband definition
        colorSource = QColor(250, 0, 0, 200)
        self.sourceEvid = QgsRubberBand(self.canvas)
        self.sourceEvid.setColor(colorSource)
        self.sourceEvid.setWidth(3)

        self.dock = attributePainterDialog(self.iface)

        #connect signals
        self.dock.layerCombo.currentIndexChanged.connect(
            self.layerComboChanged)
        self.dock.attributeCombo.currentIndexChanged.connect(
            self.attributeComboChanged)
        self.dock.labelCombo.currentIndexChanged.connect(
            self.labelComboChanged)

        self.dock.paintingButton.clicked.connect(self.startPainting)
        self.dock.saveButton.clicked.connect(self.startPainting)

        #plugin state
        self.pluginIsActive = False
        #painting state
        self.painting = False

    def initGui(self):
        # Create action that will show plugin widget
        self.action = QAction(
            QIcon(os.path.join(self.plugin_dir, "icons/select2.png")),
            # the following does not seem to work anymore, maybe since PyQt5?!
            #QIcon(':/plugins/LayerFeatureLabeler/icons/select.png'),
            u"LayerFeatureLabeler",
            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"&VectorLayerTool", self.action)

        #creating dock view intance
        # self.dock = attributePainterDialog(self.iface)
        self.dockwidget = QDockWidget("Layer Feature Labeler",
                                      self.iface.mainWindow())
        self.dockwidget.setObjectName("Layer Feature Labeler")
        self.dockwidget.setWidget(self.dock)
        self.layerHighlighted = None
        self.sourceFeat = None

        # here the map tool is choosen
        self.sourceMapTool = IdentifyGeometry(self.canvas, pickMode='active')
        self.destinationMapTool = IdentifyGeometry(self.canvas,
                                                   pickMode='active')

    def run(self):
        # show the dockwidget

        # self.loadProjectFile()
        self.initLayerCombo()

        self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)

        self.dockwidget.setWindowTitle('Layer Feature Labeler')
        self.dockwidget.show()

        self.pluginIsActive = True

        #QgsMapLayerRegistry.instance().legendLayersAdded.connect(self.initLayerCombo)

        #QGIS2:
        if version == 2:
            QgsMapLayerRegistry.instance().layersRemoved.connect(
                self.initLayerCombo)
            QgsMapLayerRegistry.instance().layersAdded.connect(
                self.initLayerCombo)
        elif version == 3:
            QgsProject.instance().layersRemoved.connect(self.initLayerCombo)
            QgsProject.instance().layersAdded.connect(self.initLayerCombo)
        else:
            print('only QGIS 2 and QGIS 3 is supported')

        self.dock.closingPlugin.connect(self.onClosePlugin)

    def onClosePlugin(self):
        print("closing plugin")

        # deactivate painting
        if self.painting == True:
            self.iface.mainWindow().findChild(
                QAction, 'mActionToggleEditing').trigger()
            self.painting == False

        self.dock.closingPlugin.disconnect(self.onClosePlugin)

    def loadProjectFile(self):

        # open the QGIS project file
        scenario_open = False
        scenario_file = os.path.join(os.path.dirname(__file__), 'data',
                                     'project.qgs')

        # check if file exists
        if os.path.isfile(scenario_file):
            self.iface.addProject(scenario_file)
            scenario_open = True
        else:
            last_dir = uf.getLastDir("PlanningToolClass")
            new_file = QtWidgets.QFileDialog.getOpenFileName(
                self, "", last_dir, "(*.qgs)")
            if new_file:
                self.iface.addProject(unicode(new_file))
                scenario_open = True

    def layerComboChanged(self):

        if self.painting == True:
            self.startPainting(
            )  # which in fact means quit painting, when the layer is changed

        text = str(self.dock.layerCombo.currentText())

        try:  #this fails if plugin is opened without a layer
            if version == 2:
                self.activeLayer = QgsMapLayerRegistry.instance(
                ).mapLayersByName(text)[
                    0]  # 0 element because it returns a list
            elif version == 3:
                self.activeLayer = QgsProject.instance().mapLayersByName(
                    text)[0]
        except:
            return

        self.iface.setActiveLayer(self.activeLayer)
        # set the columns (=attributes) of the current layer to the attribute combo box
        self.initAttributeCombo(self.activeLayer)

    def attributeComboChanged(self):
        activeAttribute = str(self.dock.attributeCombo.currentText())
        self.activeAttributeID = uf.getFieldIndex(self.activeLayer,
                                                  activeAttribute)
        self.applyStyle()

    def labelComboChanged(self):
        self.activeLabel = str(self.dock.labelCombo.currentText())

    def initLayerCombo(self):

        try:
            self.dock.layerCombo.currentIndexChanged.disconnect(
                self.layerComboChanged)
        except:
            pass

        layerList = []
        #QGIS2
        if version == 2:
            layerList = [
                layer.name() for layer in
                QgsMapLayerRegistry.instance().mapLayers().values()
            ]
        elif version == 3:
            layerList = [
                layer.name()
                for layer in list(QgsProject.instance().mapLayers().values())
            ]
        else:
            print('unkown QGIS version')

        self.dock.layerCombo.clear()
        layerList.insert(0, '')
        self.dock.layerCombo.addItems(layerList)

        #set the currently selected layer (for the first time)
        self.layerComboChanged()

        self.dock.layerCombo.currentIndexChanged.connect(
            self.layerComboChanged)

    def initAttributeCombo(self, layer):

        stringFieldNames = []
        stringFieldIDs = []
        fields = layer.fields()
        for field in fields:
            if field.typeName() == 'String':
                stringFieldNames.append(field.name())
                stringFieldIDs.append(fields.indexFromName(field.name()))

        # init label combo
        # do this first so the self.valColTuple is initialised
        self.initLabelCombo(layer, stringFieldIDs)

        #fieldList = uf.getFieldNames(layer)
        self.dock.attributeCombo.clear()
        stringFieldNames.insert(0, '')
        self.dock.attributeCombo.addItems(stringFieldNames)

        #set the currently selected attribute (for the first time)
        self.attributeComboChanged()

    def initLabelCombo(self, layer, ids):

        values = []
        for item in ids:
            uvals = layer.uniqueValues(item)
            # I don't want a list of lists but a flat list, that's why I'm doing this
            for val in uvals:
                if type(val) is unicode:
                    if uf.isNumeric(val) == False:
                        if any(char.isdigit() for char in val) == False:
                            values.append(val)
        values = sorted(set(values))

        ## initialize color list
        self.initColors(values)

        self.dock.labelCombo.clear()
        # self.dock.labelCombo.addItems(values)

        for i, item in enumerate(self.valColTuple):
            pixmap = QPixmap(16, 16)
            pixmap.fill(item[1])
            # self.dock.labelCombo.addItem(item[0])
            self.dock.labelCombo.insertItem(i, QIcon(pixmap), item[0])

        #set the currently selected label (for the first time)
        self.labelComboChanged()

    #### EDITING ####
    def startPainting(self):

        # deactivate painting
        if self.painting == True:
            self.painting = False
            self.activeLayer.selectionChanged.disconnect(self.applyLabel)
            self.dock.paintingButton.setChecked(False)
            self.iface.actionPan().trigger()
            layer = self.canvas.currentLayer()
            layer.removeSelection()
        #activate painting
        else:
            self.painting = True
            self.activeLayer.selectionChanged.connect(self.applyLabel)
            self.dock.paintingButton.setChecked(True)
            self.iface.actionSelect().trigger()

        self.iface.mainWindow().findChild(QAction,
                                          'mActionToggleEditing').trigger()

        #unfortunately this does not work:
        # TODO: actually I can use layer.startEditing in the if, and layer.commitChanges in the else statement
        # self.iface.mainWindow().findChild(QAction, 'mActionToggleEditing').activate(True)
        # self.iface.actionSelect().activate(True)

    def applyLabel(self):

        features = self.activeLayer.selectedFeatures()

        for feature in features:
            self.activeLayer.changeAttributeValue(feature.id(),
                                                  self.activeAttributeID,
                                                  self.activeLabel)
            # self.apply_style(feature)
            # self.apply_style(feature)

    #### STYLING ####
    def initColors(self, values):

        self.valColTuple = []
        for i, val in enumerate(values):
            r = random.randrange(0, 256, 1)
            g = random.randrange(0, 256, 1)
            b = random.randrange(0, 256, 1)
            self.valColTuple.append((val, QColor(r, g, b)))

    def applyStyle(self):

        #get currently active layer
        layer = self.activeLayer

        #for every possible value (=all the non-numeric values in the layer), set a color from the valColTuple
        categories = []
        for i, attribute in enumerate(self.valColTuple):
            if version == 2:
                symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
                symbol.setColor(attribute[1])
                category = QgsRendererCategoryV2(attribute[0], symbol,
                                                 attribute[0])
            elif version == 3:
                symbol = QgsSymbol.defaultSymbol(layer.geometryType())
                # symbol = QgsSymbol.defaultSymbol(feature.geometry().type())
                symbol.setColor(attribute[1])
                category = QgsRendererCategory(attribute[0], symbol,
                                               attribute[0])
            else:
                print('only QGIS 2 and QGIS 3 is supported')
            categories.append(category)

        # Apply the colors to the currently selected column
        fieldName = self.dock.attributeCombo.currentText()
        if version == 2:
            renderer = QgsCategorizedSymbolRendererV2(fieldName, categories)
            layer.setRendererV2(renderer)
        elif version == 3:
            renderer = QgsCategorizedSymbolRenderer(fieldName, categories)
            layer.setRenderer(renderer)
        else:
            print('only QGIS 2 and QGIS 3 is supported')

        # Refresh the layer
        layer.triggerRepaint()

    def unload(self):
        '''
        Remove the plugin widget and clear source feature highlight
        '''
        if self.sourceFeat:
            self.sourceEvid.reset()
        self.iface.removeToolBarIcon(self.action)
        self.iface.removeDockWidget(self.dockwidget)
        # self.canvas.mapToolSet.disconnect(self.toggleMapTool)
        # try:
        #     self.iface.legendInterface().currentLayerChanged.disconnect(self.checkOnLayerChange)
        # except:
        #     self.iface.currentLayerChanged.disconnect(self.checkOnLayerChange)
        # self.iface.projectRead.disconnect(self.resetSource)

        if self.pluginIsActive:
            self.onClosePlugin()
class VoGISProfilToolMainDialog(QDialog):
    def __init__(self, interface, settings):

        self.settings = settings
        self.iface = interface
        self.selectingVisibleRasters = False

        QDialog.__init__(self, interface.mainWindow())

        # Set up the user interface from Designer.
        self.ui = Ui_VoGISProfilToolMain()
        self.ui.setupUi(self)

        if self.settings.onlyHektoMode is True:
            self.ui.IDC_widRaster.hide()
            self.adjustSize()

        self.ui.IDC_tbFromX.setText('-30000')
        self.ui.IDC_tbFromY.setText('240000')
        self.ui.IDC_tbToX.setText('-20000')
        self.ui.IDC_tbToY.setText('230000')

        self.__addRastersToGui()

        for lLyr in self.settings.mapData.lines.lines():
            self.ui.IDC_cbLineLayers.addItem(lLyr.name, lLyr)

        if self.settings.mapData.lines.count() < 1:
            self.ui.IDC_rbDigi.setChecked(True)
            self.ui.IDC_rbShapeLine.setEnabled(False)

        #Einstellungen fuer Linie zeichen
        self.action = QAction(
            QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"),
            "VoGIS-Profiltool", self.iface.mainWindow())
        self.action.setWhatsThis("VoGIS-Profiltool")
        self.canvas = self.iface.mapCanvas()
        self.tool = ProfiletoolMapTool(self.canvas, self.action)
        self.savedTool = self.canvas.mapTool()
        self.polygon = False
        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        if QGis.QGIS_VERSION_INT >= 10900:
            #self.rubberband.setBrushStyle()
            self.rubberband.setLineStyle(Qt.SolidLine)
            self.rubberband.setWidth(4.0)
            self.rubberband.setColor(QColor(0, 255, 0))
            #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab
        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None

    def accept(self):
        try:
            #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "ACCEPTED")
            if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count(
            ) > 0:
                self.settings.onlyHektoMode = False

            if self.settings.onlyHektoMode is False:
                if self.settings.mapData.rasters.count() < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", u"Keine Raster vorhanden. Zum Hektometrieren Dialog neu öffnen.")
                    #return
                    retVal = QMessageBox.warning(
                        self.iface.mainWindow(), "VoGIS-Profiltool",
                        QApplication.translate(
                            'code',
                            'Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?',
                            None, QApplication.UnicodeUTF8),
                        QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
                    if retVal == QMessageBox.No:
                        return
                    else:
                        self.settings.onlyHektoMode = True
                        self.settings.createHekto = True

            if self.__getSettingsFromGui() is False:
                return

            if self.settings.onlyHektoMode is False:
                if len(self.settings.mapData.rasters.selectedRasters()) < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "Kein Raster selektiert!")
                    #msg =
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", msg)
                    QMessageBox.warning(
                        self.iface.mainWindow(), "VoGIS-Profiltool",
                        QApplication.translate('code',
                                               'Kein Raster selektiert!', None,
                                               QApplication.UnicodeUTF8))
                    return

            QgsMessageLog.logMessage(
                'modeLine!=line: {0}'.format(
                    self.settings.modeLine != enumModeLine.line), 'VoGis')
            QgsMessageLog.logMessage(
                'customLine is None: {0}'.format(
                    self.settings.mapData.customLine is None), 'VoGis')

            if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None:
                QMessageBox.warning(
                    self.iface.mainWindow(), "VoGIS-Profiltool",
                    QApplication.translate('code',
                                           'Keine Profillinie vorhanden!',
                                           None, QApplication.UnicodeUTF8))
                return

            #self.rubberband.reset(self.polygon)
            #QDialog.accept(self)

            QApplication.setOverrideCursor(Qt.WaitCursor)

            createProf = CreateProfile(self.iface, self.settings)
            profiles = createProf.create()
            QgsMessageLog.logMessage('ProfCnt: ' + str(len(profiles)), 'VoGis')

            if len(profiles) < 1:
                QApplication.restoreOverrideCursor()
                QMessageBox.warning(
                    self.iface.mainWindow(), "VoGIS-Profiltool",
                    QApplication.translate(
                        'code', 'Es konnten keine Profile erstellt werden.',
                        None, QApplication.UnicodeUTF8))
                return

            dlg = VoGISProfilToolPlotDialog(self.iface, self.settings,
                                            profiles)
            dlg.show()
            #result = self.dlg.exec_()
            dlg.exec_()
        except:
            QApplication.restoreOverrideCursor()
            ex = u'{0}'.format(traceback.format_exc())
            msg = 'Unexpected ERROR:\n\n{0}'.format(ex[:2000])
            QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool",
                                 msg)

    def reject(self):
        #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "REJECTED")
        self.rubberband.reset(self.polygon)
        QDialog.reject(self)

    def selectVisibleRasters(self):
        self.refreshRasterList()
        self.selectingVisibleRasters = True
        extCanvas = self.iface.mapCanvas().extent()
        #alle raster in den einstellunge deselektieren
        for r in self.settings.mapData.rasters.rasters():
            r.selected = False
        #alle raster in der ListView deselektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            item.setCheckState(Qt.Unchecked)
        #Raster im Extent selektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            if QGis.QGIS_VERSION_INT < 10900:
                raster = item.data(Qt.UserRole).toPyObject()
            else:
                raster = item.data(Qt.UserRole)
            for r in self.settings.mapData.rasters.rasters():
                if extCanvas.intersects(r.grid.extent()):
                    if r.id == raster.id:
                        r.selected = True
                        item.setCheckState(Qt.Checked)
        self.selectingVisibleRasters = False

    def lineLayerChanged(self, idx):
        if self.ui.IDC_rbShapeLine.isChecked() is False:
            self.ui.IDC_rbShapeLine.setChecked(True)
        if QGis.QGIS_VERSION_INT < 10900:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(
                self.ui.IDC_cbLineLayers.currentIndex()).toPyObject())
        else:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(
                self.ui.IDC_cbLineLayers.currentIndex()))
        lyr = lineLyr.line
        #QgsMessageLog.logMessage('{0}'.format(lyr.selectedFeatureCount()), 'VoGis')
        #QgsMessageLog.logMessage('{0}'.format(dir(lyr)), 'VoGis')
        if hasattr(lyr, 'selectedFeatureCount'):
            if (lyr.selectedFeatureCount() < 1):
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(False)
            else:
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(True)

    def valueChangedEquiDistance(self, val):
        if self.ui.IDC_rbEquiDistance.isChecked() is False:
            self.ui.IDC_rbEquiDistance.setChecked(True)

    def valueChangedVertexCount(self, val):
        if self.ui.IDC_rbVertexCount.isChecked() is False:
            self.ui.IDC_rbVertexCount.setChecked(True)

    def lvRasterItemChanged(self, item):
        if self.selectingVisibleRasters is True: return
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        iData = item.data(Qt.UserRole)
        if QGis.QGIS_VERSION_INT < 10900:
            rl = iData.toPyObject()
        else:
            rl = iData
        self.settings.mapData.rasters.getById(rl.id).selected = selected

    def refreshRasterList(self):
        legend = self.iface.legendInterface()
        availLayers = legend.layers()
        rColl = RasterCollection()

        for lyr in availLayers:
            if legend.isLayerVisible(lyr):
                lyrType = lyr.type()
                lyrName = unicodedata.normalize('NFKD',
                                                unicode(lyr.name())).encode(
                                                    'ascii', 'ignore')
                if lyrType == 1:
                    r = Raster(lyr.id(), lyrName, lyr)
                    rColl.addRaster(r)

        self.settings.mapData.rasters = rColl
        self.__addRastersToGui()

    def __addRastersToGui(self):
        self.ui.IDC_listRasters.clear()
        check = Qt.Unchecked
        if self.settings.mapData.rasters.count() == 1:
            check = Qt.Checked
            self.settings.mapData.rasters.rasters()[0].selected = True

        for rLyr in self.settings.mapData.rasters.rasters():
            item = QListWidgetItem(rLyr.name)
            item.setData(Qt.UserRole, rLyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listRasters.addItem(item)

    def drawLine(self):
        if self.ui.IDC_rbDigi.isChecked() is False:
            self.ui.IDC_rbDigi.setChecked(True)
        self.dblckltemp = None
        self.rubberband.reset(self.polygon)
        self.__cleanDigi()
        self.__activateDigiTool()
        self.canvas.setMapTool(self.tool)

    def __createDigiFeature(self, pnts):
        u = Util(self.iface)
        f = u.createQgLineFeature(pnts)
        self.settings.mapData.customLine = f

    def __lineFinished(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        self.pointsToDraw.append(newPoint)
        #launch analyses
        self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw))
        if len(self.pointsToDraw) < 2:
            self.__cleanDigi()
            self.pointsToDraw = []
            self.dblclktemp = newPoint
            self.drawnLine = None
            QMessageBox.warning(
                self, "VoGIS-Profiltool",
                QApplication.translate(
                    'code', 'Profillinie digitalisieren abgebrochen!', None,
                    QApplication.UnicodeUTF8))
        self.drawnLine = self.__createDigiFeature(self.pointsToDraw)
        self.__cleanDigi()

        self.pointsToDraw = []
        self.dblclktemp = newPoint

    def __cleanDigi(self):
        self.pointsToDraw = []
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.savedTool)

    def __activateDigiTool(self):
        QObject.connect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.connect(self.tool, SIGNAL("rightClicked"), self.__rightClicked)
        QObject.connect(self.tool, SIGNAL("leftClicked"), self.__leftClicked)
        QObject.connect(self.tool, SIGNAL("doubleClicked"),
                        self.__doubleClicked)
        QObject.connect(self.tool, SIGNAL("deactivate"),
                        self.__deactivateDigiTool)

    def __deactivateDigiTool(self):
        QObject.disconnect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.disconnect(self.tool, SIGNAL("leftClicked"),
                           self.__leftClicked)
        QObject.disconnect(self.tool, SIGNAL("rightClicked"),
                           self.__rightClicked)
        QObject.disconnect(self.tool, SIGNAL("doubleClicked"),
                           self.__doubleClicked)
        if QGis.QGIS_VERSION_INT < 10900:
            self.iface.mainWindow().statusBar().showMessage(QString(""))
        else:
            self.iface.mainWindow().statusBar().showMessage('')

    def __moved(self, position):
        if len(self.pointsToDraw) > 0:
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                position["x"], position["y"])
            self.rubberband.reset(self.polygon)
            newPnt = QgsPoint(mapPos.x(), mapPos.y())
            if QGis.QGIS_VERSION_INT < 10900:
                for i in range(0, len(self.pointsToDraw)):
                    self.rubberband.addPoint(self.pointsToDraw[i])
                self.rubberband.addPoint(newPnt)
            else:
                pnts = self.pointsToDraw + [newPnt]
                self.rubberband.setToGeometry(QgsGeometry.fromPolyline(pnts),
                                              None)

    def __rightClicked(self, position):
        self.__lineFinished(position)

    def __leftClicked(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        #if self.selectionmethod == 0:
        if newPoint == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset(self.polygon)
            self.pointsToDraw.append(newPoint)

    def __doubleClicked(self, position):
        pass

    #not in use right now
    def __lineCancel(self):
        pass

    def __getSettingsFromGui(self):
        self.settings.linesExplode = (
            self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked)
        self.settings.linesMerge = (
            self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked)
        self.settings.onlySelectedFeatures = (
            self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked)
        self.settings.equiDistance = self.ui.IDC_dblspinDistance.value()
        self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value()
        #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked)
        self.settings.nodesAndVertices = (
            self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked)

        if QGis.QGIS_VERSION_INT < 10900:
            self.settings.mapData.selectedLineLyr = (
                self.ui.IDC_cbLineLayers.itemData(
                    self.ui.IDC_cbLineLayers.currentIndex()).toPyObject())
        else:
            self.settings.mapData.selectedLineLyr = (
                self.ui.IDC_cbLineLayers.itemData(
                    self.ui.IDC_cbLineLayers.currentIndex()))

        if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount(
        ) < 1:
            QMessageBox.warning(
                self.iface.mainWindow(), "VoGIS-Profiltool",
                QApplication.translate(
                    'code',
                    u'Der gewählte Layer hat keine selektierten Elemente.',
                    None, QApplication.UnicodeUTF8))
            return False

        if self.ui.IDC_rbDigi.isChecked():
            self.settings.modeLine = enumModeLine.customLine
        elif self.ui.IDC_rbShapeLine.isChecked():
            self.settings.modeLine = enumModeLine.line
        else:
            #self.ui.IDC_rbStraigthLine
            self.settings.modeLine = enumModeLine.straightLine

        if self.ui.IDC_rbEquiDistance.isChecked():
            self.settings.modeVertices = enumModeVertices.equiDistant
        else:
            self.settings.modeVertices = enumModeVertices.vertexCnt

        if self.ui.IDC_rbStraigthLine.isChecked():
            ut = Util(self.iface)
            if ut.isFloat(
                    self.ui.IDC_tbFromX.text(),
                    QApplication.translate('code', 'Rechtswert von', None,
                                           QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromX = float(self.ui.IDC_tbFromX.text())
            if ut.isFloat(
                    self.ui.IDC_tbFromY.text(),
                    QApplication.translate('code', 'Hochwert von', None,
                                           QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromY = float(self.ui.IDC_tbFromY.text())
            if ut.isFloat(
                    self.ui.IDC_tbToX.text(),
                    QApplication.translate('code', 'Rechtswert nach', None,
                                           QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toX = float(self.ui.IDC_tbToX.text())
            if ut.isFloat(
                    self.ui.IDC_tbToY.text(),
                    QApplication.translate('code', 'Hochwert nach', None,
                                           QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toY = float(self.ui.IDC_tbToY.text())

            fromPnt = QgsPoint(fromX, fromY)
            toPnt = QgsPoint(toX, toY)

            self.settings.mapData.customLine = ut.createQgLineFeature(
                [fromPnt, toPnt])

        return True
Example #28
0
class RectFromCenterFixedTool(QgsMapTool):
    msgbar = pyqtSignal(str)
    rbFinished = pyqtSignal(object)
    rb_reset_signal = pyqtSignal()

    def __init__(self, canvas, x_length=0.0, y_length=0.0):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.nbPoints = 0
        self.rb = None
        self.mCtrl = None
        self.xc, self.yc, self.p2 = None, None, None
        self.distance = QgsDistanceArea()
        self.distance.setSourceCrs(QgsCoordinateReferenceSystem(4326),
                                   QgsProject.instance().transformContext())
        self.distance.setEllipsoid('WGS84')
        self.x_length = x_length
        self.y_length = y_length
        self.diagonal = sqrt(self.x_length / 2 * self.x_length / 2 +
                             self.y_length / 2 * self.y_length / 2)
        # our own fancy cursor
        self.cursor = QCursor(
            QPixmap([
                "16 16 3 1", "      c None", ".     c #FF0000",
                "+     c #17a51a", "                ", "       +.+      ",
                "      ++.++     ", "     +.....+    ", "    +.  .  .+   ",
                "   +.   .   .+  ", "  +.    .    .+ ", " ++.    .    .++",
                " ... ...+... ...", " ++.    .    .++", "  +.    .    .+ ",
                "   +.   .   .+  ", "   ++.  .  .+   ", "    ++.....+    ",
                "      ++.++     ", "       +.+      "
            ]))

        self.curr_geom = None
        self.last_currpoint = None
        self.curr_angle = 0.0
        self.total_angle = 0.0
        self.rectangle = Rectangle()
        self.angle_ini_rot = 0.0
        self.ini_geom = None

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = True
            self.point_ini_rot = self.toMapCoordinates(
                self.canvas.mouseLastXY())
            self.angle_ini_rot = self.curr_angle

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = False

        if event.key() == Qt.Key_Escape:
            self.nbPoints = 0
            self.xc, self.yc, self.p2 = None, None, None
            if self.rb:
                self.rb.reset(True)
            self.rb = None

            self.canvas.refresh()
            self.rb_reset_signal.emit()
            return

    def changegeomSRID(self, geom):
        layer = self.canvas.currentLayer()

        layerCRSSrsid = layer.crs().srsid()
        projectCRSSrsid = QgsMapSettings().destinationCrs().srsid()
        if layerCRSSrsid != projectCRSSrsid:
            g = QgsGeometry.fromPoint(geom)
            g.transform(QgsCoordinateTransform(projectCRSSrsid, layerCRSSrsid))
            retPoint = g.asPoint()
        else:
            retPoint = geom

        return retPoint

    def canvasPressEvent(self, event):
        layer = self.canvas.currentLayer()

        if self.nbPoints == 0:
            color = QColor(255, 0, 0, 128)
            if self.rb:
                self.rb.reset()
                self.rb = None
            self.rb = QgsRubberBand(self.canvas, True)
            self.rb.setColor(color)
            self.rb.setWidth(1)
            self.canvas.refresh()
            self.rb_reset_signal.emit()

        point = self.toLayerCoordinates(layer, event.pos())
        pointMap = self.toMapCoordinates(layer, point)

        if self.nbPoints == 0:
            self.xc = pointMap.x()
            self.yc = pointMap.y()
            if self.x_length != 0:
                self.diagonal = sqrt(self.x_length / 2 * self.x_length / 2 +
                                     self.y_length / 2 * self.y_length / 2)
                self.p2 = self.distance.computeSpheroidProject(
                    QgsPointXY(self.xc, self.yc), self.diagonal,
                    atan2(self.y_length / 2, self.x_length / 2))
        else:
            self.x_bearing = pointMap.x()
            self.y_bearing = pointMap.y()
            self.bearing = self.distance.bearing(QgsPointXY(self.xc, self.yc),
                                                 pointMap)

        self.nbPoints += 1

        if self.nbPoints == 2:
            self.nbPoints = 0
            self.xc, self.yc, self.p2 = None, None, None
            self.last_currpoint = None
            self.rbFinished.emit(self.curr_geom)
            self.curr_geom = None
            self.curr_angle = 0.0
            self.total_angle = 0.0

        if self.rb: return

    def canvasMoveEvent(self, event):
        if not self.rb or not self.xc or not self.yc: return
        currpoint = self.toMapCoordinates(event.pos())
        self.msgbar.emit(
            "Hold Ctrl to adjust track orientation. Click when finished.")

        if not self.mCtrl:
            if self.last_currpoint is None:
                self.last_currpoint = self.p2
                self.curr_geom = self.rectangle.get_rect_from_center(
                    QgsPointXY(self.xc, self.yc),
                    self.last_currpoint,
                )
                self.ini_geom = self.curr_geom

                self.curr_geom = self.rectangle.get_rect_projection(
                    self.curr_geom, QgsPointXY(self.xc, self.yc),
                    self.x_length, self.y_length)

        elif self.ini_geom is not None:
            if self.last_currpoint is None:
                self.last_currpoint = currpoint

            self.curr_geom, self.curr_angle = self.rectangle.get_rect_rotated(
                self.ini_geom, QgsPointXY(self.xc, self.yc), currpoint,
                self.point_ini_rot, self.angle_ini_rot)

            self.last_currpoint = currpoint
            self.curr_geom = self.rectangle.get_rect_projection(
                self.curr_geom, QgsPointXY(self.xc, self.yc), self.x_length,
                self.y_length)

        if self.curr_geom is not None:
            self.rb.setToGeometry(self.curr_geom, None)

    def show_settings_warning(self):
        pass

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

    def deactivate(self):
        self.nbPoints = 0
        self.xc, self.yc, self.x_p2, self.y_p2 = None, None, None, None
        if self.rb:
            self.rb.reset(True)
        self.rb = None

        self.canvas.refresh()

    def is_zoom_tool(self):
        return False

    def is_transient(self):
        return False

    def is_edit_tool(self):
        return True
Example #29
0
class MetaSearchDialog(QDialog, BASE_CLASS):

    """main dialogue"""

    def __init__(self, iface):
        """init window"""

        QDialog.__init__(self)
        self.setupUi(self)

        self.iface = iface
        self.map = iface.mapCanvas()
        self.settings = QSettings()
        self.catalog = None
        self.catalog_url = None
        self.context = StaticContext()

        version = self.context.metadata.get('general', 'version')
        self.setWindowTitle('MetaSearch %s' % version)

        self.rubber_band = QgsRubberBand(self.map, True)  # True = a polygon
        self.rubber_band.setColor(QColor(255, 0, 0, 75))
        self.rubber_band.setWidth(5)

        # form inputs
        self.startfrom = 0
        self.maxrecords = 10
        self.timeout = 10
        self.constraints = []

        # Servers tab
        self.cmbConnectionsServices.activated.connect(self.save_connection)
        self.cmbConnectionsSearch.activated.connect(self.save_connection)
        self.btnServerInfo.clicked.connect(self.connection_info)
        self.btnAddDefault.clicked.connect(self.add_default_connections)
        self.btnCapabilities.clicked.connect(self.show_xml)
        self.tabWidget.currentChanged.connect(self.populate_connection_list)

        # server management buttons
        self.btnNew.clicked.connect(self.add_connection)
        self.btnEdit.clicked.connect(self.edit_connection)
        self.btnDelete.clicked.connect(self.delete_connection)
        self.btnLoad.clicked.connect(self.load_connections)
        self.btnSave.clicked.connect(save_connections)

        # Search tab
        self.treeRecords.itemSelectionChanged.connect(self.record_clicked)
        self.treeRecords.itemDoubleClicked.connect(self.show_metadata)
        self.btnSearch.clicked.connect(self.search)
        self.leKeywords.returnPressed.connect(self.search)
        # prevent dialog from closing upon pressing enter
        self.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False)
        # launch help from button
        self.buttonBox.helpRequested.connect(self.help)
        self.btnCanvasBbox.setAutoDefault(False)
        self.btnCanvasBbox.clicked.connect(self.set_bbox_from_map)
        self.btnGlobalBbox.clicked.connect(self.set_bbox_global)

        # navigation buttons
        self.btnFirst.clicked.connect(self.navigate)
        self.btnPrev.clicked.connect(self.navigate)
        self.btnNext.clicked.connect(self.navigate)
        self.btnLast.clicked.connect(self.navigate)

        self.btnAddToWms.clicked.connect(self.add_to_ows)
        self.btnAddToWfs.clicked.connect(self.add_to_ows)
        self.btnAddToWcs.clicked.connect(self.add_to_ows)
        self.btnShowXml.clicked.connect(self.show_xml)

        # settings
        self.radioTitleAsk.clicked.connect(self.set_ows_save_title_ask)
        self.radioTitleNoAsk.clicked.connect(self.set_ows_save_title_no_ask)
        self.radioTempName.clicked.connect(self.set_ows_save_temp_name)

        self.manageGui()

    def manageGui(self):
        """open window"""

        self.tabWidget.setCurrentIndex(0)
        self.populate_connection_list()
        self.btnCapabilities.setEnabled(False)
        self.spnRecords.setValue(
            self.settings.value('/MetaSearch/returnRecords', 10, int))

        key = '/MetaSearch/%s' % self.cmbConnectionsSearch.currentText()
        self.catalog_url = self.settings.value('%s/url' % key)

        self.set_bbox_global()

        self.reset_buttons()

        # get preferred connection save strategy from settings and set it
        save_strat = self.settings.value('/MetaSearch/ows_save_strategy',
                                         'title_ask')
        if save_strat == 'temp_name':
            self.radioTempName.setChecked(True)
        elif save_strat == 'title_no_ask':
            self.radioTitleNoAsk.setChecked(True)
        else:
            self.radioTitleAsk.setChecked(True)

        # install proxy handler if specified in QGIS settings
        self.install_proxy()

    # Servers tab

    def populate_connection_list(self):
        """populate select box with connections"""

        self.settings.beginGroup('/MetaSearch/')
        self.cmbConnectionsServices.clear()
        self.cmbConnectionsServices.addItems(self.settings.childGroups())
        self.cmbConnectionsSearch.clear()
        self.cmbConnectionsSearch.addItems(self.settings.childGroups())
        self.settings.endGroup()

        self.set_connection_list_position()

        if self.cmbConnectionsServices.count() == 0:
            # no connections - disable various buttons
            state_disabled = False
            self.btnSave.setEnabled(state_disabled)
            # and start with connection tab open
            self.tabWidget.setCurrentIndex(1)
            # tell the user to add services
            msg = self.tr('No services/connections defined. To get '
                          'started with MetaSearch, create a new '
                          'connection by clicking \'New\' or click '
                          '\'Add default services\'.')
            self.textMetadata.setHtml('<p><h3>%s</h3></p>' % msg)
        else:
            # connections - enable various buttons
            state_disabled = True

        self.btnServerInfo.setEnabled(state_disabled)
        self.btnEdit.setEnabled(state_disabled)
        self.btnDelete.setEnabled(state_disabled)

    def set_connection_list_position(self):
        """set the current index to the selected connection"""
        to_select = self.settings.value('/MetaSearch/selected')
        conn_count = self.cmbConnectionsServices.count()

        if conn_count == 0:
            self.btnDelete.setEnabled(False)
            self.btnServerInfo.setEnabled(False)
            self.btnEdit.setEnabled(False)

        # does to_select exist in cmbConnectionsServices?
        exists = False
        for i in range(conn_count):
            if self.cmbConnectionsServices.itemText(i) == to_select:
                self.cmbConnectionsServices.setCurrentIndex(i)
                self.cmbConnectionsSearch.setCurrentIndex(i)
                exists = True
                break

        # If we couldn't find the stored item, but there are some, default
        # to the last item (this makes some sense when deleting items as it
        # allows the user to repeatidly click on delete to remove a whole
        # lot of items)
        if not exists and conn_count > 0:
            # If to_select is null, then the selected connection wasn't found
            # by QSettings, which probably means that this is the first time
            # the user has used CSWClient, so default to the first in the list
            # of connetions. Otherwise default to the last.
            if not to_select:
                current_index = 0
            else:
                current_index = conn_count - 1

            self.cmbConnectionsServices.setCurrentIndex(current_index)
            self.cmbConnectionsSearch.setCurrentIndex(current_index)

    def save_connection(self):
        """save connection"""

        caller = self.sender().objectName()

        if caller == 'cmbConnectionsServices':  # servers tab
            current_text = self.cmbConnectionsServices.currentText()
        elif caller == 'cmbConnectionsSearch':  # search tab
            current_text = self.cmbConnectionsSearch.currentText()

        self.settings.setValue('/MetaSearch/selected', current_text)
        key = '/MetaSearch/%s' % current_text

        if caller == 'cmbConnectionsSearch':  # bind to service in search tab
            self.catalog_url = self.settings.value('%s/url' % key)

        if caller == 'cmbConnectionsServices':  # clear server metadata
            self.textMetadata.clear()

        self.btnCapabilities.setEnabled(False)

    def connection_info(self):
        """show connection info"""

        current_text = self.cmbConnectionsServices.currentText()
        key = '/MetaSearch/%s' % current_text
        self.catalog_url = self.settings.value('%s/url' % key)

        # connect to the server
        if not self._get_csw():
            return

        QApplication.restoreOverrideCursor()

        if self.catalog:  # display service metadata
            self.btnCapabilities.setEnabled(True)
            metadata = render_template('en', self.context,
                                       self.catalog,
                                       'service_metadata.html')
            style = QgsApplication.reportStyleSheet()
            self.textMetadata.clear()
            self.textMetadata.document().setDefaultStyleSheet(style)
            self.textMetadata.setHtml(metadata)

    def add_connection(self):
        """add new service"""

        conn_new = NewConnectionDialog()
        conn_new.setWindowTitle(self.tr('New Catalogue service'))
        if conn_new.exec_() == QDialog.Accepted:  # add to service list
            self.populate_connection_list()
        self.textMetadata.clear()

    def edit_connection(self):
        """modify existing connection"""

        current_text = self.cmbConnectionsServices.currentText()

        url = self.settings.value('/MetaSearch/%s/url' % current_text)

        conn_edit = NewConnectionDialog(current_text)
        conn_edit.setWindowTitle(self.tr('Edit Catalogue service'))
        conn_edit.leName.setText(current_text)
        conn_edit.leURL.setText(url)
        if conn_edit.exec_() == QDialog.Accepted:  # update service list
            self.populate_connection_list()

    def delete_connection(self):
        """delete connection"""

        current_text = self.cmbConnectionsServices.currentText()

        key = '/MetaSearch/%s' % current_text

        msg = self.tr('Remove service %s?') % current_text

        result = QMessageBox.information(self, self.tr('Confirm delete'), msg,
                                         QMessageBox.Ok | QMessageBox.Cancel)
        if result == QMessageBox.Ok:  # remove service from list
            self.settings.remove(key)
            index_to_delete = self.cmbConnectionsServices.currentIndex()
            self.cmbConnectionsServices.removeItem(index_to_delete)
            self.cmbConnectionsSearch.removeItem(index_to_delete)
            self.set_connection_list_position()

    def load_connections(self):
        """load services from list"""

        ManageConnectionsDialog(1).exec_()
        self.populate_connection_list()

    def add_default_connections(self):
        """add default connections"""

        filename = os.path.join(self.context.ppath,
                                'resources', 'connections-default.xml')
        doc = get_connections_from_file(self, filename)
        if doc is None:
            return

        self.settings.beginGroup('/MetaSearch/')
        keys = self.settings.childGroups()
        self.settings.endGroup()

        for server in doc.findall('csw'):
            name = server.attrib.get('name')
            # check for duplicates
            if name in keys:
                msg = self.tr('%s exists.  Overwrite?') % name
                res = QMessageBox.warning(self,
                                          self.tr('Loading connections'), msg,
                                          QMessageBox.Yes | QMessageBox.No)
                if res != QMessageBox.Yes:
                    continue

            # no dups detected or overwrite is allowed
            key = '/MetaSearch/%s' % name
            self.settings.setValue('%s/url' % key, server.attrib.get('url'))

        self.populate_connection_list()

    # Settings tab

    def set_ows_save_title_ask(self):
        """save ows save strategy as save ows title, ask if duplicate"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_ask')

    def set_ows_save_title_no_ask(self):
        """save ows save strategy as save ows title, do NOT ask if duplicate"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'title_no_ask')

    def set_ows_save_temp_name(self):
        """save ows save strategy as save with a temporary name"""

        self.settings.setValue('/MetaSearch/ows_save_strategy', 'temp_name')

    # Search tab

    def set_bbox_from_map(self):
        """set bounding box from map extent"""

        crs = self.map.mapRenderer().destinationCrs()
        crsid = int(crs.authid().split(':')[1])

        extent = self.map.extent()

        if crsid != 4326:  # reproject to EPSG:4326
            src = QgsCoordinateReferenceSystem(crsid)
            dest = QgsCoordinateReferenceSystem(4326)
            xform = QgsCoordinateTransform(src, dest)
            minxy = xform.transform(QgsPoint(extent.xMinimum(),
                                             extent.yMinimum()))
            maxxy = xform.transform(QgsPoint(extent.xMaximum(),
                                             extent.yMaximum()))
            minx, miny = minxy
            maxx, maxy = maxxy
        else:  # 4326
            minx = extent.xMinimum()
            miny = extent.yMinimum()
            maxx = extent.xMaximum()
            maxy = extent.yMaximum()

        self.leNorth.setText(unicode(maxy)[0:9])
        self.leSouth.setText(unicode(miny)[0:9])
        self.leWest.setText(unicode(minx)[0:9])
        self.leEast.setText(unicode(maxx)[0:9])

    def set_bbox_global(self):
        """set global bounding box"""
        self.leNorth.setText('90')
        self.leSouth.setText('-90')
        self.leWest.setText('-180')
        self.leEast.setText('180')

    def search(self):
        """execute search"""

        self.catalog = None
        self.constraints = []

        # clear all fields and disable buttons
        self.lblResults.clear()
        self.treeRecords.clear()

        self.reset_buttons()

        # save some settings
        self.settings.setValue('/MetaSearch/returnRecords',
                               self.spnRecords.cleanText())

        # set current catalogue
        current_text = self.cmbConnectionsSearch.currentText()
        key = '/MetaSearch/%s' % current_text
        self.catalog_url = self.settings.value('%s/url' % key)

        # start position and number of records to return
        self.startfrom = 0
        self.maxrecords = self.spnRecords.value()

        # set timeout
        self.timeout = self.spnTimeout.value()

        # bbox
        minx = self.leWest.text()
        miny = self.leSouth.text()
        maxx = self.leEast.text()
        maxy = self.leNorth.text()
        bbox = [minx, miny, maxx, maxy]

        # only apply spatial filter if bbox is not global
        # even for a global bbox, if a spatial filter is applied, then
        # the CSW server will skip records without a bbox
        if bbox != ['-180', '-90', '180', '90']:
            self.constraints.append(BBox(bbox))

        # keywords
        if self.leKeywords.text():
            # TODO: handle multiple word searches
            keywords = self.leKeywords.text()
            self.constraints.append(PropertyIsLike('csw:AnyText', keywords))

        if len(self.constraints) > 1:  # exclusive search (a && b)
            self.constraints = [self.constraints]

        # build request
        if not self._get_csw():
            return

        # TODO: allow users to select resources types
        # to find ('service', 'dataset', etc.)
        try:
            self.catalog.getrecords2(constraints=self.constraints,
                                     maxrecords=self.maxrecords, esn='full')
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Search error'),
                                self.tr('Search error: %s') % err)
            return
        except Exception as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Connection error'),
                                self.tr('Connection error: %s') % err)
            return

        if self.catalog.results['matches'] == 0:
            QApplication.restoreOverrideCursor()
            self.lblResults.setText(self.tr('0 results'))
            return

        QApplication.restoreOverrideCursor()
        self.display_results()

    def display_results(self):
        """display search results"""

        self.treeRecords.clear()

        position = self.catalog.results['returned'] + self.startfrom

        msg = self.tr('Showing %d - %d of %n result(s)', 'number of results',
                      self.catalog.results['matches']) % (self.startfrom + 1,
                                                          position)

        self.lblResults.setText(msg)

        for rec in self.catalog.records:
            item = QTreeWidgetItem(self.treeRecords)
            if self.catalog.records[rec].type:
                item.setText(0, normalize_text(self.catalog.records[rec].type))
            else:
                item.setText(0, 'unknown')
            if self.catalog.records[rec].title:
                item.setText(1,
                             normalize_text(self.catalog.records[rec].title))
            if self.catalog.records[rec].identifier:
                set_item_data(item, 'identifier',
                              self.catalog.records[rec].identifier)

        self.btnShowXml.setEnabled(True)

        if self.catalog.results["matches"] < self.maxrecords:
            disabled = False
        else:
            disabled = True

        self.btnFirst.setEnabled(disabled)
        self.btnPrev.setEnabled(disabled)
        self.btnNext.setEnabled(disabled)
        self.btnLast.setEnabled(disabled)

    def record_clicked(self):
        """record clicked signal"""

        # disable only service buttons
        self.reset_buttons(True, False, False)

        if not self.treeRecords.selectedItems():
            return

        item = self.treeRecords.currentItem()
        if not item:
            return

        identifier = get_item_data(item, 'identifier')
        try:
            record = self.catalog.records[identifier]
        except KeyError as err:
            QMessageBox.warning(self,
                                self.tr('Record parsing error'),
                                'Unable to locate record identifier')
            return

        # if the record has a bbox, show a footprint on the map
        if record.bbox is not None:
            points = bbox_to_polygon(record.bbox)
            if points is not None:
                src = QgsCoordinateReferenceSystem(4326)
                dst = self.map.mapSettings().destinationCrs()
                geom = QgsGeometry.fromPolygon(points)
                if src.postgisSrid() != dst.postgisSrid():
                    ctr = QgsCoordinateTransform(src, dst)
                    try:
                        geom.transform(ctr)
                    except Exception as err:
                        QMessageBox.warning(
                            self,
                            self.tr('Coordinate Transformation Error'),
                            unicode(err))
                self.rubber_band.setToGeometry(geom, None)

        # figure out if the data is interactive and can be operated on
        self.find_services(record, item)

    def find_services(self, record, item):
        """scan record for WMS/WMTS|WFS|WCS endpoints"""

        links = record.uris + record.references

        services = {}
        for link in links:

            if 'scheme' in link:
                link_type = link['scheme']
            elif 'protocol' in link:
                link_type = link['protocol']
            else:
                link_type = None

            if link_type is not None:
                link_type = link_type.upper()

            wmswmst_link_types = map(str.upper, link_types.WMSWMST_LINK_TYPES)
            wfs_link_types = map(str.upper, link_types.WFS_LINK_TYPES)
            wcs_link_types = map(str.upper, link_types.WCS_LINK_TYPES)

            # if the link type exists, and it is one of the acceptable
            # interactive link types, then set
            if all([link_type is not None,
                    link_type in wmswmst_link_types + wfs_link_types +
                    wcs_link_types]):
                if link_type in wmswmst_link_types:
                    services['wms'] = link['url']
                    self.btnAddToWms.setEnabled(True)
                if link_type in wfs_link_types:
                    services['wfs'] = link['url']
                    self.btnAddToWfs.setEnabled(True)
                if link_type in wcs_link_types:
                    services['wcs'] = link['url']
                    self.btnAddToWcs.setEnabled(True)

            set_item_data(item, 'link', json.dumps(services))

    def navigate(self):
        """manage navigation / paging"""

        caller = self.sender().objectName()

        if caller == 'btnFirst':
            self.startfrom = 0
        elif caller == 'btnLast':
            self.startfrom = self.catalog.results['matches'] - self.maxrecords
        elif caller == 'btnNext':
            self.startfrom += self.maxrecords
            if self.startfrom >= self.catalog.results["matches"]:
                msg = self.tr('End of results. Go to start?')
                res = QMessageBox.information(self, self.tr('Navigation'),
                                              msg,
                                              (QMessageBox.Ok |
                                               QMessageBox.Cancel))
                if res == QMessageBox.Ok:
                    self.startfrom = 0
                else:
                    return
        elif caller == "btnPrev":
            self.startfrom -= self.maxrecords
            if self.startfrom <= 0:
                msg = self.tr('Start of results. Go to end?')
                res = QMessageBox.information(self, self.tr('Navigation'),
                                              msg,
                                              (QMessageBox.Ok |
                                               QMessageBox.Cancel))
                if res == QMessageBox.Ok:
                    self.startfrom = (self.catalog.results['matches'] -
                                      self.maxrecords)
                else:
                    return

        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

        try:
            self.catalog.getrecords2(constraints=self.constraints,
                                     maxrecords=self.maxrecords,
                                     startposition=self.startfrom, esn='full')
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Search error'),
                                self.tr('Search error: %s') % err)
            return
        except Exception as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('Connection error'),
                                self.tr('Connection error: %s') % err)
            return

        QApplication.restoreOverrideCursor()

        self.display_results()

    def add_to_ows(self):
        """add to OWS provider connection list"""

        conn_name_matches = []

        item = self.treeRecords.currentItem()

        if not item:
            return

        item_data = json.loads(get_item_data(item, 'link'))

        caller = self.sender().objectName()

        # stype = human name,/Qgis/connections-%s,providername
        if caller == 'btnAddToWms':
            stype = ['OGC:WMS/OGC:WMTS', 'wms', 'wms']
            data_url = item_data['wms']
        elif caller == 'btnAddToWfs':
            stype = ['OGC:WFS', 'wfs', 'WFS']
            data_url = item_data['wfs']
        elif caller == 'btnAddToWcs':
            stype = ['OGC:WCS', 'wcs', 'wcs']
            data_url = item_data['wcs']

        QApplication.restoreOverrideCursor()

        sname = '%s from MetaSearch' % stype[1]

        # store connection
        # check if there is a connection with same name
        self.settings.beginGroup('/Qgis/connections-%s' % stype[1])
        keys = self.settings.childGroups()
        self.settings.endGroup()

        for key in keys:
            if key.startswith(sname):
                conn_name_matches.append(key)
        if conn_name_matches:
            sname = conn_name_matches[-1]

        # check for duplicates
        if sname in keys:  # duplicate found
            if self.radioTitleAsk.isChecked():  # ask to overwrite
                msg = self.tr('Connection %s exists. Overwrite?') % sname
                res = QMessageBox.warning(self, self.tr('Saving server'), msg,
                                          QMessageBox.Yes | QMessageBox.No)
                if res != QMessageBox.Yes:  # assign new name with serial
                    sname = serialize_string(sname)
            elif self.radioTitleNoAsk.isChecked():  # don't ask to overwrite
                pass
            elif self.radioTempName.isChecked():  # use temp name
                sname = serialize_string(sname)

        # no dups detected or overwrite is allowed
        self.settings.beginGroup('/Qgis/connections-%s' % stype[1])
        self.settings.setValue('/%s/url' % sname, data_url)
        self.settings.endGroup()

        # open provider window
        ows_provider = QgsProviderRegistry.instance().selectWidget(stype[2],
                                                                   self)

        service_type = stype[0]

        # connect dialog signals to iface slots
        if service_type == 'OGC:WMS/OGC:WMTS':
            ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
            connect = 'on_btnConnect_clicked'
        elif service_type == 'OGC:WFS':
            ows_provider.addWfsLayer.connect(self.iface.mainWindow().addWfsLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'cmbConnections')
            connect = 'connectToServer'
        elif service_type == 'OGC:WCS':
            ows_provider.addRasterLayer.connect(self.iface.addRasterLayer)
            conn_cmb = ows_provider.findChild(QWidget, 'mConnectionsComboBox')
            connect = 'on_mConnectButton_clicked'
        ows_provider.setModal(False)
        ows_provider.show()

        # open provider dialogue against added OWS
        index = conn_cmb.findText(sname)
        if index > -1:
            conn_cmb.setCurrentIndex(index)
            # only for wfs
            if service_type == 'OGC:WFS':
                ows_provider.on_cmbConnections_activated(index)
        getattr(ows_provider, connect)()

    def show_metadata(self):
        """show record metadata"""

        if not self.treeRecords.selectedItems():
            return

        item = self.treeRecords.currentItem()
        if not item:
            return

        identifier = get_item_data(item, 'identifier')

        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            cat = CatalogueServiceWeb(self.catalog_url, timeout=self.timeout)
            cat.getrecordbyid(
                [self.catalog.records[identifier].identifier])
        except ExceptionReport as err:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, self.tr('GetRecords error'),
                                self.tr('Error getting response: %s') % err)
            return
        except KeyError as err:
            QMessageBox.warning(self,
                                self.tr('Record parsing error'),
                                'Unable to locate record identifier')
            QApplication.restoreOverrideCursor()
            return

        QApplication.restoreOverrideCursor()

        record = cat.records[identifier]
        record.xml_url = cat.request

        crd = RecordDialog()
        metadata = render_template('en', self.context,
                                   record, 'record_metadata_dc.html')

        style = QgsApplication.reportStyleSheet()
        crd.textMetadata.document().setDefaultStyleSheet(style)
        crd.textMetadata.setHtml(metadata)
        crd.exec_()

    def show_xml(self):
        """show XML request / response"""

        crd = XMLDialog()
        request_html = highlight_xml(self.context, self.catalog.request)
        response_html = highlight_xml(self.context, self.catalog.response)
        style = QgsApplication.reportStyleSheet()
        crd.txtbrXMLRequest.clear()
        crd.txtbrXMLResponse.clear()
        crd.txtbrXMLRequest.document().setDefaultStyleSheet(style)
        crd.txtbrXMLResponse.document().setDefaultStyleSheet(style)
        crd.txtbrXMLRequest.setHtml(request_html)
        crd.txtbrXMLResponse.setHtml(response_html)
        crd.exec_()

    def reset_buttons(self, services=True, xml=True, navigation=True):
        """Convenience function to disable WMS/WMTS|WFS|WCS buttons"""

        if services:
            self.btnAddToWms.setEnabled(False)
            self.btnAddToWfs.setEnabled(False)
            self.btnAddToWcs.setEnabled(False)

        if xml:
            self.btnShowXml.setEnabled(False)

        if navigation:
            self.btnFirst.setEnabled(False)
            self.btnPrev.setEnabled(False)
            self.btnNext.setEnabled(False)
            self.btnLast.setEnabled(False)

    def help(self):
        """launch help"""

        open_url(get_help_url())

    def reject(self):
        """back out of dialogue"""

        QDialog.reject(self)
        self.rubber_band.reset()

    def _get_csw(self):
        """convenience function to init owslib.csw.CatalogueServiceWeb"""

        # connect to the server
        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            self.catalog = CatalogueServiceWeb(self.catalog_url,
                                               timeout=self.timeout)
            return True
        except ExceptionReport as err:
            msg = self.tr('Error connecting to service: %s') % err
        except ValueError as err:
            msg = self.tr('Value Error: %s') % err
        except Exception as err:
            msg = self.tr('Unknown Error: %s') % err

        QMessageBox.warning(self, self.tr('CSW Connection error'), msg)
        QApplication.restoreOverrideCursor()
        return False

    def install_proxy(self):
        """set proxy if one is set in QGIS network settings"""

        # initially support HTTP for now
        if self.settings.value('/proxy/proxyEnabled') == 'true':
            if self.settings.value('/proxy/proxyType') == 'HttpProxy':
                ptype = 'http'
            else:
                return

            user = self.settings.value('/proxy/proxyUser')
            password = self.settings.value('/proxy/proxyPassword')
            host = self.settings.value('/proxy/proxyHost')
            port = self.settings.value('/proxy/proxyPort')

            proxy_up = ''
            proxy_port = ''

            if all([user != '', password != '']):
                proxy_up = '%s:%s@' % (user, password)

            if port != '':
                proxy_port = ':%s' % port

            conn = '%s://%s%s%s' % (ptype, proxy_up, host, proxy_port)
            install_opener(build_opener(ProxyHandler({ptype: conn})))
Example #30
0
class FlowEstimatorDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        super(FlowEstimatorDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        #QDialog.__init__(self, None, Qt.WindowStaysOnTopHint)
        self.iface = iface
        self.setupUi(self)

        self.btnOk = self.buttonBox.button(QDialogButtonBox.Save)
        #ajh: it seems this wasn't working, so I have changed from a stock OK button to a stock Save button
        #self.btnOk.setText("Save Data")
        self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)
        self.btnBrowse.clicked.connect(self.writeDirName)
        self.btnLoadTXT.clicked.connect(self.loadTxt)
        # ajh trying to make it work
        #self.inputFile.textChanged.connect(self.run)
        self.btnSampleLine.setEnabled(False)
        self.btnSampleSlope.setEnabled(False)
        self.calcType = 'Trap'

        # add shortcut keys to zoom in the documentation tab, because why not?
        # pinch zoom and crtl+scroll already work by default, although zooming is impossible if a font size is set
        # I guess it would be nice to add zooming to the context menu too, or provide buttons
        QShortcut(QKeySequence('Ctrl++'), self.textBrowser,
                  self.textBrowser.zoomIn)
        QShortcut(QKeySequence('Ctrl+-'), self.textBrowser,
                  self.textBrowser.zoomOut)

        # add matplotlib figure to dialog
        self.figure = Figure()
        # this controls the size of the whole dialog; if we get resizing working again I guess we need to add `, forward=True`
        self.figure.set_size_inches(6, 2.8)
        self.axes = self.figure.add_subplot(111)
        self.figure.subplots_adjust(left=.12,
                                    bottom=0.15,
                                    right=.75,
                                    top=.9,
                                    wspace=None,
                                    hspace=.2)
        self.mplCanvas = FigureCanvas(self.figure)

        #self.widgetPlotToolbar = NavigationToolbar(self.mplCanvas, self.widgetPlot)
        #lstActions = self.widgetPlotToolbar.actions()
        #self.widgetPlotToolbar.removeAction(lstActions[7])
        self.vLayout.addWidget(self.mplCanvas)
        self.vLayout.minimumSize()
        #self.vLayout.addWidget(self.widgetPlotToolbar)

        # ajh: change the colours; perhaps we could use a stylesheet instead
        # ajh: can change the colour outside the actual graph like this
        #self.figure.patch.set_facecolor("blue")
        # ajh: default transparency is 1.0; good since otherwise the exported graphs have illegible axes in Windows explorer preview due to being fully transparent, and in QGIS if using a dark theme.
        #self.figure.patch.set_alpha(0.5)
        # ajh: patch (fill) is shown by default; good as per comment above
        #self.figure.patch.set_visible(False)
        # ajh: can change the background colour of the main plot like this:
        #self.axes.set_facecolor("#eafff5")
        # ajh: these don't seem to do anything
        #self.axes.patch.set_facecolor("#eafff5")
        #self.axes.patch.set_visible(True)
        #self.axes.patch.set_alpha(0.0)

        # and configure matplotlib params
        #        rcParams["font.serif"] = "Verdana, Arial, Liberation Serif"
        #        rcParams["font.sans-serif"] = "Tahoma, Arial, Liberation Sans"
        #        rcParams["font.cursive"] = "Courier New, Arial, Liberation Sans"
        #        rcParams["font.fantasy"] = "Comic Sans MS, Arial, Liberation Sans"
        #        rcParams["font.monospace"] = "Courier New, Liberation Mono"
        #
        #print self.cbDEM.changeEvent
        self.depth.valueChanged.connect(self.run)
        self.botWidth.valueChanged.connect(self.run)
        self.leftSS.valueChanged.connect(self.run)
        self.rightSS.valueChanged.connect(self.run)
        self.n.valueChanged.connect(self.run)
        self.slope.valueChanged.connect(self.run)
        self.cbWSE.valueChanged.connect(self.run)
        self.ft.clicked.connect(self.run)
        self.m.clicked.connect(self.run)
        self.cbUDwse.valueChanged.connect(self.run)
        # ajh: this doesn't fix it
        #self.btnRefresh.clicked.connect(self.run)

        # it seems nothing has the keyboard focus initially unless we set it manually
        self.tabWidget.setFocus()

        self.manageGui()
        # ajh: I thought this would work around the crashes, but it doesn't work properly - it only sets a maximum size (almost - it can still be made slightly taller!)
        #self.setFixedSize(self.size())
        # even this doesn't help
        #self.setMinimumSize(self.size())
        self.btnSampleLine.clicked.connect(self.sampleLine)
        self.btnSampleSlope.clicked.connect(self.sampleSlope)

    def manageGui(self):
        # fix_print_with_import
        print('manageGui')
        self.cbDEM.clear()
        if utils.getRasterLayerNames():
            self.cbDEM.addItems(utils.getRasterLayerNames())
            self.btnSampleLine.setEnabled(True)
            self.btnSampleSlope.setEnabled(True)
        self.run()

#    def refreshPlot(self):
#        self.axes.clear()

    def plotter(self):

        R, area, topWidth, Q, v, depth, xGround, yGround, yGround0, xWater, yWater, yWater0 = self.args
        self.axes.clear()
        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(xGround, yGround, 'k')
        #self.axes.fill_between(xGround, yGround, yGround0, where=yGround>yGround0, facecolor='0.9', interpolate=True)
        if Q != 0:
            self.axes.plot(xWater, yWater, 'blue')
            self.axes.fill_between(xWater,
                                   yWater,
                                   yWater0,
                                   where=yWater >= yWater0,
                                   facecolor='blue',
                                   interpolate=True,
                                   alpha=0.1)
        if self.calcType == 'DEM':
            self.outText = 'INPUT\n\nSlope: {7:.3f}\nRoughness: {8:.3f}\nWSE: {9:.2f} {5}\n\nCALCULATED\n\nR: {0:.2f} {5}\nArea: {1:,.2f} {5}$^2$\nTop Width: {2:.2f} {5}\nDepth: {6:,.2f} {5}\nQ: {3:,.3f} {5}$^3$/s\nVelocity {4:,.1f} {5}/s'.format(
                R, area, topWidth, Q, v, self.units, depth, self.slope.value(),
                self.n.value(), self.cbWSE.value())
        elif self.calcType == 'UD':
            self.outText = 'INPUT\n\nSlope: {7:.3f}\nRoughness: {8:.3f}\nWSE: {9:.2f} {5}\n\nCALCULATED\n\nR: {0:.2f} {5}\nArea: {1:,.2f} {5}$^2$\nTop Width: {2:.2f} {5}\nDepth: {6:,.2f} {5}\nQ: {3:,.3f} {5}$^3$/s\nVelocity {4:,.1f} {5}/s'.format(
                R, area, topWidth, Q, v, self.units, depth, self.slope.value(),
                self.n.value(), self.cbUDwse.value())
        else:
            self.outText = 'INPUT\n\nSlope: {7:.3f}\nRoughness: {8:.3f}\nDepth: {9:.2f} {5}\n\nCALCULATED\n\nR: {0:.2f} {5}\nArea: {1:,.2f} {5}$^2$\nTop Width: {2:.2f} {5}\nDepth: {6:,.2f} {5}\nQ: {3:,.3f} {5}$^3$/s\nVelocity {4:,.1f} {5}/s'.format(
                R, area, topWidth, Q, v, self.units, depth, self.slope.value(),
                self.n.value(), self.depth.value())
        self.axes.set_xlabel('Station, ' + self.units)
        self.axes.set_ylabel('Elevation, ' + self.units)
        self.axes.set_title('Cross Section')
        #self.axes.set_ylim(bottom=0)
        #self.axes.show()

        #print self.outText
        self.refreshPlotText()

    def refreshPlotText(self):

        self.axes.annotate(self.outText,
                           xy=(.76, 0.17),
                           xycoords='figure fraction')

        # enable mouseover coordinate display if mplcursors is available
        # using click coordinate display instead could be desirable, to output it when saving results, but we currently recalculate when saving, which clears it
        if MPLCURSORS == "installed":
            mplcursors.cursor(ground, hover=True)
            # we can do this as well, but it is a bit weird interacting with both of them
            # mplcursors.cursor(water, hover=True)

        #at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
        #self.axes.add_artist(at)
        self.mplCanvas.draw()

    def run(self):
        if self.ft.isChecked():
            self.units = 'ft'
        else:
            self.units = 'm'

        if self.tabWidget.currentIndex() == 0:
            # fix_print_with_import
            print('calc trap channel')
            self.calcType = 'Trap'
            self.args = flowEstimator(self.depth.value(),
                                      self.n.value(),
                                      self.slope.value(),
                                      widthBottom=self.botWidth.value(),
                                      rightSS=self.rightSS.value(),
                                      leftSS=self.leftSS.value(),
                                      units=self.units)
            self.figure.patch.set_facecolor("white")
            self.plotter()
        elif self.tabWidget.currentIndex() == 1:
            try:
                self.calcType = 'DEM'
                #                print self.cbWSE.value(), self.n.value(), self.slope.value(), self.staElev, self.units
                self.args = flowEstimator(self.cbWSE.value(),
                                          self.n.value(),
                                          self.slope.value(),
                                          staElev=self.staElev,
                                          units=self.units)
                self.figure.patch.set_facecolor("white")
                self.plotter()
            except:
                self.figure.patch.set_facecolor("red")
                #doesn't seem to do anything: #self.mplCanvas.setEnabled(False)
                #don't think this does anything?: #self.axes.clear()
                #this doesn't help #self.plotter()
                self.mplCanvas.draw()
        else:

            try:
                self.calcType = 'UD'
                #print 'self.cbUDwse.value(), self.n.value(), self.slope.value(), staElev = self.staElev, units = self.units'
                self.args = flowEstimator(self.cbUDwse.value(),
                                          self.n.value(),
                                          self.slope.value(),
                                          staElev=self.staElev,
                                          units=self.units)
                self.figure.patch.set_facecolor("white")
                self.plotter()
            except:
                self.figure.patch.set_facecolor("red")
                #doesn't seem to do anything: #self.mplCanvas.setEnabled(False)
                #don't think this does anything?: #self.axes.clear()
                #this doesn't help #self.plotter()
                self.mplCanvas.draw()

    def sampleLine(self):
        self.hide()
        self.iface.mainWindow().activateWindow()
        #ajh don't need this if we are doing hide and show; and it is a problem if the tool is deactivated
        #self.btnSampleLine.setEnabled(False)
        self.sampleBtnCode = 'sampleLine'
        self.rubberBand()

    def sampleSlope(self):
        self.hide()
        self.iface.mainWindow().activateWindow()
        #ajh don't need this if we are doing hide and show; and it is a problem if the tool is deactivated
        #self.btnSampleSlope.setEnabled(False)
        self.sampleBtnCode = 'sampleSlope'
        self.rubberBand()
#==============================================================================
# START rubberband and related functions from
#       https://github.com/etiennesky/profiletool
#==============================================================================

    def rubberBand(self):

        # fix_print_with_import
        print('rubberband ')
        self.canvas = self.iface.mapCanvas()
        #Init class variables
        if self.sampleBtnCode == 'sampleLine':
            self.tool = ProfiletoolMapTool(
                self.canvas, self.btnSampleLine)  #the mouselistener
        else:
            self.tool = ProfiletoolMapTool(
                self.canvas, self.btnSampleSlope)  #the mouselistener
        self.pointstoDraw = None  #Polyline in mapcanvas CRS analysed
        self.dblclktemp = False  #enable distinction between leftclick and doubleclick
        # ajh: we would need to do more work to support selectionmethod = 1
        self.selectionmethod = 0  #The selection method defined in option
        self.saveTool = self.canvas.mapTool(
        )  #Save the standard mapttool for restoring it at the end
        self.textquit0 = "Click for polyline and double click to end (right click to cancel)"
        self.textquit1 = "Select the polyline in a vector layer (Right click to quit)"
        #Listeners of mouse
        self.connectTool()
        #init the mouse listener comportement and save the classic to restore it on quit
        self.canvas.setMapTool(self.tool)
        #init the temp layer where the polyline is draw
        self.polygon = False
        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        self.rubberband.setWidth(2)
        if self.sampleBtnCode == 'sampleLine':
            color = Qt.red
        else:
            color = Qt.blue
        self.rubberband.setColor(QColor(color))
        #init the table where is saved the polyline
        self.pointstoDraw = []
        self.pointstoCal = []
        self.lastClicked = [[-9999999999.9, 9999999999.9]]
        # The last valid line we drew to create a free-hand profile
        self.lastFreeHandPoints = []
        #Help about what doing
        if self.selectionmethod == 0:
            self.iface.mainWindow().statusBar().showMessage(self.textquit0)
        elif self.selectionmethod == 1:
            self.iface.mainWindow().statusBar().showMessage(self.textquit1)

    #************************************* Mouse listener actions ***********************************************

    def moved(self,
              position):  #draw the polyline on the temp layer (rubberband)
        #print 'moved'
        if self.selectionmethod == 0:
            if len(self.pointstoDraw) > 0:
                #Get mouse coords
                mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                    position["x"], position["y"])
                try:
                    self.rubberband.reset(QgsWkbTypes.LineGeometry)
                except:
                    self.rubberband.reset(QGis.Line)
                for i in range(0, len(self.pointstoDraw)):
                    self.rubberband.addPoint(
                        QgsPointXY(self.pointstoDraw[i][0],
                                   self.pointstoDraw[i][1]))
                self.rubberband.addPoint(QgsPointXY(mapPos.x(), mapPos.y()))
#        if self.selectionmethod == 1:
#            return

    def tooldeactivated(self):
        self.rubberband.reset(self.polygon)
        self.iface.mainWindow().statusBar().showMessage("")
        self.show()

    def rightClicked(self, position):  #used to quit the current action
        # fix_print_with_import
        print('rightclicked')
        if self.selectionmethod == 0:
            if len(self.pointstoDraw) > 0:
                self.pointstoDraw = []
                self.pointstoCal = []
                self.rubberband.reset(self.polygon)
            else:
                self.cleaning()
                # ajh2: don't actually need this now, as we hide the window instead of deactivating the button
                # ajh: need this otherwise the plugin needs to be restarted to reenable the button
                #if self.sampleBtnCode == 'sampleLine':
                #    self.btnSampleLine.setEnabled(True)
                #else :
                #    self.btnSampleSlope.setEnabled(True)
                # ajh2: don't seem to need this now
                # ajh: need to raise the window
                #self.activateWindow()

    def leftClicked(self, position):  #Add point to analyse
        # fix_print_with_import
        print('leftclicked')
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoints = [[mapPos.x(), mapPos.y()]]
        if self.selectionmethod == 0:
            if newPoints == self.dblclktemp:
                self.dblclktemp = None
                return
            else:
                if len(self.pointstoDraw) == 0:
                    self.rubberband.reset(self.polygon)
                self.pointstoDraw += newPoints

    def doubleClicked(self, position):
        # fix_print_with_import
        print('doubleclicked')
        # ajh: doing show first avoids problems with dialog not showing in some cases after running slope estimator
        # and it also means the user can see the graph before deciding whether to accept the slope
        self.show()
        if self.selectionmethod == 0:
            #Validation of line
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                position["x"], position["y"])
            newPoints = [[mapPos.x(), mapPos.y()]]
            self.pointstoDraw += newPoints
            #launch analyses
            self.iface.mainWindow().statusBar().showMessage(
                str(self.pointstoDraw))

            if self.sampleBtnCode == 'sampleLine':
                self.staElev, error = self.doRubberbandProfile()
                if error:
                    pass
                    #ajh it would be good to restart the selection again after an error
                else:
                    self.doIrregularProfileFlowEstimator()
                #ajh don't need this if we are doing hide and show
                #self.btnSampleLine.setEnabled(True)
                self.deactivate()
            else:
                staElev, error = self.doRubberbandProfile()
                if error:
                    pass
                    #ajh it would be good to restart the selection again after an error
                else:
                    self.doRubberbandSlopeEstimator(staElev)
                #ajh don't need this if we are doing hide and show
                #self.btnSampleSlope.setEnabled(True)
                self.deactivate()

            #Reset
            self.lastFreeHandPoints = self.pointstoDraw
            self.pointstoDraw = []
            #temp point to distinct leftclick and dbleclick
            self.dblclktemp = newPoints
            self.iface.mainWindow().statusBar().showMessage("")

            # ajh: trying to make something like this work:
            #self.iface.mainWindow.setWindowState(self.iface.mainWindow.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
            #self.iface.mainWindow.raise_()
            #self.iface.mainWindow.show()
            # ajh: this is (really) it; needs a hide first... but we are moving it to the start as discussed there
            #self.show()

            # ajh: thought this just wasn't working on windows as per
            # https://stackoverflow.com/questions/22815608/how-to-find-the-active-pyqt-window-and-bring-it-to-the-front
            # see https://forum.qt.io/topic/1939/activatewindow-does-not-send-window-to-front/11
            #self.iface.mainWindow.activateWindow()

            # but actually, this is the solution:
            #self.activateWindow()
            return

###***********************************************

    def connectTool(self):
        # fix_print_with_import
        print('connecting')
        self.tool.moved.connect(self.moved)
        self.tool.rightClicked.connect(self.rightClicked)
        self.tool.leftClicked.connect(self.leftClicked)
        self.tool.doubleClicked.connect(self.doubleClicked)
        self.tool.deactivated.connect(self.tooldeactivated)

    def deactivate(self):  #enable clean exit of the plugin
        self.cleaning()
        try:
            self.tool.moved.disconnect(self.moved)
            self.tool.leftClicked.disconnect(self.leftClicked)
            self.tool.rightClicked.disconnect(self.rightClicked)
            self.tool.doubleClicked.disconnect(self.doubleClicked)
            self.tool.deactivated.disconnect(self.tooldeactivated)
        except:
            pass
#        self.rubberband.reset(self.polygon)
#        self.iface.mainWindow().statusBar().showMessage("")

#        self.depth.setEnabled(True)
#        self.botWidth.setEnabled(True)
#        self.leftSS.setEnabled(True)
#        self.rightSS.setEnabled(True)
#        self.n.setEnabled(True)
#        self.slope.setEnabled(True)
#        self.cbWSE.setEnabled(True)
#        self.ft.setEnabled(True)
#        self.m.setEnabled(True)
#        self.cbDEM.setEnabled(True)

    def cleaning(self):  #used on right click and deactivate
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.saveTool)
        self.rubberband.reset(self.polygon)
        self.iface.mainWindow().statusBar().showMessage(
            ""
        )  # ajh: I guess there might have been a statusBar message associated with the saveTool which we should restore
#==============================================================================
# END rubberband and related functions from
#       https://github.com/etiennesky/profiletool
#==============================================================================

    def doRubberbandProfile(self):
        layerString = self.cbDEM.currentText()
        layer = utils.getRasterLayerByName(' '.join(
            layerString.split(' ')[:-1]))
        try:
            if layer.isValid():
                self.xRes = layer.rasterUnitsPerPixelX()
        except:
            QMessageBox.warning(self, 'Error', 'Selected DEM layer is missing')
            return [None, 'error']
        line = LineString(self.pointstoDraw[:-1])
        xyzdList = utils.elevationSampler(line, self.xRes, layer)
        sta = xyzdList[-1]
        elev = xyzdList[-2]
        staElev = np.array(list(zip(sta, elev)))
        try:
            np.isnan(np.sum(staElev[:, 1]))
            return [staElev, None]
        except:
            QMessageBox.warning(self, 'Error',
                                'Sampled line not within bounds of DEM')
            # ajh: don't think we need this
            #self.cleaning()

            return [staElev, 'error']

    def doIrregularProfileFlowEstimator(self):
        thalweig = self.staElev[np.where(
            self.staElev[:, 1] == np.min(self.staElev[:, 1]))]
        thalweigX = thalweig[:, 0][0]
        minElev = thalweig[:, 1][0] + .01
        try:
            lbMaxEl = self.staElev[np.where(
                self.staElev[:, 0] > thalweigX)][:, 1].max()
        except:
            QMessageBox.warning(self, 'Error', 'Channel not found')
            # ajh: don't think we need this
            #self.deactivate()
            return
        try:
            rbMaxEl = self.staElev[np.where(
                self.staElev[:, 0] < thalweigX)][:, 1].max()
        except:
            QMessageBox.warning(self, 'Error', 'Channel not found')
            # ajh: don't think we need this
            #self.deactivate()
            return
        maxElev = np.array([lbMaxEl, rbMaxEl]).min(
        ) - .001  # ajh: let the user set WSE up to 1mm (if units in m) below the crest
        WSE = maxElev
        WSE = (self.staElev[:, 1].max() -
               self.staElev[:, 1].min()) / 2. + self.staElev[:, 1].min()
        self.cbWSE.setValue(WSE)
        self.cbWSE.setMinimum(minElev)
        self.cbWSE.setMaximum(maxElev)
        self.cbUDwse.setValue(WSE)
        self.cbUDwse.setMinimum(minElev)
        self.cbUDwse.setMaximum(maxElev)
        # ajh: doing it like this might be beneficial if switch from WSE to UD (or vice versa) and then fail to load a section succcessfully
        # as it was it just meant we had a section with the wrong minimum and maximum values if we switched, loaded a section successfully, and then switched back
        # if we are going to do it this way we should store two different sections (one for each tab) and reload when we switch tabs
        # if self.tabWidget.currentIndex() == 1:
        # self.cbWSE.setValue(WSE)
        # self.cbWSE.setMinimum(minElev)
        # self.cbWSE.setMaximum(maxElev)
        # elif self.tabWidget.currentIndex() == 2:
        # self.cbUDwse.setValue(WSE)
        # self.cbUDwse.setMinimum(minElev)
        # self.cbUDwse.setMaximum(maxElev)
        # else:
        # return

        # ajh: I don't think this was doing anything
        #self.run()

    def doRubberbandSlopeEstimator(self, staElev):

        slope = -(staElev[:, 1][-1] - staElev[:, 1][0]) / staElev[:, 0][-1]
        # fix_print_with_import
        print(slope)

        self.axes.clear()

        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(staElev[:, 0], staElev[:, 1], 'k', label='Sampled DEM')
        x = np.array([staElev[0, 0], staElev[-1, 0]])
        y = np.array([staElev[0, 1], staElev[-1, 1]])
        self.axes.plot(x, y, label='Slope')
        self.axes.set_xlabel('Station, ' + self.units)
        self.axes.set_ylabel('Elevation, ' + self.units)
        #self.axes.set_title('DEM Derived Slope = '+str(slope))
        self.axes.set_title('DEM Derived Slope = ' + str(slope.astype('U8')))
        self.axes.legend()
        self.mplCanvas.draw()
        if slope <= 0:
            QMessageBox.warning(
                self, 'Error',
                'Negative or zero slope\nPlease check sampled area\n\nWater flows downhill you know!'
            )
            # fix_print_with_import
            print('error: negative slope')
        else:
            reply = QMessageBox.question(
                self, 'Message',
                'DEM Derived Slope is {}\nWould you like to use this value?'.
                format(str(slope.astype('U8'))),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.slope.setValue(slope)

            else:
                pass

    def writeDirName(self):
        self.outputDir.clear()
        self.dirName = QFileDialog.getExistingDirectory(
            self, 'Select Output Directory')
        self.outputDir.setText(self.dirName)

    def loadTxt(self):
        try:
            filePath, __ = QFileDialog.getOpenFileNameAndFilter(
                self,
                'Select tab or space delimited text file containing station and elevation data'
            )  # QGIS2 (using this rather than getOpenFileName will avoid opening a dialog twice)
        except:
            filePath, __ = QFileDialog.getOpenFileName(
                self,
                'Select tab or space delimited text file containing station and elevation data'
            )
        # fix_print_with_import
        print(filePath)
        try:
            self.staElev = np.loadtxt(filePath)
            self.inputFile.setText(filePath)
            self.calcType = 'UD'
            self.doIrregularProfileFlowEstimator()
        except:
            if (filePath == ('')):  # null string for cancel
                return
            QMessageBox.warning(
                self, 'Error',
                'Please check that the text file is space or tab delimited and does not contain header information'
            )

    def accept(self):
        # recalculate in case save has been hit twice (otherwise instead of saving the cross-section png it saves a second copy of the rating curve).
        self.run()
        # assign results to numpy array for quick csv dump
        outPath = self.outputDir.text()
        home = os.path.expanduser("~")
        if outPath == '':
            outPath = os.path.join(home, 'Desktop', 'QGISFlowEstimatorFiles')
            self.outputDir.setText(outPath)
        # Note that in Python 3.2+ we will be able to just do: os.makedirs("path/to/directory", exist_ok=True)
        if not os.path.exists(outPath):
            os.makedirs(outPath)
        fileName = outPath + '/FlowEstimatorResults.txt'
        # ajh I think we've fixed the file/folder locking problem on windows by not doing chdir to outPath
        # keeping these old comments just in case:
        # one way to prevent it may be to open like this:
        # outFile = open(fileName, 'w', False)
        # another way may be to do outFile = None after closing
        outFile = open(fileName, 'w')
        outHeader = '*' * 20 + '\nFlow Estimator - A QGIS plugin\nEstimates uniform, steady flow in a channel using Mannings equation\n' + '*' * 20
        if self.calcType == 'DEM':
            try:
                proj4 = utils.getRasterLayerByName(
                    self.cbDEM.currentText().split(
                        ' EPSG')[0]).crs().toProj4()
            except:
                proj4 = "Unknown"
            outHeader += '\n' * 5 + 'Type:\tCross Section from DEM\nUnits:\t{0}\nDEM Layer:\t{1}\nProjection (Proj4 format):\t{2}\nChannel Slope:\t{3:.06f}\nMannings n:\t{4:.02f}\n\n\n\nstation\televation\n'.format(
                self.units, self.cbDEM.currentText(), proj4,
                self.slope.value(), self.n.value())
            outFile.write(outHeader)
            np.savetxt(outFile, self.staElev, fmt='%.3f', delimiter='\t')
            wseMax = self.cbWSE.value()
            wseMin = self.cbWSE.minimum()
        elif self.calcType == 'UD':
            outHeader += '\n' * 5 + 'Type:\tUser Defined Cross Section\nUnits:\t{0}\nChannel Slope:\t{1:.06f}\nMannings n:\t{2:.02f}\n\n\n\nstation\televation\n'.format(
                self.units, self.slope.value(), self.n.value())
            outFile.write(outHeader)
            np.savetxt(outFile, self.staElev, fmt='%.3f', delimiter='\t')
            wseMax = self.cbUDwse.value()
            wseMin = self.cbUDwse.minimum()

        else:
            outHeader += '\n' * 5 + 'Type:\tTrapezoidal Channel\nUnits:\t{0}\nChannel Slope:\t{1:.06f}\nMannings n:\t{2:.02f}\nBottom Width:\t{3:.02f}\nRight Side Slope:\t{4:.02f}\nLeft Side Slope:\t{5:.02f}\n'.format(
                self.units, self.slope.value(), self.n.value(),
                self.botWidth.value(), self.rightSS.value(),
                self.leftSS.value())
            outFile.write(outHeader)
            wseMax = self.depth.value()
            wseMin = 0.001
        self.mplCanvas.print_figure(outPath + '/FlowEstimatorResultsXSFigure')
        outHeader = '\n\n\n\n\n\n\nwater surface elevation\tflow\tvelocity\tR\tarea\ttop width\tdepth\n'
        outFile.write(outHeader)
        ###do loop here
        step = 0.1
        wseList = []
        qList = []
        for wse in utils.frange(wseMin, wseMax, step):
            if self.calcType == 'DEM' or self.calcType == 'UD':
                args = flowEstimator(wse,
                                     self.n.value(),
                                     self.slope.value(),
                                     staElev=self.staElev,
                                     units=self.units)
            else:
                args = flowEstimator(wse,
                                     self.n.value(),
                                     self.slope.value(),
                                     widthBottom=self.botWidth.value(),
                                     rightSS=self.rightSS.value(),
                                     leftSS=self.leftSS.value(),
                                     units=self.units)
            R, area, topWidth, Q, v, depth, xGround, yGround, yGround0, xWater, yWater, yWater0 = args
            data = '{0}\t{1:.02f}\t{2:.02f}\t{3:.02f}\t{4:.02f}\t{5:.02f}\t{6:.02f}\n'.format(
                wse, Q, v, R, area, topWidth, depth)
            outFile.write(data)
            wseList.append(wse)
            qList.append(Q)

        self.axes.clear()
        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(qList, wseList, 'k', label='Rating Curve')
        self.axes.set_ylabel('Water Surface Elevation, ' + self.units)
        self.axes.set_xlabel('Discharge, {0}$^3$/s'.format(self.units))
        self.axes.set_title('Rating Curve')
        self.axes.grid()
        self.mplCanvas.draw()
        self.mplCanvas.print_figure(outPath + '/FlowEstimatorRatingCurve')

        outFile.close()
        #ajh this may help force the file lock to be released
        outFile = None

        self.iface.messageBar().pushMessage(
            "Flow Estimator",
            'Output files saved to {}'.format(outPath),
            duration=30)
Example #31
0
class teamqgisDock(QDockWidget, Ui_teamqgis):
    dockRemoved = pyqtSignal(str)

    def __init__(self, iface, layer, currentFeature):
        self.iface = iface
        self.layer = layer
        self.proj = QgsProject.instance()
        self.renderer = self.iface.mapCanvas().mapRenderer()
        self.settings = MySettings()
        QDockWidget.__init__(self)
        self.setupUi(self)

        # Track attr warnings so they are not repeated for multiple items
        self.warned_attr_values = []

        self.setWindowTitle("teamqgis: %s" % layer.name())
        if layer.hasGeometryType() is False:
            self.panCheck.setChecked(False)
            self.panCheck.setEnabled(False)
            self.scaleCheck.setChecked(False)
            self.scaleCheck.setEnabled(False)

        self.previousButton.setArrowType(Qt.LeftArrow)
        self.nextButton.setArrowType(Qt.RightArrow)
        icon = QIcon(":/plugins/teamqgis/icons/openform.svg")
        self.editFormButton.setIcon(icon)

        # actions
        icon = QIcon(":/plugins/teamqgis/icons/action.svg")
        self.actionButton.setIcon(icon)
        self.attrAction = layer.actions()
        actions = [self.attrAction[i] for i in range(self.attrAction.size())]
        preferredAction = layer.customProperty("teamqgisPreferedAction", "")
        if preferredAction not in actions:
            dfltAction = self.attrAction.defaultAction()
            if dfltAction > len(actions):
                preferredAction = self.attrAction[dfltAction].name()
        preferredActionFound = False
        for i, action in enumerate(actions):
            qAction = QAction(QIcon(":/plugins/teamqgis/icons/action.svg"), action.name(), self)
            qAction.triggered.connect(lambda: self.doAction(i))
            self.actionButton.addAction(qAction)
            if action.name() == preferredAction:
                self.actionButton.setDefaultAction(qAction)
                preferredActionFound = True
        if len(actions) == 0:
            self.actionButton.setEnabled(False)
        elif not preferredActionFound:
            self.actionButton.setDefaultAction(self.actionButton.actions()[0])

        self.nameComboBoxes = [self.fieldOneNameComboBox, self.fieldTwoNameComboBox, self.fieldThreeNameComboBox]
        self.valueComboBoxes = [self.fieldOneValueComboBox, self.fieldTwoValueComboBox, self.fieldThreeValueComboBox]

        self.updateNameComboBoxes()

        # Restore saved nameComboBox current indices if they exist
        for nameComboBox in self.nameComboBoxes:
            fieldName = self.layer.customProperty("teamqgis" + nameComboBox.objectName())
            if fieldName != None:
                nameComboBox.setCurrentIndex(nameComboBox.findText(fieldName))

        self.rubber = QgsRubberBand(self.iface.mapCanvas())
        self.selectionChanged()
        if currentFeature == self.listCombo.currentIndex():
            self.on_listCombo_currentIndexChanged(currentFeature)
        else:
            self.listCombo.setCurrentIndex(currentFeature)
        self.layer.layerDeleted.connect(self.close)
        self.layer.selectionChanged.connect(self.selectionChanged)
        self.layer.layerModified.connect(self.layerChanged)
        self.layer.editingStopped.connect(self.editingStopped)
        self.layer.editingStarted.connect(self.editingStarted)

        QObject.connect(self.proj, SIGNAL("allowedClassesChanged()"), self.updateValueComboBoxes)

    def updateNameComboBoxes(self):
        fieldNameMap = self.layer.dataProvider().fieldNameMap()
        allFields = fieldNameMap.keys()
        if 'ID' in allFields: allFields.remove('ID')
        if 'FID' in allFields: allFields.remove('FID')
        for nameComboBox in self.nameComboBoxes:
            nameComboBox.clear()
            nameComboBox.addItems(allFields)

    def updateValueComboBoxes(self):
        feature = self.getCurrentItem()
        for (valueComboBox, nameComboBox) in zip(self.valueComboBoxes, 
                self.nameComboBoxes):
            valueComboBox.clear()
            allowedClasses, hasAllowedClasses = self.proj.readListEntry("teamqgis", "allowedClasses")
            if hasAllowedClasses:
                valueComboBox.addItems(allowedClasses)
            attr_value = str(feature[nameComboBox.currentText()])
            if (allowedClasses == None) or (attr_value not in allowedClasses) and (attr_value not in self.warned_attr_values):
                self.iface.messageBar().pushMessage("Class name not in allowed class list",
                    'Assign an allowed class or add "%s" to allowed class list'%attr_value,
                    level=QgsMessageBar.WARNING, duration=3)
                self.warned_attr_values.append(attr_value)
                valueComboBox.addItem(attr_value)
            valueComboBox.setCurrentIndex(valueComboBox.findText(attr_value))

    def setRubber(self, feature):
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.rubber.setWidth(self.settings.value("rubberWidth"))
        ##self.rubber.setLineStyle(Qt.DotLine)
        self.rubber.setBrushStyle(Qt.NoBrush)
        self.rubber.setToGeometry(feature.geometry(), self.layer)

    def closeEvent(self, e):
        self.rubber.reset()
        self.layer.layerDeleted.disconnect(self.close)
        self.layer.selectionChanged.disconnect(self.selectionChanged)
        self.layer.layerModified.disconnect(self.layerChanged)
        self.layer.editingStopped.disconnect(self.editingStopped)
        self.layer.editingStarted.disconnect(self.editingStarted)
        if self.settings.value("saveSelectionInProject"):
            self.layer.setCustomProperty("teamqgisSelection", repr([]))
        self.dockRemoved.emit(self.layer.id())
          
    def selectionChanged(self):
        self.cleanBrowserFields()
        self.rubber.reset()
        nItems = self.layer.selectedFeatureCount()
        if nItems < 1:
            self.close()
            self.layer.emit(SIGNAL("browserNoItem()"))
            return
        self.browseFrame.setEnabled(True)
        self.subset = self.layer.selectedFeaturesIds()
        if self.settings.value("saveSelectionInProject"):
            self.layer.setCustomProperty("teamqgisSelection", repr(self.subset))
        for fid in self.subset:
            self.listCombo.addItem("%u" % fid)
        self.setRubber(self.getCurrentItem())
        self.updateValueComboBoxes()

    def layerChanged(self):
        self.applyChangesButton.setEnabled(True)

    def editingStarted(self):
        for valueComboBox in self.valueComboBoxes:
            valueComboBox.setEnabled(True)
        self.translateRightButton.setEnabled(True)
        self.translateLeftButton.setEnabled(True)
        self.translateUpButton.setEnabled(True)
        self.translateDownButton.setEnabled(True)
        self.editFormButton.setDown(True)

    def editingStopped(self):
        self.applyChangesButton.setEnabled(False)
        for valueComboBox in self.valueComboBoxes:
            valueComboBox.setEnabled(False)
        self.translateRightButton.setEnabled(False)
        self.translateLeftButton.setEnabled(False)
        self.translateUpButton.setEnabled(False)
        self.translateDownButton.setEnabled(False)
        self.editFormButton.setDown(False)

    def cleanBrowserFields(self):
        self.currentPosLabel.setText('0/0')
        self.listCombo.clear()
          
    def panScaleToItem(self, feature):
        if self.panCheck.isChecked() is False:
            return
        featBobo = feature.geometry().boundingBox()
        # if scaling and bobo has width and height (i.e. not a point)
        if self.scaleCheck.isChecked() and featBobo.width() != 0 and featBobo.height() != 0:
            featBobo.scale(self.settings.value("scale"))
            ul = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMaximum()))
            ur = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMaximum()))
            ll = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMinimum(), featBobo.yMinimum()))
            lr = self.renderer.layerToMapCoordinates(self.layer, QgsPoint(featBobo.xMaximum(), featBobo.yMinimum()))
            x = (ul.x(), ur.x(), ll.x(), lr.x())
            y = (ul.y(), ur.y(), ll.y(), lr.y())
            x0 = min(x)
            y0 = min(y)
            x1 = max(x)
            y1 = max(y)
        else:
            panTo = self.renderer.layerToMapCoordinates(self.layer, featBobo.center())
            mapBobo = self.iface.mapCanvas().extent()
            xshift = panTo.x() - mapBobo.center().x()
            yshift = panTo.y() - mapBobo.center().y()
            x0 = mapBobo.xMinimum() + xshift
            y0 = mapBobo.yMinimum() + yshift
            x1 = mapBobo.xMaximum() + xshift
            y1 = mapBobo.yMaximum() + yshift
        self.iface.mapCanvas().setExtent(QgsRectangle(x0, y0, x1, y1))
        self.iface.mapCanvas().refresh()

    def getCurrentItem(self):
        i = self.listCombo.currentIndex()
        if i == -1:
            return None
        f = QgsFeature()
        if self.layer.getFeatures(QgsFeatureRequest().setFilterFid(self.subset[i])).nextFeature(f):
            return f
        else:
            raise NameError("feature not found")

    def doAction(self, i):
        f = self.getCurrentItem()
        self.actionButton.setDefaultAction(self.actionButton.actions()[i])
        self.layer.setCustomProperty("teamqgisPreferedAction", self.attrAction[i].name())
        self.attrAction.doActionFeature(i, f)

    def doTranslate(self, trans):
        # Based on the "doaffine" function in the qgsAffine plugin
        if (self.layer.geometryType() == 2):
            start=1
        else:
            start=0
        if (not self.layer.isEditable()):
            self.iface.messageBar().pushMessage("Layer not in edit mode",
                    'Select a vector layer and choose "Toggle Editing"', level=QgsMessageBar.WARNING)
        else:
            feature = self.getCurrentItem()
            result = feature.geometry()
            i = start
            vertex = result.vertexAt(i)
            fid = feature.id()
            while (vertex != QgsPoint(0, 0)):
                newx = vertex.x() + trans[0] * float(self.settings.value("xres"))
                newy = vertex.y() + trans[1] * float(self.settings.value("yres"))
                result.moveVertex(newx, newy, i)
                i += 1
                vertex = result.vertexAt(i)
            self.layer.changeGeometry(fid, result)
            self.iface.mapCanvas().refresh()
            self.rubber.reset()
            self.setRubber(feature)

    def changeAttribute(self, i, fieldNameComboBox, fieldValueComboBox):
        fieldValueComboBox.setCurrentIndex(i)
        feature = self.getCurrentItem()
        attr_index = self.layer.dataProvider().fieldNameMap()[fieldNameComboBox.currentText()]
        self.layer.changeAttributeValue(feature.id(), attr_index, 
                fieldValueComboBox.currentText())
        self.iface.mapCanvas().refresh()
        self.updateValueComboBoxes()

    def nameComboBox_activated(self, i, nameComboBox):
        self.layer.setCustomProperty('teamqgis' + nameComboBox.objectName(), nameComboBox.currentText())

    @pyqtSlot(name="on_previousButton_clicked")
    def previousFeature(self):
        i = self.listCombo.currentIndex()
        n = max(0, i-1)
        self.listCombo.setCurrentIndex(n)
        self.saveCurrentFeature(n)

    @pyqtSlot(name="on_nextButton_clicked")
    def nextFeature(self):
        self.warned_attr_values = [] # Reset attr warnings
        i = self.listCombo.currentIndex()
        c = self.listCombo.count()
        n = min(i+1, c-1)
        self.listCombo.setCurrentIndex(n)
        self.saveCurrentFeature(n)

    @pyqtSlot(int, name="on_listCombo_activated")
    def saveCurrentFeature(self, i):
        if self.settings.value("saveSelectionInProject"):
            self.layer.setCustomProperty("teamqgisCurrentItem", i)

    @pyqtSlot(int, name="on_fieldOneNameComboBox_activated")
    def fieldOneNameComboBox_activated(self, i):
        self.nameComboBox_activated(i, self.fieldOneNameComboBox)

    @pyqtSlot(int, name="on_fieldTwoNameComboBox_activated")
    def fieldTwoNameComboBox_activated(self, i):
        self.nameComboBox_activated(i, self.fieldTwoNameComboBox)

    @pyqtSlot(int, name="on_fieldThreeNameComboBox_activated")
    def fieldThreeNameComboBox_activated(self, i):
        self.nameComboBox_activated(i, self.fieldThreeNameComboBox)

    @pyqtSlot(int, name="on_listCombo_currentIndexChanged")
    def on_listCombo_currentIndexChanged(self, i):
        feature = self.getCurrentItem()
        if feature is None: 
            return
        self.rubber.reset()
        if self.listCombo.count() > 1:
            self.setRubber(feature)
            self.updateValueComboBoxes()
        # scale to feature
        self.panScaleToItem(feature)
        # Update browser
        self.currentPosLabel.setText("%u/%u" % (i+1, len(self.subset)))
        # emit signal
        self.layer.emit(SIGNAL("browserCurrentItem(long)"), feature.id())
          
    @pyqtSlot(int, name="on_panCheck_stateChanged")
    def on_panCheck_stateChanged(self, i):
        if self.panCheck.isChecked():
            self.scaleCheck.setEnabled(True)
            feature = self.getCurrentItem()
            if feature is None:
                return
            self.panScaleToItem(feature)
        else:
            self.scaleCheck.setEnabled(False)
               
    @pyqtSlot(int, name="on_scaleCheck_stateChanged")
    def on_scaleCheck_stateChanged(self, i):
        if self.scaleCheck.isChecked():
            feature = self.getCurrentItem()
            if feature is None: 
                return
            self.panScaleToItem(feature)

    @pyqtSlot(name="on_editFormButton_clicked")
    def openFeatureForm(self):
        if (self.layer.isEditable()):
            self.layer.commitChanges()
        else:
            self.layer.startEditing()

    @pyqtSlot(name="on_translateRightButton_clicked")
    def doTranslateRight(self):
        self.doTranslate((1, 0))

    @pyqtSlot(name="on_translateLeftButton_clicked")
    def doTranslateLeft(self):
        self.doTranslate((-1, 0))

    @pyqtSlot(name="on_translateUpButton_clicked")
    def doTranslateUp(self):
        self.doTranslate((0, 1))

    @pyqtSlot(name="on_translateDownButton_clicked")
    def doTranslateDown(self):
        self.doTranslate((0, -1))

    @pyqtSlot(name="on_applyChangesButton_clicked")
    def applyChanges(self):
        self.layer.commitChanges()
        self.layer.startEditing()
        self.layer.updateExtents()
        self.iface.mapCanvas().refresh()

    @pyqtSlot(int, name="on_fieldOneValueComboBox_activated")
    def on_fieldOneValueComboBox_activated(self, i):
        self.changeAttribute(i, self.fieldOneNameComboBox, self.fieldOneValueComboBox)

    @pyqtSlot(int, name="on_fieldTwoValueComboBox_activated")
    def on_fieldTwoValueComboBox_activated(self, i):
        self.changeAttribute(i, self.fieldTwoNameComboBox, self.fieldTwoValueComboBox)

    @pyqtSlot(int, name="on_fieldThreeValueComboBox_activated")
    def on_fieldThreeValueComboBox_activated(self, i):
        self.changeAttribute(i, self.fieldThreeNameComboBox, self.fieldThreeValueComboBox)
Example #32
0
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        """ Constructor """
        super().__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.setAttribute(Qt.WA_OpaquePaintEvent)

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

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

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

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

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

        self._isinit = False
        self._MGRS = False

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

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

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

        self.parent = parent.parent()

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

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

        self.lastMouseX = -1
        self.lastMouseY = -1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        if GetGCPGeoTransform(
        ) is not None and self._interaction.measureDistance:
            self.drawMeasureDistance.append([None, None, None])
            self.parent.actionMeasureDistance.toggle()
            return

        if GetGCPGeoTransform() is not None and self._interaction.measureArea:
            self.drawMeasureArea.append([None, None, None])
            self.parent.actionMeasureArea.toggle()
            return

        if GetGCPGeoTransform(
        ) is not None and self._interaction.polygonDrawer:

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

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

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

        self.UpdateSurface()
        scr = QApplication.desktop().screenNumber(self)
        self.setGeometry(QApplication.desktop().screenGeometry(scr))
        self.setFullScreen(not self.isFullScreen())
        event.accept()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def RemoveVideoDrawings(self):
        """ Remove Video Drawings """
        (
            self.poly_coordinates,
            self.drawPtPos,
            self.drawLines,
            self.drawMeasureDistance,
            self.drawMeasureArea,
            self.drawPolygon,
        ) = ([], [], [], [], [], [])

    def paintEvent(self, event):
        """
        @type event: QPaintEvent
        @param event:
        @return:
        """

        if not self.surface.isActive():
            return

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

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

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

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

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

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

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

            else:
                self._isinit = False
                del self.tracker

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

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

        self.painter.end()
        return

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

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

        @type values: list
        @param values: Points list

        @type Longitude: float
        @param Longitude: Longitude value

        @type Latitude: float
        @param Latitude: Latitude value

        @type Altitude: float
        @param Altitude: Altitude value

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

        self.UpdateSurface()

    def mouseMoveEvent(self, event, useLast=False):
        """
        @type event: QMouseEvent
        @param event:
        @return:
        """
        if event is not None:
            self.lastMouseX = event.x()
            self.lastMouseY = event.y()

        if useLast is False and self.lastMouseX != -1 and self.lastMouseY != -1:
            # generates an event that simulates a mouse move, because even if
            # mouse is still, video is running and mouse lat/lon must be
            # updated.
            event = QMouseEvent(
                QEvent.MouseMove,
                QPoint(self.lastMouseX, self.lastMouseY),
                Qt.NoButton,
                Qt.NoButton,
                Qt.NoModifier,
            )
        else:
            return

        # Magnifier can move on black screen for show image borders
        if self._interaction.magnifier:
            self.dragPos = event.pos()
            self.UpdateSurface()

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

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

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

        # Cursor Coordinates
        if GetGCPGeoTransform() is not None:
            Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                event, self.surface)

            tr = QgsCoordinateTransform(
                QgsCoordinateReferenceSystem("EPSG:4326"),
                iface.mapCanvas().mapSettings().destinationCrs(),
                QgsProject.instance().transformContext(),
            )
            mapPt = tr.transform(QgsPointXY(Longitude, Latitude))

            vertices = self.Cursor_Canvas_RubberBand.numberOfVertices()
            if vertices > 0:
                self.Cursor_Canvas_RubberBand.removePoint(0, True, 0)
                self.Cursor_Canvas_RubberBand.movePoint(mapPt, 0)
            else:
                self.Cursor_Canvas_RubberBand.addPoint(mapPt)

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

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

            else:

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

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

            self.parent.lb_cursor_coord.setText(txt)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                AddDrawLineOnMap(self.drawLines)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def leaveEvent(self, _):
        """
        @type _: QEvent
        @param _:
        @return:
        """
        # Remove coordinates label value
        self.parent.lb_cursor_coord.setText("")
        # Change cursor
        self.setCursor(QCursor(Qt.ArrowCursor))
        # Reset mouse rubberband
        self.Cursor_Canvas_RubberBand.reset(QgsWkbTypes.PointGeometry)
class RectangleMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface, dbm, imageRegistry, apisLayer):
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.dbm = dbm
        self.imageRegistry = imageRegistry
        self.apisLayer = apisLayer

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setColor(QColor(255, 128, 0, 255))
        self.rubberBand.setFillColor(QColor(255, 128, 0, 128))
        self.rubberBand.setWidth(1)

        self.topic = 'image'  # 'image', 'site', 'findspot'

        self.reset()

        self.imageSelectionListDlg = APISImageSelectionList(
            self.iface,
            self.dbm,
            self.imageRegistry,
            self.apisLayer,
            parent=self.iface.mainWindow())
        self.siteSelectionListDlg = APISSiteSelectionList(
            self.iface,
            self.dbm,
            self.imageRegistry,
            self.apisLayer,
            parent=self.iface.mainWindow())
        self.findspotSelectionListDlg = APISFindspotSelectionList(
            self.iface,
            self.dbm,
            self.imageRegistry,
            self.apisLayer,
            parent=self.iface.mainWindow())

        self.worker = None

    def setTopic(self, topic):
        self.topic = topic

    def deactivate(self):
        super(RectangleMapTool, self).deactivate()
        self.deactivated.emit()

    def activate(self):
        self.canvas.setCursor(
            QgsApplication.getThemeCursor(QgsApplication.Cursor.Select))

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

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        r = self.rectangle()

        #QMessageBox.warning(None, "Bild", u"Punkt: {0}".format(epsg))

        srcCrs = self.canvas.mapSettings().destinationCrs()
        destCrs = QgsCoordinateReferenceSystem(
            4312, QgsCoordinateReferenceSystem.EpsgCrsId)
        ct = QgsCoordinateTransform(srcCrs, destCrs, QgsProject.instance())
        if r is None:
            #QMessageBox.warning(None, "Bild", u"Punkt: {0}".format(self.endPoint.wellKnownText()))

            p = QgsGeometry.fromPointXY(self.endPoint)
            p.transform(ct)
            #QMessageBox.warning(None, "Bild", u"Punkt: {0}".format(self.endPoint.x()))
            #self.openImageSelectionListDialogByLocation(p.asWkt(8))
            self.startWorker(p.asWkt(8))

        else:
            #.warning(None, "Bild", u"Rechteck: {0}, {1}, {2}, {3}".format(r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()))

            r2 = QgsGeometry.fromRect(r)
            r2.transform(ct)
            #QMessageBox.warning(None, "Bild", u"Polygon: {0}".format(r2.asoWkt(8)))
            #self.openImageSelectionListDialogByLocation(r2.asoWkt(8))
            self.startWorker(r2.asWkt(8))
            #print "Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()

    def openImageSelectionListDialogByLocation(self, query):
        # progressMessageBar = self.iface.messageBar().createMessage("Luftbilder werden gesucht")
        # progress = QProgressBar()
        # progress.setMinimum(0)
        # progress.setMaximum(0)
        # progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
        # progressMessageBar.layout().addWidget(progress)
        # self.iface.messageBar().pushWidget(progressMessageBar, self.iface.messageBar().INFO)

        res = self.imageSelectionListDlg.loadImageListBySqlQuery(query)
        if res:
            self.imageSelectionListDlg.show()
            if self.imageSelectionListDlg.exec_():
                pass

        self.rubberBand.hide()

    def openSiteSelectionListDialogByLocation(self, query):
        info = u"gefunden für den ausgewählten Bereich."
        res = self.siteSelectionListDlg.loadSiteListBySpatialQuery(query, info)
        if res:
            self.siteSelectionListDlg.show()
            if self.siteSelectionListDlg.exec_():
                pass

        self.rubberBand.hide()

    def openFindspotSelectionListDialogByLocation(self, query):
        info = u"gefunden für den ausgewählten Bereich."
        res = self.findspotSelectionListDlg.loadFindspotListBySpatialQuery(
            query, info)
        if res:
            self.findspotSelectionListDlg.show()
            #if self.findspotSelectionListDlg.exec_():
            #    pass

        self.rubberBand.hide()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

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

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

        return QgsRectangle(self.startPoint, self.endPoint)

    def startWorker(self, geometry):
        # create a new worker instance

        if self.worker is None:

            worker = Worker(self.dbm, geometry, self.topic)

            # configure the QgsMessageBar
            messageBar = self.iface.messageBar().createMessage(
                u'Räumliche Suche wird durchgeführt ...', )
            progressBar = QProgressBar()
            progressBar.setMinimum(0)
            progressBar.setMaximum(0)
            progressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            cancelButton = QPushButton()
            cancelButton.setText('Cancel')
            cancelButton.clicked.connect(self.killWorker)
            messageBar.layout().addWidget(progressBar)
            self.progressBar = progressBar
            messageBar.layout().addWidget(cancelButton)
            self.iface.messageBar().pushWidget(messageBar, Qgis.Info)
            self.messageBar = messageBar

            # start the worker in a new thread
            thread = QThread(self)
            worker.moveToThread(thread)
            worker.finished.connect(self.workerFinished)
            worker.error.connect(self.workerError)
            #worker.progress.connect(progressBar.setValue)
            thread.started.connect(worker.run)
            thread.start()
            self.thread = thread
            self.worker = worker

    def killWorker(self):
        self.worker.kill()
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(100)

    def workerFinished(self, query, topic):
        # clean up the worker and thread
        self.worker.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()
        # remove widget from message bar
        self.iface.messageBar().popWidget(self.messageBar)
        if query is not None:
            # report the result
            #query = result
            if not self.worker.killed:
                if topic == 'image':
                    self.openImageSelectionListDialogByLocation(query)
                elif topic == 'site':
                    self.openSiteSelectionListDialogByLocation(query)
                elif topic == 'findspot':
                    self.openFindspotSelectionListDialogByLocation(query)
            else:
                self.rubberBand.hide()
            #self.iface.messageBar().pushMessage('Result')
        else:
            # notify the user that something went wrong
            self.iface.messageBar().pushMessage(
                'Something went wrong! See the message log for more information.',
                level=Qgis.Critical,
                duration=3)

        self.worker = None

    def workerError(self, e, exception_string):
        QgsMessageLog.logMessage(
            'APIS Search Worker thread raised an exception:\n'.format(
                exception_string),
            tag='APIS',
            level=Qgis.Critical)
Example #34
0
class LeggerMapVisualisation(object):
    # self.line_layer.crs()
    def __init__(self, iface, source_crs):
        self.iface = iface

        self.source_crs = source_crs

        # temp layer for side profile trac
        self.rb = QgsRubberBand(self.iface.mapCanvas())
        self.rb.setColor(Qt.red)
        self.rb.setWidth(2)

        # temp layer for last selected point
        self.point_markers = []
        self.active_route = None

        self.hover_marker = QgsVertexMarker(self.iface.mapCanvas())
        self.hover_marker.setIconType(QgsVertexMarker.ICON_X)
        self.hover_marker.setColor(Qt.red)
        self.hover_marker.setPenWidth(6)

        self.dist_calc = QgsDistanceArea()

    def close(self):
        self.reset()
        self.iface.mapCanvas().scene().removeItem(self.hover_marker)

    def set_sideview_route(self, route):

        self.reset()

        self.active_route = route
        transform = QgsCoordinateTransform(
            self.source_crs,
            self.iface.mapCanvas().mapRenderer().destinationCrs())

        for pnt in route.path_vertexes:
            t_pnt = transform.transform(pnt)
            self.rb.addPoint(t_pnt)

        for point, point_id, dist in route.path_points:

            marker = QgsVertexMarker(self.iface.mapCanvas())
            marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            marker.setColor(Qt.red)
            marker.setPenWidth(4)
            marker.setCenter(transform.transform(point))
            self.point_markers.append(marker)

    def reset(self):
        self.rb.reset()
        self.active_route = None

        for marker in self.point_markers:
            self.iface.mapCanvas().scene().removeItem(marker)

        self.point_markers = []

        self.hover_marker.setCenter(QgsPoint(0.0, 0.0))

    def hover_graph(self, meters_from_start):

        transform = QgsCoordinateTransform(
            self.source_crs,
            self.iface.mapCanvas().mapRenderer().destinationCrs())

        if self.active_route is None:
            return

        if meters_from_start < 0.0:
            meters_from_start = 0.0
        elif (len(self.active_route.path) > 0 and
              meters_from_start > self.active_route.path[-1][-1][1]):
            meters_from_start = self.active_route.path[-1][-1][1]

        for route_part in self.active_route.path:
            if meters_from_start <= route_part[-1][1]:
                for part in route_part:
                    if meters_from_start <= part[1]:
                        if part[3] == 1:
                            distance_on_line = meters_from_start - part[0]
                        else:
                            distance_on_line = part[1] - meters_from_start

                        length, unit_type = self.dist_calc.convertMeasurement(
                            distance_on_line,
                            QGis.Meters, QGis.Degrees, False)  # QGis.Degrees

                        point = part[4].geometry().interpolate(length)
                        self.hover_marker.setCenter(
                            transform.transform(point.asPoint()))
                        return

    def hover_map(self, point_geometry):
        pass

    def show_selectable_points(self, graph_tree):
        pass

    def hide_selectable_points(self):
        pass
Example #35
0
class RectangleMapTool(QgsMapToolEmitPoint):

    rectangleCreated = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setColor(QColor(255, 0, 0, 100))
        self.rubberBand.setWidth(2)

        self.reset()

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

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        if self.rectangle() is not None:
            self.rectangleCreated.emit()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

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

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

        return QgsRectangle(self.startPoint, self.endPoint)

    def setRectangle(self, rect):
        if rect == self.rectangle():
            return False

        if rect is None:
            self.reset()
        else:
            self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum())
            self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum())
            self.showRect(self.startPoint, self.endPoint)
        return True

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #36
0
class PickerAOIPointTool(QgsMapTool):
    def __init__(self, cad):
        QgsMapTool.__init__(self, cad.render_widget.canvas)
        self.cad = cad
        # set rubber band style
        color = QColor("red")
        color.setAlpha(70)
        # create the main polygon rubber band
        self.rubber_band = QgsRubberBand(cad.render_widget.canvas,
                                         QgsWkbTypes.PolygonGeometry)
        self.rubber_band.setColor(color)
        self.rubber_band.setWidth(3)
        # create the mouse/tmp polygon rubber band, this is main rubber band + current mouse position
        self.tmp_rubber_band = QgsRubberBand(cad.render_widget.canvas,
                                             QgsWkbTypes.PolygonGeometry)
        self.tmp_rubber_band.setColor(color)
        self.tmp_rubber_band.setWidth(3)
        self.tmp_rubber_band.setLineStyle(Qt.DotLine)

    def finish_drawing(self):
        self.rubber_band = None
        self.tmp_rubber_band = None
        # restart point tool
        self.clean()
        self.cad.render_widget.canvas.unsetMapTool(self)
        self.cad.render_widget.canvas.setMapTool(
            self.cad.render_widget.pan_zoom_tool)

    def canvasMoveEvent(self, event):
        if self.tmp_rubber_band is None:
            return
        if self.tmp_rubber_band and self.tmp_rubber_band.numberOfVertices():
            x = event.pos().x()
            y = event.pos().y()
            point = self.cad.render_widget.canvas.getCoordinateTransform(
            ).toMapCoordinates(x, y)
            self.tmp_rubber_band.removeLastPoint()
            self.tmp_rubber_band.addPoint(point)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete:
            self.rubber_band.removeLastPoint()
            self.tmp_rubber_band.removeLastPoint()
        if event.key() == Qt.Key_Escape:
            self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
            self.tmp_rubber_band.reset(QgsWkbTypes.PolygonGeometry)

    def canvasPressEvent(self, event):
        if self.rubber_band is None:
            self.finish_drawing()
            return
        # new point on polygon
        if event.button() == Qt.LeftButton:
            x = event.pos().x()
            y = event.pos().y()
            point = self.cad.render_widget.canvas.getCoordinateTransform(
            ).toMapCoordinates(x, y)
            self.rubber_band.addPoint(point)
            self.tmp_rubber_band.addPoint(point)
        # save polygon
        if event.button() == Qt.RightButton:
            if self.rubber_band and self.rubber_band.numberOfVertices():
                if self.rubber_band.numberOfVertices() < 3:
                    self.finish_drawing()
                    return
                self.tmp_rubber_band.removeLastPoint()
                new_feature = QgsFeature()
                new_feature.setGeometry(self.rubber_band.asGeometry())
                self.cad.rubber_bands.append(self.rubber_band)
                self.cad.tmp_rubber_band.append(self.tmp_rubber_band)
                self.rubber_band = None
                self.tmp_rubber_band = None
                self.finish_drawing()
                # add the new feature and update the statistics
                self.cad.aoi_changes(new_feature)

    def keyReleaseEvent(self, event):
        if event.key() in [
                Qt.Key_Up, Qt.Key_Down, Qt.Key_Right, Qt.Key_Left,
                Qt.Key_PageUp, Qt.Key_PageDown
        ]:
            QTimer.singleShot(
                10, self.cad.render_widget.parent_view.canvas_changed)
class RectangleMapTool(QgsMapToolEmitPoint):
    """Map tool that lets the user define the analysis extents."""

    rectangle_created = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        """Constructor for the map tool.

        :param canvas: Canvas that tool will interact with.
        :type canvas: QgsMapCanvas
        """
        self.canvas = canvas
        self.start_point = None
        self.end_point = None
        self.is_emitting_point = False

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line)
        self.rubber_band.setColor(QColor(0, 0, 240, 100))
        # Needs QGIS 2.6
        # self.rubber_band.setFillColor(QColor(0, 0, 240, 0))
        self.rubber_band.setWidth(1)

        self.reset()

    def reset(self):
        """
        Clear the rubber band for the analysis extents.
        """
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Handle canvas press events so we know when user is capturing the rect.

        :param e: A Qt event object.
        :type: QEvent
        """
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
        self.is_emitting_point = True

        self.show_rectangle(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):
        """
        Handle canvas release events  has finished capturing e

        :param e: A Qt event object.
        :type: QEvent
        """
        _ = e
        self.is_emitting_point = False
        self.rectangle_created.emit()

    def canvasMoveEvent(self, e):
        """

        :param e:
        :return:
        """
        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rectangle(self.start_point, self.end_point)

    def show_rectangle(self, start_point, end_point):
        """
        Show the rectangle on the canvas.

        :param start_point: QGIS Point object representing the origin (
            top left).
        :type start_point: QgsPoint

        :param end_point: QGIS Point object representing the contra-origin (
            bottom right).
        :type end_point: QgsPoint

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

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

        update_canvas = False
        self.rubber_band.addPoint(point1, update_canvas)
        self.rubber_band.addPoint(point2, update_canvas)
        self.rubber_band.addPoint(point3, update_canvas)
        self.rubber_band.addPoint(point4, update_canvas)
        # noinspection PyArgumentEqualDefault
        # no False so canvas will update
        # close the polygon otherwise it shows as a filled rect
        self.rubber_band.addPoint(point1)
        self.rubber_band.show()

    def rectangle(self):
        """
        Accessor for the rectangle.

        :return: A rectangle showing the designed extent.
        :rtype: QgsRectangle
        """
        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 set_rectangle(self, rectangle):
        """
        Set the rectangle for the selection.
        :param rectangle:
        :return:
        """
        if rectangle == self.rectangle():
            return False

        if rectangle is None:
            self.reset()
        else:
            self.start_point = QgsPoint(rectangle.xMinimum(),
                                        rectangle.yMinimum())
            self.end_point = QgsPoint(rectangle.xMaximum(),
                                      rectangle.yMaximum())
            self.show_rectangle(self.start_point, self.end_point)
        return True

    def deactivate(self):
        """
        Disable the tool.
        """
        self.rubber_band.reset(QGis.Polygon)
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #38
0
class GeodesicMeasureDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent):
        super(GeodesicMeasureDialog, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface
        self.canvas = iface.mapCanvas()
        qset = QSettings()

        self.restoreGeometry(
            qset.value("ShapeTools/MeasureDialogGeometry",
                       QByteArray(),
                       type=QByteArray))
        self.closeButton.clicked.connect(self.closeDialog)
        self.newButton.clicked.connect(self.newDialog)
        self.saveToLayerButton.clicked.connect(self.saveToLayer)
        self.saveToLayerButton.setEnabled(False)

        self.unitsComboBox.addItems(DISTANCE_LABELS)

        self.tableWidget.setColumnCount(3)
        self.tableWidget.setSortingEnabled(False)
        self.tableWidget.setHorizontalHeaderLabels(
            [tr('Heading To'),
             tr('Heading From'),
             tr('Distance')])

        self.unitsComboBox.activated.connect(self.unitsChanged)

        self.capturedPoints = []
        self.distances = []
        self.activeMeasuring = True
        self.lastMotionPt = None
        self.unitsChanged()
        self.currentDistance = 0.0

        self.pointRb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.pointRb.setColor(settings.rubberBandColor)
        self.pointRb.setIconSize(10)
        self.lineRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.lineRb.setColor(settings.rubberBandColor)
        self.lineRb.setWidth(3)
        self.tempRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.tempRb.setColor(settings.rubberBandColor)
        self.tempRb.setWidth(3)

    def ready(self):
        return self.activeMeasuring

    def stop(self):
        self.activeMeasuring = False
        self.lastMotionPt = None

    def closeEvent(self, event):
        self.closeDialog()

    def closeDialog(self):
        self.clear()
        QSettings().setValue("ShapeTools/MeasureDialogGeometry",
                             self.saveGeometry())
        self.close()

    def newDialog(self):
        self.clear()
        self.initGeodLabel()

    def initGeodLabel(self):
        label = tr('Ellipsoid: ') + settings.ellipseDescription
        self.geodLabel.setText(label)

    def keyPressed(self, key):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        if self.motionReady():
            if self.lastMotionPt == None:
                return
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 1],
                                             self.lastMotionPt)
        else:
            if index < 2:
                return
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 2],
                                             self.capturedPoints[index - 1])

        distance = self.unitDistance(distance)
        clipboard = QApplication.clipboard()
        if key == Qt.Key_1 or key == Qt.Key_F:
            s = '{:.{prec}f}'.format(startAngle,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Heading to {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_2 or key == Qt.Key_T:
            s = '{:.{prec}f}'.format(endAngle,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Heading from {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_3 or key == Qt.Key_D:
            s = '{:.{prec}f}'.format(distance,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Distance {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_4 or key == Qt.Key_A:
            total = 0.0
            num = len(self.capturedPoints)
            for i in range(1, num):
                (d, startA,
                 endA) = self.calcParameters(self.capturedPoints[i - 1],
                                             self.capturedPoints[i])
                total += d
            total = self.unitDistance(total)
            # Add in the motion distance
            if self.motionReady():
                total += distance
            s = '{:.{prec}f}'.format(total,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Total distance {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        else:
            return

    def unitsChanged(self):
        label = "Distance [{}]".format(
            DISTANCE_LABELS[self.unitsComboBox.currentIndex()])
        item = QTableWidgetItem(label)
        self.tableWidget.setHorizontalHeaderItem(2, item)
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                item = QTableWidgetItem('{:.4f}'.format(
                    self.unitDistance(self.distances[i])))
                self.tableWidget.setItem(i, 2, item)
                i += 1
            self.formatTotal()

    def motionReady(self):
        if len(self.capturedPoints) > 0 and self.activeMeasuring:
            return True
        return False

    def addPoint(self, pt, button):
        self.currentDistance = 0
        index = len(self.capturedPoints)
        if index > 0 and pt == self.capturedPoints[index - 1]:
            # the clicked point is the same as the previous so just ignore it
            return
        self.capturedPoints.append(pt)
        # Add rubber band points
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        ptCanvas = transform.transform(pt.x(), pt.y())
        self.pointRb.addPoint(ptCanvas, True)
        # If there is more than 1 point add it to the table
        if index > 0:
            self.saveToLayerButton.setEnabled(True)
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 1],
                                             self.capturedPoints[index])
            self.distances.append(distance)
            self.insertParams(index, distance, startAngle, endAngle)
            # Add Rubber Band Line
            linePts = self.getLinePts(distance, self.capturedPoints[index - 1],
                                      self.capturedPoints[index])
            self.lineRb.addGeometry(QgsGeometry.fromPolylineXY(linePts), None)
        self.formatTotal()

    def inMotion(self, pt):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        (self.currentDistance, startAngle,
         endAngle) = self.calcParameters(self.capturedPoints[index - 1], pt)
        self.insertParams(index, self.currentDistance, startAngle, endAngle)
        self.formatTotal()
        linePts = self.getLinePts(self.currentDistance,
                                  self.capturedPoints[index - 1], pt)
        self.lastMotionPt = pt
        self.tempRb.setToGeometry(QgsGeometry.fromPolylineXY(linePts), None)

    def calcParameters(self, pt1, pt2):
        l = geod.Inverse(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        az2 = (l['azi2'] + 180) % 360.0
        if az2 > 180:
            az2 = az2 - 360.0
        az1 = l['azi1']

        # Check to see if the azimuth values should be in the range or 0 to 360
        # The default is -180 to 180
        if settings.mtAzMode:
            if az1 < 0:
                az1 += 360.0
            if az2 < 0:
                az2 += 360
        return (l['s12'], az1, az2)

    def getLinePts(self, distance, pt1, pt2):
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        pt1c = transform.transform(pt1.x(), pt1.y())
        pt2c = transform.transform(pt2.x(), pt2.y())
        if distance < 10000:
            return [pt1c, pt2c]
        l = geod.InverseLine(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        n = int(math.ceil(distance / 10000.0))
        if n > 20:
            n = 20
        seglen = distance / n
        pts = [pt1c]
        for i in range(1, n):
            s = seglen * i
            g = l.Position(
                s,
                Geodesic.LATITUDE | Geodesic.LONGITUDE | Geodesic.LONG_UNROLL)
            ptc = transform.transform(g['lon2'], g['lat2'])
            pts.append(ptc)
        pts.append(pt2c)
        return pts

    def saveToLayer(self):
        units = self.unitDesignator()
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        fields = QgsFields()
        fields.append(QgsField("label", QVariant.String))
        fields.append(QgsField("value", QVariant.Double))
        fields.append(QgsField("units", QVariant.String))
        fields.append(QgsField("heading_to", QVariant.Double))
        fields.append(QgsField("heading_from", QVariant.Double))
        fields.append(QgsField("total_dist", QVariant.Double))

        layer = QgsVectorLayer("LineString?crs={}".format(canvasCrs.authid()),
                               "Measurements", "memory")
        dp = layer.dataProvider()
        dp.addAttributes(fields)
        layer.updateFields()

        num = len(self.capturedPoints)
        total = 0.0
        for i in range(1, num):
            (distance, startA,
             endA) = self.calcParameters(self.capturedPoints[i - 1],
                                         self.capturedPoints[i])
            total += distance
        total = self.unitDistance(total)
        for i in range(1, num):
            (distance, startA,
             endA) = self.calcParameters(self.capturedPoints[i - 1],
                                         self.capturedPoints[i])
            pts = self.getLinePts(distance, self.capturedPoints[i - 1],
                                  self.capturedPoints[i])
            distance = self.unitDistance(distance)
            feat = QgsFeature(layer.fields())
            feat.setAttribute(0, "{:.2f} {}".format(distance, units))
            feat.setAttribute(1, distance)
            feat.setAttribute(2, units)
            feat.setAttribute(3, startA)
            feat.setAttribute(4, endA)
            feat.setAttribute(5, total)
            feat.setGeometry(QgsGeometry.fromPolylineXY(pts))
            dp.addFeatures([feat])

        label = QgsPalLayerSettings()
        label.fieldName = 'label'
        try:
            label.placement = QgsPalLayerSettings.Line
        except:
            label.placement = QgsPalLayerSettings.AboveLine
        format = label.format()
        format.setColor(settings.measureTextColor)
        format.setNamedStyle('Bold')
        label.setFormat(format)
        labeling = QgsVectorLayerSimpleLabeling(label)
        layer.setLabeling(labeling)
        layer.setLabelsEnabled(True)
        renderer = layer.renderer()
        renderer.symbol().setColor(settings.measureLineColor)
        renderer.symbol().setWidth(0.5)

        layer.updateExtents()
        QgsProject.instance().addMapLayer(layer)

    def insertParams(self, position, distance, startAngle, endAngle):
        if position > self.tableWidget.rowCount():
            self.tableWidget.insertRow(position - 1)
        item = QTableWidgetItem('{:.4f}'.format(self.unitDistance(distance)))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 2, item)
        item = QTableWidgetItem('{:.4f}'.format(startAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 0, item)
        item = QTableWidgetItem('{:.4f}'.format(endAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 1, item)

    def formatTotal(self):
        total = self.currentDistance
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                total += self.distances[i]
                i += 1
        self.distanceLineEdit.setText('{:.2f}'.format(
            self.unitDistance(total)))

    def updateRBColor(self):
        self.pointRb.setColor(settings.rubberBandColor)
        self.lineRb.setColor(settings.rubberBandColor)
        self.tempRb.setColor(settings.rubberBandColor)

    def clear(self):
        self.tableWidget.setRowCount(0)
        self.capturedPoints = []
        self.distances = []
        self.activeMeasuring = True
        self.currentDistance = 0.0
        self.distanceLineEdit.setText('')
        self.pointRb.reset(QgsWkbTypes.PointGeometry)
        self.lineRb.reset(QgsWkbTypes.LineGeometry)
        self.tempRb.reset(QgsWkbTypes.LineGeometry)
        self.saveToLayerButton.setEnabled(False)
        self.updateRBColor()

    def unitDistance(self, distance):
        units = self.unitsComboBox.currentIndex()
        if units == 0:  # kilometers
            return distance / 1000.0
        elif units == 1:  # meters
            return distance
        elif units == 2:  # centimeters
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceCentimeters)
        elif units == 3:  # miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceMiles)
        elif units == 4:  # yards
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceYards)
        elif units == 5:  # feet
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet)
        elif units == 6:  # inches
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet) * 12
        elif units == 7:  # nautical miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters,
                QgsUnitTypes.DistanceNauticalMiles)

    def unitDesignator(self):
        units = self.unitsComboBox.currentIndex()
        return unitsAbbr[units]
class AuditDialog(QDialog, Ui_audit, SettingDialog):
    rejectShowEvent = pyqtSignal()
    performSearchAtShowEvent = pyqtSignal()

    def __init__(self, iface, layerId=None, featureId=None):
        QDialog.__init__(self)
        self.setupUi(self)
        self.settings = MySettings()
        SettingDialog.__init__(self, self.settings, False, True)  # column chooser, advanced search options

        #init variables
        self.layerId = layerId
        self.featureId = featureId
        self.layer = None
        self.rubber = QgsRubberBand(iface.mapCanvas())
        self.mapCanvas = iface.mapCanvas()
        self.resuts = dict()

        # connect "pan and show geometry" check box to draw in rubber band
        self.panShowGeometry.clicked.connect(self.displayGeomDifference)

        # reject properly showEvent if checking fails
        self.rejectShowEvent.connect(self.reject, Qt.QueuedConnection)
        # start search directly at the end of showEvent if enough params
        self.performSearchAtShowEvent.connect(self.on_searchButton_clicked, Qt.QueuedConnection)

        # setup layer - field combo, with primary key selector as field
        self.layerComboManager = VectorLayerCombo(self.layerCombo, layerId,
                                                  {"dataProvider": "postgres", "finishInit": False,
                                                   "skipLayers": [lambda: self.settings.value("logLayer")]})
        self.layerComboManager.finishInit()

        # log layer
        self.logLayer = LogLayer()
        self.logLayer.setProgressMax.connect(self.progressBar.setMaximum)
        self.logLayer.setProgressMin.connect(self.progressBar.setMinimum)
        self.logLayer.setProgressValue.connect(self.progressBar.setValue)

        # logged actions table
        self.loggedActionsLayout = QGridLayout(self.loggedActionsWidget)
        self.loggedActionsTable = LoggedActionsTable(self.loggedActionsWidget)
        self.loggedActionsLayout.addWidget(self.loggedActionsTable, 0, 0, 1, 1)
        self.loggedActionsTable.itemSelectionChanged.connect(self.displayDifference)

        # difference viewer
        self.differenceLayout = QGridLayout(self.differenceViewerWidget)
        self.differenceViewer = DifferenceViewer(self.differenceViewerWidget)
        self.differenceLayout.addWidget(self.differenceViewer, 0, 0, 1, 1)

        # set dates
        now = QDateTime.currentDateTime()
        self.searchBeforeDate.setDateTime(now)
        self.searchAfterDate.setDateTime(now.addDays(-7))

        # finish ui
        self.buttonDisplayMode(False)
        self.restoreButton.setEnabled(False)
        if featureId is not None:
            self.featureEdit.setText("%s" % featureId)
        self.adjustSize()

    def closeEvent(self, e):
        self.rubber.reset()

    def showEvent(self, e):
        SettingDialog.showEvent(self, e)
        while not self.logLayer.isValid():
            if not LoggedActionsTableChooserDialog().exec_():
                self.rejectShowEvent.emit()
                return
        if self.layerId is not None:
            self.layerCombo.setEnabled(False)
            layer = self.layerComboManager.getLayer()
            if layer is None:
                self.rejectShowEvent.emit()
                return
            if self.featureId is not None:
                self.featureEdit.setEnabled(False)
                f = QgsFeature()
                featReq = QgsFeatureRequest().setFilterFid(self.featureId).setFlags(QgsFeatureRequest.NoGeometry)
                if layer.getFeatures(featReq).nextFeature(f) is False:
                    self.rejectShowEvent.emit()
                    return
                self.performSearchAtShowEvent.emit()
        else:
            layer = self.mapCanvas.currentLayer()
            self.layerComboManager.setLayer(layer)


    @pyqtSignature("on_layerCombo_currentIndexChanged(int)")
    def on_layerCombo_currentIndexChanged(self, i):
        self.layer = self.layerComboManager.getLayer()
        self.panShowGeometry.setEnabled(self.layer is not None and self.layer.hasGeometryType())

    @pyqtSignature("on_stopButton_clicked()")
    def on_stopButton_clicked(self):
        self.logLayer.interrupt()

    @pyqtSignature("on_searchButton_clicked()")
    def on_searchButton_clicked(self):
        self.layer = self.layerComboManager.getLayer()
        pkeyName = primaryKey(self.layer)
        if self.layer is None or pkeyName is None:
            return
        self.loggedActionsTable.geomColumn = self.layer.hasGeometryType()
        featureId = int(self.featureEdit.text() or 0)
        searchBeforeDate = QDateTime()
        if self.searchBefore.isChecked():
            searchBeforeDate = self.searchAfterDate.dateTime()
        searchAfterDate = QDateTime()
        if self.searchAfter.isChecked():
            searchAfterDate = self.searchAfterDate.dateTime()
        self.buttonDisplayMode(True)
        self.results = self.logLayer.performSearch(self.layer, featureId, pkeyName,
                                                   self.searchInserts.isChecked(), self.searchUpdates.isChecked(),
                                                   self.searchDeletes.isChecked(), self.searchOnlyGeometry.isChecked(),
                                                   searchAfterDate, searchBeforeDate)
        self.buttonDisplayMode(False)
        self.panShowGeometry.setEnabled(self.layer.hasGeometryType())
        self.displayLoggedActions()

    def buttonDisplayMode(self, searchOn):
        self.searchButton.setVisible(not searchOn)
        self.stopButton.setVisible(searchOn)
        self.progressBar.setVisible(searchOn)

    def displayLoggedActions(self):
        self.differenceViewer.clearRows()
        self.loggedActionsTable.displayColumns()
        self.loggedActionsTable.displayRows(self.results)

    def displayDifference(self):
        self.differenceViewer.clearRows()
        self.restoreButton.setEnabled(False)
        item = self.loggedActionsTable.selectedItems()
        if len(item) == 0:
            return
        rowId = item[0].data(Qt.UserRole)
        logRow = self.results[rowId]
        if logRow.featureLayer.isEditable():
            self.restoreButton.setEnabled(True)
        self.differenceViewer.display(logRow)
        self.displayGeomDifference()

    def displayGeomDifference(self):
        self.rubber.reset()
        item = self.loggedActionsTable.selectedItems()
        if len(item) == 0:
            return
        rowId = item[0].data(Qt.UserRole)
        logRow = self.results[rowId]

        if self.layer.hasGeometryType() and self.panShowGeometry.isChecked():
            geom = logRow.geometry()
            self.rubber.setToGeometry(geom, self.layer)
            panTo = self.mapCanvas.mapRenderer().layerExtentToOutputExtent(self.layer, geom.boundingBox())
            panTo.scale(1.5)
            self.mapCanvas.setExtent(panTo)
            self.mapCanvas.refresh()

    @pyqtSignature("on_columnChooserButton_clicked()")
    def on_columnChooserButton_clicked(self):
        ColumnChooserDialog().exec_()
        self.loggedActionsTable.displayColumns()
        self.loggedActionsTable.displayRows(self.results)

    @pyqtSignature("on_restoreButton_clicked()")
    def on_restoreButton_clicked(self):
        item = self.loggedActionsTable.selectedItems()
        if len(item) == 0:
            return
        rowId = item[0].data(Qt.UserRole)
        logRow = self.results[rowId]
        if not logRow.featureLayer.isEditable():
            return
        logRow.restoreFeature()
        self.mapCanvas.refresh()
Example #40
0
class ObstacleAreaJigSelectArea(QgsMapTool):
    def __init__(self, canvas, areaType):
        self.mCanvas = canvas
        self.areaType = areaType
        QgsMapTool.__init__(self, canvas)
        self.mCursor = Qt.ArrowCursor
        self.mRubberBand = None
        self.mDragging = False
        self.mSelectRect = QRect()
        self.mRubberBandResult = None
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.lineCount = 0
        self.resultGeomList = []
        self.geomList = []
        self.area = None
        self.isFinished = False


#     QgsRubberBand* mRubberBand;
#     def reset(self):
#         self.startPoint = None
#         self.endPoint = None
#         self.isDrawing = False
#         SelectByRect.RubberRect.reset(QGis.Polygon)
#         self.layer = self.canvas.currentLayer()

    def canvasPressEvent(self, e):
        QgisHelper.ClearRubberBandInCanvas(define._canvas)
        self.mSelectRect.setRect(0, 0, 0, 0)
        self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon)
        self.startPoint, self.pointID, self.layer = self.snapPoint(e.pos())

    def canvasMoveEvent(self, e):
        if self.areaType == ProtectionAreaType.Secondary:
            if self.lineCount == 0:
                define._messageLabel.setText(
                    "Select a line or arc representing the INNER edge of the secondary area."
                )
            elif self.lineCount == 1:
                define._messageLabel.setText(
                    "Select a line representing the OUTER edge of the secondary area."
                )
        elif self.areaType == ProtectionAreaType.Primary:
            define._messageLabel.setText("")
        elif self.areaType == ProtectionAreaType.PrimaryAndSecondary:
            if self.lineCount == 0:
                define._messageLabel.setText(
                    "Select a line or arc representing the INNER edge of the FIRST secondary area."
                )
            elif self.lineCount == 1:
                define._messageLabel.setText(
                    "Select a line representing the OUTER edge of the FIRST secondary area."
                )
            elif self.lineCount == 2:
                define._messageLabel.setText(
                    "Select a line or arc representing the INNER edge of the SECOND secondary area."
                )
            elif self.lineCount == 3:
                define._messageLabel.setText(
                    "Select a line representing the OUTER edge of the SECOND secondary area."
                )
        else:
            define._messageLabel.setText("")

        if (e.buttons() != Qt.LeftButton):
            return
        if (not self.mDragging):
            self.mDragging = True
            self.mSelectRect.setTopLeft(e.pos())
        self.mSelectRect.setBottomRight(e.pos())
        QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect,
                                            self.mRubberBand)

    def canvasReleaseEvent(self, e):
        self.endPoint, self.pointID, self.layer = self.snapPoint(e.pos())

        vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer(self.mCanvas)
        if (vlayer == None):
            if (self.mRubberBand != None):
                self.mRubberBand.reset(QGis.Polygon)
                del self.mRubberBand
                self.mRubberBand = None
                self.mDragging = False
            return

        if (not self.mDragging):
            QgsMapToolSelectUtils.expandSelectRectangle(
                self.mSelectRect, vlayer, e.pos())
        else:
            if (self.mSelectRect.width() == 1):
                self.mSelectRect.setLeft(self.mSelectRect.left() + 1)
            if (self.mSelectRect.height() == 1):
                self.mSelectRect.setBottom(self.mSelectRect.bottom() + 1)

        if (self.mRubberBand != None):
            QgsMapToolSelectUtils.setRubberBand(self.mCanvas, self.mSelectRect,
                                                self.mRubberBand)
            selectGeom = self.mRubberBand.asGeometry()

            selectedFeatures = QgsMapToolSelectUtils.setSelectFeaturesOrRubberband_Tas_1(
                self.mCanvas, selectGeom, e)
            if len(selectedFeatures) > 0:
                self.lineCount += 1
                geom = selectedFeatures[0].geometry()
                resultArray = QgisHelper.findArcOrLineInLineGeometry(
                    geom, selectGeom)
                # if resultArray != None:
                #     bulge = MathHelper.smethod_60(resultArray[0], resultArray[int(len(resultArray)/2)], resultArray[len(resultArray)-1])
                #     bulge1 = MathHelper.smethod_60(resultArray[len(resultArray)-1], resultArray[int(len(resultArray)/2)], resultArray[0])
                #     n = 0
                pointArray0 = geom.asPolyline()
                self.resultGeomList.append(resultArray)
                self.geomList.append(pointArray0)
                if self.lineCount == 2 and self.areaType != ProtectionAreaType.PrimaryAndSecondary and self.areaType != ProtectionAreaType.Complex:
                    self.area = self.makeArea(self.resultGeomList,
                                              self.areaType)
                    pointArray = self.getPointArray(
                        self.resultGeomList).method_14_closed()
                    self.mRubberBandResult = None
                    self.mRubberBandResult = QgsRubberBand(
                        self.mCanvas, QGis.Polygon)
                    self.mRubberBandResult.setFillColor(
                        QColor(255, 255, 255, 100))
                    self.mRubberBandResult.setBorderColor(QColor(0, 0, 0))
                    for point in pointArray:
                        self.mRubberBandResult.addPoint(point)
                    self.mRubberBandResult.show()

                    self.emit(SIGNAL("outputResult"), self.area,
                              self.mRubberBandResult)
                    self.lineCount = 0
                    self.resultGeomList = []
                    self.isFinished = True
                    # self.rubberBandLine.reset(QGis.Line)
                elif self.lineCount == 4 and self.areaType == ProtectionAreaType.PrimaryAndSecondary:
                    self.area = self.makeArea(self.resultGeomList,
                                              self.areaType)
                    pointArray = self.getPointArray(
                        [self.resultGeomList[1],
                         self.resultGeomList[3]]).method_14_closed()
                    self.mRubberBandResult = None
                    self.mRubberBandResult = QgsRubberBand(
                        self.mCanvas, QGis.Polygon)
                    self.mRubberBandResult.setFillColor(
                        QColor(255, 255, 255, 100))
                    self.mRubberBandResult.setBorderColor(QColor(0, 0, 0))
                    for point in pointArray:
                        self.mRubberBandResult.addPoint(point)
                    self.mRubberBandResult.show()

                    self.emit(SIGNAL("outputResult"), self.area,
                              self.mRubberBandResult)
                    self.lineCount = 0
                    self.resultGeomList = []
                # else:
                #     return
            del selectGeom

            self.mRubberBand.reset(QGis.Polygon)
            del self.mRubberBand
            self.mRubberBand = None
        self.mDragging = False

    def getPointArray(self, geomList):
        pointArrayInner = geomList[0]
        pointArray1Outer = geomList[1]

        innerStartPoint = pointArrayInner[0]
        innerEndPoint = pointArrayInner[1]
        innerBulge = pointArrayInner[2]
        outerStartPoint = pointArray1Outer[0]
        outerEndPoint = pointArray1Outer[1]
        outerBulge = pointArray1Outer[2]

        line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint])
        line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint])

        # for i in range(1, len(pointArray0)):

        if line0.intersects(line1):
            tempPoint = outerStartPoint
            outerStartPoint = outerEndPoint
            outerEndPoint = tempPoint
            outerBulge = -outerBulge

        polylineArea = PolylineArea()
        polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge))
        polylineArea.Add(PolylineAreaPoint(innerEndPoint))
        polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge))
        polylineArea.Add(PolylineAreaPoint(outerStartPoint))
        return polylineArea

    def makeArea(self, geomList, areaType):
        if areaType == ProtectionAreaType.Primary or areaType == ProtectionAreaType.Secondary:
            return self.makePrimaryAreaOrSecondaryArea(geomList, areaType)
        elif areaType == ProtectionAreaType.PrimaryAndSecondary:
            pointArray0 = geomList[0]
            pointArray1 = geomList[1]
            pointArray2 = geomList[2]
            pointArray3 = geomList[3]
            primaryArea = self.makePrimaryAreaOrSecondaryArea(
                [pointArray0, pointArray2], ProtectionAreaType.Primary)
            secondaryArea1 = self.makePrimaryAreaOrSecondaryArea(
                [pointArray0, pointArray1], ProtectionAreaType.Secondary)
            secondaryArea2 = self.makePrimaryAreaOrSecondaryArea(
                [pointArray2, pointArray3], ProtectionAreaType.Secondary)
            return PrimarySecondaryObstacleArea(primaryArea, secondaryArea1,
                                                secondaryArea2)
            # if len(geomList[0]) == 2 and len(geomList[1]) == 2 and len(geomList[2]) == 2 and len(geomList[3]) == 2:
            #     for i in range(1, len(geomList)):
            #         pointArray0 = geomList[0]
            #         pointArray1 = geomList[i]
            #         line0 = QgsGeometry.fromPolyline([pointArray0[0], pointArray1[0]])
            #         line1 = QgsGeometry.fromPolyline([pointArray0[len(pointArray0) - 1], pointArray1[len(pointArray1) - 1]])
            #         if line0.intersects(line1):
            #             pointArray1.reverse()
            #     pointArray0 = geomList[0]
            #     pointArray1 = geomList[1]
            #     pointArray2 = geomList[2]
            #     pointArray3 = geomList[3]
            #     area = PrimarySecondaryObstacleArea()
            #     area.set_areas(pointArray0, pointArray1, pointArray2, pointArray3)
            #     return area
            # return None

        return None

    def makePrimaryAreaOrSecondaryArea(self, geomList, areaType):
        pointArrayInner = geomList[0]
        pointArray1Outer = geomList[1]

        innerStartPoint = pointArrayInner[0]
        innerEndPoint = pointArrayInner[1]
        innerBulge = pointArrayInner[2]
        outerStartPoint = pointArray1Outer[0]
        outerEndPoint = pointArray1Outer[1]
        outerBulge = pointArray1Outer[2]

        line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint])
        line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint])

        # for i in range(1, len(pointArray0)):

        if line0.intersects(line1):
            tempPoint = Point3D(outerStartPoint.get_X(),
                                outerStartPoint.get_Y())
            outerStartPoint = Point3D(outerEndPoint.get_X(),
                                      outerEndPoint.get_Y())
            outerEndPoint = Point3D(tempPoint.get_X(), tempPoint.get_Y())
            outerBulge = -outerBulge
        if areaType == ProtectionAreaType.Primary:
            polylineArea = PolylineArea()
            polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge))
            polylineArea.Add(PolylineAreaPoint(innerEndPoint))
            polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge))
            polylineArea.Add(PolylineAreaPoint(outerStartPoint))
            return PrimaryObstacleArea(polylineArea)
        elif areaType == ProtectionAreaType.Secondary:
            if innerBulge == 0 and outerBulge == 0:
                return SecondaryObstacleArea(
                    innerStartPoint, innerEndPoint, outerStartPoint,
                    outerEndPoint,
                    MathHelper.getBearing(innerStartPoint, innerEndPoint))
            elif innerBulge != 0 and outerBulge != 0:
                if round(innerBulge, 1) != round(outerBulge, 1):
                    return None
                innerCenterPoint = MathHelper.smethod_71(
                    innerStartPoint, innerEndPoint, innerBulge)
                outerCenterPoint = MathHelper.smethod_71(
                    outerStartPoint, outerEndPoint, outerBulge)

                innerRadius = MathHelper.calcDistance(innerCenterPoint,
                                                      innerStartPoint)
                outerRadius = MathHelper.calcDistance(outerCenterPoint,
                                                      outerStartPoint)

                bearing = (
                    MathHelper.getBearing(innerCenterPoint, innerStartPoint) +
                    MathHelper.getBearing(innerCenterPoint, innerEndPoint)) / 2
                innerMiddlePoint = MathHelper.distanceBearingPoint(
                    innerCenterPoint, bearing, innerRadius)
                if round(
                        MathHelper.smethod_60(innerStartPoint,
                                              innerMiddlePoint, innerEndPoint),
                        4) != round(outerBulge, 4):
                    bearing += 3.14159265358979
                    innerMiddlePoint = MathHelper.distanceBearingPoint(
                        innerCenterPoint, bearing, innerRadius)

                bearing = (
                    MathHelper.getBearing(outerCenterPoint, outerStartPoint) +
                    MathHelper.getBearing(outerCenterPoint, outerEndPoint)) / 2
                outerMiddlePoint = MathHelper.distanceBearingPoint(
                    outerCenterPoint, bearing, outerRadius)
                if round(
                        MathHelper.smethod_60(outerStartPoint,
                                              outerMiddlePoint, outerEndPoint),
                        4) != round(outerBulge, 4):
                    bearing += 3.14159265358979
                    outerMiddlePoint = MathHelper.distanceBearingPoint(
                        outerCenterPoint, bearing, outerRadius)
                return SecondaryObstacleArea(innerStartPoint, innerMiddlePoint,
                                             innerEndPoint, outerStartPoint,
                                             None, outerMiddlePoint,
                                             outerEndPoint, innerBulge,
                                             innerBulge)
            return None

    def snapPoint(self, p, bNone=False):
        if define._snapping == False:
            return (
                define._canvas.getCoordinateTransform().toMapCoordinates(p),
                None, None)
        snappingResults = self.mSnapper.snapToBackgroundLayers(p)
        if (snappingResults[0] != 0 or len(snappingResults[1]) < 1):

            if bNone:
                return (None, None, None)
            else:
                return (define._canvas.getCoordinateTransform().
                        toMapCoordinates(p), None, None)
        else:
            return (snappingResults[1][0].snappedVertex,
                    snappingResults[1][0].snappedAtGeometry,
                    snappingResults[1][0].layer)
Example #41
0
class QgepMapToolConnectNetworkElements(QgsMapTool):
    """
    This map tool connects wastewater networkelements.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.reset()

        self.action.setChecked(True)

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

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

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

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

        self.rbline.movePoint(pt)

        self.snapresult = snap_match

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

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

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

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

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

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

        properties = list()

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

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

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

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

        self.reset()
Example #42
0
class MapWidget(Ui_CanvasWidget, QMainWindow):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        self.setupUi(self)

        self.firstshow = True
        self.layerbuttons = []
        self.editfeaturestack = []
        self.lastgpsposition = None
        self.project = None
        self.gps = None
        self.gpslogging = None
        self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas))

        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor)

        if hasattr(self.canvas, 'setParallelRenderingEnabled'):
            self.canvas.setParallelRenderingEnabled(True)

        pal = QgsPalLabeling()
        self.canvas.mapRenderer().setLabelingEngine(pal)
        self.canvas.setFrameStyle(QFrame.NoFrame)

        self.editgroup = QActionGroup(self)
        self.editgroup.setExclusive(True)
        self.editgroup.addAction(self.actionPan)
        self.editgroup.addAction(self.actionZoom_In)
        self.editgroup.addAction(self.actionZoom_Out)
        self.editgroup.addAction(self.actionInfo)

        self.actionGPS = GPSAction(":/icons/gps", self.canvas, self)
        self.projecttoolbar.addAction(self.actionGPS)

        gpsspacewidget= QWidget()
        gpsspacewidget.setMinimumWidth(30)
        gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget)

        self.dataentryselection = QAction(self.projecttoolbar)
        self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection)
        self.dataentryselection.triggered.connect(self.select_data_entry)

        self.marker = GPSMarker(self.canvas)
        self.marker.hide()

        self.currentfeatureband = QgsRubberBand(self.canvas)
        self.currentfeatureband.setIconSize(20)
        self.currentfeatureband.setWidth(10)
        self.currentfeatureband.setColor(QColor(186, 93, 212, 76))

        self.gpsband = QgsRubberBand(self.canvas)
        self.gpsband.setColor(QColor(0, 0, 212, 76))
        self.gpsband.setWidth(5)

        RoamEvents.editgeometry.connect(self.queue_feature_for_edit)
        RoamEvents.selectioncleared.connect(self.clear_selection)
        RoamEvents.selectionchanged.connect(self.highlight_selection)
        RoamEvents.featureformloaded.connect(self.feature_form_loaded)

        self.connectButtons()

    def init_qgisproject(self, doc):
        parser = ProjectParser(doc)
        canvasnode = parser.canvasnode
        self.canvas.freeze()
        self.canvas.mapRenderer().readXML(canvasnode)
        self.canvaslayers = parser.canvaslayers()
        self.canvas.setLayerSet(self.canvaslayers)
        #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0];
        #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0];
        #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0];
        #color = QColor(red, green, blue);
        #self.canvas.setCanvasColor(color)
        self.canvas.updateScale()
        return self.canvas.mapRenderer().destinationCrs()

    def showEvent(self, *args, **kwargs):
        if self.firstshow:
            self.canvas.refresh()
            self.canvas.repaint()
            self.firstshow = False

    def feature_form_loaded(self, form, feature, project, editmode):
        self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer)

    def highlight_selection(self, results):
        self.clear_selection()
        for layer, features in results.iteritems():
            band = self.selectionbands[layer]
            band.setColor(QColor(255, 0, 0, 200))
            band.setIconSize(20)
            band.setWidth(2)
            band.setBrushStyle(Qt.NoBrush)
            band.reset(layer.geometryType())
            for feature in features:
                band.addGeometry(feature.geometry(), layer)

    def highlight_active_selection(self, layer, feature, features):
        self.clear_selection()
        self.highlight_selection({layer: features})
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)

    def clear_selection(self):
        # Clear the main selection rubber band
        self.currentfeatureband.reset()
        # Clear the rest
        for band in self.selectionbands.itervalues():
            band.reset()

        self.editfeaturestack = []

    def queue_feature_for_edit(self, form, feature):
        def trigger_default_action():
            for action in self.projecttoolbar.actions():
                if action.property('dataentry') and action.isdefault:
                    action.trigger()
                    break

        self.editfeaturestack.append((form, feature))
        self.load_form(form)
        trigger_default_action()

    def clear_temp_objects(self):
        def clear_tool_band():
            """
            Clear the rubber band of the active tool if it has one
            """
            tool = self.canvas.mapTool()
            try:
                tool.clearBand()
            except AttributeError:
                # No clearBand method found, but that's cool.
                pass

        self.currentfeatureband.reset()
        clear_tool_band()


    def settings_updated(self, settings):
        self.actionGPS.updateGPSPort()
        gpslogging = settings.get('gpslogging', True)
        if self.gpslogging:
            self.gpslogging.logging = gpslogging

    def set_gps(self, gps, logging):
        self.gps = gps
        self.gpslogging = logging
        self.gps.gpsposition.connect(self.gps_update_canvas)
        self.gps.firstfix.connect(self.gps_first_fix)
        self.gps.gpsdisconnected.connect(self.gps_disconnected)

    def gps_update_canvas(self, position, gpsinfo):
        # Recenter map if we go outside of the 95% of the area
        if self.gpslogging.logging:
            self.gpsband.addPoint(position)
            self.gpsband.show()

        if roam.config.settings.get('gpscenter', True):
            if not self.lastgpsposition == position:
                self.lastposition = position
                rect = QgsRectangle(position, position)
                extentlimt = QgsRectangle(self.canvas.extent())
                extentlimt.scale(0.95)

                if not extentlimt.contains(position):
                    self.zoom_to_location(position)

        self.marker.show()
        self.marker.setCenter(position)

    def gps_first_fix(self, postion, gpsinfo):
        zoomtolocation = roam.config.settings.get('gpszoomonfix', True)
        if zoomtolocation:
            self.canvas.zoomScale(1000)
            self.zoom_to_location(postion)

    def zoom_to_location(self, position):
        rect = QgsRectangle(position, position)
        self.canvas.setExtent(rect)
        self.canvas.refresh()

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

    def select_data_entry(self):
        def showformerror(form):
            pass

        def actions():
            for form in self.project.forms:
                action = form.createuiaction()
                valid, failreasons = form.valid
                if not valid:
                    roam.utils.warning("Form {} failed to load".format(form.label))
                    roam.utils.warning("Reasons {}".format(failreasons))
                    action.triggered.connect(partial(showformerror, form))
                else:
                    action.triggered.connect(partial(self.load_form, form))
                yield action

        formpicker = PickActionDialog(msg="Select data entry form")
        formpicker.addactions(actions())
        formpicker.exec_()

    def project_loaded(self, project):
        self.project = project
        self.actionPan.trigger()
        try:
            firstform = project.forms[0]
            self.load_form(firstform)
            self.dataentryselection.setVisible(True)
        except IndexError:
            self.dataentryselection.setVisible(False)

        # Enable the raster layers button only if the project contains a raster layer.
        layers = QgsMapLayerRegistry.instance().mapLayers().values()
        hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers)
        self.actionRaster.setEnabled(hasrasters)
        self.defaultextent = self.canvas.extent()
        roam.utils.info("Extent: {}".format(self.defaultextent.toString()))

        self.infoTool.selectionlayers = project.selectlayersmapping()

        self.canvas.freeze(False)
        self.canvas.refresh()

    def setMapTool(self, tool, *args):
        self.canvas.setMapTool(tool)

    def connectButtons(self):
        def connectAction(action, tool):
            action.toggled.connect(partial(self.setMapTool, tool))

        def cursor(name):
            pix = QPixmap(name)
            pix = pix.scaled(QSize(24,24))
            return QCursor(pix)

        self.zoomInTool = QgsMapToolZoom(self.canvas, False)
        self.zoomOutTool = QgsMapToolZoom(self.canvas, True)
        self.panTool = PanTool(self.canvas)
        self.infoTool = InfoTool(self.canvas)

        connectAction(self.actionZoom_In, self.zoomInTool)
        connectAction(self.actionZoom_Out, self.zoomOutTool)
        connectAction(self.actionPan, self.panTool)
        connectAction(self.actionInfo, self.infoTool)

        self.zoomInTool.setCursor(cursor(':/icons/in'))
        self.zoomOutTool.setCursor(cursor(':/icons/out'))
        self.infoTool.setCursor(cursor(':/icons/info'))

        self.actionRaster.triggered.connect(self.toggleRasterLayers)

        self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit)

        self.actionHome.triggered.connect(self.homeview)

    def homeview(self):
        """
        Zoom the mapview canvas to the extents the project was opened at i.e. the
        default extent.
        """
        self.canvas.setExtent(self.defaultextent)
        self.canvas.refresh()

    def load_form(self, form):
        self.clearCapatureTools()
        self.dataentryselection.setIcon(QIcon(form.icon))
        self.dataentryselection.setText(form.icontext)
        self.create_capture_buttons(form)

    def create_capture_buttons(self, form):
        tool = form.getMaptool()(self.canvas)
        for action in tool.actions:
            # Create the action here.
            if action.ismaptool:
                action.toggled.connect(partial(self.setMapTool, tool))

            # Set the action as a data entry button so we can remove it later.
            action.setProperty("dataentry", True)
            self.editgroup.addAction(action)
            self.layerbuttons.append(action)
            self.projecttoolbar.insertAction(self.topspaceraction, action)
            action.setChecked(action.isdefault)

        if hasattr(tool, 'geometryComplete'):
            add = partial(self.add_new_feature, form)
            tool.geometryComplete.connect(add)
        else:
            tool.finished.connect(self.openForm)
            tool.error.connect(partial(self.showUIMessage, form.label))

    def add_new_feature(self, form, geometry):
        """
        Add a new new feature to the given layer
        """
        # TODO Extract into function.
        # NOTE This function is doing too much, acts as add and also edit.
        layer = form.QGISLayer
        if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]:
            geometry.convertToMultiType()

        try:
            form, feature = self.editfeaturestack.pop()
            self.editfeaturegeometry(form, feature, newgeometry=geometry)
            return
        except IndexError:
            pass

        layer = form.QGISLayer
        fields = layer.pendingFields()

        feature = QgsFeature(fields)
        feature.setGeometry(geometry)

        for index in xrange(fields.count()):
            pkindexes = layer.dataProvider().pkAttributeIndexes()
            if index in pkindexes and layer.dataProvider().name() == 'spatialite':
                continue

            value = layer.dataProvider().defaultValue(index)
            feature[index] = value

        RoamEvents.open_feature_form(form, feature, editmode=False)

    def editfeaturegeometry(self, form, feature, newgeometry):
        # TODO Extract into function.
        layer = form.QGISLayer
        layer.startEditing()
        feature.setGeometry(newgeometry)
        layer.updateFeature(feature)
        saved = layer.commitChanges()
        if not saved:
            map(roam.utils.error, layer.commitErrors())
        self.canvas.refresh()
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        RoamEvents.editgeometry_complete.emit(form, feature)

    def clearCapatureTools(self):
        captureselected = False
        for action in self.projecttoolbar.actions():
            if action.objectName() == "capture" and action.isChecked():
                captureselected = True

            if action.property('dataentry'):
                self.projecttoolbar.removeAction(action)
        return captureselected

    def toggleRasterLayers(self):
        """
        Toggle all raster layers on or off.
        """
        if not self.canvaslayers:
            return

        #Freeze the canvas to save on UI refresh
        self.canvas.freeze()
        for layer in self.canvaslayers:
            if layer.layer().type() == QgsMapLayer.RasterLayer:
                layer.setVisible(not layer.isVisible())
                # Really!? We have to reload the whole layer set every time?
            # WAT?
        self.canvas.setLayerSet(self.canvaslayers)
        self.canvas.freeze(False)
        self.canvas.refresh()

    def cleanup(self):
        self.gpsband.reset()
        self.gpsband.hide()
        self.clear_selection()
        self.clear_temp_objects()
        self.clearCapatureTools()
        self.canvas.freeze()
        self.canvas.clear()
        self.canvas.freeze(False)
        for action in self.layerbuttons:
            self.editgroup.removeAction(action)
Example #43
0
class MoveTool(QgsMapToolAdvancedDigitizing):
    """
    Map tool class to move or copy an object
    """

    def __init__(self, iface):
        """
        Constructor
        :param iface: interface
        """
        QgsMapToolAdvancedDigitizing.__init__(self,  iface.mapCanvas(), iface.cadDockWidget())
        self.__iface = iface
        self.icon_path = ':/plugins/VDLTools/icons/move_icon.png'
        self.text = QCoreApplication.translate("VDLTools", "Move/Copy a feature")
        self.setCursor(Qt.ArrowCursor)
        self.__isEditing = False
        self.__findVertex = False
        self.__onMove = False
        self.__layer = None
        self.__confDlg = None
        self.__lastFeatureId = None
        self.__selectedFeature = None
        self.__rubberBand = None
        self.__rubberSnap = None
        self.__newFeature = None
        self.__selectedVertex = None

    def activate(self):
        """
        When the action is selected
        """
        QgsMapToolAdvancedDigitizing.activate(self)
        if self.__layer.geometryType() == QGis.Point:
            self.setMode(self.CaptureLine)
        else:
            self.setMode(self.CaptureNone)

    def deactivate(self):
        """
        When the action is deselected
        """
        self.__cancel()
        QgsMapToolAdvancedDigitizing.deactivate(self)

    def toolName(self):
        """
        To get the tool name
        :return: tool name
        """
        return QCoreApplication.translate("VDLTools", "Move/Copy")

    def startEditing(self):
        """
        To set the action as enable, as the layer is editable
        """
        self.action().setEnabled(True)
        Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing)
        self.__layer.editingStopped.connect(self.stopEditing)

    def stopEditing(self):
        """
        To set the action as disable, as the layer is not editable
        """
        self.action().setEnabled(False)
        Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing)
        self.__layer.editingStarted.connect(self.startEditing)
        if self.canvas().mapTool() == self:
            self.__iface.actionPan().trigger()

    def setTool(self):
        """
        To set the current tool as this one
        """
        self.canvas().setMapTool(self)

    def __cancel(self):
        """
        To cancel used variables
        """
        if self.__rubberBand is not None:
            self.canvas().scene().removeItem(self.__rubberBand)
            self.__rubberBand.reset()
            self.__rubberBand = None
        if self.__rubberSnap is not None:
            self.canvas().scene().removeItem(self.__rubberSnap)
            self.__rubberSnap.reset()
            self.__rubberSnap = None
        self.__isEditing = False
        self.__findVertex = False
        self.__onMove = False
        self.__lastFeatureId = None
        self.__selectedFeature = None
        self.__confDlg = None
        self.__newFeature = None
        self.__selectedVertex = None
        self.__layer.removeSelection()
        if self.__layer.geometryType() == QGis.Point:
            self.setMode(self.CaptureLine)
        else:
            self.setMode(self.CaptureNone)

    def __removeLayer(self):
        """
        To remove the current working layer
        """
        if self.__layer is not None:
            if self.__layer.isEditable():
                Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing)
            else:
                Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing)
            self.__layer = None

    def setEnable(self, layer):
        """
        To check if we can enable the action for the selected layer
        :param layer: selected layer
        """
        if layer is not None and layer.type() == QgsMapLayer.VectorLayer:
            if layer == self.__layer:
                return

            if self.__layer is not None:
                if self.__layer.isEditable():
                    Signal.safelyDisconnect(self.__layer.editingStopped, self.stopEditing)
                else:
                    Signal.safelyDisconnect(self.__layer.editingStarted, self.startEditing)
            self.__layer = layer

            if self.__layer.geometryType() == QGis.Point:
                self.setMode(self.CaptureLine)
            else:
                self.setMode(self.CaptureNone)

            if self.__layer.isEditable():
                self.action().setEnabled(True)
                self.__layer.editingStopped.connect(self.stopEditing)
            else:
                self.action().setEnabled(False)
                self.__layer.editingStarted.connect(self.startEditing)
                if self.canvas().mapTool() == self:
                    self.__iface.actionPan().trigger()
            return
        self.action().setEnabled(False)
        if self.canvas().mapTool() == self:
            self.__iface.actionPan().trigger()
        self.__removeLayer()

    def __pointPreview(self, point):
        """
        To create a point geometry preview (rubberBand)
        :param point: new position as mapPoint
        """
        point_v2 = GeometryV2.asPointV2(self.__selectedFeature.geometry(), self.__iface)
        self.__newFeature = QgsPointV2(point.x(), point.y())
        self.__newFeature.addZValue(point_v2.z())
        self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point)
        self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.clone()), None)

    def __linePreview(self, point):
        """
        To create a line geometry preview (rubberBand)
        :param point: new position as mapPoint
        """
        line_v2, curved = GeometryV2.asLineV2(self.__selectedFeature.geometry(), self.__iface)
        vertex = QgsPointV2()
        line_v2.pointAt(self.__selectedVertex, vertex)
        self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line)
        dx = vertex.x() - point.x()
        dy = vertex.y() - point.y()
        if isinstance(curved, (list, tuple)):
            self.__newFeature = QgsCompoundCurveV2()
            for pos in range(line_v2.nCurves()):
                curve_v2 = self.__newCurve(curved[pos], line_v2.curveAt(pos), dx, dy)
                self.__newFeature.addCurve(curve_v2)
                if pos == 0:
                    self.__rubberBand.setToGeometry(QgsGeometry(curve_v2.curveToLine()), None)
                else:
                    self.__rubberBand.addGeometry(QgsGeometry(curve_v2.curveToLine()), None)
        else:
            self.__newFeature = self.__newCurve(curved, line_v2, dx, dy)
            self.__rubberBand.setToGeometry(QgsGeometry(self.__newFeature.curveToLine()), None)

    @staticmethod
    def __newCurve(curved, line_v2, dx, dy):
        """
        To create a new moved line
        :param curved: if the line is curved
        :param line_v2: the original line
        :param dx: x translation
        :param dy: y translation
        :return: the new line
        """
        if curved:
            newCurve = QgsCircularStringV2()
        else:
            newCurve = QgsLineStringV2()
        points = []
        for pos in range(line_v2.numPoints()):
            x = line_v2.pointN(pos).x() - dx
            y = line_v2.pointN(pos).y() - dy
            pt = QgsPointV2(x, y)
            pt.addZValue(line_v2.pointN(pos).z())
            points.append(pt)
        newCurve.setPoints(points)
        return newCurve

    def __polygonPreview(self, point):
        """
        To create a polygon geometry preview (rubberBand)
        :param point: new position as mapPoint
        """
        polygon_v2, curved = GeometryV2.asPolygonV2(self.__selectedFeature.geometry(), self.__iface)
        vertex = polygon_v2.vertexAt(GeometryV2.polygonVertexId(polygon_v2, self.__selectedVertex))
        dx = vertex.x() - point.x()
        dy = vertex.y() - point.y()
        self.__newFeature = QgsCurvePolygonV2()
        self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Line)
        line_v2 = self.__newCurve(curved[0], polygon_v2.exteriorRing(), dx, dy)
        self.__newFeature.setExteriorRing(line_v2)
        self.__rubberBand.setToGeometry(QgsGeometry(line_v2.curveToLine()), None)
        for num in range(polygon_v2.numInteriorRings()):
            line_v2 = self.__newCurve(curved[num+1], polygon_v2.interiorRing(num), dx, dy)
            self.__newFeature.addInteriorRing(line_v2)
            self.__rubberBand.addGeometry(QgsGeometry(line_v2.curveToLine()), None)

    def __onConfirmCancel(self):
        """
        When the Cancel button in Move Confirm Dialog is pushed
        """
        self.__confDlg.reject()

    def __onConfirmMove(self):
        """
        When the Move button in Move Confirm Dialog is pushed
        """
        geometry = QgsGeometry(self.__newFeature)
        if not geometry.isGeosValid():
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0)
        self.__layer.changeGeometry(self.__selectedFeature.id(), geometry)
        self.__confDlg.accept()
        self.__cancel()

    def __onConfirmCopy(self):
        """
        When the Copy button in Move Confirm Dialog is pushed
        """
        geometry = QgsGeometry(self.__newFeature)
        if not geometry.isGeosValid():
            self.__iface.messageBar().pushMessage(
                QCoreApplication.translate("VDLTools", "Geos geometry problem"), level=QgsMessageBar.CRITICAL, duration=0)
        feature = QgsFeature(self.__layer.pendingFields())
        feature.setGeometry(geometry)
        primaryKey = QgsDataSourceURI(self.__layer.source()).keyColumn()
        for field in self.__selectedFeature.fields():
            if field.name() != primaryKey:
                feature.setAttribute(field.name(), self.__selectedFeature.attribute(field.name()))
        if len(self.__selectedFeature.fields()) > 0 and self.__layer.editFormConfig().suppress() != \
                QgsEditFormConfig.SuppressOn:
            self.__iface.openFeatureForm(self.__layer, feature)
        else:
            self.__layer.addFeature(feature)
        self.__confDlg.accept()
        self.__cancel()

    def keyReleaseEvent(self, event):
        """
        When keyboard is pressed
        :param event: keyboard event
        """
        if event.key() == Qt.Key_Escape:
            self.__cancel()

    def cadCanvasMoveEvent(self, event):
        """
        When the mouse is moved
        :param event: mouse event
        """

        if type(event) == QMoveEvent:
            map_point = self.toMapCoordinates(event.pos())
        else:
            map_point = event.mapPoint()

        if not self.__isEditing and not self.__findVertex and not self.__onMove:
            laySettings = QgsSnappingUtils.LayerConfig(self.__layer, QgsPointLocator.All, 10,
                                                       QgsTolerance.Pixels)
            f_l = Finder.findClosestFeatureAt(map_point, self.canvas(), [laySettings])
            if f_l is not None and self.__lastFeatureId != f_l[0].id():
                self.__lastFeatureId = f_l[0].id()
                self.__layer.setSelectedFeatures([f_l[0].id()])
            if f_l is None:
                self.__layer.removeSelection()
                self.__lastFeatureId = None
        elif self.__findVertex:
            if self.__rubberBand is not None:
                self.__rubberBand.reset()
            closest = self.__selectedFeature.geometry().closestVertex(map_point)
            color = QColor("red")
            color.setAlphaF(0.78)
            self.__rubberBand.setColor(color)
            self.__rubberBand.setIcon(4)
            self.__rubberBand.setIconSize(20)
            self.__rubberBand.setToGeometry(QgsGeometry().fromPoint(closest[0]), None)
        elif self.__onMove:
            if self.__rubberBand is not None:
                self.__rubberBand.reset()
            if self.__layer.geometryType() == QGis.Polygon:
                self.__polygonPreview(map_point)
            elif self.__layer.geometryType() == QGis.Line:
                self.__linePreview(map_point)
            else:
                self.__pointPreview(map_point)
            color = QColor("red")
            color.setAlphaF(0.78)
            self.__rubberBand.setColor(color)
            self.__rubberBand.setWidth(2)
            if self.__layer.geometryType() != QGis.Point:
                self.__rubberBand.setLineStyle(Qt.DotLine)
            else:
                self.__rubberBand.setIcon(4)
                self.__rubberBand.setIconSize(8)
            if self.__rubberSnap is not None:
                self.__rubberSnap.reset()
            else:
                self.__rubberSnap = QgsRubberBand(self.canvas(), QGis.Point)
            self.__rubberSnap.setColor(color)
            self.__rubberSnap.setWidth(2)
            self.__rubberSnap.setIconSize(20)
            match = Finder.snap(map_point, self.canvas())
            if match.hasVertex() or match.hasEdge():
                point = match.point()
                if match.hasVertex():
                    if match.layer():
                        self.__rubberSnap.setIcon(4)
                    else:
                        self.__rubberSnap.setIcon(1)
                if match.hasEdge():
                    intersection = Finder.snapCurvedIntersections(point, self.canvas(), self)
                    if intersection is not None:
                        self.__rubberSnap.setIcon(1)
                        point = intersection
                    else:
                        self.__rubberSnap.setIcon(3)
                self.__rubberSnap.setToGeometry(QgsGeometry().fromPoint(point), None)

    def cadCanvasReleaseEvent(self, event):
        """
        When the mouse is clicked
        :param event: mouse event
        """
        if not self.__isEditing and not self.__findVertex and not self.__onMove:
            found_features = self.__layer.selectedFeatures()
            if len(found_features) > 0:
                if len(found_features) > 1:
                    self.__iface.messageBar().pushMessage(
                        QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO)
                    return
                self.__selectedFeature = found_features[0]
                if self.__layer.geometryType() != QGis.Point:
                    self.__iface.messageBar().pushMessage(
                        QCoreApplication.translate("VDLTools",
                                                   "Select vertex for moving (ESC to undo)"),
                        level=QgsMessageBar.INFO, duration=3)
                    self.__findVertex = True
                    self.setMode(self.CaptureLine)
                    self.__rubberBand = QgsRubberBand(self.canvas(), QGis.Point)
                else:
                    self.setMode(self.CaptureNone)
                    self.__onMove = True
        elif self.__findVertex:
            self.__findVertex = False
            self.setMode(self.CaptureNone)
            closest = self.__selectedFeature.geometry().closestVertex(event.mapPoint())
            self.__selectedVertex = closest[1]
            self.__onMove = True
        elif self.__onMove:
            self.__onMove = False
            mapPoint = event.mapPoint()
            match = Finder.snap(event.mapPoint(), self.canvas())
            if match.hasVertex() or match.hasEdge():
                mapPoint = match.point()
                if match.hasEdge():
                    intersection = Finder.snapCurvedIntersections(mapPoint, self.canvas(), self)
                    if intersection is not None:
                        mapPoint = intersection
            self.__isEditing = True
            if self.__rubberBand is not None:
                self.__rubberBand.reset()
            if self.__layer.geometryType() == QGis.Polygon:
                self.__polygonPreview(mapPoint)
            elif self.__layer.geometryType() == QGis.Line:
                self.__linePreview(mapPoint)
            else:
                self.__pointPreview(mapPoint)
            color = QColor("red")
            color.setAlphaF(0.78)
            self.__rubberBand.setColor(color)
            if self.__layer.geometryType() != QGis.Point:
                self.__rubberBand.setWidth(2)
                self.__rubberBand.setLineStyle(Qt.DotLine)
            else:
                self.__rubberBand.setIcon(4)
                self.__rubberBand.setIconSize(20)
            self.__confDlg = MoveConfirmDialog()
            self.__confDlg.rejected.connect(self.__cancel)
            self.__confDlg.moveButton().clicked.connect(self.__onConfirmMove)
            self.__confDlg.copyButton().clicked.connect(self.__onConfirmCopy)
            self.__confDlg.cancelButton().clicked.connect(self.__onConfirmCancel)
            self.__confDlg.show()
class VoGISProfilToolMainDialog(QDialog):
    def __init__(self, interface, settings):

        self.settings = settings
        self.iface = interface
        self.selectingVisibleRasters = False
        self.thread = None

        QDialog.__init__(self, interface.mainWindow())

        # Set up the user interface from Designer.
        self.ui = Ui_VoGISProfilToolMain()
        self.ui.setupUi(self)

        if self.settings.onlyHektoMode is True:
            self.ui.IDC_widRaster.hide()
            self.adjustSize()

        validator = QIntValidator(-32768, 32768, self)
        self.ui.IDC_tbNoDataExport.setValidator(validator)

        self.ui.IDC_tbFromX.setText('-30000')
        self.ui.IDC_tbFromY.setText('240000')
        self.ui.IDC_tbToX.setText('-20000')
        self.ui.IDC_tbToY.setText('230000')

        self.__addRastersToGui()
        self.__addPolygonsToGui()

        for line_lyr in self.settings.mapData.lines.lines():
            self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr)

        if self.settings.mapData.lines.count() < 1:
            self.ui.IDC_rbDigi.setChecked(True)
            self.ui.IDC_rbShapeLine.setEnabled(False)

        #Einstellungen fuer Linie zeichen
        self.action = QAction(QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"), "VoGIS-Profiltool", self.iface.mainWindow())
        self.action.setWhatsThis("VoGIS-Profiltool")
        self.canvas = self.iface.mapCanvas()
        self.tool = ProfiletoolMapTool(self.canvas, self.action)
        self.savedTool = self.canvas.mapTool()
        self.polygon = False
        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        if QGis.QGIS_VERSION_INT >= 10900:
            #self.rubberband.setBrushStyle()
            self.rubberband.setLineStyle(Qt.SolidLine)
            self.rubberband.setWidth(4.0)
            self.rubberband.setColor(QColor(0, 255, 0))
            #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab
        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None

    def accept(self):
        try:
            #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "ACCEPTED")

            #QgsMessageLog.logMessage('nodata: {0}'.format(self.settings.nodata_value), 'VoGis')
            self.settings.nodata_value = int(self.ui.IDC_tbNoDataExport.text())
            QgsMessageLog.logMessage('maindlg: nodata: {0}'.format(self.settings.nodata_value), 'VoGis')

            if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count() > 0:
                self.settings.onlyHektoMode = False

            if self.settings.onlyHektoMode is False:
                if self.settings.mapData.rasters.count() < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", u"Keine Raster vorhanden. Zum Hektometrieren Dialog neu öffnen.")
                    #return
                    retVal = QMessageBox.warning(self.iface.mainWindow(),
                                                 "VoGIS-Profiltool",
                                                 QApplication.translate('code', 'Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?', None, QApplication.UnicodeUTF8),
                                                 QMessageBox.Yes | QMessageBox.No,
                                                 QMessageBox.Yes)
                    if retVal == QMessageBox.No:
                        return
                    else:
                        self.settings.onlyHektoMode = True
                        self.settings.createHekto = True

            if self.__getSettingsFromGui() is False:
                return

            if self.settings.onlyHektoMode is False:
                if len(self.settings.mapData.rasters.selectedRasters()) < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "Kein Raster selektiert!")
                    #msg =
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", msg)
                    QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Kein Raster selektiert!', None, QApplication.UnicodeUTF8))
                    return

            QgsMessageLog.logMessage('modeLine!=line: {0}'.format(self.settings.modeLine != enumModeLine.line), 'VoGis')
            QgsMessageLog.logMessage('customLine is None: {0}'.format(self.settings.mapData.customLine is None), 'VoGis')

            if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None:
                QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Profillinie vorhanden!', None, QApplication.UnicodeUTF8))
                return

            if len(self.settings.mapData.polygons.selected_polygons()) > 0 and len(self.settings.mapData.rasters.selectedRasters()) > 1:
                raster_names = list(raster.name for raster in self.settings.mapData.rasters.selectedRasters())
                sel_raster, ok_clicked = QInputDialog.getItem(
                                                self.iface.mainWindow(),
                                                u'DHM?',
                                                u'Welches DHM soll zur Flächenverschneidung verwendet werden?',
                                                raster_names,
                                                0,
                                                False
                                                )
                if ok_clicked is False:
                    return
                self.settings.intersection_dhm_idx = raster_names.index(sel_raster)

            #self.rubberband.reset(self.polygon)
            #QDialog.accept(self)

            QApplication.setOverrideCursor(Qt.WaitCursor)

            create_profile = CreateProfile(self.iface, self.settings)
            thread = QThread(self)
            create_profile.moveToThread(thread)
            create_profile.finished.connect(self.profiles_finished)
            create_profile.error.connect(self.profiles_error)
            create_profile.progress.connect(self.profiles_progress)
            thread.started.connect(create_profile.create)
            thread.start(QThread.LowestPriority)
            self.thread = thread
            self.create_profile = create_profile
            self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
        except:
            QApplication.restoreOverrideCursor()
            ex = u'{0}'.format(traceback.format_exc())
            msg = 'Unexpected ERROR:\n\n{0}'.format(ex[:2000])
            QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", msg)


    def profiles_finished(self, profiles, intersections):
        QApplication.restoreOverrideCursor()
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
        #self.create_profile.deleteLater()
        self.thread.quit()
        self.thread.wait()
        #self.thread.deleteLater()

        #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090
        self.iface.mainWindow().statusBar().showMessage('VoGIS-Profiltool, {0} Profile'.format(len(profiles)))
        QgsMessageLog.logMessage(u'Profile Count: {0}'.format(len(profiles)), 'VoGis')

        if len(profiles) < 1:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Es konnten keine Profile erstellt werden.', None, QApplication.UnicodeUTF8))
            return

        dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles, intersections)
        dlg.show()
        #result = self.dlg.exec_()
        dlg.exec_()


    def profiles_error(self, exception_string):
        QApplication.restoreOverrideCursor()
        QgsMessageLog.logMessage(u'Error during profile creation: {0}'.format(exception_string), 'VoGis')
        QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", exception_string)


    def profiles_progress(self, msg):
        self.iface.mainWindow().statusBar().showMessage(msg)
        self.ui.IDC_lblCreateStatus.setText(msg)
        #QgsMessageLog.logMessage(msg, 'VoGis')
        QApplication.processEvents()


    def reject(self):
        if not self.thread is None:
            if self.thread.isRunning():
                self.create_profile.abort()
                return

        self.rubberband.reset(self.polygon)
        QDialog.reject(self)


    def selectVisibleRasters(self):
        self.refreshRasterList()
        self.selectingVisibleRasters = True
        extCanvas = self.iface.mapCanvas().extent()
        #alle raster in den einstellunge deselektieren
        for r in self.settings.mapData.rasters.rasters():
            r.selected = False
        #alle raster in der ListView deselektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            item.setCheckState(Qt.Unchecked)
        #Raster im Extent selektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            if QGis.QGIS_VERSION_INT < 10900:
                raster = item.data(Qt.UserRole).toPyObject()
            else:
                raster = item.data(Qt.UserRole)
            for r in self.settings.mapData.rasters.rasters():
                if extCanvas.intersects(r.grid.extent()):
                    if r.id == raster.id:
                        r.selected = True
                        item.setCheckState(Qt.Checked)
        self.selectingVisibleRasters = False


    def lineLayerChanged(self, idx):
        if self.ui.IDC_rbShapeLine.isChecked() is False:
            self.ui.IDC_rbShapeLine.setChecked(True)
        if QGis.QGIS_VERSION_INT < 10900:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()).toPyObject())
        else:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))
        lyr = lineLyr.line
        #QgsMessageLog.logMessage('{0}'.format(lyr.selectedFeatureCount()), 'VoGis')
        #QgsMessageLog.logMessage('{0}'.format(dir(lyr)), 'VoGis')
        if hasattr(lyr, 'selectedFeatureCount'):
            if(lyr.selectedFeatureCount() < 1):
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(False)
            else:
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(True)


    def valueChangedEquiDistance(self, val):
        if self.ui.IDC_rbEquiDistance.isChecked() is False:
            self.ui.IDC_rbEquiDistance.setChecked(True)


    def valueChangedVertexCount(self, val):
        if self.ui.IDC_rbVertexCount.isChecked() is False:
            self.ui.IDC_rbVertexCount.setChecked(True)


    def lvRasterItemChanged(self, item):
        if self.selectingVisibleRasters is True:
            return
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        if QGis.QGIS_VERSION_INT < 10900:
            raster_lyr = item_data.toPyObject()
        else:
            raster_lyr = item_data
        self.settings.mapData.rasters.getById(raster_lyr.id).selected = selected


    def lvPolygonItemChanged(self, item):
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        if QGis.QGIS_VERSION_INT < 10900:
            poly_lyr = item_data.toPyObject()
        else:
            poly_lyr = item_data
        self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected


    def refreshRasterList(self):
        legend = self.iface.legendInterface()
        avail_lyrs = legend.layers()
        raster_coll = RasterCollection()

        for lyr in avail_lyrs:
            if legend.isLayerVisible(lyr):
                lyr_type = lyr.type()
                lyr_name = unicodedata.normalize('NFKD', unicode(lyr.name())).encode('ascii', 'ignore')
                if lyr_type == 1:
                    if lyr.bandCount() < 2:
                        new_raster = Raster(lyr.id(), lyr_name, lyr)
                        raster_coll.addRaster(new_raster)

        self.settings.mapData.rasters = raster_coll
        self.__addRastersToGui()

    def __addRastersToGui(self):
        self.ui.IDC_listRasters.clear()
        check = Qt.Unchecked
        if self.settings.mapData.rasters.count() == 1:
            check = Qt.Checked
            self.settings.mapData.rasters.rasters()[0].selected = True

        for raster_lyr in self.settings.mapData.rasters.rasters():
            item = QListWidgetItem(raster_lyr.name)
            item.setData(Qt.UserRole, raster_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listRasters.addItem(item)


    def __addPolygonsToGui(self):
        self.ui.IDC_listPolygons.clear()
        check = Qt.Unchecked
        for poly_lyr in self.settings.mapData.polygons.polygons():
            item = QListWidgetItem(poly_lyr.name)
            item.setData(Qt.UserRole, poly_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listPolygons.addItem(item)


    def drawLine(self):
        if self.ui.IDC_rbDigi.isChecked() is False:
            self.ui.IDC_rbDigi.setChecked(True)
        self.dblckltemp = None
        self.rubberband.reset(self.polygon)
        self.__cleanDigi()
        self.__activateDigiTool()
        self.canvas.setMapTool(self.tool)


    def __createDigiFeature(self, pnts):
        u = Util(self.iface)
        f = u.createQgLineFeature(pnts)
        self.settings.mapData.customLine = f


    def __lineFinished(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        self.pointsToDraw.append(newPoint)
        #launch analyses
        self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw))
        if len(self.pointsToDraw) < 2:
            self.__cleanDigi()
            self.pointsToDraw = []
            self.dblclktemp = newPoint
            self.drawnLine = None
            QMessageBox.warning(self, "VoGIS-Profiltool", QApplication.translate('code', 'Profillinie digitalisieren abgebrochen!', None, QApplication.UnicodeUTF8))
        self.drawnLine = self.__createDigiFeature(self.pointsToDraw)
        self.__cleanDigi()

        self.pointsToDraw = []
        self.dblclktemp = newPoint

    def __cleanDigi(self):
        self.pointsToDraw = []
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.savedTool)

    def __activateDigiTool(self):
        QObject.connect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.connect(self.tool, SIGNAL("rightClicked"), self.__rightClicked)
        QObject.connect(self.tool, SIGNAL("leftClicked"), self.__leftClicked)
        QObject.connect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked)
        QObject.connect(self.tool, SIGNAL("deactivate"), self.__deactivateDigiTool)

    def __deactivateDigiTool(self):
        QObject.disconnect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.disconnect(self.tool, SIGNAL("leftClicked"), self.__leftClicked)
        QObject.disconnect(self.tool, SIGNAL("rightClicked"), self.__rightClicked)
        QObject.disconnect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked)
        if QGis.QGIS_VERSION_INT < 10900:
            self.iface.mainWindow().statusBar().showMessage(QString(""))
        else:
            self.iface.mainWindow().statusBar().showMessage('')

    def __moved(self, position):
        if len(self.pointsToDraw) > 0:
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
            self.rubberband.reset(self.polygon)
            newPnt = QgsPoint(mapPos.x(), mapPos.y())
            if QGis.QGIS_VERSION_INT < 10900:
                for i in range(0, len(self.pointsToDraw)):
                    self.rubberband.addPoint(self.pointsToDraw[i])
                self.rubberband.addPoint(newPnt)
            else:
                pnts = self.pointsToDraw + [newPnt]
                self.rubberband.setToGeometry(QgsGeometry.fromPolyline(pnts),None)


    def __rightClicked(self, position):
        self.__lineFinished(position)

    def __leftClicked(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        #if self.selectionmethod == 0:
        if newPoint == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset(self.polygon)
            self.pointsToDraw.append(newPoint)

    def __doubleClicked(self, position):
        pass

    #not in use right now
    def __lineCancel(self):
        pass

    def __getSettingsFromGui(self):
        self.settings.linesExplode = (self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked)
        self.settings.linesMerge = (self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked)
        self.settings.onlySelectedFeatures = (self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked)
        self.settings.equiDistance = self.ui.IDC_dblspinDistance.value()
        self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value()
        #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked)
        self.settings.nodesAndVertices = (self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked)

        if QGis.QGIS_VERSION_INT < 10900:
            self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(
                                                     self.ui.IDC_cbLineLayers.currentIndex()
                                                     ).toPyObject()
                                                     )
        else:
            self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))

        if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount() < 1:
            QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', u'Der gewählte Layer hat keine selektierten Elemente.', None, QApplication.UnicodeUTF8))
            return False

        if self.ui.IDC_rbDigi.isChecked():
            self.settings.modeLine = enumModeLine.customLine
        elif self.ui.IDC_rbShapeLine.isChecked():
            self.settings.modeLine = enumModeLine.line
        else:
            #self.ui.IDC_rbStraigthLine
            self.settings.modeLine = enumModeLine.straightLine

        if self.ui.IDC_rbEquiDistance.isChecked():
            self.settings.modeVertices = enumModeVertices.equiDistant
        else:
            self.settings.modeVertices = enumModeVertices.vertexCnt

        if self.ui.IDC_rbStraigthLine.isChecked():
            ut = Util(self.iface)
            if ut.isFloat(self.ui.IDC_tbFromX.text(), QApplication.translate('code', 'Rechtswert von', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromX = float(self.ui.IDC_tbFromX.text())
            if ut.isFloat(self.ui.IDC_tbFromY.text(), QApplication.translate('code', 'Hochwert von', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromY = float(self.ui.IDC_tbFromY.text())
            if ut.isFloat(self.ui.IDC_tbToX.text(), QApplication.translate('code', 'Rechtswert nach', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toX = float(self.ui.IDC_tbToX.text())
            if ut.isFloat(self.ui.IDC_tbToY.text(), QApplication.translate('code', 'Hochwert nach', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toY = float(self.ui.IDC_tbToY.text())

            fromPnt = QgsPoint(fromX, fromY)
            toPnt = QgsPoint(toX, toY)

            self.settings.mapData.customLine = ut.createQgLineFeature([fromPnt, toPnt])

        return True
Example #45
0
class RectangleMapTool(QgsMapToolEmitPoint):
  def __init__(self, canvas):
    self.canvas = canvas
    QgsMapToolEmitPoint.__init__(self, self.canvas)

    self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
    self.rubberBand.setColor(QColor(255, 0, 0, 180))
    self.rubberBand.setWidth(1)
    self.reset()

  def reset(self):
    self.startPoint = self.endPoint = None
    self.isEmittingPoint = False
    self.rubberBand.reset(QGis.Polygon)

  def canvasPressEvent(self, e):
    self.startPoint = self.toMapCoordinates(e.pos())
    self.endPoint = self.startPoint
    self.isEmittingPoint = True
    self.showRect(self.startPoint, self.endPoint)

  def canvasReleaseEvent(self, e):
    self.isEmittingPoint = False
    self.emit(SIGNAL("rectangleCreated()"))

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

  def showRect(self, startPoint, endPoint):
    self.rubberBand.reset(QGis.Polygon)
    if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
      return

    point1 = QgsPoint(startPoint.x(), startPoint.y())
    point2 = QgsPoint(startPoint.x(), endPoint.y())
    point3 = QgsPoint(endPoint.x(), endPoint.y())
    point4 = QgsPoint(endPoint.x(), startPoint.y())

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

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

    return QgsRectangle(self.startPoint, self.endPoint)

  def setRectangle(self, rect):
    if rect == self.rectangle():
      return False

    if rect == None:
      self.reset()
    else:
      self.startPoint = QgsPoint(rect.xMaximum(), rect.yMaximum())
      self.endPoint = QgsPoint(rect.xMinimum(), rect.yMinimum())
      self.showRect(self.startPoint, self.endPoint)
    return True
Example #46
0
class EditTool(MapTool):
    """
        Inspection tool which copies the feature to a new layer
        and copies selected data from the underlying feature.
    """
    
    finished = pyqtSignal(object, QgsFeature)
    featuresfound = pyqtSignal(dict)

    def __init__(self, canvas, forms, snapradius = 2):
        MapTool.__init__(self, canvas, [])
        self.canvas = canvas
        self.radius = snapradius
        self.forms = forms
        
        self.band = QgsRubberBand(self.canvas)
        self.band.setColor(QColor.fromRgb(224,162,16))
        self.band.setWidth(3)
        
        self.selectband = None
        
        self.selectrect = QRect()
        self.dragging = False

        self.cursor = QCursor(QPixmap(["16 16 3 1",
            "      c None",
            ".     c #FF0000",
            "+     c #FFFFFF",
            "                ",
            "       +.+      ",
            "      ++.++     ",
            "     +.....+    ",
            "    +.     .+   ",
            "   +.   .   .+  ",
            "  +.    .    .+ ",
            " ++.    .    .++",
            " ... ...+... ...",
            " ++.    .    .++",
            "  +.    .    .+ ",
            "   +.   .   .+  ",
            "   ++.     .+   ",
            "    ++.....+    ",
            "      ++.++     ",
            "       +.+      "]))

    def addForm(self, form):
        self.forms.append(form)
        self.layersupdated.emit(True)

    def layers(self):
        """
        Return a set of layers that this edit tool can work on
        """
        return set([form.QGISLayer for form in self.forms])

    def formsforlayer(self, layer):
        for form in self.forms:
            if form.QGISLayer == layer:
                yield form

    def reset(self):
        self.forms = []
        self.layersupdated.emit(False)

    def getFeatures(self, rect):
        rq = QgsFeatureRequest().setFilterRect(rect)

        self.band.reset()
        for layer in self.layers():
            forms = list(self.formsforlayer(layer))
            rq = QgsFeatureRequest().setFilterRect(rect)
            for feature in layer.getFeatures(rq):
                if feature.isValid():
                    yield feature, forms
                    
    def toSearchRect(self, point):
        searchRadius =  self.canvas.extent().width() * ( self.radius / 100.0 )

        point = self.toMapCoordinates(point)

        rect = QgsRectangle()                                                 
        rect.setXMinimum(point.x() - searchRadius)
        rect.setXMaximum(point.x() + searchRadius)
        rect.setYMinimum(point.y() - searchRadius)
        rect.setYMaximum(point.y() + searchRadius)
        return rect

    def canvasPressEvent(self, event):
        self.selectrect.setRect( 0, 0, 0, 0 )
        
        self.selectband = QgsRubberBand(self.canvas, QGis.Polygon )
        self.selectband.setColor(QColor.fromRgb(0,0,255, 65))
        self.selectband.setWidth(5)
        
    def canvasMoveEvent(self, event):
        if not event.buttons() == Qt.LeftButton:
            return
        
        if not self.dragging:
            self.dragging = True
            self.selectrect.setTopLeft(event.pos())
        self.selectrect.setBottomRight(event.pos())
        
        maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband)  
                     
    def canvasReleaseEvent(self, event):
        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()            
        else:
            rect = self.toSearchRect(event.pos())
            
        self.dragging = False
        self.selectband.reset()
            
        features = dict(self.getFeatures(rect))
        print features
            
        if len(features) == 1:
            feature = features.keys()[0]
            forms = features.values()[0]
            if len(forms) == 1:
                self.finished.emit(forms[0], feature)
            else:
                self.featuresfound.emit(features)
        elif len(features) > 0:
            self.featuresfound.emit(features)

    def isEditTool(self):
        return True
Example #47
0
class QgepProfileMapTool( QgepMapTool ):
    '''
    The map tool used for PROFILE
    
    Allows to find the shortest path between several nodes.
    '''
    profileChanged = pyqtSignal( object )
    profile = QgepProfile()
    segmentOffset = 0

    selectedPathPoints = []
    pathPolyline = []
    
    def __init__( self, canvas, button, networkAnalyzer ):
        QgepMapTool.__init__(self, canvas, button)
        settings = QSettings()
        
        helperLineColor = settings.value( "/QGEP/HelperLineColor", u'#FFD900' )
        highlightColor  = settings.value( "/QGEP/HighlightColor",  u'#40FF40' )
        
        self.networkAnalyzer = networkAnalyzer
        
        # Init rubberband to visualize current status
        self.rbHelperLine = QgsRubberBand( self.canvas )
        self.rbHelperLine.setColor( QColor( helperLineColor ) )
        self.rbHelperLine.setWidth( 2 )
        
        self.rbHighlight = QgsRubberBand( self.canvas )
        self.rbHighlight.setColor( QColor( highlightColor ) )
        self.rbHighlight.setWidth( 5 )
        
        self.profile.setRubberband( self.rbHighlight )

    def setActive( self ):
        '''
        activates this map tool
        '''
        self.saveTool = self.canvas.mapTool()
        self.canvas.setMapTool( self )

    def deactivate(self):
        '''
        Called whenever this map tool is deactivated.
        Used to clean up code
        '''
        QgepMapTool.deactivate(self)
        self.rubberBand.reset()
        self.rbHelperLine.reset()
        self.selectedPathPoints = []
        self.pathPolyline = []
        
    def findPath( self, pStart, pEnd ):
        '''
        Tries to find the shortest path between pStart and pEnd.
        If it finds a path:
         * The path is visualized with a QgsRubberband
         * The profile plot is updated to represent the current path
    
        @param pStart: The id of the start point of the path 
        @param pEnd:   The id of the end point of the path
        '''
        backupCursor = self.canvas.cursor()
        self.canvas.setCursor(Qt.WaitCursor)
        #try:
        ( vertices, edges ) = self.networkAnalyzer.shortestPath( pStart, pEnd )
        self.appendProfile( vertices, edges )
#        except:
#            pass
        self.canvas.setCursor(backupCursor)
        if len( vertices ) > 0:
            return True
        else:
            return False
        
    def appendProfile( self, vertices, edges ):
        '''
        Appends to the current profile
        
        @param vertices: A collection of vertices to append
        @param edges:    A collection of edges which connect the vertices
        '''
        self.logger.debug( 'Append profile' )
        self.logger.info( ' * ' + `len( vertices )` + ' vertices' )
        for v in vertices:
            self.logger.debug( '   *' + `v`)
        self.logger.info( ' * ' + `len( edges )` + ' edges')
        for e in edges:
            self.logger.debug( '   *' + `e`)
            
        # Fetch all the needed edges in one batch
        edgeLayer = self.networkAnalyzer.getReachLayer()
        edgeAttrs = edgeLayer.dataProvider().attributeIndexes()
        edgeIds = [edge['feature'] for p1, p2, edge in edges]
        
        edgeFeatures = self.networkAnalyzer.getFeaturesById(edgeLayer, edgeAttrs, edgeIds, True)

        # We need some additional nodes, where we need to interpolate...
        interpolateNodesFrom = [edgeFeatures.attrAsUnicode( feat, u'from_obj_id_interpolate' ) for feat in edgeFeatures.asDict().values()]
        interpolateNodesTo   = [edgeFeatures.attrAsUnicode( feat, u'to_obj_id_interpolate' ) for feat in edgeFeatures.asDict().values()]
        additionalIds = [self.networkAnalyzer.vertexIds[node] for node in interpolateNodesFrom]
        additionalIds += [self.networkAnalyzer.vertexIds[node] for node in interpolateNodesTo]
        
        # Now, fetch the nodes we need
        nodeLayer = self.networkAnalyzer.getNodeLayer()
        nodeIds = vertices + additionalIds
        nodeAttrs = nodeLayer.dataProvider().attributeIndexes()
        nodeFeatures = self.networkAnalyzer.getFeaturesById(nodeLayer, nodeAttrs, nodeIds, False)
        
        if len( vertices ) > 1:
            self.rubberBand.reset()
            
            elem = QgepProfileNodeElement( vertices[0], nodeFeatures, 0 )
            self.profile.addElement( vertices[0], elem )
            
            for p1, p2, edge in edges:
                fromOffset = self.segmentOffset
                toOffset = self.segmentOffset + edge['weight']
                
                if 'reach' == edge['objType']:
                    if self.profile.hasElement( edge['baseFeature'] ):
                        self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                    else:
                        elem = QgepProfileReachElement( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                        self.profile.addElement(elem.objId, elem)
                    
                elif 'special_structure' == edge['objType']:
                    if self.profile.hasElement( edge['baseFeature'] ):
                        self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                    else:
                        elem = QgepProfileSpecialStructureElement( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                        self.profile.addElement(elem.objId, elem)
                
                elem = QgepProfileNodeElement( p2, nodeFeatures, toOffset )
                self.profile.addElement(p2, elem)
                
                self.segmentOffset = toOffset

            self.profileChanged.emit( self.profile )
            
            # Create rubberband geometry
            for featId in edgeIds:
                self.pathPolyline.extend( edgeFeatures[featId].geometry().asPolyline() )
            
            self.rubberBand.addGeometry( QgsGeometry.fromPolyline( self.pathPolyline ), nodeLayer )
            self.profileChanged.emit( self.profile )
            return True
        else:
            return False

    def mouseMoved( self, event ):
        '''
        Mouse moved: update helper line
        
        @param event: The mouse event with coordinates and all
        '''
        if len( self.selectedPathPoints ) > 0:
            self.rbHelperLine.reset()
            for point in self.selectedPathPoints:
                self.rbHelperLine.addPoint( point[1] )
            mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() )
            self.rbHelperLine.addPoint( mousePos )

    def rightClicked( self, event ):
        '''
        Cancel any ongoing path selection
        
        @param event: The mouse event with coordinates and all
        '''
        self.selectedPathPoints = []
        self.pathPolyline = []
        self.rbHelperLine.reset()
        self.profile.reset()
        self.segmentOffset = 0

    def leftClicked( self, event ):
        '''
        Select startpoint / intermediate point / endpoint
        
        @param event: The mouse event with coordinates and all
        '''
        snappedPoint = self.networkAnalyzer.snapPoint( event )
        
        if snappedPoint is not None:
            if len( self.selectedPathPoints ) > 0:
                pf = self.findPath( self.selectedPathPoints[-1][0], snappedPoint.snappedAtGeometry )
                if pf:
                    self.selectedPathPoints.append( ( snappedPoint.snappedAtGeometry, QgsPoint( snappedPoint.snappedVertex ) ) )
                else:
                    msg = self.msgBar.createMessage( 'No path found' )
                    self.msgBar.pushWidget( msg, QgsMessageBar.WARNING )
            else:
                self.selectedPathPoints.append( ( snappedPoint.snappedAtGeometry, QgsPoint( snappedPoint.snappedVertex ) ) )
Example #48
0
class CaptureCoordinateToolUpdate(QgsMapTool):
    def __init__(self, canvas, dataBaseProcedureData0, point3d0,
                 procEntityListType0):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.rubberBand = QgsRubberBand(canvas, QGis.Point)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(10)
        self.rubberBandClick = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandClick.setColor(Qt.green)
        self.rubberBandClick.setWidth(3)
        self.obstaclesLayerList = QgisHelper.getSurfaceLayers(
            SurfaceTypes.Obstacles)
        self.demLayerList = QgisHelper.getSurfaceLayers(SurfaceTypes.DEM)
        self.reset()

        self.dataBaseProcedureData_0 = dataBaseProcedureData0
        self.point3d_0 = point3d0
        self.procEntityListType_0 = procEntityListType0

    def reset(self):
        self.Point = None

    def canvasReleaseEvent(self, e):
        pointBackground = e.pos()
        self.Point, self.pointID, self.layer = self.snapPoint(e.pos())
        self.selectedLayerFromSnapPoint = None
        resultValueList = []
        self.rubberBandClick.reset(QGis.Point)

        self.rubberBandClick.addPoint(self.Point)
        self.rubberBandClick.show()
        if self.obstaclesLayerList != None:
            for obstacleLayer in self.obstaclesLayerList:
                if self.layer == None:
                    break
                if obstacleLayer.name() == self.layer.name():
                    self.selectedLayerFromSnapPoint = self.layer
                    break
#         itemList = []
        if self.selectedLayerFromSnapPoint != None:
            dataProvider = self.selectedLayerFromSnapPoint.dataProvider()
            featureIter = dataProvider.getFeatures(
                QgsFeatureRequest(self.pointID))
            feature = None
            for feature0 in featureIter:
                feature = feature0

            idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Name')
            idValue = feature.attributes()[idx]
            resultValueList.append(idValue.toString())

            resultValueList.append(str(self.Point.x()))
            resultValueList.append(str(self.Point.y()))

            idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Altitude')
            altitudeValue = feature.attributes()[idx]

            resultValueList.append(altitudeValue.toString())
        else:
            if self.Point != None:
                identifyResult = None
                idValue = "Background"
                if self.demLayerList != None:

                    for demLayer in self.demLayerList:
                        identifyResults = demLayer.dataProvider().identify(
                            self.Point, QgsRaster.IdentifyFormatValue)
                        identifyResult = identifyResults.results()
                if identifyResult != None and identifyResult[1].toString(
                ) != "":
                    idValue = "DEM"

                resultValueList.append(idValue)
                resultValueList.append(str(self.Point.x()))
                resultValueList.append(str(self.Point.y()))
                if identifyResult != None:
                    resultValueList.append(identifyResult[1].toString())
                else:
                    resultValueList.append("0")
        self.point3d_0 = Point3D(self.Point.x(), self.Point.y())
        self.emit(SIGNAL("resultPointValueList"), resultValueList,
                  self.dataBaseProcedureData_0, self.point3d_0,
                  self.procEntityListType_0, self)

    def canvasMoveEvent(self, e):
        if define._snapping == False:
            return
        self.rubberBand.reset(QGis.Point)
        #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)
        snapPoint, snapPointID, layer = self.snapPoint(e.pos(), True)
        if snapPoint == None:
            return
        self.rubberBand.addPoint(snapPoint)
        self.rubberBand.show()
#         print snapPointID

    def snapPoint(self, p, bNone=False):
        if define._snapping == False:
            return (
                define._canvas.getCoordinateTransform().toMapCoordinates(p),
                None, None)
        snappingResults = self.mSnapper.snapToBackgroundLayers(p)
        if (snappingResults[0] != 0 or len(snappingResults[1]) < 1):

            if bNone:
                return (None, None, None)
            else:
                return (define._canvas.getCoordinateTransform().
                        toMapCoordinates(p), None, None)
        else:
            return (snappingResults[1][0].snappedVertex,
                    snappingResults[1][0].snappedAtGeometry,
                    snappingResults[1][0].layer)

    def deactivate(self):
        self.rubberBand.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Example #49
0
class DsgLineTool(QgsMapTool):

    lineCreated = pyqtSignal(QgsGeometry)

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

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

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

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

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

    def canvasMoveEvent(self, e):
        """
        Reimplementation to move the rubber band
        """
        if not self.isEmittingPoint:
            return
        
        point = self.snapPoint(e.pos())
        self.rubberBand.movePoint(point)
        
    def snapPoint(self, p):
        """
        Reimplementation to make use of the snap
        """
        m = self.canvas.snappingUtils().snapToMap(p)
        if m.isValid():
            return m.point()
        else:
            return self.canvas.getCoordinateTransform().toMapCoordinates(p)  
Example #50
0
class MoveRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.isLayerVisible = True

        self.reset()

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.originalCenter = self.layer.center
        # this tool do the displacement itself TODO update so it is done by
        # transformed coordinates + new center)
        self.originalCornerPoints = self.layer.transformedCornerCoordinates(
            *self.layer.transformParameters())

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        self.showDisplacement(self.startPoint, self.endPoint)
        self.layer.history.append({
            "action": "move",
            "center": self.layer.center
        })

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

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        x = self.originalCenter.x() + self.endPoint.x() - self.startPoint.x()
        y = self.originalCenter.y() + self.endPoint.y() - self.startPoint.y()
        self.layer.setCenter(QgsPointXY(x, y))

        setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        self.layer.repaint()

        self.layer.commitTransformParameters()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showDisplacement(self.startPoint, self.endPoint)

    def showDisplacement(self, startPoint, endPoint):
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(endPoint.x(), endPoint.y())
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in self.originalCornerPoints:
            self._addDisplacementToPoint(self.rubberBandExtent, point, False)
        # for closing
        self._addDisplacementToPoint(self.rubberBandExtent,
                                     self.originalCornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(
            self.endPoint.x() - self.startPoint.x(),
            self.endPoint.y() - self.startPoint.y(), True)
        self.rasterShadow.show()

    def _addDisplacementToPoint(self, rubberBand, point, doUpdate):
        x = point.x() + self.endPoint.x() - self.startPoint.x()
        y = point.y() + self.endPoint.y() - self.startPoint.y()
        self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
Example #51
0
class InfoTool(QgsMapTool):
    infoResults = pyqtSignal(dict)

    def __init__(self, canvas, snapradius = 2):
        super(InfoTool, self).__init__(canvas)
        self.canvas = canvas
        self.radius = snapradius

        self.band = QgsRubberBand(self.canvas)
        self.band.setColor(QColor.fromRgb(224,162,16))
        self.band.setWidth(3)

        self.selectband = None
        self.selectrect = QRect()
        self.dragging = False
        self.selectionlayers = []

    def getFeatures(self, rect):
        self.band.reset()
        for layer in self.selectionlayers:
            if (not layer.type() == QgsMapLayer.VectorLayer
                or layer.geometryType() == QGis.NoGeometry):
                continue

            rect = self.toLayerCoordinates(layer, rect)

            rq = QgsFeatureRequest().setFilterRect(rect).setFlags(QgsFeatureRequest.ExactIntersect)
            features = []
            for feature in layer.getFeatures(rq):
                if feature.isValid():
                    features.append(feature)

            yield layer, features

    def toSearchRect(self, point):
        searchRadius =  self.canvas.extent().width() * ( self.radius / 100.0 )

        point = self.toMapCoordinates(point)

        rect = QgsRectangle()
        rect.setXMinimum(point.x() - searchRadius)
        rect.setXMaximum(point.x() + searchRadius)
        rect.setYMinimum(point.y() - searchRadius)
        rect.setYMaximum(point.y() + searchRadius)
        return rect

    def canvasPressEvent(self, event):
        self.dragging = False
        self.selectrect.setRect( 0, 0, 0, 0 )

        self.selectband = QgsRubberBand(self.canvas, QGis.Polygon )
        self.selectband.setColor(QColor.fromRgb(0,0,255, 65))
        self.selectband.setWidth(5)

    def canvasMoveEvent(self, event):
        if not event.buttons() == Qt.LeftButton:
            return

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

        maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband)

    def canvasReleaseEvent(self, event):
        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()
        else:
            rect = self.toSearchRect(event.pos())

        self.dragging = False
        self.selectband.reset()

        results = OrderedDict((l,f) for l, f in self.getFeatures(rect))
        print results
        self.infoResults.emit(results)
Example #52
0
class AdjustRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.rubberBandAdjustSide = QgsRubberBand(self.canvas,
                                                  QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.setColor(Qt.red)
        self.rubberBandAdjustSide.setWidth(3)

        self.reset()

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        # find the side of the rectangle closest to the click and some data
        # necessary to compute the new cneter and scale
        topLeft, topRight, bottomRight, bottomLeft = \
            self.layer.cornerCoordinates()
        top = [topLeft, topRight]
        right = [bottomRight, topRight]
        bottom = [bottomRight, bottomLeft]
        left = [bottomLeft, topLeft]

        click = QgsGeometry.fromPointXY(self.toMapCoordinates(e.pos()))

        # order is important (for referenceSide)
        sides = [top, right, bottom, left]
        distances = [
            click.distance(QgsGeometry.fromPolylineXY(side)) for side in sides
        ]
        self.indexSide = self.minDistance(distances)
        self.side = sides[self.indexSide]
        self.sidePoint = self.center(self.side)
        self.vector = self.directionVector(self.side)
        # side that does not move (opposite of indexSide)
        self.referenceSide = sides[(self.indexSide + 2) % 4]
        self.referencePoint = self.center(self.referenceSide)
        self.referenceDistance = self.distance(self.sidePoint,
                                               self.referencePoint)
        self.isXScale = self.indexSide % 2 == 1

        self.startPoint = click.asPoint()
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        adjustment = self.computeAdjustment()
        self.showAdjustment(*adjustment)
        self.layer.history.append({
            "action": "adjust",
            "center": self.layer.center,
            "xScale": self.layer.xScale,
            "yScale": self.layer.yScale
        })

    def minDistance(self, distances):
        sortedDistances = [
            i[0] for i in sorted(enumerate(distances), key=itemgetter(1))
        ]
        # first is min
        return sortedDistances[0]

    def directionVector(self, side):
        sideCenter = self.center(side)
        layerCenter = self.layer.center
        vector = [
            sideCenter.x() - layerCenter.x(),
            sideCenter.y() - layerCenter.y()
        ]
        norm = math.sqrt(vector[0]**2 + vector[1]**2)
        normedVector = [vector[0] / norm, vector[1] / norm]
        return normedVector

    def center(self, side):
        return QgsPointXY((side[0].x() + side[1].x()) / 2,
                          (side[0].y() + side[1].y()) / 2)

    def distance(self, pt1, pt2):
        return math.sqrt((pt1.x() - pt2.x())**2 + (pt1.y() - pt2.y())**2)

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

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        center, xScale, yScale = self.computeAdjustment()
        self.layer.setCenter(center)
        self.layer.setScale(xScale * self.layer.xScale,
                            yScale * self.layer.yScale)

        setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        self.layer.repaint()

        self.layer.commitTransformParameters()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())

        adjustment = self.computeAdjustment()
        self.showAdjustment(*adjustment)

    def computeAdjustment(self):
        dX = self.endPoint.x() - self.startPoint.x()
        dY = self.endPoint.y() - self.startPoint.y()
        # project on vector
        dp = dX * self.vector[0] + dY * self.vector[1]

        # do not go beyond 5% of the current size of side
        if dp < -0.95 * self.referenceDistance:
            dp = -0.95 * self.referenceDistance

        updatedSidePoint = QgsPointXY(self.sidePoint.x() + dp * self.vector[0],
                                      self.sidePoint.y() + dp * self.vector[1])

        center = self.center([self.referencePoint, updatedSidePoint])
        scaleFactor = self.distance(self.referencePoint, updatedSidePoint)
        if self.isXScale:
            xScale = scaleFactor / self.referenceDistance
            yScale = 1.0
        else:
            xScale = 1.0
            yScale = scaleFactor / self.referenceDistance

        return (center, xScale, yScale)

    def showAdjustment(self, center, xScale, yScale):
        _, rotation, originalXScale, originalYScale = \
            self.layer.transformParameters()
        newXScale = xScale * originalXScale
        newYScale = yScale * originalYScale
        cornerPoints = self.layer.transformedCornerCoordinates(
            center, rotation, newXScale, newYScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        # show rubberband for side
        # see def of indexSide in init:
        # cornerpoints are (topLeft, topRight, bottomRight, bottomLeft)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.addPoint(cornerPoints[self.indexSide % 4],
                                           False)
        self.rubberBandAdjustSide.addPoint(
            cornerPoints[(self.indexSide + 1) % 4], True)
        self.rubberBandAdjustSide.show()

        self.rasterShadow.reset(self.layer)
        dx = center.x() - self.layer.center.x()
        dy = center.y() - self.layer.center.y()
        self.rasterShadow.setDeltaDisplacement(dx, dy, False)
        self.rasterShadow.setDeltaScale(xScale, yScale, True)
        self.rasterShadow.show()
Example #53
0
class ProfiletoolMapTool(QgsMapTool):
    
    # Signals
    sig_clearMap = pyqtSignal()
    sig_createProfile = pyqtSignal()
    sig_changeCoord = pyqtSignal(QgsPointXY, str)


    def __init__(self, canvas, drawLineButton, showProfileButton): #buttonShowProf
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        
        self.cursor = QCursor(Qt.CrossCursor)

        # Red line
        self.rubberband = QgsRubberBand(self.canvas)
        self.rubberband.setWidth(3)
        self.rubberband.setColor(QColor(231, 28, 35))
    
        # Buttons from main dialog
        self.drawLineButton = drawLineButton
        self.buttonShowProf = showProfileButton

        # Coordinates of drawn line points
        self.pointsToDraw = []
        # Temporary save double clicks
        self.dblclktemp = None
        # Drawn line geometry
        self.drawnLine = None
        # Point markers on each end of the line
        self.markers = []
        
        # Backup the last active Tool before the pofile tool became active
        self.savedTool = self.canvas.mapTool()


    def drawLine(self):
        # Emit signal that clears map and deletes profile
        self.sig_clearMap.emit()
        self.reset()
        self.canvas.setMapTool(self)        # runs function self.activate()


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


    def deactivate(self):
        self.canvas.setCursor(QCursor(Qt.OpenHandCursor))
        self.pointsToDraw = []
        # Stop pressing down button
        self.drawLineButton.setChecked(False)


    def reset(self):
        self.removeStueMarker()
        self.canvas.setMapTool(self.savedTool)
        self.rubberband.reset()
        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None
        
        
    def canvasMoveEvent(self, event):
        if len(self.pointsToDraw) > 0:
            self.rubberband.reset()
            line = [self.pointsToDraw[0], event.mapPoint()]
            self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(line), None)
 

    def canvasReleaseEvent(self, event):
        mapPos = event.mapPoint()
        if mapPos == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            # Mark point with marker symbol
            self.drawStueMarker(mapPos)
            
            # Klick ist first point of line
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset()
                self.pointsToDraw.append(mapPos)
                return
            
            # Klick is second point of line
            elif len(self.pointsToDraw) == 1:
                self.pointsToDraw.append(mapPos)
                self.removeStueMarker()
                self.dblclktemp = mapPos
                self.drawnLine = self.createDigiFeature(self.pointsToDraw)
                self.sig_changeCoord.emit(self.pointsToDraw[0], 'A')
                self.sig_changeCoord.emit(self.pointsToDraw[1], 'E')
                self.canvas.setMapTool(self.savedTool)      # self.deactivate()


    def setCursor(self, cursor):
        self.cursor = cursor


    def updateLine(self, points):
        self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(points), None)
        self.drawnLine = self.createDigiFeature(points)
        self.drawStueMarker(points[0])
        self.drawStueMarker(points[1])


    def drawStueMarker(self, point):
        marker = QgsStueMarker(self.canvas)
        marker.setCenter(point)
        self.markers.append(marker)
        self.canvas.refresh()


    def removeStueMarker(self, position=-1):
        if position >= 0:
            marker = self.markers[position]
            self.canvas.scene().removeItem(marker)
            self.markers.pop(position)
        else:
            for marker in self.markers:
                self.canvas.scene().removeItem(marker)
            self.markers = []
        self.canvas.refresh()


    @staticmethod
    def createDigiFeature(pnts):
        line = QgsGeometry.fromPolylineXY(pnts)
        qgFeat = QgsFeature()
        qgFeat.setGeometry(line)
        return qgFeat
Example #54
0
class MapWidget(Ui_CanvasWidget, QMainWindow):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        self.setupUi(self)
        self.snapping = True

        icon = roam_style.iconsize()
        self.projecttoolbar.setIconSize(QSize(icon, icon))

        self.current_form = None
        self.last_form = None
        self.firstshow = True
        self.layerbuttons = []
        self.editfeaturestack = []
        self.lastgpsposition = None
        self.project = None
        self.gps = None
        self.gpslogging = None
        self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas))

        self.bridge = QgsLayerTreeMapCanvasBridge(
            QgsProject.instance().layerTreeRoot(), self.canvas)
        self.bridge.setAutoSetupOnFirstLayer(False)
        QgsProject.instance().writeProject.connect(self.bridge.writeProject)
        QgsProject.instance().readProject.connect(self.bridge.readProject)

        # self.canvas.setInteractive(False)
        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor)

        self.snappingutils = SnappingUtils(self.canvas, self)
        self.canvas.setSnappingUtils(self.snappingutils)
        QgsProject.instance().readProject.connect(
            self.snappingutils.readConfigFromProject)

        if hasattr(self.canvas, 'setParallelRenderingEnabled'):
            threadcount = QThread.idealThreadCount()
            threadcount = 2 if threadcount > 2 else 1
            QgsApplication.setMaxThreads(threadcount)
            self.canvas.setParallelRenderingEnabled(True)

        pal = QgsPalLabeling()
        self.canvas.mapRenderer().setLabelingEngine(pal)
        self.canvas.setFrameStyle(QFrame.NoFrame)

        self.editgroup = QActionGroup(self)
        self.editgroup.setExclusive(True)
        self.editgroup.addAction(self.actionPan)
        self.editgroup.addAction(self.actionZoom_In)
        self.editgroup.addAction(self.actionZoom_Out)
        self.editgroup.addAction(self.actionInfo)

        self.actionGPS = GPSAction(":/icons/gps", self.canvas, self)
        self.projecttoolbar.addAction(self.actionGPS)

        if roam.config.settings.get('north_arrow', False):
            self.northarrow = NorthArrow(":/icons/north", self.canvas)
            self.northarrow.setPos(10, 10)
            self.canvas.scene().addItem(self.northarrow)

        smallmode = roam.config.settings.get("smallmode", False)
        self.projecttoolbar.setSmallMode(smallmode)

        self.scalebar_enabled = roam.config.settings.get('scale_bar', False)
        if self.scalebar_enabled:
            self.scalebar = ScaleBarItem(self.canvas)
            self.canvas.scene().addItem(self.scalebar)

        self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu)

        gpsspacewidget = QWidget()
        gpsspacewidget.setMinimumWidth(30)
        gpsspacewidget.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Expanding)

        self.topspaceraction = self.projecttoolbar.insertWidget(
            self.actionGPS, gpsspacewidget)

        self.dataentryselection = QAction(self.projecttoolbar)
        self.dataentryaction = self.projecttoolbar.insertAction(
            self.topspaceraction, self.dataentryselection)
        self.dataentryselection.triggered.connect(self.select_data_entry)

        self.marker = GPSMarker(self.canvas)
        self.marker.hide()

        self.currentfeatureband = CurrentSelection(self.canvas)
        self.currentfeatureband.setIconSize(30)
        self.currentfeatureband.setWidth(10)
        self.currentfeatureband.setColor(QColor(186, 93, 212, 50))
        self.currentfeatureband.setOutlineColour(QColor(186, 93, 212))

        self.gpsband = QgsRubberBand(self.canvas)
        self.gpsband.setColor(QColor(165, 111, 212, 75))
        self.gpsband.setWidth(5)

        RoamEvents.editgeometry.connect(self.queue_feature_for_edit)
        RoamEvents.selectioncleared.connect(self.clear_selection)
        RoamEvents.selectionchanged.connect(self.highlight_selection)
        RoamEvents.openfeatureform.connect(self.feature_form_loaded)
        RoamEvents.sync_complete.connect(self.refresh_map)
        RoamEvents.snappingChanged.connect(self.snapping_changed)

        self.snappingbutton = QToolButton()
        self.snappingbutton.setText("Snapping: On")
        self.snappingbutton.setAutoRaise(True)
        self.snappingbutton.pressed.connect(self.toggle_snapping)

        spacer = QWidget()
        spacer2 = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        self.scalewidget = QgsScaleComboBox()

        self.scalebutton = QToolButton()
        self.scalebutton.setAutoRaise(True)
        self.scalebutton.setMaximumHeight(self.statusbar.height())
        self.scalebutton.pressed.connect(self.selectscale)
        self.scalebutton.setText("Scale")

        self.scalelist = BigList(parent=self.canvas,
                                 centeronparent=True,
                                 showsave=False)
        self.scalelist.hide()
        self.scalelist.setlabel("Map Scale")
        self.scalelist.setmodel(self.scalewidget.model())
        self.scalelist.closewidget.connect(self.scalelist.close)
        self.scalelist.itemselected.connect(self.update_scale_from_item)
        self.scalelist.itemselected.connect(self.scalelist.close)

        self.positionlabel = QLabel('')
        self.gpslabel = QLabel("GPS: Not active")
        self.gpslabelposition = QLabel("")

        self.statusbar.addWidget(self.snappingbutton)
        self.statusbar.addWidget(spacer2)
        self.statusbar.addWidget(self.gpslabel)
        self.statusbar.addWidget(self.gpslabelposition)
        self.statusbar.addPermanentWidget(self.scalebutton)

        self.canvas.extentsChanged.connect(self.updatestatuslabel)
        self.canvas.scaleChanged.connect(self.updatestatuslabel)

        GPS.gpsposition.connect(self.update_gps_label)
        GPS.gpsdisconnected.connect(self.gps_disconnected)

        self.connectButtons()

    def clear_plugins(self):
        toolbars = self.findChildren(QToolBar)
        for toolbar in toolbars:
            if toolbar.property("plugin_toolbar"):
                toolbar.unload()
                self.removeToolBar(toolbar)
                toolbar.deleteLater()

    def add_plugins(self, pluginnames):
        for name in pluginnames:
            # Get the plugin
            try:
                plugin_mod = plugins.loaded_plugins[name]
            except KeyError:
                continue

            if not hasattr(plugin_mod, 'toolbars'):
                roam.utils.warning(
                    "No toolbars() function found in {}".format(name))
                continue

            toolbars = plugin_mod.toolbars()
            self.load_plugin_toolbars(toolbars)

    def load_plugin_toolbars(self, toolbars):
        for ToolBarClass in toolbars:
            toolbar = ToolBarClass(plugins.api, self)
            self.addToolBar(Qt.BottomToolBarArea, toolbar)
            toolbar.setProperty("plugin_toolbar", True)

    def snapping_changed(self, snapping):
        """
        Called when the snapping settings have changed. Updates the label in the status bar.
        :param snapping:
        """
        if snapping:
            self.snappingbutton.setText("Snapping: On")
        else:
            self.snappingbutton.setText("Snapping: Off")

    def toggle_snapping(self):
        """
        Toggle snapping on or off.
        """
        self.snapping = not self.snapping
        try:
            self.canvas.mapTool().toggle_snapping()
        except AttributeError:
            pass

        RoamEvents.snappingChanged.emit(self.snapping)

    def selectscale(self):
        """
        Show the select scale widget.
        :return:
        """
        self.scalelist.show()

    def update_scale_from_item(self, index):
        """
        Update the canvas scale from the selected scale item.
        :param index: The index of the selected item.
        """
        scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole))
        self.canvas.zoomScale(1.0 / scale)

    def update_gps_label(self, position, gpsinfo):
        """
        Update the GPS label in the status bar with the GPS status.
        :param position: The current GPS position.
        :param gpsinfo: The current extra GPS information.
        """
        self.gpslabel.setText(
            "GPS: PDOP <b>{0:.2f}</b> HDOP <b>{1:.2f}</b>    VDOP <b>{2:.2f}</b>"
            .format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop))

        places = roam.config.settings.get("gpsplaces", 8)
        self.gpslabelposition.setText(
            "X <b>{x:.{places}f}</b> Y <b>{y:.{places}f}</b>".format(
                x=position.x(), y=position.y(), places=places))

    def gps_disconnected(self):
        """
        Called when the GPS is disconnected. Updates the label in the status bar with the message.
        :return:
        """
        self.gpslabel.setText("GPS Not Active")
        self.gpslabelposition.setText("")

    def zoom_to_feature(self, feature):
        box = feature.geometry().boundingBox()
        xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum(
        ), box.yMaximum()
        xmin -= 5
        xmax += 5
        ymin -= 5
        ymax += 5
        box = QgsRectangle(xmin, ymin, xmax, ymax)
        self.canvas.setExtent(box)
        self.canvas.refresh()

    def updatestatuslabel(self, *args):
        """
        Update the status bar labels when the information has changed.
        """
        extent = self.canvas.extent()
        self.positionlabel.setText("Map Center: {}".format(
            extent.center().toString()))
        scale = 1.0 / self.canvas.scale()
        scale = self.scalewidget.toString(scale)
        self.scalebutton.setText(scale)

    def refresh_map(self):
        """
        Refresh the map
        """
        self.canvas.refresh()

    def updatescale(self):
        """
        Update the scale of the map with the current scale from the scale widget
        :return:
        """
        self.canvas.zoomScale(1.0 / self.scalewidget.scale())

    def init_qgisproject(self, doc):
        """
        Called when the project file is read for the firs time.
        :param doc: The XML doc.
        :return: The current canvas CRS
        :note: This method is old and needs to be refactored into something else.
        """
        return self.canvas.mapSettings().destinationCrs()

    def showEvent(self, *args, **kwargs):
        """
        Handle the show event of the of the map widget. We have to do a little hack here to make the QGIS map refresh.
        """
        if QGis.QGIS_VERSION_INT == 20200 and self.firstshow:
            self.canvas.refresh()
            self.canvas.repaint()
            self.firstshow = False

    def feature_form_loaded(self, form, feature, *args):
        """
        Called when the feature form is loaded.
        :param form: The Form object. Holds a reference to the forms layer.
        :param feature: The current capture feature
        """
        self.currentfeatureband.setToGeometry(feature.geometry(),
                                              form.QGISLayer)

    def highlight_selection(self, results):
        """
        Highlight the selection on the canvas.  This updates all selected objects based on the result set.
        :param results: A dict-of-list of layer-features.
        """
        self.clear_selection()
        for layer, features in results.iteritems():
            band = self.selectionbands[layer]
            band.setColor(QColor(255, 0, 0))
            band.setIconSize(25)
            band.setWidth(5)
            band.setBrushStyle(Qt.NoBrush)
            band.reset(layer.geometryType())
            band.setZValue(self.currentfeatureband.zValue() - 1)
            for feature in features:
                band.addGeometry(feature.geometry(), layer)
        self.canvas.update()

    def highlight_active_selection(self, layer, feature, features):
        """
        Update the current active selected feature.
        :param layer: The layer of the active feature.
        :param feature: The active feature.
        :param features: The other features in the set to show as non active selection.
        :return:
        """
        self.clear_selection()
        self.highlight_selection({layer: features})
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        self.canvas.update()

    def clear_selection(self):
        """
        Clear the selection from the canvas.   Resets all selection rubbber bands.
        :return:
        """
        # Clear the main selection rubber band
        self.canvas.scene().update()
        self.currentfeatureband.reset()
        # Clear the rest
        for band in self.selectionbands.itervalues():
            band.reset()

        self.canvas.update()
        self.editfeaturestack = []

    def queue_feature_for_edit(self, form, feature):
        """
        Push a feature on the edit stack so the feature can have the geometry edited.
        :note: This is a big hack and I don't like it!
        :param form: The form for the current feature
        :param feature: The active feature.
        """
        def trigger_default_action():
            for action in self.projecttoolbar.actions():
                if action.property('dataentry') and action.isdefault:
                    action.trigger()
                    self.canvas.mapTool().setEditMode(True, feature.geometry())
                    break

        self.editfeaturestack.append((form, feature))
        self.save_current_form()
        self.load_form(form)
        trigger_default_action()

    def save_current_form(self):
        self.last_form = self.current_form

    def restore_last_form(self):
        self.load_form(self.last_form)

    def clear_temp_objects(self):
        """
        Clear all temp objects from the canvas.
        :return:
        """
        def clear_tool_band():
            """
            Clear the rubber band of the active tool if it has one
            """
            tool = self.canvas.mapTool()
            try:
                tool.clearBand()
            except AttributeError:
                # No clearBand method found, but that's cool.
                pass

        self.currentfeatureband.reset()
        clear_tool_band()

    def settings_updated(self, settings):
        """
        Called when the settings have been updated in the Roam config.
        :param settings: A dict of the settings.
        """
        self.actionGPS.updateGPSPort()
        gpslogging = settings.get('gpslogging', True)
        if self.gpslogging:
            self.gpslogging.logging = gpslogging

    def set_gps(self, gps, logging):
        """
        Set the GPS for the map widget.  Connects GPS signals
        """
        self.gps = gps
        self.gpslogging = logging
        self.gps.gpsposition.connect(self.gps_update_canvas)
        self.gps.firstfix.connect(self.gps_first_fix)
        self.gps.gpsdisconnected.connect(self.gps_disconnected)

    def gps_update_canvas(self, position, gpsinfo):
        """
        Updates the map canvas based on the GPS position.  By default if the GPS is outside the canvas
        extent the canvas will move to center on the GPS.  Can be turned off in settings.
        :param postion: The current GPS position.
        :param gpsinfo: The extra GPS information
        """
        # Recenter map if we go outside of the 95% of the area
        if self.gpslogging.logging:
            self.gpsband.addPoint(position)
            self.gpsband.show()

        if roam.config.settings.get('gpscenter', True):
            if not self.lastgpsposition == position:
                self.lastposition = position
                rect = QgsRectangle(position, position)
                extentlimt = QgsRectangle(self.canvas.extent())
                extentlimt.scale(0.95)

                if not extentlimt.contains(position):
                    self.zoom_to_location(position)

        self.marker.show()
        self.marker.setCenter(position, gpsinfo)

    def gps_first_fix(self, postion, gpsinfo):
        """
        Called the first time the GPS gets a fix.  If set this will zoom to the GPS after the first fix
        :param postion: The current GPS position.
        :param gpsinfo: The extra GPS information
        """
        zoomtolocation = roam.config.settings.get('gpszoomonfix', True)
        if zoomtolocation:
            self.canvas.zoomScale(1000)
            self.zoom_to_location(postion)

    def zoom_to_location(self, position):
        """
        Zoom to ta given position on the map..
        """
        rect = QgsRectangle(position, position)
        self.canvas.setExtent(rect)
        self.canvas.refresh()

    def gps_disconnected(self):
        """
        Called when the GPS is disconnected
        """
        self.marker.hide()

    def select_data_entry(self):
        """
        Open the form selection widget to allow the user to pick the active capture form.
        """
        def showformerror(form):
            pass

        def actions():
            for form in self.project.forms:
                if not self.form_valid_for_capture(form):
                    continue

                action = form.createuiaction()
                valid, failreasons = form.valid
                if not valid:
                    roam.utils.warning("Form {} failed to load".format(
                        form.label))
                    roam.utils.warning("Reasons {}".format(failreasons))
                    action.triggered.connect(partial(showformerror, form))
                else:
                    action.triggered.connect(partial(self.load_form, form))
                yield action

        formpicker = PickActionDialog(msg="Select data entry form", wrap=5)
        formpicker.addactions(actions())
        formpicker.exec_()

    def project_loaded(self, project):
        """
        Called when the project is loaded. Main entry point for a loade project.
        :param project: The Roam project that has been loaded.
        """
        self.project = project
        self.actionPan.trigger()
        firstform = self.first_capture_form()
        if firstform:
            self.load_form(firstform)
            self.dataentryselection.setVisible(True)
        else:
            self.dataentryselection.setVisible(False)

        # Enable the raster layers button only if the project contains a raster layer.
        layers = QgsMapLayerRegistry.instance().mapLayers().values()
        hasrasters = any(layer.type() == QgsMapLayer.RasterLayer
                         for layer in layers)
        self.actionRaster.setEnabled(hasrasters)
        self.defaultextent = self.canvas.extent()
        roam.utils.info("Extent: {}".format(self.defaultextent.toString()))

        self.infoTool.selectionlayers = project.selectlayersmapping()

        self.canvas.refresh()

        projectscales, _ = QgsProject.instance().readBoolEntry(
            "Scales", "/useProjectScales")
        if projectscales:
            projectscales, _ = QgsProject.instance().readListEntry(
                "Scales", "/ScalesList")

            self.scalewidget.updateScales(projectscales)
        else:
            scales = [
                "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000",
                "1:500", "1:250", "1:200", "1:100"
            ]
            scales = roam.config.settings.get('scales', scales)
            self.scalewidget.updateScales(scales)

        if self.scalebar_enabled:
            self.scalebar.update()

        self.actionPan.toggle()
        self.clear_plugins()
        self.add_plugins(project.enabled_plugins)

    def setMapTool(self, tool, *args):
        """
        Set the active map tool in the canvas.
        :param tool: The QgsMapTool to set.
        """
        if tool == self.canvas.mapTool():
            return

        if hasattr(tool, "setSnapping"):
            tool.setSnapping(self.snapping)
        self.canvas.setMapTool(tool)

    def connectButtons(self):
        """
        Connect the default buttons in the interface. Zoom, pan, etc
        """
        def connectAction(action, tool):
            action.toggled.connect(partial(self.setMapTool, tool))

        def cursor(name):
            pix = QPixmap(name)
            pix = pix.scaled(QSize(24, 24))
            return QCursor(pix)

        self.zoomInTool = QgsMapToolZoom(self.canvas, False)
        self.zoomOutTool = QgsMapToolZoom(self.canvas, True)
        self.panTool = PanTool(self.canvas)
        self.infoTool = InfoTool(self.canvas)

        self.infoTool.setAction(self.actionInfo)
        self.zoomInTool.setAction(self.actionZoom_In)
        self.zoomOutTool.setAction(self.actionZoom_Out)
        self.panTool.setAction(self.actionPan)

        connectAction(self.actionZoom_In, self.zoomInTool)
        connectAction(self.actionZoom_Out, self.zoomOutTool)
        connectAction(self.actionPan, self.panTool)
        connectAction(self.actionInfo, self.infoTool)

        self.zoomInTool.setCursor(cursor(':/icons/in'))
        self.zoomOutTool.setCursor(cursor(':/icons/out'))
        self.infoTool.setCursor(cursor(':/icons/select'))

        self.actionRaster.triggered.connect(self.toggleRasterLayers)
        self.actionHome.triggered.connect(self.homeview)

    def homeview(self):
        """
        Zoom the mapview canvas to the extents the project was opened at i.e. the
        default extent.
        """
        self.canvas.setExtent(self.defaultextent)
        self.canvas.refresh()

    def form_valid_for_capture(self, form):
        """
        Check if the given form is valid for capture.
        :param form: The form to check.
        :return: True if valid form for capture
        """
        return form.has_geometry and self.project.layer_can_capture(
            form.QGISLayer)

    def first_capture_form(self):
        """
        Return the first valid form for capture.
        """
        for form in self.project.forms:
            if self.form_valid_for_capture(form):
                return form

    def load_form(self, form):
        """
        Load the given form so it's the active one for capture
        :param form: The form to load
        """
        self.clearCaptureTools()
        self.dataentryselection.setIcon(QIcon(form.icon))
        self.dataentryselection.setText(form.icontext)
        self.create_capture_buttons(form)
        self.current_form = form

    def create_capture_buttons(self, form):
        """
        Create the capture buttons in the toolbar for the given form.
        :param form: The active form.
        """
        layer = form.QGISLayer
        tool = form.getMaptool()(self.canvas, form.settings)
        for action in tool.actions:
            # Create the action here.
            if action.ismaptool:
                action.toggled.connect(partial(self.setMapTool, tool))

            # Set the action as a data entry button so we can remove it later.
            action.setProperty("dataentry", True)
            self.editgroup.addAction(action)
            self.layerbuttons.append(action)
            self.projecttoolbar.insertAction(self.topspaceraction, action)
            action.setChecked(action.isdefault)

        if hasattr(tool, 'geometryComplete'):
            add = partial(self.add_new_feature, form)
            tool.geometryComplete.connect(add)
        else:
            tool.finished.connect(self.openForm)

        tool.error.connect(self.show_invalid_geometry_message)

    def show_invalid_geometry_message(self, message):
        RoamEvents.raisemessage("Invalid geometry capture",
                                message,
                                level=RoamEvents.CRITICAL)

    def add_new_feature(self, form, geometry):
        """
        Add a new new feature to the given layer
        """
        # TODO Extract into function.
        # NOTE This function is doing too much, acts as add and also edit.
        layer = form.QGISLayer
        if layer.geometryType() in [
                QGis.WKBMultiLineString, QGis.WKBMultiPoint,
                QGis.WKBMultiPolygon
        ]:
            geometry.convertToMultiType()

        try:
            form, feature = self.editfeaturestack.pop()
            self.editfeaturegeometry(form, feature, newgeometry=geometry)
            return
        except IndexError:
            pass

        feature = form.new_feature(geometry=geometry)
        RoamEvents.load_feature_form(form, feature, editmode=False)

    def editfeaturegeometry(self, form, feature, newgeometry):
        # TODO Extract into function.
        layer = form.QGISLayer
        layer.startEditing()
        feature.setGeometry(newgeometry)
        layer.updateFeature(feature)
        saved = layer.commitChanges()
        if not saved:
            map(roam.utils.error, layer.commitErrors())
        self.canvas.refresh()
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        RoamEvents.editgeometry_complete.emit(form, feature)
        self.canvas.mapTool().setEditMode(False, None)
        self.restore_last_form()

    def clearCaptureTools(self):
        """
        Clear the capture tools from the toolbar.
        :return: True if the capture button was active at the time of clearing.
        """
        captureselected = False
        for action in self.projecttoolbar.actions():
            if action.objectName() == "capture" and action.isChecked():
                captureselected = True

            if action.property('dataentry'):
                self.projecttoolbar.removeAction(action)
        return captureselected

    def toggleRasterLayers(self):
        """
        Toggle all raster layers on or off.
        """
        # Freeze the canvas to save on UI refresh
        self.canvas.freeze()
        tree = QgsProject.instance().layerTreeRoot()
        for node in tree.findLayers():
            if node.layer().type() == QgsMapLayer.RasterLayer:
                if node.isVisible() == Qt.Checked:
                    state = Qt.Unchecked
                else:
                    state = Qt.Checked
                node.setVisible(state)

        self.canvas.freeze(False)
        self.canvas.refresh()

    def cleanup(self):
        """
        Clean up when the project has changed.
        :return:
        """
        self.bridge.clear()
        self.gpsband.reset()
        self.gpsband.hide()
        self.clear_selection()
        self.clear_temp_objects()
        self.clearCaptureTools()
        self.canvas.freeze()
        self.canvas.clear()
        self.canvas.freeze(False)
        for action in self.layerbuttons:
            self.editgroup.removeAction(action)
Example #55
0
class ObstacleAreaJigCreateArea(QgsMapTool):
    def __init__(self, canvas, areaType):
        QgsMapTool.__init__(self, canvas)
        self.mCanvas = canvas
        self.areaType = areaType
        self.annotation = None
        self.rubberBand = QgsRubberBand(canvas, QGis.Point)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(10)
        self.rubberBandClick = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandClick.setColor(Qt.green)
        self.rubberBandClick.setWidth(3)
        self.obstaclesLayerList = QgisHelper.getSurfaceLayers(
            SurfaceTypes.Obstacles)
        self.demLayerList = QgisHelper.getSurfaceLayers(SurfaceTypes.DEM)

        self.mRubberBand = None
        self.mRubberBand0 = QgsRubberBand(self.mCanvas, QGis.Polygon)
        self.mCursor = Qt.ArrowCursor
        self.mFillColor = QColor(254, 178, 76, 63)
        self.mBorderColour = QColor(254, 58, 29, 100)
        self.mRubberBand0.setBorderColor(self.mBorderColour)
        self.polygonGeom = None
        self.drawFlag = False
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.resultPolylineArea = PolylineArea()
        #         self.constructionLayer = constructionLayer
        self.menuString = ""
        self.isPrimaryPolylineStarted = False
        self.primaryPolyline = PolylineArea()

    def createContextMenu(self, areaType, isStarted=False):
        menu = QMenu()
        # h = QHBoxLayout(menu)
        # c = QCalendarWidget()
        # h.addWidget(c)
        if areaType == ProtectionAreaType.Primary:
            actionEnter = QgisHelper.createAction(menu, "Enter",
                                                  self.menuEnterClick)
            actionCancel = QgisHelper.createAction(menu, "Cancel",
                                                   self.menuCancelClick)
            actionArc = QgisHelper.createAction(menu, "Arc", self.menuArcClick)
            actionUndo = QgisHelper.createAction(menu, "Undo",
                                                 self.menuUndoClick)
            menu.addAction(actionEnter)
            menu.addAction(actionCancel)
            menu.addAction(actionArc)
            menu.addAction(actionUndo)
        elif areaType == ProtectionAreaType.Secondary:
            if not isStarted:
                actionEnter = QgisHelper.createAction(menu, "Enter",
                                                      self.menuEnterClick)
                actionCancel = QgisHelper.createAction(menu, "Cancel",
                                                       self.menuCancelClick)
                actionUndo = QgisHelper.createAction(menu, "Undo",
                                                     self.menuUndoClick)
                actionPrimatyPolylineStart = QgisHelper.createAction(
                    menu, "Strat INNER edge of the secondary area",
                    self.menuPrimaryStartClick)
                actionPrimatyPolylineEnd = QgisHelper.createAction(
                    menu, "End INNER edge of the secondary area",
                    self.menuPrimaryEndClick)
                menu.addAction(actionEnter)
                menu.addAction(actionCancel)
                menu.addAction(actionUndo)
                menu.addAction(actionPrimatyPolylineStart)
                menu.addAction(actionPrimatyPolylineEnd)
                actionPrimatyPolylineStart.setEnabled(
                    not self.isPrimaryPolylineStarted)
                actionPrimatyPolylineEnd.setEnabled(
                    self.isPrimaryPolylineStarted)
            else:
                actionPrimatyPolylineStart = QgisHelper.createAction(
                    menu, "Strat INNER edge of the secondary area",
                    self.menuPrimaryStartClick)
                actionPrimatyPolylineEnd = QgisHelper.createAction(
                    menu, "End INNER edge of the secondary area",
                    self.menuPrimaryEndClick)
                menu.addAction(actionPrimatyPolylineStart)
                menu.addAction(actionPrimatyPolylineEnd)
                actionPrimatyPolylineStart.setEnabled(
                    not self.isPrimaryPolylineStarted)
                actionPrimatyPolylineEnd.setEnabled(
                    self.isPrimaryPolylineStarted)
        return menu

    def menuPrimaryStartClick(self):
        self.primaryPolyline = PolylineArea()
        self.isPrimaryPolylineStarted = True
        # self.menuString = "Enter"
    def menuPrimaryEndClick(self):
        self.isPrimaryPolylineStarted = False
        # self.menuString = "Enter"
    def menuEnterClick(self):
        self.menuString = "Enter"

    def menuCancelClick(self):
        self.menuString = "Cancel"

    def menuArcClick(self):
        self.menuString = "Arc"

    def menuUndoClick(self):
        self.menuString = "Undo"

    def reset(self):
        self.Point = None

    def canvasPressEvent(self, e):
        define._messageLabel.setText("")
        self.menuString = ""
        pointBackground = e.pos()
        #         self.Point = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas)
        self.Point, self.pointID, self.layer = self.snapPoint(e.pos())
        self.selectedLayerFromSnapPoint = None

        if (self.mRubberBand == None):
            self.resultPolylineArea = PolylineArea()
            self.mRubberBand0.reset(QGis.Polygon)
            #             define._canvas.clearCache ()
            self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon)
            self.mRubberBand0 = QgsRubberBand(self.mCanvas, QGis.Polygon)
            self.mRubberBand.setFillColor(self.mFillColor)
            self.mRubberBand.setBorderColor(self.mBorderColour)
            self.mRubberBand0.setFillColor(QColor(255, 255, 255, 100))
            self.mRubberBand0.setBorderColor(QColor(0, 0, 0))
        if (e.button() == Qt.LeftButton):
            if self.Point == None:
                self.mRubberBand.addPoint(self.toMapCoordinates(e.pos()))
                self.resultPolylineArea.Add(
                    PolylineAreaPoint(self.toMapCoordinates(e.pos())))
                if self.isPrimaryPolylineStarted:
                    self.primaryPolyline.Add(
                        PolylineAreaPoint(self.toMapCoordinates(e.pos())))
            else:
                self.mRubberBand.addPoint(self.Point)
                self.resultPolylineArea.Add(PolylineAreaPoint(self.Point))
                if self.isPrimaryPolylineStarted:
                    self.primaryPolyline.Add(
                        PolylineAreaPoint(self.toMapCoordinates(e.pos())))
        else:
            menu = None
            if self.areaType == ProtectionAreaType.Secondary and len(
                    self.resultPolylineArea) == 0:
                menu = self.createContextMenu(self.areaType, True)
                menu.exec_(define._canvas.mapToGlobal(e.pos()))
                return

            if (self.mRubberBand.numberOfVertices() > 2):
                self.polygonGeom = self.mRubberBand.asGeometry()
            else:
                return
#                 QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, polygonGeom, e )
            menu = self.createContextMenu(self.areaType)
            menu.exec_(define._canvas.mapToGlobal(e.pos()))

            if self.menuString == "Cancel" or self.menuString == "Arc":
                return
            elif self.menuString == "Undo":
                if (self.mRubberBand.numberOfVertices() > 0):

                    self.mRubberBand = None
                    QgisHelper.ClearRubberBandInCanvas(define._canvas)
                    self.mRubberBand = QgsRubberBand(self.mCanvas,
                                                     QGis.Polygon)
                    self.mRubberBand.setFillColor(self.mFillColor)
                    self.mRubberBand.setBorderColor(self.mBorderColour)
                    self.resultPolylineArea[self.resultPolylineArea.Count -
                                            2].bulge = 0.0
                    self.resultPolylineArea.pop(self.resultPolylineArea.Count -
                                                1)
                    if self.isPrimaryPolylineStarted and len(
                            self.primaryPolyline) > 0:
                        self.primaryPolyline.pop(self.primaryPolyline.Count -
                                                 1)
                    for pt in self.resultPolylineArea.method_14():
                        self.mRubberBand.addPoint(pt)
                return
            elif self.menuString == "Enter":
                # if self.areaType == ProtectionAreaType.Secondary:
                #     if self.resultPolylineArea.Count != 4:
                #         define._messageLabel.setText("The count of point of Secondary Area must be 4.")
                #         return
                self.mRubberBand.reset(QGis.Polygon)
                self.mRubberBand0.reset(QGis.Polygon)
                #             define._canvas.clearCache ()

                self.mRubberBand0 = QgsRubberBand(self.mCanvas, QGis.Polygon)

                self.mRubberBand0.setFillColor(QColor(255, 255, 255, 100))
                self.mRubberBand0.setBorderColor(QColor(0, 0, 0))
                for pt in self.resultPolylineArea.method_14():
                    self.mRubberBand0.addPoint(pt)
                # self.mRubberBand0.addGeometry(self.polygonGeom, None)
                n = self.mRubberBand0.numberOfVertices()
                self.mRubberBand0.show()
                self.mRubberBand = None
                area = None
                if self.areaType == ProtectionAreaType.Primary:
                    area = PrimaryObstacleArea(self.resultPolylineArea)
                elif self.areaType == ProtectionAreaType.Secondary:
                    if len(self.resultPolylineArea) == 4:
                        area = SecondaryObstacleArea(
                            self.resultPolylineArea[0].Position,
                            self.resultPolylineArea[1].Position,
                            self.resultPolylineArea[3].Position,
                            self.resultPolylineArea[2].Position,
                            MathHelper.getBearing(
                                self.resultPolylineArea[0].Position,
                                self.resultPolylineArea[1].Position))

                    else:
                        if self.primaryPolyline.Count < 2:
                            define._messageLabel.setText(
                                "The PrimaryLine in Secondary Area must exist."
                            )
                            return
                        if self.isPrimaryPolylineStarted:
                            define._messageLabel.setText(
                                "You must finish  the input of  PrimaryLine.")
                            return
                        area = SecondaryObstacleAreaWithManyPoints(
                            self.resultPolylineArea, self.primaryPolyline)
                self.emit(SIGNAL("outputResult"), area, self.mRubberBand0)
            n = 0

    def canvasMoveEvent(self, e):
        self.rubberBand.reset(QGis.Point)
        #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper , define._canvas, True)
        snapPoint, snapPointID, layer = self.snapPoint(e.pos(), True)
        if snapPoint != None:
            self.rubberBand.addPoint(snapPoint)
            self.rubberBand.show()
        if (self.mRubberBand == None):
            return

        if (self.mRubberBand.numberOfVertices() > 0):
            if self.menuString != "Undo":
                self.mRubberBand.removeLastPoint(0)
            else:
                self.menuString = ""
            point2 = None
            if snapPoint != None:
                self.mRubberBand.addPoint(snapPoint)
                point2 = snapPoint
            else:
                self.mRubberBand.addPoint(self.toMapCoordinates(e.pos()))
                point2 = self.toMapCoordinates(e.pos())
            if self.menuString == "Arc":
                point0 = self.resultPolylineArea[self.resultPolylineArea.Count
                                                 - 2].Position
                point1 = self.resultPolylineArea[self.resultPolylineArea.Count
                                                 - 1].Position
                # point2 = self.mRubberBand.getPoint(self.mRubberBand.numberOfVertices() - 1)
                bulge = MathHelper.smethod_60(point0, point1, point2)
                self.resultPolylineArea[self.resultPolylineArea.Count -
                                        2].bulge = bulge
                self.mRubberBand = None
                QgisHelper.ClearRubberBandInCanvas(define._canvas)
                self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon)
                self.mRubberBand.setFillColor(self.mFillColor)
                self.mRubberBand.setBorderColor(self.mBorderColour)

                for pt in self.resultPolylineArea.method_14():
                    self.mRubberBand.addPoint(pt)
                self.mRubberBand.addPoint(point2)

    def snapPoint(self, p, bNone=False):
        if define._snapping == False:
            return (
                define._canvas.getCoordinateTransform().toMapCoordinates(p),
                None, None)
        snappingResults = self.mSnapper.snapToBackgroundLayers(p)
        if (snappingResults[0] != 0 or len(snappingResults[1]) < 1):

            if bNone:
                return (None, None, None)
            else:
                return (define._canvas.getCoordinateTransform().
                        toMapCoordinates(p), None, None)
        else:
            return (snappingResults[1][0].snappedVertex,
                    snappingResults[1][0].snappedAtGeometry,
                    snappingResults[1][0].layer)

    def deactivate(self):
        self.rubberBand.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Example #56
0
class ScaleRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.reset()

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        pressed_button = e.button()
        if pressed_button == 1:
            self.startPoint = e.pos()
            self.endPoint = self.startPoint
            self.isEmittingPoint = True
            self.height = float(self.canvas.height())
            self.width = float(self.canvas.width())

            modifiers = QApplication.keyboardModifiers()
            self.isKeepRelativeScale = bool(modifiers & Qt.ControlModifier)

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            scaling = self.computeScaling()
            self.showScaling(*scaling)
        self.layer.history.append({
            "action": "scale",
            "xScale": self.layer.xScale,
            "yScale": self.layer.yScale
        })

    def canvasReleaseEvent(self, e):
        pressed_button = e.button()
        if pressed_button == 1:
            self.isEmittingPoint = False

            self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
            self.rasterShadow.reset()

            xScale, yScale = self.computeScaling()
            self.layer.setScale(xScale * self.layer.xScale,
                                yScale * self.layer.yScale)

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        elif pressed_button == 2:
            number, ok = QInputDialog.getText(
                None, "Scale & DPI", "Enter scale,dpi (e.g. 3000,96)")
            if not ok:
                self.layer.history.pop()
                return
            scales = number.split(',')
            if len(scales) != 2:
                self.layer.history.pop()
                QMessageBox.information(self.iface.mainWindow(), "Error",
                                        "Must be 2 numbers")
                return
            scale = tryfloat(scales[0])
            dpi = tryfloat(scales[1])
            if scale and dpi:
                xScale = scale / (dpi / 0.0254)
                yScale = xScale
            else:
                self.layer.history.pop()
                QMessageBox.information(
                    self.iface.mainWindow(), "Error",
                    "Bad format: Must be scale,dpi (e.g. 3000,96)")
                return

            self.layer.setScale(xScale, yScale)

        self.layer.repaint()
        self.layer.commitTransformParameters()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = e.pos()
        scaling = self.computeScaling()
        self.showScaling(*scaling)

    def computeScaling(self):
        dX = -(self.endPoint.x() - self.startPoint.x())
        dY = self.endPoint.y() - self.startPoint.y()
        xScale = 1.0 - (dX / (self.width * 1.1))
        yScale = 1.0 - (dY / (self.height * 1.1))

        if self.isKeepRelativeScale:
            # keep same scale in both dimensions
            return (xScale, xScale)
        else:
            return (xScale, yScale)

    def showScaling(self, xScale, yScale):
        if xScale == 0 and yScale == 0:
            return

        center, rotation, originalXScale, originalYScale = \
            self.layer.transformParameters()
        newXScale = xScale * originalXScale
        newYScale = yScale * originalYScale
        cornerPoints = self.layer.transformedCornerCoordinates(
            center, rotation, newXScale, newYScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaScale(xScale, yScale, True)
        self.rasterShadow.show()
class RectangleMapTool(QgsMapToolEmitPoint):
    """
    Map tool that lets the user define the analysis extents.
    """
    rectangle_created = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        """Constructor for the map tool.

        :param canvas: Canvas that tool will interact with.
        :type canvas: QgsMapCanvas
        """
        self.canvas = canvas
        self.start_point = None
        self.end_point = None
        self.is_emitting_point = False

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line)
        self.rubber_band.setColor(QColor(0, 0, 240, 100))
        # Needs QGIS 2.6
        # self.rubber_band.setFillColor(QColor(0, 0, 240, 0))
        self.rubber_band.setWidth(1)

        self.reset()

    def reset(self):
        """
        Clear the rubber band for the analysis extents.
        """
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Handle canvas press events so we know when user is capturing the rect.

        :param e: A Qt event object.
        :type: QEvent
        """
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
        self.is_emitting_point = True

        self.show_rectangle(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):
        """
        Handle canvas release events  has finished capturing e

        :param e: A Qt event object.
        :type: QEvent
        """
        _ = e
        self.is_emitting_point = False
        self.rectangle_created.emit()

    def canvasMoveEvent(self, e):
        """

        :param e:
        :return:
        """
        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rectangle(self.start_point, self.end_point)

    def show_rectangle(self, start_point, end_point):
        """
        Show the rectangle on the canvas.

        :param start_point: QGIS Point object representing the origin (
            top left).
        :type start_point: QgsPoint

        :param end_point: QGIS Point object representing the contra-origin (
            bottom right).
        :type end_point: QgsPoint

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

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

        update_canvas = False
        self.rubber_band.addPoint(point1, update_canvas)
        self.rubber_band.addPoint(point2, update_canvas)
        self.rubber_band.addPoint(point3, update_canvas)
        self.rubber_band.addPoint(point4, update_canvas)
        # noinspection PyArgumentEqualDefault
        # no False so canvas will update
        # close the polygon otherwise it shows as a filled rect
        self.rubber_band.addPoint(point1)
        self.rubber_band.show()

    def rectangle(self):
        """
        Accessor for the rectangle.

        :return: A rectangle showing the designed extent.
        :rtype: QgsRectangle
        """
        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 set_rectangle(self, rectangle):
        """
        Set the rectangle for the selection.
        :param rectangle:
        :return:
        """
        if rectangle == self.rectangle():
            return False

        if rectangle is None:
            self.reset()
        else:
            self.start_point = QgsPoint(
                rectangle.xMinimum(), rectangle.yMinimum())
            self.end_point = QgsPoint(
                rectangle.xMaximum(), rectangle.yMaximum())
            self.show_rectangle(self.start_point, self.end_point)
        return True

    def deactivate(self):
        """
        Disable the tool.
        """
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #58
0
class LatLonTools:
    digitizerDialog = None

    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.crossRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.crossRb.setColor(Qt.red)
        self.provider = LatLonToolsProvider()
        self.toolbar = self.iface.addToolBar('Lat Lon Tools Toolbar')
        self.toolbar.setObjectName('LatLonToolsToolbar')

    def initGui(self):
        '''Initialize Lot Lon Tools GUI.'''
        # Initialize the Settings Dialog box
        self.settingsDialog = SettingsWidget(self, self.iface,
                                             self.iface.mainWindow())
        self.mapTool = CopyLatLonTool(self.settingsDialog, self.iface)
        self.showMapTool = ShowOnMapTool(self.iface)

        # Add Interface for Coordinate Capturing
        icon = QIcon(os.path.dirname(__file__) + "/images/copyicon.png")
        self.copyAction = QAction(icon, "Copy Latitude, Longitude",
                                  self.iface.mainWindow())
        self.copyAction.setObjectName('latLonToolsCopy')
        self.copyAction.triggered.connect(self.startCapture)
        self.copyAction.setCheckable(True)
        self.toolbar.addAction(self.copyAction)
        self.iface.addPluginToMenu("Lat Lon Tools", self.copyAction)

        # Add Interface for External Map
        icon = QIcon(os.path.dirname(__file__) + "/images/mapicon.png")
        self.externMapAction = QAction(icon, "Show in External Map",
                                       self.iface.mainWindow())
        self.externMapAction.setObjectName('latLonToolsExternalMap')
        self.externMapAction.triggered.connect(self.setShowMapTool)
        self.externMapAction.setCheckable(True)
        self.toolbar.addAction(self.externMapAction)
        self.iface.addPluginToMenu("Lat Lon Tools", self.externMapAction)

        # Add Interface for Zoom to Coordinate
        icon = QIcon(os.path.dirname(__file__) + "/images/zoomicon.png")
        self.zoomToAction = QAction(icon, "Zoom To Latitude, Longitude",
                                    self.iface.mainWindow())
        self.zoomToAction.setObjectName('latLonToolsZoom')
        self.zoomToAction.triggered.connect(self.showZoomToDialog)
        self.toolbar.addAction(self.zoomToAction)
        self.iface.addPluginToMenu('Lat Lon Tools', self.zoomToAction)

        self.zoomToDialog = ZoomToLatLon(self, self.iface,
                                         self.iface.mainWindow())
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.zoomToDialog)
        self.zoomToDialog.hide()

        # Add Interface for Multi point zoom
        icon = QIcon(os.path.dirname(__file__) + '/images/multizoom.png')
        self.multiZoomToAction = QAction(icon, "Multi-location Zoom",
                                         self.iface.mainWindow())
        self.multiZoomToAction.setObjectName('latLonToolsMultiZoom')
        self.multiZoomToAction.triggered.connect(self.multiZoomTo)
        self.toolbar.addAction(self.multiZoomToAction)
        self.iface.addPluginToMenu('Lat Lon Tools', self.multiZoomToAction)

        self.multiZoomDialog = MultiZoomWidget(self, self.settingsDialog,
                                               self.iface.mainWindow())
        self.multiZoomDialog.hide()
        self.multiZoomDialog.setFloating(True)

        # Create the conversions menu
        menu = QMenu()
        icon = QIcon(os.path.dirname(__file__) + '/images/field2geom.png')
        action = menu.addAction(icon, "Fields to point layer", self.field2geom)
        action.setObjectName('latLonToolsField2Geom')
        icon = QIcon(os.path.dirname(__file__) + '/images/geom2field.png')
        action = menu.addAction(icon, "Point layer to fields", self.geom2Field)
        action.setObjectName('latLonToolsGeom2Field')
        icon = QIcon(os.path.dirname(__file__) + '/images/pluscodes.png')
        action = menu.addAction(icon, "Plus Codes to point layer",
                                self.PlusCodestoLayer)
        action.setObjectName('latLonToolsPlusCodes2Geom')
        action = menu.addAction(icon, "Point layer to Plus Codes",
                                self.toPlusCodes)
        action.setObjectName('latLonToolsGeom2PlusCodes')
        icon = QIcon(os.path.dirname(__file__) + '/images/mgrs2point.png')
        action = menu.addAction(icon, "MGRS to point layer", self.MGRStoLayer)
        action.setObjectName('latLonToolsMGRS2Geom')
        icon = QIcon(os.path.dirname(__file__) + '/images/point2mgrs.png')
        action = menu.addAction(icon, "Point layer to MGRS", self.toMGRS)
        action.setObjectName('latLonToolsGeom2MGRS')
        self.conversionsAction = QAction(icon, "Conversions",
                                         self.iface.mainWindow())
        self.conversionsAction.setMenu(menu)
        self.iface.addPluginToMenu('Lat Lon Tools', self.conversionsAction)

        # Add to Digitize Toolbar
        icon = QIcon(os.path.dirname(__file__) + '/images/latLonDigitize.png')
        self.digitizeAction = QAction(icon, "Lat Lon Digitize",
                                      self.iface.mainWindow())
        self.digitizeAction.setObjectName('latLonToolsDigitize')
        self.digitizeAction.triggered.connect(self.digitizeClicked)
        self.digitizeAction.setEnabled(False)
        self.toolbar.addAction(self.digitizeAction)
        self.iface.addPluginToMenu('Lat Lon Tools', self.digitizeAction)

        # Add Interface for copying the canvas extent
        icon = QIcon(os.path.dirname(__file__) + "/images/copycanvas.png")
        self.copyCanvasAction = QAction(icon, "Copy Canvas Bounding Box",
                                        self.iface.mainWindow())
        self.copyCanvasAction.setObjectName('latLonToolsCopyCanvas')
        self.copyCanvasAction.triggered.connect(self.copyCanvas)
        self.toolbar.addAction(self.copyCanvasAction)
        self.iface.addPluginToMenu("Lat Lon Tools", self.copyCanvasAction)

        # Initialize the Settings Dialog Box
        settingsicon = QIcon(
            os.path.dirname(__file__) + '/images/settings.png')
        self.settingsAction = QAction(settingsicon, "Settings",
                                      self.iface.mainWindow())
        self.settingsAction.setObjectName('latLonToolsSettings')
        self.settingsAction.triggered.connect(self.settings)
        self.iface.addPluginToMenu('Lat Lon Tools', self.settingsAction)

        # Help
        icon = QIcon(os.path.dirname(__file__) + '/images/help.png')
        self.helpAction = QAction(icon, "Help", self.iface.mainWindow())
        self.helpAction.setObjectName('latLonToolsHelp')
        self.helpAction.triggered.connect(self.help)
        self.iface.addPluginToMenu('Lat Lon Tools', self.helpAction)

        self.iface.currentLayerChanged.connect(self.currentLayerChanged)
        self.canvas.mapToolSet.connect(self.unsetTool)
        self.enableDigitizeTool()
        # Add the processing provider

        QgsApplication.processingRegistry().addProvider(self.provider)

    def unsetTool(self, tool):
        '''Uncheck the Copy Lat Lon tool'''
        try:
            if not isinstance(tool, CopyLatLonTool):
                self.copyAction.setChecked(False)
                self.multiZoomDialog.stopCapture()
                self.mapTool.capture4326 = False
            if not isinstance(tool, ShowOnMapTool):
                self.externMapAction.setChecked(False)
        except:
            pass

    def unload(self):
        '''Unload LatLonTools from the QGIS interface'''
        self.zoomToDialog.removeMarker()
        self.multiZoomDialog.removeMarkers()
        self.canvas.unsetMapTool(self.mapTool)
        self.canvas.unsetMapTool(self.showMapTool)
        self.iface.removePluginMenu('Lat Lon Tools', self.copyAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.copyCanvasAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.externMapAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.zoomToAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.multiZoomToAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.conversionsAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.settingsAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.helpAction)
        self.iface.removePluginMenu('Lat Lon Tools', self.digitizeAction)
        self.iface.removeDockWidget(self.zoomToDialog)
        self.iface.removeDockWidget(self.multiZoomDialog)
        # Remove Toolbar Icons
        self.iface.removeToolBarIcon(self.copyAction)
        self.iface.removeToolBarIcon(self.copyCanvasAction)
        self.iface.removeToolBarIcon(self.zoomToAction)
        self.iface.removeToolBarIcon(self.externMapAction)
        self.iface.removeToolBarIcon(self.multiZoomToAction)
        self.iface.removeToolBarIcon(self.digitizeAction)
        del self.toolbar

        self.zoomToDialog = None
        self.multiZoomDialog = None
        self.settingsDialog = None
        self.showMapTool = None
        self.mapTool = None
        self.digitizerDialog = None
        QgsApplication.processingRegistry().removeProvider(self.provider)

    def startCapture(self):
        '''Set the focus of the copy coordinate tool and check it'''
        self.copyAction.setChecked(True)
        self.canvas.setMapTool(self.mapTool)

    def copyCanvas(self):
        extent = self.iface.mapCanvas().extent()
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        if settings.bBoxCrs == 0 and canvasCrs != epsg4326:
            transform = QgsCoordinateTransform(canvasCrs, epsg4326,
                                               QgsProject.instance())
            p1x, p1y = transform.transform(float(extent.xMinimum()),
                                           float(extent.yMinimum()))
            p2x, p2y = transform.transform(float(extent.xMaximum()),
                                           float(extent.yMaximum()))
            extent.set(p1x, p1y, p2x, p2y)
        delim = settings.bBoxDelimiter
        prefix = settings.bBoxPrefix
        suffix = settings.bBoxSuffix
        precision = settings.bBoxDigits
        outStr = ''
        minX = extent.xMinimum()
        minY = extent.yMinimum()
        maxX = extent.xMaximum()
        maxY = extent.yMaximum()
        if settings.bBoxFormat == 0:  # minX,minY,maxX,maxY - using the delimiter
            outStr = '{:.{prec}f}{}{:.{prec}f}{}{:.{prec}f}{}{:.{prec}f}'.format(
                minX, delim, minY, delim, maxX, delim, maxY, prec=precision)
        elif settings.bBoxFormat == 1:  # minX,maxX,minY,maxY - Using the selected delimiter'
            outStr = '{:.{prec}f}{}{:.{prec}f}{}{:.{prec}f}{}{:.{prec}f}'.format(
                minX, delim, maxX, delim, minY, delim, maxY, prec=precision)
        elif settings.bBoxFormat == 2:  # x1 y1,x2 y2,x3 y3,x4 y4,x1 y1 - Polygon format
            outStr = '{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f}'.format(
                minX,
                minY,
                minX,
                maxY,
                maxX,
                maxY,
                maxX,
                minY,
                minX,
                minY,
                prec=precision)
        elif settings.bBoxFormat == 3:  # x1,y1 x2,y2 x3,y3 x4,y4 x1,y1 - Polygon format
            outStr = '{:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f} {:.{prec}f},{:.{prec}f}'.format(
                minX,
                minY,
                minX,
                maxY,
                maxX,
                maxY,
                maxX,
                minY,
                minX,
                minY,
                prec=precision)
        elif settings.bBoxFormat == 4:  # WKT Polygon
            outStr = extent.asWktPolygon()
        elif settings.bBoxFormat == 5:  # bbox: [minX, minY, maxX, maxY] - MapProxy
            outStr = 'bbox: [{}, {}, {}, {}]'.format(minX, minY, maxX, maxY)
        elif settings.bBoxFormat == 6:  # bbox: [minX, minY, maxX, maxY] - MapProxy
            outStr = 'bbox={},{},{},{}'.format(minX, minY, maxX, maxY)
        outStr = '{}{}{}'.format(prefix, outStr, suffix)
        clipboard = QApplication.clipboard()
        clipboard.setText(outStr)
        self.iface.messageBar().pushMessage(
            "",
            "'{}' copied to the clipboard".format(outStr),
            level=Qgis.Info,
            duration=4)

    def setShowMapTool(self):
        '''Set the focus of the external map tool and check it'''
        self.externMapAction.setChecked(True)
        self.canvas.setMapTool(self.showMapTool)

    def showZoomToDialog(self):
        '''Show the zoom to docked widget.'''
        self.zoomToDialog.show()

    def multiZoomTo(self):
        '''Display the Multi-zoom to dialog box'''
        self.multiZoomDialog.show()

    def field2geom(self):
        '''Convert layer containing a point x & y coordinate to a new point layer'''
        results = processing.execAlgorithmDialog('latlontools:field2geom', {})

    def geom2Field(self):
        '''Convert layer geometry to a text string'''
        results = processing.execAlgorithmDialog('latlontools:geom2field', {})

    def toMGRS(self):
        '''Display the to MGRS  dialog box'''
        results = processing.execAlgorithmDialog('latlontools:point2mgrs', {})

    def MGRStoLayer(self):
        '''Display the to MGRS  dialog box'''
        results = processing.execAlgorithmDialog('latlontools:mgrs2point', {})

    def toPlusCodes(self):
        results = processing.execAlgorithmDialog('latlontools:point2pluscodes',
                                                 {})

    def PlusCodestoLayer(self):
        results = processing.execAlgorithmDialog('latlontools:pluscodes2point',
                                                 {})

    def settings(self):
        '''Show the settings dialog box'''
        self.settingsDialog.show()

    def help(self):
        '''Display a help page'''
        url = QUrl.fromLocalFile(os.path.dirname(__file__) +
                                 "/index.html").toString()
        webbrowser.open(url, new=2)

    def settingsChanged(self):
        # Settings may have changed so we need to make sure the zoomToDialog window is configured properly
        self.zoomToDialog.configure()
        self.multiZoomDialog.settingsChanged()

    def zoomTo(self, srcCrs, lat, lon):
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(srcCrs, canvasCrs,
                                           QgsProject.instance())
        x, y = transform.transform(float(lon), float(lat))

        rect = QgsRectangle(x, y, x, y)
        self.canvas.setExtent(rect)

        pt = QgsPointXY(x, y)
        self.highlight(pt)
        self.canvas.refresh()
        return pt

    def highlight(self, point):
        currExt = self.canvas.extent()

        leftPt = QgsPoint(currExt.xMinimum(), point.y())
        rightPt = QgsPoint(currExt.xMaximum(), point.y())

        topPt = QgsPoint(point.x(), currExt.yMaximum())
        bottomPt = QgsPoint(point.x(), currExt.yMinimum())

        horizLine = QgsGeometry.fromPolyline([leftPt, rightPt])
        vertLine = QgsGeometry.fromPolyline([topPt, bottomPt])

        self.crossRb.reset(QgsWkbTypes.LineGeometry)
        self.crossRb.addGeometry(horizLine, None)
        self.crossRb.addGeometry(vertLine, None)

        QTimer.singleShot(700, self.resetRubberbands)

    def resetRubberbands(self):
        self.crossRb.reset()

    def digitizeClicked(self):
        if self.digitizerDialog == None:
            from .digitizer import DigitizerWidget
            self.digitizerDialog = DigitizerWidget(self, self.iface,
                                                   self.iface.mainWindow())
        self.digitizerDialog.show()

    def currentLayerChanged(self):
        layer = self.iface.activeLayer()
        if layer != None:
            try:
                layer.editingStarted.disconnect(self.layerEditingChanged)
            except:
                pass
            try:
                layer.editingStopped.disconnect(self.layerEditingChanged)
            except:
                pass

            if isinstance(layer, QgsVectorLayer):
                layer.editingStarted.connect(self.layerEditingChanged)
                layer.editingStopped.connect(self.layerEditingChanged)

        self.enableDigitizeTool()

    def layerEditingChanged(self):
        self.enableDigitizeTool()

    def enableDigitizeTool(self):
        self.digitizeAction.setEnabled(False)
        layer = self.iface.activeLayer()

        if layer != None and isinstance(layer, QgsVectorLayer) and (
                layer.geometryType()
                == QgsWkbTypes.PointGeometry) and layer.isEditable():
            self.digitizeAction.setEnabled(True)
        else:
            if self.digitizerDialog != None:
                self.digitizerDialog.close()
class RectangleMapTool(QgsMapToolEmitPoint):

    rectangleCreated = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setColor(QColor(255, 0, 0, 100))
        self.rubberBand.setWidth(2)

        self.reset()

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

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        if self.rectangle() is not None:
            self.rectangleCreated.emit()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

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

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

        return QgsRectangle(self.startPoint, self.endPoint)

    def setRectangle(self, rect):
        if rect == self.rectangle():
            return False

        if rect is None:
            self.reset()
        else:
            self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum())
            self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum())
            self.showRect(self.startPoint, self.endPoint)
        return True

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #60
0
class RotateRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        # In case of rotation around pressed point (ctrl)
        # Use rubberBand for displaying an horizontal line.
        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.reset()

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        self.startY = e.pos().y()
        self.endY = self.startY
        self.isEmittingPoint = True
        self.height = self.canvas.height()

        modifiers = QApplication.keyboardModifiers()
        self.isRotationAroundPoint = bool(modifiers & Qt.ControlModifier)
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        rotation = self.computeRotation()
        self.showRotation(rotation)
        self.layer.history.append({
            "action": "rotation",
            "rotation": None,
            "center": self.layer.center
        })  # rotation set

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

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        rotation = self.computeRotation()
        if self.isRotationAroundPoint:
            self.layer.moveCenterFromPointRotate(self.startPoint, rotation, 1,
                                                 1)
        val = self.layer.rotation + rotation
        if val > 180:
            val = val - 360
        # repainting is performed within the setValue trigger event.
        self.iface.mainWindow().findChild(
            QDoubleSpinBox,
            'FreehandRasterGeoreferencer_spinbox').setValue(val)
        setLayerVisible(self.iface, self.layer, self.isLayerVisible)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endY = e.pos().y()
        rotation = self.computeRotation()
        self.showRotation(rotation)

        self.endPoint = self.toMapCoordinates(e.pos())

    def computeRotation(self):
        if self.isRotationAroundPoint:
            dX = self.endPoint.x() - self.startPoint.x()
            dY = self.endPoint.y() - self.startPoint.y()
            return math.degrees(math.atan2(-dY, dX))
        else:
            dY = self.endY - self.startY
            return 90.0 * dY / self.height

    def showRotation(self, rotation):
        if self.isRotationAroundPoint:
            cornerPoints = self.layer.transformedCornerCoordinatesFromPoint(
                self.startPoint, rotation, 1, 1)

            self.rasterShadow.reset(self.layer)
            self.rasterShadow.setDeltaRotationFromPoint(
                rotation, self.startPoint, True)
            self.rasterShadow.show()

            self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
            point0 = QgsPointXY(self.startPoint.x() + 10, self.startPoint.y())
            point1 = QgsPointXY(self.startPoint.x(), self.startPoint.y())
            point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y())
            self.rubberBandDisplacement.addPoint(point0, False)
            self.rubberBandDisplacement.addPoint(point1, False)
            self.rubberBandDisplacement.addPoint(point2,
                                                 True)  # true to update canvas
            self.rubberBandDisplacement.show()
        else:
            center, originalRotation, xScale, yScale = \
                self.layer.transformParameters()
            newRotation = rotation + originalRotation
            cornerPoints = self.layer.transformedCornerCoordinates(
                center, newRotation, xScale, yScale)

            self.rasterShadow.reset(self.layer)
            self.rasterShadow.setDeltaRotation(rotation, True)
            self.rasterShadow.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()