Esempio n. 1
0
class NorthArrow(QgsMapCanvasItem):
    def __init__(self, proj, canvas):
        super(NorthArrow, self).__init__(canvas)
        self.proj = proj
        self.canvas = canvas
        self.map_pos = QgsPointXY(0.0, 0.0)
        self.svg = QSvgRenderer(":/resources/arrow.svg")
        self.size = QSize(42, 64)
        self.corner = 1

    def paint(self, painter, xxx, xxx2):
        """Paint north arrow on painter"""
        if self.svg.isValid():
            pos = self.set_position(self.corner,
                                    painter.device().width(),
                                    painter.device().height())

            rotation = QgsBearingUtils.bearingTrueNorth(
                self.canvas.mapSettings().destinationCrs(),
                self.canvas.mapSettings().transformContext(),
                self.canvas.extent().center())
            rotation += self.canvas.rotation()

            painter.save()
            painter.rotate(-rotation)  # To translate correctly
            painter.translate(pos.x(), pos.y())
            painter.rotate(
                rotation
            )  # To rotate north arrow along with canvas, always pointing north

            # do the drawing, and draw a smooth north arrow even when rotated
            rectangle = QRectF(-self.size.width() / 2, -self.size.height() / 2,
                               self.size.width(), self.size.height())
            self.svg.render(painter, rectangle)

            painter.restore()

    def set_position(self, corner, width, height):
        """
        Returns the position of the specified corner with a concrete width and height
        :param corner: can be 1, 2, 3 or 4. top left, top right, bot left and bot right respectively
        :param width: width of the paint space
        :param height: height of the paint space
        :return: QgsPointXY of the specified corner
        """
        if corner == 1:  # top left corner
            return QgsPointXY(0 + self.size.height() / 2,
                              0 + self.size.height() / 2)
        elif corner == 2:  # top right corner
            return QgsPointXY(width - self.size.height() / 2,
                              0 + self.size.height() / 2)
        elif corner == 3:  # bottom left corner
            return QgsPointXY(0 + self.size.height() / 2,
                              height - self.size.height() / 2)
        elif corner == 4:  # bottom right corner
            return QgsPointXY(width - self.size.height() / 2,
                              height - self.size.height() / 2)
    def _draw_plate(self, background_path, font_path, target_template,
                    symbols):

        if background_path.suffix == '.svg':
            renderer = QSvgRenderer(str(background_path))
            assert renderer.isValid()
            width = target_template['width']
            w, h = renderer.viewBox().width(), renderer.viewBox().height()
            aspect_ratio = w / h
            w, h = width, width / aspect_ratio
            image = QImage(w, h, QImage.Format_ARGB32)
            image.fill(Qt.transparent)  # workaround for clean image
            painter = QPainter(image)
            painter.setRenderHint(QPainter.Antialiasing, True)
            painter.setRenderHint(QPainter.TextAntialiasing, True)
            painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
            renderer.render(painter)
        else:
            image = QPixmap(str(background_path))
            assert not image.isNull()
            width = target_template['width']
            w, h = image.width(), image.height()
            aspect_ratio = w / h
            w, h = width, width / aspect_ratio
            image.scaled(w, h, Qt.KeepAspectRatio)
            image = image.toImage()
            painter = QPainter(image)

        font = get_font(font_path)
        pen = QPen(QColor.fromRgb(int(target_template['font_color'], base=16)),
                   2, Qt.SolidLine)
        painter.setPen(pen)

        for _, sym in symbols.items():
            rect = QRect(sym.x, sym.y, sym.w, sym.h)
            font.setPointSizeF(sym.font_size)
            painter.setFont(font)
            painter.drawText(rect, Qt.AlignCenter, sym.sym)

        painter.end()

        return qimage_to_nparr(image)
