Esempio n. 1
0
class MapGraphicsTextItem(QGraphicsTextItem, MapItem):
    """Text item for the MapGraphicsScene
    """

    QtParentClass = QGraphicsSimpleTextItem

    def __init__(self,
                 longitude,
                 latitude,
                 text,
                 parent=None,
                 min_zoom_visibility=None):
        QGraphicsSimpleTextItem.__init__(self, text, parent=parent)
        MapItem.__init__(self)
        self._min_zoom = min_zoom_visibility
        self._lon, self._lat = longitude, latitude
        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

    def resetMinZoomVisibility(self):
        """Delete level of zoom under which the text disappears. """
        self._min_zoom = None

    def setMinZoomVisibility(self, zoom_level):
        """Update level of zoom under which the text disappears. """
        self._min_zoom = zoom_level

    def updatePosition(self, scene):
        """Update the origin position of the item."""

        pos = scene.posFromLonLat(self._lon, self._lat)
        self.setPos(pos[0], pos[1])
        if self._min_zoom is not None:
            self.setVisible(scene._zoom >= self._min_zoom)
Esempio n. 2
0
class MapGraphicsLabelItem(QGraphicsTextItem, MapItem):
    """ Label for an item - updates its position with the item
    """

    QtParentClass = QGraphicsSimpleTextItem

    def __init__(self,
                 other_item,
                 text,
                 parent=None,
                 min_zoom_visibility=None):
        QGraphicsSimpleTextItem.__init__(self, text, parent=parent)
        MapItem.__init__(self)
        self.other_item = other_item
        self._min_zoom = min_zoom_visibility
        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

    def resetMinZoomVisibility(self):
        """Delete level of zoom under which the text disappears. """
        self._min_zoom = None

    def setMinZoomVisibility(self, zoom_level):
        """Update level of zoom under which the text disappears. """
        self._min_zoom = zoom_level

    def updatePosition(self, scene):
        """Update the origin position of the item."""
        pos = self.other_item.getLabelLocation()
        self.setPos(pos[0], pos[1])
        if self._min_zoom is not None:
            self.setVisible(scene._zoom >= self._min_zoom)
Esempio n. 3
0
    def __init__(self, anchor, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        anchorPos = self._posForAnchors[anchor]
        self._anchorPos = QPointF(anchorPos)
        self._anchor = anchor

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()

        imgfile = os.path.dirname(__file__) + os.sep + 'zoom_in_symbol.png'
        img = QPixmap(24, 24)
        img.load(imgfile)
        img = img.scaled(24, 24)
        img = ImageButton(img, parent=self)
        self.zoom_in_button = img
        self.addEntry(self.zoom_in_button)

        imgfile = os.path.dirname(__file__) + os.sep + 'zoom_out_symbol.png'
        img2 = QPixmap(24, 24)
        img2.load(imgfile)
        img2 = img2.scaled(24, 24)
        img2 = ImageButton(img2, parent=self)
        self.zoom_out_button = img2
        self.addEntry(self.zoom_out_button)
Esempio n. 4
0
    def __init__(self, lon0, lat0, lon1, lat1, svg_filename, parent=None):
        """Constructor.

        Args:
            longitude(float): Longitude of the upper left corner
            latitude(float): Latitude of the upper left corner
            longitude(float): Longitude of the lower right corner
            latitude(float): Latitude of the lower right corner
            svg_filename: Svg file name
            scene(MapGraphicsScene): Scene the item belongs to.
            parent(QGraphicsItem): Parent item.

        This will display an svg file with the corners geo-registered
        """
        QGraphicsSvgItem.__init__(self, svg_filename, parent=parent)
        MapItem.__init__(self)

        self._lon0 = lon0
        self._lat0 = lat0
        self._lon1 = lon1
        self._lat1 = lat1
        self._xsize = 0
        self._ysize = 0

        self.x_mult = 1
        self.y_mult = 1
        self._renderer = QSvgRenderer(svg_filename)
        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(Qt.black)
Esempio n. 5
0
    def addRect(self, text, color, border=None, size=20.0):
        shape = QGraphicsRectItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))
Esempio n. 6
0
 def __init__(self,
              other_item,
              text,
              parent=None,
              min_zoom_visibility=None):
     QGraphicsSimpleTextItem.__init__(self, text, parent=parent)
     MapItem.__init__(self)
     self.other_item = other_item
     self._min_zoom = min_zoom_visibility
     self._border = QGraphicsRectItem(parent=self)
     self._border.setPen(QPen(Qt.NoPen))
     self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))
Esempio n. 7
0
 def __init__(self,
              longitude,
              latitude,
              text,
              parent=None,
              min_zoom_visibility=None):
     QGraphicsSimpleTextItem.__init__(self, text, parent=parent)
     MapItem.__init__(self)
     self._min_zoom = min_zoom_visibility
     self._lon, self._lat = longitude, latitude
     self._border = QGraphicsRectItem(parent=self)
     self._border.setPen(QPen(Qt.NoPen))
     self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))
