martes, 22 de diciembre de 2020

Producir rectángulos por dragado del Map Canvas con PyQGIS 3

Modificando el código de la respuesta que se encuentra en este link es posible construir capas vectoriales tipo polígono, con forma rectángular, como memory layers. El código se presenta a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
map_canvas = iface.mapCanvas()

class dragRectangle(QgsMapToolEmitPoint):
    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.start_point = None
        self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, True)
        self.rubber_band.setColor(Qt.red)
        self.rubber_band.setOpacity(0.7)
        
    def canvasPressEvent(self, e):
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
    
    def canvasMoveEvent(self, e):
        if self.start_point:
            end_point = self.toMapCoordinates(e.pos())
            self.rubber_band.reset()
            p = self.get_rect_points(self.start_point, end_point)
            self.rubber_band.setToGeometry(QgsGeometry.fromPolygonXY(p), None)
                
    def canvasReleaseEvent(self, e):
        self.end_point = self.toMapCoordinates(e.pos())
        r = self.get_rectangle()
        self.rubber_band.reset()
        self.start_point = None
        self.end_point = None

        rect_feat = r.asWktPolygon()
        
        #definng Status Bar
        statusBar = iface.mainWindow().statusBar()
        #selecting elements in Status Bar
        elements = statusBar.children()
        #selecting widget in Status Bar with ESPG
        EPSG = elements[1].children()[10]
        EPSG = EPSG.text().split(':')

        uri = "Polygon?crs=epsg:" + EPSG[1] + "&field=id:integer""&index=yes"

        mem_layer = QgsVectorLayer(uri,
                                   'rectangle',
                                   'memory')

        prov = mem_layer.dataProvider()

        feat = QgsFeature()
        feat.setAttributes([0])
        feat.setGeometry(QgsGeometry.fromWkt(rect_feat))
        prov.addFeatures([feat])
        QgsProject.instance().addMapLayer(mem_layer)
      
    def get_rect_points(self, startPoint, endPoint):
        points = [[QgsPointXY(startPoint.x(), startPoint.y()), QgsPointXY(endPoint.x(), startPoint.y()), QgsPointXY(endPoint.x(), endPoint.y()), QgsPointXY(startPoint.x(), endPoint.y())]]
        return points
        
    def get_rectangle(self): 
        rect = QgsRectangle(self.start_point, self.end_point)
        return rect
    
T = dragRectangle(map_canvas)
map_canvas.setMapTool(T)
#T.deactivated.connect(lambda: print('Tool deactivated'))

Después de ejecutado el código en la Python Console de QGIS 3, el cursor toma forma de cruz señalando que es posible dragar el Map Canvas para producir una capa vectorial con forma de rectángulo. En la imagen siguiente se observa la superficie dragada en el Map Canvas.

Una vez que se suelta el cursor se produce en breves instantes la capa vectorial esperada. El CRS de la misma es el que por defecto presentan los proyectos que no contienen capa alguna (EPSG:4326). Por esta razón la proporcion es diferente al de la imagen anterior.

Para verificar que funciona de la manera esperada vamos a cargar una capa ráster con EPSG:32612 y dragamos en una superficie arbitraria sobre la misma; tal como se observa en la imagen siguiente.

Una vez que se libera el cursor la capa vectorial, tal como se esperaba, se produce sobre la misma superfice dragada de la imagen anterior.

No hay comentarios: