[Gvsig_desarrolladores] Consulta de AbstractEvaluator

Joaquin Jose del Cerro Murciano jjdelcerro en gvsig.org
Dom Jun 4 12:49:29 CEST 2017


El 1 de junio de 2017, 20:09, Alex Irmel Oviedo Solis <
alleinerwolf en gmail.com> escribió:

> Buenas tardes, continuo modificando la extension LandRegistryViewer y
> necesito obtener registros asociados a un poligono pero de la forma actual
> de la extension se muestran más resultados de los que deberian y no
> entiendo del todo el codigo para modificar ese comportamiento.
>
> Por lo poco que entiendo, la clase IntersectsEvaluator que extiende a
> AbstractEvaluator es la que realiza la consulta de intersección de un punto
> con los poligonos y que al parecer tiene un buffer alto y por esto
> intersecta a más de un poligono y lo que requiero es que el buffer sea
> minimo para obtener un solo poligono.
>
> Espero que me puedan dar una ayudita en este problema, gracias de
> antemano. Saludos
>
> _______________________________________________
> gvSIG_desarrolladores mailing list
> gvSIG_desarrolladores en listserv.gva.es
> Para ver histórico de mensajes, editar sus preferencias de usuario o darse
> de baja en esta lista, acuda a la siguiente dirección:
> https://listserv.gva.es/cgi-bin/mailman/listinfo/gvsig_desarrolladores
>
>


Hola Alex,
no entiendo cual es tu problema, te voy contando a
ver si te sirve algo de lo que te cuento y con todo ya ves
de concretar un poco mas la duda.

La forma de recuperar registros de una fuente de datos
seria algo como:

  FeatureStore store = ... ;
  FeatureSet set = null;
  DisposableIterator it = null;

  try {
    set = store.getFeatureStore();
    it = set.fastIterator();
    while( it.hasNext() ) {
      Feature f = (Feature) it.next();

      ... hacer lo que toque con la feature ...

    }
  } catch(Throwable th) {
    ... tratamiento de errores ...
  } finally {
    DisposeUtils.disposeQuietly(it);
    DisposeUtils.disposeQuietly(set);
  }