Esempio n. 3
0
    def drawGraphSymbo(self, renderContext):

        painter = renderContext.painter()
        mapToPixel = renderContext.mapToPixel()

        crs = QgsCoordinateReferenceSystem(
            4326, QgsCoordinateReferenceSystem.PostgisCrsId)
        xform = QgsCoordinateTransform(self.crs(), crs, QgsProject.instance())

        xml = self.symbo_reader.read(utils.resolve('render.xml'))

        pen = QPen()
        brush = QBrush()
        diameter = 0

        nodes = self.readGraph().getListNode()

        edges = self.readGraph().getListEdge()

        #Dessin des arcs
        for edge in edges:
            start = nodes[edge.getNodeA()]
            end = nodes[edge.getNodeB()]

            #Gestion des configurations de propriétés graphiques
            """
            Le fichier xml correspond à un dictionnaire de dictionnaire de rules:
            graphrenderer = {"node_rules": GraphRules, "edge_rules": GraphRules}
            """
            if 'edge_rules' in xml:

                #Récupération de la valeur par défaut de la rule du xml
                #Cas où il n'y a pas de ruleunit pour la rule en question
                for key, val in xml['edge_rules'].items():
                    rule_prop = key
                    graphRule = val
                    attribute_name = graphRule.getName()
                    default_prop = graphRule.getDefaultProp().value()
                    list_ruleunit = graphRule.getRule()
                    if (len(list_ruleunit) == 0):
                        if (rule_prop == "fgcolor"):
                            color = default_prop
                            pen.setColor(color)
                        elif (rule_prop == "linewidth"):
                            variant = default_prop
                            pen.setWidth(variant)
                        elif (rule_prop == "linestyle"):
                            variant = default_prop
                            pen.setStyle(Qt.PenStyle(variant))

            #Cas où il y a une ou plusieurs ruleunit dans le xml
            dict_features = edge.getFeatures()
            for edge_att_name, edge_att_val in dict_features.items():
                if 'edge_rules' in xml:
                    for key, val in xml['edge_rules'].items():
                        rule_prop = key
                        graphRule = val
                        attribute_name = graphRule.getName()
                        default_prop = graphRule.getDefaultProp().value()
                        list_ruleunit = graphRule.getRule()

                        if (attribute_name == edge_att_name):
                            if (len(list_ruleunit) != 0):
                                #Permet d'affecter la prop_val à l'attr_val correspondant du fichier graph
                                flag = 0
                                for index in range(len(list_ruleunit)):
                                    attribute_val = list_ruleunit[
                                        index].attr_val.value()
                                    prop_val = list_ruleunit[
                                        index].prop_val.value()
                                    if (str(edge_att_val) == str(attribute_val)
                                        ):
                                        if (rule_prop == "fgcolor"):
                                            color = prop_val
                                            pen.setColor(color)
                                        elif (rule_prop == "linewidth"):
                                            variant = prop_val
                                            pen.setWidth(variant)
                                        elif (rule_prop == "linestyle"):
                                            variant = prop_val
                                            pen.setStyle(Qt.PenStyle(variant))
                                        flag = 1
                                        break
                                #Affecte la valeur par défaut à toutes les autres attr_val n'étant pas présentent dans la liste des rule_unit
                                if (flag == 0):
                                    if (rule_prop == "fgcolor"):
                                        color = default_prop
                                        pen.setColor(color)
                                    elif (rule_prop == "linewidth"):
                                        variant = default_prop
                                        pen.setWidth(variant)
                                    elif (rule_prop == "linestyle"):
                                        variant = default_prop
                                        pen.setStyle(Qt.PenStyle(variant))

            painter.setPen(pen)
            painter.setBrush(brush)

            pointA = mapToPixel.transform(
                xform.transform((QgsPointXY(int(start.getX()),
                                            int(start.getY())))))
            pointB = mapToPixel.transform(
                xform.transform((QgsPointXY(int(end.getX()),
                                            int(end.getY())))))
            painter.drawLine(pointA.x(), pointA.y(), pointB.x(), pointB.y())

        #Même chose pour le dessin des noeuds, avec des rule_prop différentes
        for id in nodes:
            x = nodes[id].getX()
            y = nodes[id].getY()
            if 'node_rules' in xml:

                #Récupération de la valeur par défaut de la rule du xml
                #Cas où il n'y a pas de ruleunit pour la rule en question
                for key, val in xml['node_rules'].items():
                    rule_prop = key
                    graphRule = val
                    attribute_name = graphRule.getName()
                    default_prop = graphRule.getDefaultProp().value()
                    list_ruleunit = graphRule.getRule()
                    if (len(list_ruleunit) == 0):
                        if (rule_prop == "bgcolor"):
                            color = default_prop
                            brush.setColor(color)
                            brush.setStyle(Qt.SolidPattern)
                        elif (rule_prop == "fgcolor"):
                            color = default_prop
                            pen.setColor(color)
                        elif (rule_prop == "linewidth"):
                            variant = default_prop
                            pen.setWidth(variant)
                        elif (rule_prop == "size"):
                            diameter = default_prop
                        elif (rule_prop == "shape"):
                            shape = default_prop

            #Cas où il y a une ou plusieurs ruleunit dans le xml
            dict_features = nodes[id].getFeatures()
            for node_att_name, node_att_val in dict_features.items():
                if 'node_rules' in xml:
                    for key, val in xml['node_rules'].items():
                        rule_prop = key
                        graphRule = val
                        attribute_name = graphRule.getName()
                        default_prop = graphRule.getDefaultProp().value()
                        list_ruleunit = graphRule.getRule()

                        if (attribute_name == node_att_name):
                            if (len(list_ruleunit) != 0):
                                #Permet d'affecter la prop_val à l'attr_val correspondant du fichier graph
                                flag = 0
                                for index in range(len(list_ruleunit)):
                                    attribute_val = list_ruleunit[
                                        index].attr_val.value()
                                    prop_val = list_ruleunit[
                                        index].prop_val.value()
                                    if (str(node_att_val) == str(attribute_val)
                                        ):
                                        if (rule_prop == "bgcolor"):
                                            color = prop_val
                                            brush.setColor(color)
                                            brush.setStyle(Qt.SolidPattern)
                                        elif (rule_prop == "fgcolor"):
                                            color = prop_val
                                            pen.setColor(color)
                                        elif (rule_prop == "linewidth"):
                                            variant = prop_val
                                            pen.setWidth(variant)
                                        elif (rule_prop == "size"):
                                            diameter = prop_val
                                        elif (rule_prop == "shape"):
                                            shape = prop_val
                                        flag = 1
                                        break
                                #Affecte la valeur par défaut à toutes les autres attr_val n'étant pas présentent dans la liste des rule_unit
                                if (flag == 0):
                                    if (rule_prop == "bgcolor"):
                                        color = default_prop
                                        brush.setColor(color)
                                        brush.setStyle(Qt.SolidPattern)
                                    elif (rule_prop == "fgcolor"):
                                        color = default_prop
                                        pen.setColor(color)
                                    elif (rule_prop == "linewidth"):
                                        variant = default_prop
                                        pen.setWidth(variant)
                                    elif (rule_prop == "size"):
                                        diameter = default_prop
                                    elif (rule_prop == "shape"):
                                        shape = default_prop

            painter.setPen(pen)
            painter.setBrush(brush)
            point = mapToPixel.transform(xform.transform((QgsPointXY(x, y))))

            #Différentes formes possibles pour la rule shape
            if (shape != ""):
                if (shape == "circle"):
                    painter.drawEllipse(point.x() - diameter / 2,
                                        point.y() - diameter / 2, diameter,
                                        diameter)
                elif (shape == "rectangle"):
                    painter.drawRect(point.x() - diameter / 2,
                                     point.y() - diameter / 2, diameter,
                                     diameter)
                elif (shape == "cross"):
                    painter.drawLine(point.x() - diameter / 2,
                                     point.y() - diameter / 2,
                                     point.x() + diameter / 2,
                                     point.y() + diameter / 2)
                    painter.drawLine(point.x() - diameter / 2,
                                     point.y() + diameter / 2,
                                     point.x() + diameter / 2,
                                     point.y() - diameter / 2)
                else:
                    #Draw SVG Node
                    svgr = QSvgRenderer(shape)
                    if (svgr.isValid()):
                        svgr.render(
                            painter,
                            QRectF(point.x() - diameter / 2,
                                   point.y() - diameter / 2, diameter,
                                   diameter))
                    else:
                        painter.drawEllipse(point.x() - diameter / 2,
                                            point.y() - diameter / 2, diameter,
                                            diameter)
            else:
                #default is circle
                painter.drawEllipse(point.x() - diameter / 2,
                                    point.y() - diameter / 2, diameter,
                                    diameter)
