Subclassing una Class en PyQGIS

A menudo es necesario crear una clase que herede el comportamiento de una clase existente. Esto se logra mediante el “subclassing”; lo que resulta en una nueva clase que hereda todos los rasgos de la clase parental. Uno de los requerimientos más deseados en el comportamiento de QGIS es que permita manejar las geometrías 3D. En un artículo en GeoTux se afirma que QGIS o PyQGIS no saben tratar las geometrías 3D porque las consideran como shapefiles 2D. En realidad si “sabe” pero hay que construir la clase desde “cero” mediante subclassing de la clase QgsPoint.

Si se realiza un dir(QgsPoint) en la Python Console se puede comprobar que no existe componente z para los QgsPoint:

['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__getitem__', 
'__gt__', '__hash__', '__init__', '__le__', '__len__', 
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'azimuth', 
'multiply', 'onSegment', 'set', 'setX', 'setY', 'sqrDist', 
'sqrDistToSegment', 'toDegreesMinutes', 'toDegreesMinutesSeconds', 
'toString', 'wellKnownText', 'x', 'y']

Consideremos el archivo point3d.py y coloquemos el siguiente código en su interior en el editor de la Python Console:

from qgis.core import QgsPoint

class Point3D(QgsPoint):
    
    def __init__(self,x,y,z):
        super(Point3D,self).__init__(x,y)
        self.z_value=z
        
    def setZ(self,z):
        self.z_value=z
        
    def z(self):
        return self.z_value

Se ha definido una clase que contiene un constructor que asigna también una componente z y dos métodos. El primero asigna un nuevo valor de z a un objeto ya creado y el segundo lo muestra cuando se requiere. Sin embargo, todos los otros métodos los hereda de la clase QgsPoint. Hagamos un dir(Point3D) a ver si incluye la componente z:

dir(Point3D)
['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__getitem__', 
'__gt__', '__hash__', '__init__', '__le__', '__len__', 
'__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'azimuth', 
'multiply', 'onSegment', 'set', 'setX', 'setY', 'setZ', 
'sqrDist', 'sqrDistToSegment', 'toDegreesMinutes', 
'toDegreesMinutesSeconds', 'toString', 'wellKnownText', 'x', 
'y', 'z']

Efectivamente la incluye. Ahora vamos a probarlo. En la Python Console se teclea:

>>>from points3d import Point3D
>>>p1 = Point3D(1,2,4)
>>>p2 = Point3D(3,5,7)
>>>p1
(1,2) #lo imprime como 2D!
>>>p2
(3,5) #lo imprime como 2D!
>>>p1.z()
4 #reconoce su componente z
>>>p2.z()
7 #reconoce su componente z
>>>p1.setZ(3) #asignamos nueva componente z a p1
>>>p1.z()
3 #hizo la asignacion como se esperaba
>>>p1.sqrDist(p2)
13.0 #distancia punto (1,2) a (3,5); no considera puntos 3D

Vamos a agregar dos nuevos métodos a la clase Point3D: ‘__str__’ y ‘sqrDist3D’. Tendríamos entonces:

from qgis.core import QgsPoint

class Point3D(QgsPoint):
    
    def __init__(self,x,y,z):
        super(Point3D,self).__init__(x,y)
        self.z_value=z
     
    def __str__(self):
        return '(' + str(self.x()) + ', ' + str(self.y()) + ', ' + str(self.z()) + ')'

    def setZ(self,z):
        self.z_value=z
        
    def z(self):
        return self.z_value
        
    def sqrDist3D(self,point):
        return (self.x()-point.x())**2+\
        (self.y()-point.y())**2+\
        (self.z()-point.z())**2   

Probando los nuevos métodos en la Python Console:

>>>p1.sqrDist3D(p2)
29.0
>>>print p1
(1.0, 2.0, 3)

donde el resultado de 29 es el esperado para el cuadrado de la distancia entre los puntos (1,2,3) y (3,5,7) y el método ‘__str__’ ha cambiado el comportamiento de print y ahora se puede observar simultáneamente la impresión de las tres coordenadas del punto.

Esta entrada fue publicada en Código Python, PyQGIS, SIG, Software Libre. Guarda el enlace permanente.

Responder

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s