Esempio n. 8
0
    def __init__(self, pos=None, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        self._anchorPos = QPointF(pos) if pos is not None else QPointF(
            10.0, 10.0)

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()
        self._entriesGroup = QGraphicsItemGroup(parent=self)
Esempio n. 9
0
    def __init__(self, lon, lat, width, height, parent=None):
        """Constructor.

        Args:
            lon0(float): Longitude of the center point
            lat0(float): Latitude of the center point
            width(int): width in pixels
            height(int): height in pixels
            parent(QGraphicsItem): Parent item, default None.

        """
        QGraphicsRectItem.__init__(self, parent=parent)
        MapItem.__init__(self)

        self._lon = lon
        self._lat = lat
        self._width = width
        self._height = height
Esempio n. 10
0
    def __init__(self, lon0, lat0, lon1, lat1, parent=None):
        """Constructor.

        Args:
            lon0(float): Longitude of the top left point.
            lat0(float): Latitude of the top left point.
            lon1(float): Longitude of the bottom right point.
            lat1(float): Latitude of the bottom right point.
            parent(QGraphicsItem): Parent item, default None.

        Note:
            The management of the parent item is work in progress.
        """
        QGraphicsRectItem.__init__(self, parent=parent)
        MapItem.__init__(self)

        self._lon0 = lon0
        self._lat0 = lat0
        self._lon1 = lon1
        self._lat1 = lat1
Esempio n. 11
0
    def __init__(self, lon0, lat0, lon1, lat1, parent=None):
        """Constructor.

        Args:
            lon0(float): Longitude of the top left point.
            lat0(float): Latitude of the top left point.
            lon1(float): Longitude of the bottom right point.
            lat1(float): Latitude of the bottom right point.
            parent(QGraphicsItem): Parent item, default None.

        Note:
            The management of the parent item is work in progress.
        """
        QGraphicsRectItem.__init__(self, parent=parent)
        MapItem.__init__(self)

        self._lon0 = lon0
        self._lat0 = lat0
        self._lon1 = lon1
        self._lat1 = lat1
Esempio n. 12
0
    def addRect(self, text, color, border=None, size=20.0):
        shape = QGraphicsRectItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))
Esempio n. 13
0
    def __init__(self, pos=None, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        self._anchorPos = QPointF(pos) if pos is not None else QPointF(10.0, 10.0)

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()
        self._entriesGroup = QGraphicsItemGroup(parent=self)
Esempio n. 14
0
 def mouseMoveEvent(self, evt):
     '''Catch right-click events for rectangle drawing'''
     if self.rubberband_enabled and self.rect_start:
         pos = evt.scenePos()
         #lon,lat = self.lonLatFromPos(pos.x(), pos.y())
         self.rect_end = pos
         if not self.rubberband:
             self.rubberband = QGraphicsRectItem(
                 min(self.rect_start.x(), self.rect_end.x()),
                 min(self.rect_start.y(), self.rect_end.y()),
                 abs(self.rect_end.x() - self.rect_start.x()),
                 abs(self.rect_end.y() - self.rect_start.y()))
             clr = QColor(240, 240, 240, 100)
             self.rubberband.setBrush(clr)
             self.rubberband.setPen(QPen(QBrush(Qt.blue), 1.0))
             self.addItem(self.rubberband)
         else:
             self.rubberband.setRect(
                 min(self.rect_start.x(), self.rect_end.x()),
                 min(self.rect_start.y(), self.rect_end.y()),
                 abs(self.rect_end.x() - self.rect_start.x()),
                 abs(self.rect_end.y() - self.rect_start.y()))
Esempio n. 15
0
class MapLegendItem(QGraphicsObject, MapItem):

    QtParentClass = QGraphicsObject

    def __init__(self, pos=None, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        self._anchorPos = QPointF(pos) if pos is not None else QPointF(
            10.0, 10.0)

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()
        self._entriesGroup = QGraphicsItemGroup(parent=self)

    def _sceneChanged(self, oldScene, newScene):
        if oldScene is not None:
            oldScene.sceneRectChanged.disconnect(self.setSceneRect)
        if newScene is not None:
            newScene.sceneRectChanged.connect(self.setSceneRect)
            # Setup the new position of the item
            self.setSceneRect(newScene.sceneRect())

    def updatePosition(self, scene):
        pass

    def addPoint(self, text, color, border=None, size=20.0):
        shape = QGraphicsEllipseItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))

    def addRect(self, text, color, border=None, size=20.0):
        shape = QGraphicsRectItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))

    def addLine(self, text, color, width=1.):
        shape = QGraphicsLineItem(10., 10., 20., 20.)
        pen = makePen(color, width=width)
        shape.setPen(pen)
        self.addEntry(MapLegendEntryItem(shape, text))

    def addEntry(self, entry):
        self._entries.append(entry)
        self._entriesGroup.addToGroup(entry)
        self._updateLayout()

    def boundingRect(self):
        return self._border.boundingRect()

    def paint(*args, **kwargs):
        pass

    @Slot(QRectF)
    def setSceneRect(self, rect):
        self.setPos(rect.topLeft() + self._anchorPos)

    def _updateLayout(self):
        self.prepareGeometryChange()

        bottom = 0.0
        left = 0.0
        right = 0.0
        for entry in self._entries:
            entry.setPos(left, bottom)
            bottom += entry.bottom() + 5.0
            right = max(right, entry.right() + 5.0)

        self._border.setRect(0.0, 0.0, right, bottom + 5.0)

    def pen(self):
        """Pen for the background of the legend

        Returns:
            QPen: Pen for the background of the legend
        """
        return self._border.pen()

    def brush(self):
        """Brush for the background of the legend

        Returns:
            QBrush: Brush for the background of the legend
        """
        return self._border.brush()

    def setPen(self, *args, **kwargs):
        """Set the pen for the background of the legend

        The arguments are the same of the :func:`makePen` function
        """
        return self._border.setPen(makePen(*args, **kwargs))

    def setBrush(self, *args, **kwargs):
        """Set the brush for the background of the legend

        The arguments are the same of the :func:`makeBrush` function
        """
        return self._border.setBrush(makeBrush(*args, **kwargs))