Cuando sea posible recomiendo usar un visitor en lugar de iterar sobre
los registros pero entiendo que sea mas facil entender la version con
el iterador. De todos modos dejo aqui la version del visitor.

  FeatureStore store = ... ;

  FeatureSet set = null;
  DisposableIterator it = null;

  try {
    set = store.getFeatureStore();
    set.accept(new Visitor() {
      public void visit(Object obj) throws VisitCanceledException,
BaseException {
        Feature f = (Feature) obj;

        ... hacer lo que toque con la feature ...
      }
    );

  } catch(Throwable th) {
    ... tratamiento de errores ...
  } finally {
    DisposeUtils.disposeQuietly(set);
  }

Bueno, elejimos una u otra forma para recorrer las features de una fuente
de datos.

Ahora bien asi, nos recorremos todas las features de esa fuente de datos.
¿ Y si solo queremos unas pocas ?
Si solo queremos las features cuya geometria intersecte con un poligono
dado.

Invocaremos al metodo getFeatureStore, pero pasandole la condicion de
filtrado
que deseemos. Vamos a ver como hacerlo.


    FeatureQuery query = store.createFeatureQuery();
    Evaluator filtro = MyIntersectsEvaluator(...);
    query.setFilter(filtro);
    set = store.getFeatureStore(query);

De esta forma obtendriamos las features que cumplen el filtro especificado.
¿ Y que es ese filtro ?

El filtro es una instancia de Evaluator.
Simplificando la explicacion, la libreria de acceso a datos lo que hace es,
recoger todas las features y para cada una de ellas invoca al metodo
evaluate del filtro. Si este metodo devuelbe true, esa feature es incluida
en
el resultado de la consulta, si no, no es incluida.

El metodo evaluate recive los datos de la feature para que puedas realizar
con
ellos la operacion que necesites. Vamos a ver un ejemplo. El de
interseccion con
un punto. El metodo evaluate podria ser algo como:


  public Object evaluate(EvaluatorData data) throws EvaluatorException {
    Geometry geom = (Geometry) data.getDataValue("the_geom");
    try {

      return punto.intersects(geom);

    } catch (GeometryOperationNotSupportedException e) {
      throw new EvaluatorException(e);

    } catch (GeometryOperationException e) {
      throw new EvaluatorException(e);

    }
  }


para cada feature de nuestra fuente de datos se llamara a este evaluate.
En data recibiremos los datos de la feature. Asumo que la geometria esta
en el campo "the_geom", asi que lo primero es recuperar la geometria.
Luego, simplemente compruebo si intersecta con mi punto y devuelbo el
resultado (si intersecta o no).

La clase MyIntersectsEvaluator podia quedar algo como:


public class MyIntersectsEvaluator extends AbstractEvaluator {

  private Geometry punto;

  public MyIntersectsEvaluator(Geometry punto) throws
GeometryOperationNotSupportedException, GeometryOperationException {
    this.punto = punto;
  }

  public String getName() {
    return "IntersectaConPunto";
  }

  public Object evaluate(EvaluatorData data) throws EvaluatorException {
    Geometry geom = (Geometry) data.getDataValue("the_geom");
    try {

      return punto.intersects(geom);

    } catch (GeometryOperationNotSupportedException e) {
      throw new EvaluatorException(e);

    } catch (GeometryOperationException e) {
      throw new EvaluatorException(e);

    }
  }

}

Si creamos uno de estos y lo aplicamos al query como un filtro, el set solo
nos
devolbera las features que intersecten con nuestro poligono.

Si lo dejamos asi funcionara, y con un shape, o un dxf, ira bien; pero con
una
BBDD ira muy lento. Esto es por que la libreria de acceso a datos, se
traera
todas las filas de la tabla y comprobara una a una si cumplen el criterio
indicado.

Podemos optimizar esto añadiendo el metodo getCQL a nuestra clase con algo
como:


  public String getCQL() {
    where = MessageFormat.format(
      " intersects(the_geom, GeomFromText('{1}','{2}')) ",
      new Object[] {
        punto.convertToWKT(),
        proj.getAbbrev()
      }
    );
    return where;
  }

Y añadiremos en el constructo la rojeccion en la que se encuentra el
poligono:

  public MyIntersectsEvaluator(Geometry punto, IProjection proj) throws
GeometryOperationNotSupportedException, GeometryOperationException {
    this.punto = punto;
    this.proj = proj;
  }

¿ Que es lo que conseguimos con esto ?

Si aplicamos este filtro a un shape, nada. El resultado sera el mismo que
antes.
Sim embargo, si lo aplicamos a un tabla de PostgreSQL tendremos unas
mejoras
sustanciales en el rendimiento.

El proveedor de datos de PostgreSQL de gvSIG, ve que el metodo getCQL
devuelbe
una cadena, y la añade al where de la sentencia SQL que va a usar para
recuperar
los datos. Asi que la BBDD solo devolvera los datos que cumplan el criterio
que
hemos indicado en esa funcion. Luego, la libreria de acceso a datos volvera
a
aplicar el filtro de nuestro evaluador a cada una de las features
recuperadas, pero
ya no sera a todas las de la tabla, si no solo a las que hayamos
restringido con
lo que devuelba el getCQL.

Es muy importante que la proyeccion del punto y la de las geometrias de la
tabla
de la BBDD sean la misma, si no los resultados pueden ser algo
impredecibles.

Con gvSIG 2.3.3 y 2.4 se han añadido mejoras que permiten independizar como
construimos lo que devuelbe el getCQL de la BBDD que se esta usando para
que
asi nuestra consulta funcione con todas las BBDD que soporte gvSIG, pero de
momento voy a dejarlo asi.

Tambien podriamos pasarle a muestra clase MyIntersectsEvaluator como se
llama
la columna geometria con la que queremos comparar nuestro punto (por si no
se llama "the_geom"). Asi nuestra clase seria independiente de ese valor.

Sobre lo del buffer que comentas... en la clase IntersectsEvaluator que hay
en
la implementacion de langregistryviewer no he visto que se haga ningun
buffer, ni
tampoco antes de pasarle el punto sobre el que se realiza la interseccion.
¿ Podria ser que tuvieses en la fuente de datos geometrias que se
superponen ?

Bueno, lo dejo aqui y ya vas preguntando cosas mas concretas.

Por cierto, el codigo lo he picado directamente aqui, podria haberme
confundido
en el nombre de algun identificador, espero que no.

Un saludo
Joaquin


-- 
--------------------------------------
Joaquin Jose del Cerro Murciano
Development and software arquitecture manager at gvSIG Team
jjdelcerro en gvsig.com
jjdelcerro en gvsig.org
gvSIG Association
www.gvsig.com
www.gvsig.org
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listserv.gva.es/pipermail/gvsig_desarrolladores/attachments/20170604/332cc7e6/attachment.html>


Más información sobre la lista de distribución gvSIG_desarrolladores