Esempio n. 4
0
class CanvasMarker(QgsMapCanvasItem):
    def __init__(self, canvas, color, svg=None, width=0.0, length=0.0, orientation=True, marker_mode=False, config=None):
        super(CanvasMarker, self).__init__(canvas)
        self.canvas = canvas
        self.config = config
        self.size = 20
        self.changing_scale = 400
        self.marker_mode = marker_mode
        self.color = color
        self.pointbrush = QBrush(self.color)
        self.pointpen = QPen(Qt.black)
        self.pointpen.setWidth(1)
        self.map_pos = QgsPointXY(0.0, 0.0)
        self.heading = 0
        self.width = width
        self.length = length
        self.orientation = orientation
        if svg is not None:
            # set crs and ellipsoid
            crs = self.canvas.mapSettings().destinationCrs()
            self.distance_calc = QgsDistanceArea()
            self.distance_calc.setSourceCrs(crs, QgsProject.instance().transformContext())
            self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())

            self.svg = QSvgRenderer(svg)
        else:
            self.svg = None

    def set_size(self, size):
        self.size = size

    def set_color(self, color):
        self.color = color

    def set_marker_mode(self, canvas_marker_mode):
        self.marker_mode = canvas_marker_mode

    def paint(self, painter, xxx, xxx2):
        pos = self.toCanvasCoordinates(self.map_pos)
        self.setPos(pos)

        if self.marker_mode:
            mode = self.config.csettings["canvas_marker_mode"]

            if mode == 'auto':
                self.set_size(20)
                transform = self.canvas.getCoordinateTransform()
                start_point = transform.toMapCoordinates(pos.x(), pos.y())
                map_end_point_width = endpoint(start_point, self.width, 90 + math.degrees(self.heading))
                map_end_point_length = endpoint(start_point, self.length, math.degrees(self.heading))

                # to canvas coordinates
                canvas_end_point_width = self.toCanvasCoordinates(map_end_point_width)
                canvas_end_point_length = self.toCanvasCoordinates(map_end_point_length)

                width = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_width))
                height = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_length))

                if width < self.size and height < self.size:
                    self.changing_scale = self.canvas.scale()
                else:
                    self.changing_scale = self.canvas.scale() * 2

            elif mode == 'manual':
                self.changing_scale = self.config.csettings["canvas_marker_scale"]
        else:
            self.changing_scale = 400

        if self.svg is None or self.canvas.scale() >= self.changing_scale:
            self.set_size(20)
            half_size = self.size / 2.0
            rect = QRectF(0 - half_size, 0 - half_size, self.size, self.size)
            painter.setRenderHint(QPainter.Antialiasing)

            self.pointpen.setColor(Qt.black)
            self.pointpen.setWidth(2)
            self.pointbrush.setColor(self.color)

            painter.setBrush(self.pointbrush)
            painter.setPen(self.pointpen)
            y = 0 - half_size
            x = rect.width() / 2 - half_size
            line = QLine(x, y, x, rect.height() - half_size)
            y = rect.height() / 2 - half_size
            x = 0 - half_size
            line2 = QLine(x, y, rect.width() - half_size, y)

            # Arrow
            p = QPolygonF()
            p.append(QPoint(0 - half_size, 0))
            p.append(QPoint(0, -self.size))
            x = rect.width() - half_size
            p.append(QPoint(x, 0))
            p.append(QPoint(0, 0))

            offsetp = QPolygonF()
            offsetp.append(QPoint(0 - half_size, 0))
            offsetp.append(QPoint(0, -self.size))
            x = rect.width() - half_size
            offsetp.append(QPoint(x, 0))
            offsetp.append(QPoint(0, 0))

            painter.save()
            painter.rotate(math.degrees(self.heading) + self.canvas.rotation())
            if self.orientation:
                path = QPainterPath()
                path.addPolygon(p)
                painter.drawPath(path)
            painter.restore()
            painter.drawEllipse(rect)
            painter.drawLine(line)
            painter.drawLine(line2)

        # svg valid
        elif self.svg is not None and self.svg.isValid():

            # get rotation
            rotation = self.canvas.rotation()

            painter.save()

            transform = self.canvas.getCoordinateTransform()
            start_point = transform.toMapCoordinates(pos.x(), pos.y())
            map_end_point_width = endpoint(start_point, self.width, 90 + math.degrees(self.heading))
            map_end_point_length = endpoint(start_point, self.length, math.degrees(self.heading))

            # to canvas coordinates
            canvas_end_point_width = self.toCanvasCoordinates(map_end_point_width)
            canvas_end_point_length = self.toCanvasCoordinates(map_end_point_length)

            width = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_width))
            height = magnitude(self.toCanvasCoordinates(start_point), QgsPointXY(canvas_end_point_length))

            if width > height:
                self.set_size(width)
            else:
                self.set_size(height)

            if width != 0 and height != 0:
                center_x = width / 2.0
                center_y = height / 2.0
                # work out how to shift the image so that it rotates
                #           properly about its center
                # ( x cos a + y sin a - x, -x sin a + y cos a - y)
                myradians = math.radians(rotation + math.degrees(self.heading))
                xshift = int(((center_x * math.cos(myradians)) +
                              (center_y * math.sin(myradians)))
                             - center_x)
                yshift = int(((-center_x * math.sin(myradians)) +
                              (center_y * math.cos(myradians)))
                             - center_y)

                painter.translate(-width / 2, -height / 2)
                painter.rotate(math.degrees(self.heading) + self.canvas.rotation())
                self.svg.render(painter, QRectF(xshift, yshift, width, height))
            painter.restore()

    def boundingRect(self):
        size = self.size * 2
        return QRectF(-size, -size, 2.0 * size, 2.0 * size)

    def updatePosition(self):
        self.set_center(self.map_pos, self.heading)

    def set_center(self, map_pos, heading):
        self.heading = heading
        self.map_pos = map_pos
        self.setPos(self.toCanvasCoordinates(self.map_pos))

    def set_width(self, width):
        self.width = width

    def set_length(self, length):
        self.length = length