Esempio n. 16
0
class MapLegendItem(QGraphicsObject, MapItem):

    QtParentClass = QGraphicsObject

    def __init__(self, pos=None, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        self._anchorPos = QPointF(pos) if pos is not None else QPointF(10.0, 10.0)

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()
        self._entriesGroup = QGraphicsItemGroup(parent=self)

    def _sceneChanged(self, oldScene, newScene):
        if oldScene is not None:
            oldScene.sceneRectChanged.disconnect(self.setSceneRect)
        if newScene is not None:
            newScene.sceneRectChanged.connect(self.setSceneRect)
            # Setup the new position of the item
            self.setSceneRect(newScene.sceneRect())

    def updatePosition(self, scene):
        pass

    def addPoint(self, text, color, border=None, size=20.0):
        shape = QGraphicsEllipseItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))

    def addRect(self, text, color, border=None, size=20.0):
        shape = QGraphicsRectItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))

    def addLine(self, text, color, width=1.):
        shape = QGraphicsLineItem(10., 10., 20., 20.)
        pen = makePen(color, width=width)
        shape.setPen(pen)
        self.addEntry(MapLegendEntryItem(shape, text))

    def addEntry(self, entry):
        self._entries.append(entry)
        self._entriesGroup.addToGroup(entry)
        self._updateLayout()

    def boundingRect(self):
        return self._border.boundingRect()

    def paint(*args, **kwargs):
        pass

    @Slot(QRectF)
    def setSceneRect(self, rect):
        self.setPos(rect.topLeft() + self._anchorPos)

    def _updateLayout(self):
        self.prepareGeometryChange()

        bottom = 0.0
        left = 0.0
        right = 0.0
        for entry in self._entries:
            entry.setPos(left, bottom)
            bottom += entry.bottom() + 5.0
            right = max(right, entry.right() + 5.0)

        self._border.setRect(0.0, 0.0, right, bottom + 5.0)

    def pen(self):
        """Pen for the background of the legend

        Returns:
            QPen: Pen for the background of the legend
        """
        return self._border.pen()

    def brush(self):
        """Brush for the background of the legend

        Returns:
            QBrush: Brush for the background of the legend
        """
        return self._border.brush()

    def setPen(self, *args, **kwargs):
        """Set the pen for the background of the legend

        The arguments are the same of the :func:`makePen` function
        """
        return self._border.setPen(makePen(*args, **kwargs))

    def setBrush(self, *args, **kwargs):
        """Set the brush for the background of the legend

        The arguments are the same of the :func:`makeBrush` function
        """
        return self._border.setBrush(makeBrush(*args, **kwargs))
Esempio n. 17
0
    def __init__(self, block, debug=False):
        self._block = block
        self._debug = debug
        self.modified_callback = None

        self._base_zvalue = None
        self._top_zvalue = 1
        self._vpad = 5
        self._footer_height = self._vpad
        self._editing = False
        self._start_move_connector_row = None
        self.highlight_background_color = QColor(127, 255, 127, 255)  # RGBA

        super().__init__(0, 0, block.width, block.height)
        self.setBrush(QBrush(Qt.gray))
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsFocusable)
        self.setFlag(self.ItemSendsGeometryChanges)

        t = self._title = Block_Title(self._block.name)
        t.setParentItem(self)
        t.setPos(0, self._vpad)
        text_height = t.boundingRect().height()

        self._row_height = text_height
        self._insert_receptor_height = text_height / 2.0
        self._header_height = text_height + 2 * self._vpad
        self._grid_size = self._row_height / 2.0

        tr = self._title_rect = QGraphicsRectItem(
            0, 0, 10, self._header_height)  # width set later
        tr.setParentItem(self)
        self._title.setParentItem(tr)

        cl = self._connector_layer = QGraphicsRectItem(self.rect())
        cl.setParentItem(self)
        cl.setBrush(QBrush(Qt.NoBrush))
        #cl.setBrush(QBrush(Qt.blue))
        cl.setPen(QPen(Qt.NoPen))

        self._connectors = []
        for i, c in enumerate(block.connectors):
            self.add_connector(c, quick=True)

        rl = self._receptor_layer = QGraphicsRectItem(self.rect())
        rl.setParentItem(self)
        rl.setBrush(QBrush(Qt.NoBrush))
        #rl.setBrush(QBrush(Qt.blue))
        rl.setPen(QPen(Qt.NoPen))

        self._receptors = receptor.Grid(
            parent_item=self._receptor_layer,
            n_cols=3,
            cell_height=self._row_height,
            top_border=self._header_height,
            bottom_border=self._footer_height,
            sensitive=False,
            debug_color=Qt.cyan,
            debug=self._debug,
        )

        irl = self._insert_receptor_layer = QGraphicsRectItem(self.rect())
        irl.setParentItem(self)
        irl.setBrush(QBrush(Qt.NoBrush))
        #irl.setBrush(QBrush(Qt.blue))
        irl.setPen(QPen(Qt.NoPen))

        self._insert_receptors = receptor.Grid(
            parent_item=self._insert_receptor_layer,
            n_cols=3,
            cell_height=self._insert_receptor_height,
            row_spacing=self._row_height - self._insert_receptor_height,
            top_border=self._header_height -
            self._insert_receptor_height / 2.0,
            stretch_last_row=True,
            sensitive=False,
            debug_color=Qt.yellow,
            debug=self._debug,
        )

        self._resizer = resizer.Frame(self, debug=self._debug)

        self._header_avoid_shape = None
        self._row_avoid_shapes = []
        self._row_divider_avoid_shapes = []
        self._footer_avoid_shape = None
        self._avoid_shape = None

        self._ensure_minimum_size()
        self._set_default_appearance()
        self.set_editing_mode(self._editing)
Esempio n. 18
0
class MapGraphicsScene(QGraphicsScene):
    """Graphics scene for showing a slippy map.
    """

    sigZoomChanged = Signal(int)
    sigSelectionDrawn = Signal(float, float, float, float)
    customSceneRectChanged = Signal(float, float, float, float)

    def __init__(self, tileSource, parent=None):
        """Constructor.

        Args:
            tileSource(MapTileSource): Source for loading the tiles.
            parent(QObject): Parent object, default `None`
        """
        QGraphicsScene.__init__(self, parent=parent)

        self._zoom = 8

        self._tileSource = tileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)
        tdim = self._tileSource.tileSize()

        self._emptyTile = QPixmap(tdim, tdim)
        self._emptyTile.fill(Qt.lightGray)

        self._tilesRect = QRect()
        self._tilePixmaps = {}

        self._tileInDownload = list()

        self.setSceneRect(0.0, 0.0, 400, 300)
        self.sceneRectChanged.connect(self.onSceneRectChanged)

        # Rubberband Support for Drawing Areas
        self.rect_start = None
        self.rect_end = None
        self.rubberband = None
        self.rubberband_enabled = False

    @Slot()
    def close(self):
        self._tileSource.close()

    def setTileSource(self, newTileSource):
        self._tileSource.tileReceived.disconnect(self.setTilePixmap)
        self._tileSource.close()

        self._tilePixmaps.clear()
        self._tileInDownload = list()

        self._tileSource = newTileSource
        self._tileSource.setParent(self)
        self._tileSource.tileReceived.connect(self.setTilePixmap)

        self.requestTiles()

        self.invalidate()
        self.update()

    def mousePressEvent(self, evt):
        '''Catch right-click events for rectangle drawing'''
        if self.rubberband_enabled and evt.button() == 2:
            evt.accept()
            pos = evt.scenePos()
            self.rect_start = pos

            if self.rubberband != None:
                self.removeItem(self.rubberband)
                self.rubberband = None

        else:
            evt.ignore()
            QGraphicsScene.mousePressEvent(self, evt)

    def mouseReleaseEvent(self, evt):
        '''Catch right-click events for rectangle drawing'''
        if self.rubberband_enabled and evt.button() == 2:
            evt.accept()
            pos = evt.scenePos()
            lon0, lat0 = self.lonLatFromPos(self.rect_start.x(),
                                            self.rect_start.y())
            lon1, lat1 = self.lonLatFromPos(pos.x(), pos.y())
            self.removeItem(self.rubberband)

            self.rect_start = None
            self.rect_end = None
            self.rubberband = None

            self.sigSelectionDrawn.emit(lon0, lat0, lon1, lat1)

        else:
            evt.ignore()
            QGraphicsScene.mouseReleaseEvent(self, evt)

    def mouseMoveEvent(self, evt):
        '''Catch right-click events for rectangle drawing'''
        if self.rubberband_enabled and self.rect_start:
            pos = evt.scenePos()
            #lon,lat = self.lonLatFromPos(pos.x(), pos.y())
            self.rect_end = pos
            if not self.rubberband:
                self.rubberband = QGraphicsRectItem(
                    min(self.rect_start.x(), self.rect_end.x()),
                    min(self.rect_start.y(), self.rect_end.y()),
                    abs(self.rect_end.x() - self.rect_start.x()),
                    abs(self.rect_end.y() - self.rect_start.y()))
                clr = QColor(240, 240, 240, 100)
                self.rubberband.setBrush(clr)
                self.rubberband.setPen(QPen(QBrush(Qt.blue), 1.0))
                self.addItem(self.rubberband)
            else:
                self.rubberband.setRect(
                    min(self.rect_start.x(), self.rect_end.x()),
                    min(self.rect_start.y(), self.rect_end.y()),
                    abs(self.rect_end.x() - self.rect_start.x()),
                    abs(self.rect_end.y() - self.rect_start.y()))

    @Slot(QRectF)
    def onSceneRectChanged(self, rect):
        """Callback for the changing of the visible rect.

        Evaluate the visible tiles and request to load the new tiles.

        Args:
            rect(QRectF): Current visible area.
        """
        tdim = self._tileSource.tileSize()
        center = rect.center()
        ct = self.tileFromPos(center.x(), center.y())
        tx = ct.x()
        ty = ct.y()

        width = rect.width()
        height = rect.height()
        # top left corner of the center tile
        xp = int(width / 2.0 - (tx - floor(tx)) * tdim)
        yp = int(height / 2.0 - (ty - floor(ty)) * tdim)

        # first tile vertical and horizontal
        xs = tx - (xp + tdim - 1) / tdim
        ys = ty - (yp + tdim - 1) / tdim

        # last tile vertical and horizontal
        xe = (width - xp - 1) / tdim - xs + 1 + tx
        ye = (height - yp - 1) / tdim - ys + 1 + ty

        # define the rect of visible tiles
        self._tilesRect = QRect(xs, ys, xe, ye)

        # Request the loading of new tiles (if needed)
        self.requestTiles()

        self.invalidate()
        self.update()
        lon0, lat0 = self.lonLatFromPos(rect.x(), rect.y())
        lon1, lat1 = self.lonLatFromPos(rect.x() + rect.width(),
                                        rect.y() + rect.height())

        self.customSceneRectChanged.emit(lon0, lat0, lon1, lat1)

    def drawBackground(self, painter, rect):
        """Draw the background tiles.

        If a tile is not available, draw a gray rectangle.

        Args:
            painter(QPainter): Painter for drawing.
            rect(QRectF): Current visible area.
        """
        tilesRect = self._tilesRect
        left = tilesRect.left()
        top = tilesRect.top()
        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        tdim = self._tileSource.tileSize()
        pixRect = QRectF(0.0, 0.0, tdim, tdim)
        emptyTilePix = self._emptyTile
        tilePixmaps = self._tilePixmaps

        for x in iterRange(numXtiles + 1):
            for y in iterRange(numYtiles + 1):
                tp = (x + left, y + top)
                box = self.tileRect(tp[0], tp[1])
                # Use default gray image if tile image is missing
                pix = tilePixmaps.get(tp, emptyTilePix)
                painter.drawPixmap(box, pix, pixRect)

    def zoomTo(self, pos, zoomlevel):
        """Zoom to a specific zoom level.

        If the level is out of range, the zoom action is ignored.

        clear the current tile cache, evaluate the new center and
        update the position of all the items.

        Args:
            zoomlevel(int): New zoom level.
        """

        tileSource = self._tileSource
        if zoomlevel > tileSource.maxZoom() or zoomlevel < tileSource.minZoom(
        ):
            return

        # Get the coordinates of the center using the position in pixels of the mouse
        pos_corr = self.views()[0].mapToScene(pos)
        coord = self.lonLatFromPos(pos_corr.x(), pos_corr.y())

        # Set the new zoom level
        self._zoom = zoomlevel

        # Clear cache and abort active requests
        self._tileSource.abortAllRequests()
        self._tilePixmaps.clear()

        # Re-center map so that the point on which it was zoomed is in the same position
        self.setCenter(coord[0], coord[1])
        pos_corr = self.views()[0].mapToScene(pos)
        center = self.sceneRect().center()
        self.translate(center.x() - pos_corr.x(), center.y() - pos_corr.y())

        self.sigZoomChanged.emit(zoomlevel)

    def zoomIn(self, pos=None):
        """Increments the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = QPoint(self.width() / 2, self.height() / 2)
        self.zoomTo(pos, self._zoom + 1)

    def zoomOut(self, pos=None):
        """Decrements the zoom level

        Args:
            pos (QPointF): Center position, Latitude and Longitude. Default None for the
                           current center position.
        """
        if pos is None:
            pos = QPoint(self.width() / 2, self.height() / 2)
        self.zoomTo(pos, self._zoom - 1)

    @Slot()
    def handleZoomIn(self):
        self.zoomIn()

    @Slot()
    def handleZoomOut(self):
        self.zoomOut()

    def zoom(self):
        return self._zoom

    @Slot(int, int, int, QPixmap)
    def setTilePixmap(self, x, y, zoom, pixmap):
        """Set the image of the tile.

        Args:
            x(int): X coordinate of the tile.
            y(int): Y coordinate of the tile.
            zoom(int): Zoom coordinate of the tile.
            pixmap(QPixmap): Image for the tile.
        """
        if self._zoom == zoom:
            self._tilePixmaps[(x, y)] = pixmap
        self.update()

    def requestTiles(self):
        """Request the loading of tiles.

        Check the loaded tiles and requests only
        the missing tiles.
        """
        tilesRect = self._tilesRect
        tilePixmaps = self._tilePixmaps

        numXtiles = tilesRect.width()
        numYtiles = tilesRect.height()
        left = tilesRect.left()
        top = tilesRect.top()
        tileSource = self._tileSource
        zoom = self._zoom

        # Request load of new tiles
        for x in iterRange(numXtiles + 1):
            for y in iterRange(numYtiles + 1):
                tp = (left + x, top + y)
                # Request tile only if missing
                if tp not in tilePixmaps:
                    pix = tileSource.requestTile(tp[0], tp[1], zoom)
                    if pix is not None:
                        tilePixmaps[tp] = pix

        self.update()

    def tileRect(self, tx, ty):
        """Area for a specific tile.

        Args:
            tx(int): X coordinate of the tile.
            ty(int): Y coordinate of the tile.

        Returns:
            QRectF, the area of the tile.
        """
        tdim = self._tileSource.tileSize()
        return QRectF(tx * tdim, ty * tdim, tdim, tdim)

    def setSize(self, width, height):
        """Set the size of the visible area in pixels.

        Update the scene rect.

        Args:
            width(int): Width of the visible area.
            height(int): Height of the visible area.
        """
        rect = QRectF(self.sceneRect().topLeft(), QSizeF(width, height))
        self.setSceneRect(rect)

    def setCenter(self, lon, lat, zoom=None):
        """Move the center of the visible area to new coordinates.

        Update the scene rect.

        Args:
            lon(float): New longitude of the center.
            lat(float): New latitude of the center.
            zoom(int [1:15]): Zoom Level
        """
        if zoom != None and zoom < 15 and zoom > 0:
            self._zoom = zoom

        rect = QRectF(self.sceneRect())
        pos = self.posFromLonLat(lon, lat)
        rect.moveCenter(QPointF(pos[0], pos[1]))
        self.setSceneRect(rect)

    def center(self):
        centerPos = self.sceneRect().center()
        centerCoord = self.lonLatFromPos(centerPos.x(), centerPos.y())
        return QPointF(centerCoord[0], centerCoord[1])

    def translate(self, dx, dy):
        """Translate the visible area by dx, dy pixels.

        Update the scene rect.

        Args:
            dx(int): Increments for the center x coord in pixels.
            dy(int): Increments for the center y coord in pixels.
        """
        self.setSceneRect(self.sceneRect().translated(dx, dy))

    def posFromLonLat(self, lon, lat):
        """Position in scene coordinate of the WGS84 coordinates.

        Convert from WGS84 reference system to scene reference system.

        Args:
            lon(float or numpy.ndarray): Longitude value or values.
            lat(float or numpy.ndarray): Latitude value or values.

        Returns:
            tuple: (x, y) with the positions of the input coordinates.
        """
        return posFromLonLat(lon, lat, self._zoom, self._tileSource.tileSize())

    def lonLatFromPos(self, x, y):
        """Position in WGS84 coordinate of the scene coordinates.

        Convert from scene reference system to WGS84 reference system.

        Args:
            x(float, int or numpy.ndarray): X value or values.
            y(float, int or numpy.ndarray): Y value or values.

        Returns:
            tuple: (lon, lat) with the coordinates of the input positions.
        """
        return lonLatFromPos(x, y, self._zoom, self._tileSource.tileSize())

    def tileFromPos(self, x, y):
        """Tile in the selected position.

        Args:
            x(float, int): X value for position.
            y(float, int): Y value for position.

        Returns:
            QPointF with the coordinates of the tile.
        """
        tdim = float(self._tileSource.tileSize())
        return QPointF(x / tdim, y / tdim)

    def addRectShape(self, longitude, latitude, width, height):
        """Add a new rectangle with fixed width/height

        Args:
            longitude(float): Longitude of the top left.
            latitude(float): Latitude of the top left
            width (float): width in pixels
            height(float): height in pixels

        Returns:
            MapGraphicsCircleItem added to the scene.
        """

        item = MapGraphicsRectShapeItem(longitude, latitude, width, height)
        self.addItem(item)
        return item

    def addCircle(self, longitude, latitude, radius):
        """Add a new circle to the graphics scene.

        Args:
            longitude(float): Longitude of the center of the circle.
            latitude(float): Latitude of the center of the circle.
            radius(float): Longitude of the center of the circle.

        Returns:
            MapGraphicsCircleItem added to the scene.
        """
        item = MapGraphicsCircleItem(longitude, latitude, radius)
        self.addItem(item)
        return item

    def addLine(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the start point.
            lat0(float): Latitude of the start point.
            lon1(float): Longitude of the end point.
            lat1(float): Latitude of the end point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsLineItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addRect(self, lon0, lat0, lon1, lat1):
        """Add a newline) to the graphics scene.

        Args:
            lon0(float): Longitude of the top left point.
            lat0(float): Latitude of the top left point.
            lon1(float): Longitude of the bottom right point.
            lat1(float): Latitude of the bottom right point.

        Returns:
            MapGraphicsLineItem added to the scene.
        """
        item = MapGraphicsRectItem(lon0, lat0, lon1, lat1)
        self.addItem(item)
        return item

    def addPolyline(self, longitudes, latitudes):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitudes(iterable): Longitudes of all the points of the polyline.
            latitudes(iterable): Latitudes of all the points of the polyline.

        Returns:
            MapGraphicsPolylineItem added to the scene.
        """
        item = MapGraphicsPolylineItem(longitudes, latitudes)
        self.addItem(item)
        return item

    def addPin(self, lon, lat):
        """Add a location pin to the graphics scene.

        Args:
            longitude(float): Longitude (decimal degrees WGS84) of the pin
            latitude(float): Latitude of the Pin

        Returns:
            MapGraphicsPixmapItem added to the scene.
        """
        pinfile = os.path.dirname(__file__) + os.sep + 'red_pin.png'
        pixmap = QPixmap()
        pixmap.load(pinfile)
        item = MapGraphicsPixmapItem(lon, lat, pixmap)
        self.addItem(item)
        return item

    def addPixmap(self, longitude, latitude, pixmap):
        """Add a new circle (point) to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the pixmap.
            latitude(float): Latitude of the center of the pixmap.
            pixmap(QPixmap): Pixmap.

        Returns:
            MapGraphicsPixmapItem added to the scene.

        Note:
            Use `MapGraphicsPixmapItem.setOffset(off)` to translate by `off` pixels
            the pixmap respect the origin coordinates.
        """
        item = MapGraphicsPixmapItem(longitude, latitude, pixmap)
        self.addItem(item)
        return item

    def addGeoSvg(self, lon0, lat0, lon1, lat1, svg):
        '''Add a geo-registered pixmap to the scene

        Args:
            lon0(float): Longitude (decimal degress WGS84) upper left
            lat0(float): Lattitude (decimal degrees WGS84) upper left
            lon1(float): Longitude lower right
            lat1(float): Lattitudelower right
        
        Returns:
            MapGraphicsGeoPixmapItem
        '''
        item = MapGraphicsGeoSvgItem(lon0, lat0, lon1, lat1, svg)
        self.addItem(item)
        return item

    def addGeoPixmap(self, lon0, lat0, lon1, lat1, pixmap):
        '''Add a geo-registered pixmap to the scene

        Args:
            lon0(float): Longitude (decimal degress WGS84) upper left
            lat0(float): Lattitude (decimal degrees WGS84) upper left
            lon1(float): Longitude lower right
            lat1(float): Lattitudelower right
        
        Returns:
            MapGraphicsGeoPixmapItem
        '''
        item = MapGraphicsGeoPixmapItem(lon0, lat0, lon1, lat1, pixmap)
        self.addItem(item)
        return item

    def addGeoPixmapCorners(self, lon0, lat0, lon1, lat1, lon2, lat2, lon3,
                            lat3, pixmap):
        '''Add a geo-registered pixmap to the scene using 4 lat-lon corners

        Args:
            lon0(float): Longitude (decimal degress WGS84) upper left of image
            lat0(float): Lattitude (decimal degrees WGS84) upper left of image
            lon1(float): Lat of next point clockwise
            lat1(float): Lon of next point clockwise
            lon2(float): Lat of next point clockwise
            lat2(float): Lon of next point clockwise
            lon3(float): Lat of next point clockwise
            lat3(float): Lon of next point clockwise

        Returns:
            MapGraphicsGeoPixmapItem
        '''
        item = MapGraphicsGeoPixmapItemCorners(lon0, lat0, lon1, lat1, lon2,
                                               lat2, lon3, lat3, pixmap)
        self.addItem(item)
        return item

    def addText(self, longitude, latitude, text):
        """Add a test item to the graphics scene.

        Args:
            longitude(float): Longitude of the origin of the text
            latitude(float): Latitude of the origin of the text

        Returns:
            MapGraphicsTextItem added to the scene.
        """
        item = MapGraphicsTextItem(longitude, latitude, text)
        self.addItem(item)
        return item

    def addNavItem(self, anchor):
        self.nav_item = MapNavItem(anchor)
        self.addItem(self.nav_item)
        self.nav_item.zoom_in_button.clicked.connect(self.handleZoomIn)
        self.nav_item.zoom_out_button.clicked.connect(self.handleZoomOut)
        return self.nav_item

    def addLegend(self, pos=QPointF(10.0, 10.0)):
        legend = MapLegendItem(pos=pos)
        self.addItem(legend)
        return legend

    def addScale(self, **kwargs):
        """Add a scale bar with text on the right bottom of the map

        Keyword Args:
            textPen: QPen to use for drawing the text. Default 'black'.
            barBrush: QBrush to use for drawing the scale bar. Default (190, 190, 190, 160)
            barPen: QPen to use for drawing the scale bar border. Default (190, 190, 190, 240)
            barBrushHover:  QBrush to use for drawing the scale bar when the mouse is over it.
                Default (110, 110, 110, 255).
            barPenHover: QPen to use for drawing the scale bar borderwhen the mouse is over it.
                Default (90, 90, 90, 255).

        Note:
            Almost all the argumnets accepted by the functions.makeBrush() and functions.makePen()
            are accepted.
        """
        scaleItem = MapScaleItem(**kwargs)
        self.addItem(scaleItem)
        return scaleItem

    def addLinesGroup(self, longitudes, latitudes):
        item = MapGraphicsLinesGroupItem(longitudes, latitudes)
        self.addItem(item)
        return item
Esempio n. 19
0
class MapNavItem(QGraphicsObject, MapItem):

    QtParentClass = QGraphicsObject

    _posForAnchors = {
        Qt.TopLeftCorner: QPointF(20.0, 75.0),
        Qt.TopRightCorner: QPointF(40.0, -15.0),
        Qt.BottomLeftCorner: QPointF(20.0, -15.0),
        Qt.BottomRightCorner: QPointF(30.0, 75.0),
    }

    def __init__(self, anchor, parent=None):
        QGraphicsObject.__init__(self, parent=parent)
        MapItem.__init__(self)
        self.setZValue(200.0)

        anchorPos = self._posForAnchors[anchor]
        self._anchorPos = QPointF(anchorPos)
        self._anchor = anchor

        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(QPen(Qt.NoPen))
        self._border.setBrush(QBrush(QColor(190, 190, 190, 160)))

        self._entries = list()

        imgfile = os.path.dirname(__file__) + os.sep + 'zoom_in_symbol.png'
        img = QPixmap(24, 24)
        img.load(imgfile)
        img = img.scaled(24, 24)
        img = ImageButton(img, parent=self)
        self.zoom_in_button = img
        self.addEntry(self.zoom_in_button)

        imgfile = os.path.dirname(__file__) + os.sep + 'zoom_out_symbol.png'
        img2 = QPixmap(24, 24)
        img2.load(imgfile)
        img2 = img2.scaled(24, 24)
        img2 = ImageButton(img2, parent=self)
        self.zoom_out_button = img2
        self.addEntry(self.zoom_out_button)

    def _sceneChanged(self, oldScene, newScene):
        if oldScene is not None:
            oldScene.sceneRectChanged.disconnect(self.setSceneRect)
        if newScene is not None:
            newScene.sceneRectChanged.connect(self.setSceneRect)
            # Setup the new position of the item
            self.setSceneRect(newScene.sceneRect())

    def updatePosition(self, scene):
        pass

    def addRect(self, text, color, border=None, size=20.0):
        shape = QGraphicsRectItem(size / 2.0, size / 2.0, size, size)
        brush = makeBrush(color)
        shape.setBrush(brush)
        shape.setPen(makePen(border))

        self.addEntry(MapLegendEntryItem(shape, text))

    def addEntry(self, entry):
        self._entries.append(entry)
        self._updateLayout()

    def boundingRect(self):
        return self._border.boundingRect()

    def paint(*args, **kwargs):
        pass

    @Slot(QRectF)
    def setSceneRect(self, rect):
        anchorPos = self._anchorPos
        anchor = self._anchor
        newPos = None
        if anchor == Qt.BottomRightCorner:
            newPos = rect.bottomRight() - anchorPos
        elif anchor == Qt.TopRightCorner:
            newPos = rect.topRight() - anchorPos
        elif anchor == Qt.TopLeftCorner:
            newPos = rect.topLeft() + anchorPos
        elif anchor == Qt.BottomLeftCorner:
            newPos = rect.bottomLeft() + anchorPos
        else:
            raise NotImplementedError(
                'Other corner have not actually been implemented')

        self.setPos(newPos)

    def _updateLayout(self):
        self.prepareGeometryChange()

        bottom = 0.0
        left = 0.0
        right = 0.0
        for entry in self._entries:
            entry.setPos(left, bottom)
            bottom += entry.boundingRect().bottom()
            right = max(right, entry.boundingRect().right() + 1.0)

        self._border.setRect(0.0, 0.0, right, bottom + 1.0)

    def pen(self):
        """Pen for the background of the legend

        Returns:
            QPen: Pen for the background of the legend
        """
        return self._border.pen()

    def brush(self):
        """Brush for the background of the legend

        Returns:
            QBrush: Brush for the background of the legend
        """
        return self._border.brush()

    def setPen(self, *args, **kwargs):
        """Set the pen for the background of the legend

        The arguments are the same of the :func:`makePen` function
        """
        return self._border.setPen(makePen(*args, **kwargs))

    def setBrush(self, *args, **kwargs):
        """Set the brush for the background of the legend

        The arguments are the same of the :func:`makeBrush` function
        """
        return self._border.setBrush(makeBrush(*args, **kwargs))
Esempio n. 20
0
class MapGraphicsGeoSvgItem(QGraphicsSvgItem, MapItem):

    QtParentClass = QGraphicsSvgItem

    def __init__(self, lon0, lat0, lon1, lat1, svg_filename, parent=None):
        """Constructor.

        Args:
            longitude(float): Longitude of the upper left corner
            latitude(float): Latitude of the upper left corner
            longitude(float): Longitude of the lower right corner
            latitude(float): Latitude of the lower right corner
            svg_filename: Svg file name
            scene(MapGraphicsScene): Scene the item belongs to.
            parent(QGraphicsItem): Parent item.

        This will display an svg file with the corners geo-registered
        """
        QGraphicsSvgItem.__init__(self, svg_filename, parent=parent)
        MapItem.__init__(self)

        self._lon0 = lon0
        self._lat0 = lat0
        self._lon1 = lon1
        self._lat1 = lat1
        self._xsize = 0
        self._ysize = 0

        self.x_mult = 1
        self.y_mult = 1
        self._renderer = QSvgRenderer(svg_filename)
        self._border = QGraphicsRectItem(parent=self)
        self._border.setPen(Qt.black)

    def updatePosition(self, scene):
        pos0 = scene.posFromLonLat(self._lon0, self._lat0)
        pos1 = scene.posFromLonLat(self._lon1, self._lat1)
        self.prepareGeometryChange()
        xsize = abs(int(pos1[0] - pos0[0]))
        ysize = abs(int(pos0[1] - pos1[1]))

        rect = scene.sceneRect()
        x = rect.x()
        y = rect.y()
        width = rect.width()
        height = rect.height()
        self.ul_x = min(pos0[0], pos1[0])
        self.ul_y = min(pos0[1], pos1[1])
        self.lr_x = max(pos0[0], pos1[0])
        self.lr_y = max(pos0[1], pos1[1])
        #self.scale(width, height)

        #print ("screen rect: {0}:{1}, {2}:{3}".format(int(x), int(x+width), int(y), int(y+height)),
        #       "img rect: {0}:{1}, {2}:{3}".format(int(self.ul_x), int(self.lr_x), int(self.ul_y), int(self.lr_y)))

        #if xsize != self._xsize or ysize != self._ysize:
        self._xsize = xsize
        self._ysize = ysize
        self.ul_x = min(pos0[0], pos1[0])
        self.ul_y = min(pos0[1], pos1[1])
        self.setPos(self.ul_x, self.ul_y)

    # Scaled approach - does weird smoothing
    def paint(self, painter, option, widget=None):
        #print (self.x_mult, self.y_mult, self.orig_pixmap.width(), self.orig_pixmap.height())
        self._renderer.render(painter, QRectF(0, 0, self._xsize, self._ysize))

    def boundingRect(self):
        return QRectF(0, 0, self._xsize, self._ysize)

    def getGeoRect(self):
        ''' get geo referenced rectangle for this object

        Returns:
            QRectF (upper left x, upper left y, width, height)
        '''
        pos0 = self.scene().posFromLonLat(self._lon0, self._lat0)
        pos1 = self.scene().posFromLonLat(self._lon1, self._lat1)
        xsize = abs(int(pos1[0] - pos0[0]))
        ysize = abs(int(pos0[1] - pos1[1]))
        ul_x = min(pos0[0], pos1[0])
        ul_y = min(pos0[1], pos1[1])
        rect = QRectF(ul_x, ul_y, xsize, ysize)
        return rect

    def setLonLat(self, lon0, lat0, lon1, lat1):
        self._lon0 = lon0
        self._lat0 = lat0
        self._lon1 = lon1
        self._lat1 = lat1
        scene = self.scene()
        if scene is not None:
            self.updatePosition(self.scene())