Usando PersistenceFactory para persistir muchas clases con un interface comun

Hola a todos.

El otro día un compañero me planteo un problema relacionado con la persistencia del proyecto. Tenia un montón de clases que implementaban un interfaz Filtro, con un montón quiero decir mas de 100, y todas ellas debían persistir los mismos atributos en el proyecto. Además estas implementaciones de Filtro, vivían en librerías, jars, distintos que se desplegaban en la aplicación en varios plugins.

Para su primera aproximación, lo que había echo es persistir los atributos comunes a todas junto con el nombre de la clase, y luego al levantarlos usaba Class.forName(filterClassName). El problema es que si la clase vivía en otro plugin de gvSIG el Class.forName fallaba.

En principio, todo el mecanismo de persistencia diseñado alrededor de la persistencia del proyecto en gvSIG esta pensado para que estas cosas no ocurran, y nunca deberíamos guardar nombres de clase en los atributos de nuestros objetos al persistirlos en el proyecto.

Para que algo sea persistente podemos:

Para nuestro caso, lo que necesitamos es una factoría de persistencia. En principio están pensadas para:

  • Dotar de persistencia a objetos que no podemos tocar, por ejemplo no podemos hacer que la clase Color de java implemente Persistent. Por ejemplo, en el proyecto org.gvsig.fmap.mapcontext se implementa la factoria ColorPersistenceFactory para gestionar la persistencia de java.awt.Color.
  • También podemos utilizarlas para persistir objetos que implementan un interfaz común, como por ejemplo IProjection. En gvSIG existe una sola factoria de persistencia para todas las implementaciones de proyecciones, ProjectionPersistenceFactory.
  • O para dotar de persistencia a un conjunto de clases cuales sean. No tienen por que implementar un interfaz común, ni siquiera tener un conjunto de atributos común Por ejemplo en los test de org.gvsig.tools.lib podemos encontrar la clase AwtFactory.

En nuestro caso deberíamos tener una factoría de persistencia por librería, jar, que aporte un filtro, y en su Library, registrarla en el manager de persistencia. Siguiendo con lo del Color, en el doPostInitialize de MapContextLibrary se registra el ColorPersistenceFactory.

Para implementar factorías de persistencia podemos:

  • Implementar directamente el interfaz PersistenceFactory, Tiene métodos como:
    • public boolean manages(Object obj)
    • public boolean manages(PersistentState state)

    Que deberían responder true si manejan la persistencia del objeto. Y otros como:

    • public Class getManagedClass(PersistentState state)
    • public Class getManagedClass(Object object)
    • public String getManagedClassName(Object object)

    Que nos dicen que clase java representa a un objeto dado.

    Con esto tendríamos el control para que cada librería indique que clases es capaz de levantar y no tendríamos problemas con los class-paths ya que maneja Class y no nombres de clase.

  • Extender de AbstractSinglePersistenceFactory que nos da ya casi todo hecho, solo tendríamos que implementar un par de métodos; pero no creo que nos valga ya que esta pensado para que la factoría trabaje con una clase o interfaz, y aunque pueda parecer que en nuestro caso tenemos un interfaz, como necesitaríamos tener varias factorías para ese interfaz, no nos valdría ya que cada factoría debería responder, no al interfaz común, si no solo a las implementaciones individuales que es capaz de levantar.
  • Extender de AbstractMultiPersistenceFactory. Este caso seria una buena aproximacion a nuestro problema. Actualmente no conozco ningún uso en gvSIG de esta clase abstracta, aunque en org.gvsig.tools.lib tenemos un test que la usa, AwtFactory , y no la usa exactamente para lo que precisaríamos nosotros ahora.

Me voy a extender un poco mas sobre esta ultima opcion ya que parece ser la mas adecuada para lo que necesitamos.

En nuestro caso precisaríamos extender de el e implementar tres métodos:

  • public Object createFromState(PersistentState state)
  • public void saveToState(PersistentState state, Object obj)
  • protected void makeDefinitions()

En el makeDefinitions se crearía la definición de persistencia invocando a addDefinition y creando nuestra definición de forma similar a como lo haríamos para cualquier objeto que implementase Persistent ; pero además deberemos llenar la variable de instancia “classes” con la lista de objetos Class que la factoría vaya a gestionar, y esto ya no es tan simple ya que hay que mantener la coherencia con un Map auxiliar que se usa internamente.

A la clase AbstractMultiPersistenceFactory le faltaría disponer de un método para ir añadiendo clases a una definición (por cierto, se lo añado ya para próximos usos 🙂 ), pero podemos implementarlo en nuestra factoría. Seria algo como:

protected void addManagedClass(Class managedClass, DynClass definition ) {
    if( !this.classes.contains(managedClass) ) {
        this.classes.add(managedClass);
    }
    this.nameToClass.put(managedClass.getName(), managedClass);
    this.nameToClass.put(definition.getFullName(), managedClass);
    if( definition.getNamespace().equals(PersistenceManager.PERSISTENCE_NAMESPACE) ) {
        this.nameToClass.put(definition.getName(), managedClass);
    }
}

Esto nos permitiría añadir varias clases con la misma definición de persistencia. Por ejemplo, si tuviésemos una factoría que fuese a gestionar tres implementaciones del interfaz Filter, FilterA, FilterB y FilterC podríamosacer en el método makeDefinitions() algo como:

protected void makeDefinitions() {
  // Creamos la definicion de persistencia asociandola a la primera clase FilterA
  DynStruct definition = this.addDefinition(FilterA.class, 
      "FilterNoseque", "Filtros de noseque") 

  definition.addDynField....
  ...

  // Ahora asociamos las demas clases a la misma definicion de persistencia.
  this.addManagedClass(FilterB.class,definition);
  this.addManagedClass(FilterC.class,definition);

}

Ojo con el “FilterNoseque”, ya que ese “Noseque” deberá ser distinto en cada factoría que creemos para cada librería. De alguna manera debería identificar el grupo de filtros que gestiona esa factoría de persistencia.

Ahora echemos un vistazo a los otros dos métodos, createFromState y saveToState. Nuestra factoría, en el createFromState lo primero que debería hacer es identificar de que clase filtro se trata, y en función de ello levantarla y rellenar sus propiedades. Pero esto no es tan simple, ya que solo hay una definición de persistencia para todos los filtros que soporta nuestra factoría. Para identificarla tendremos que persistir, además de los atributos del filtro, un identificativo de la clase. En este punto podríamos decidir persistir el nombre de la clase y usar un Class.forName para levantarla, ya que la factoría solo debe manejar lo que este implementado en su librería, así que no tendría problemas con el class-path. Sin embargo no soy partidario de usarlo ya que dificulta la identificación de las dependencias entre las clases. Personalmente prefiero mantener un Map que me devuelva la Class a partir del nombre de esta, lo me dejara constancia de las dependencias dentro de la librería. Añadiremos a la factoría una variable de instancia myfilters que inicializaremos en el makeDefinitions() que podría quedar algo como:

protected void makeDefinitions() {
  // Creamos la definicion de persistencia asociandola a la primera clase FilterA
  DynStruct definition = this.addDefinition(FilterA.class, 
      "FilterNoseque", "Filtros de noseque"); 

  definition.addDynFieldString("filterName");
  definition.addDynField....
  ... ;

  // Ahora asociamos las demas clases a la misma definicion de persistencia
  // y creamos nuestro map.

  this.myfilters = new HashMap();
  Class[] myclasses = {
      FilterA.class,
      FilterB.class,
      FilterC.class
  };
  for( int i=0; i<myclasses.length ; i++ ) {
      this.addManagedClass(myclasses[i],definition);
      this.myfilters.put(myclasses[i].getName(), myclasses[i]);

  }
}

Una vez tenemos inicializado myfilters, nuestros métodos createFromState y saveToState podrían quedar algo como:

public void saveToState(PersistentState state, Object obj)
            throws PersistenceException {
    Filter filter = (Filter) obj;
    state.set("filterName", filter.getClass().getSimpleName());
    // Seguimos persistiendo el resto de propiedades de nuestro filtro
    state.set(...  
    ...
}

public Object createFromState(PersistentState state)
            throws PersistenceException {
    String filterName = state.getString("filterName");
    Class filterClass = (Class) this.myfilters.get(filterName);
    if( filterClass==null ) {
            throw new PersistenceException("Can't manage filter '"+filterName+"'.");
    }
    // Ahora creamos e inicializamos ya nuestro filtro.
    Filter filter = (Filter) filterClass.newInstance();
    filter.setXXX( state.get("XXX"));

    return filter;
}

Si lo hacemos así, cada factoría solo maneja las clases para las que ha sido creada y nunca se levanta una instancia de clase por nombre, con lo que solo se crean objetos con los que nuestro código ha sido compilado. La responsabilidad de levantar otros filtros recaerá en otra factoría que sabe hacerlo, y no esta.

Las implementaciones que he puesto son solo ideas, cada cual que las adapte según lo que necesite.

Bueno, supongo que con esto, ya es ponerse a hacer pruebas.

Un saludo

Joaquin

Posted in development, gvSIG Desktop, spanish | Leave a comment

First incursion in symbology on scripting in gvSIG 2.0

Hello everyone.

Other day a friend wrote in gvSIG user’s list about a project he was dealing in  gvSIG and needed to access symbology from scripting of a layer.

First, scripting’s API has nothing prepared to access symbology… well, we believe that was added a pair of functions for something very basic.

Question is he needed to export symbology’s configuration applied to a set of layers and he asked us how to do it.

As the answer was not “cut it” and could be useful to others gvSIG users we thought bring it here, in gvSIG blog, not only in users’s list.

Well, to grain…

Access legend’s configuration of a layer is relatively simple. With:

layer = currentLayer()
legend = layer.getLegend()

And we have an object legend of gvSIG.

Problem is that in gvSIG legend are recordable. So, doesn’t exist a “Legend”, but the different plugins of gvSIG can record many legends. The result is that it could be very difficult to know what operations the legend we’ll get with calling to getLegend().

We will focus on the basic types of legend that come with gvSIG 2.0 (in gvSIG 2.1 are included more legend types, but if it is necessary we’ll talk about them in other moment).

One classification could be:

  • Vector legends (IVectorLegend)
  • Raster legends (IRaterLegend)

But for now we will talk on vector ones.

Other classification could be:

Each legend type offers many operations, so what we do first is determine  what legend we are working. We let here some little functions to that. Simple, but if we need it, and meanwhile they’re not in scripting library, we can paste the entire block in our script.

#==========================================================
#
# Functions to dealing with basic types of legends
#
from org.gvsig.fmap.mapcontext.rendering.legend import ISingleSymbolLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialIntervalLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialUniqueValueLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedVectorLegend

def getLegendName(legend):
  return legend.getClass().getSimpleName()

def isSingleSymbolLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/ISingleSymbolLegend.html
  return isinstance(legend,ISingleSymbolLegend)

def isVectorialIntervalLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialIntervalLegend.html
  return isinstance(legend,IVectorialIntervalLegend)

def isVectorialUniqueValueLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialUniqueValueLegend.html
  return isinstance(legend,IVectorialUniqueValueLegend)

def isClassifiedLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedLegend.html
  return isinstance(legend,IClassifiedLegend)

def isClassifiedVectorLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedVectorLegend.html
  return isinstance(legend,IClassifiedVectorLegend)

It doesn’t matter to understand mucho the code, it’s enough know that once included in our script we can know our legend is of a type with something like:

layer = currentLayer()
legend = layer.getLegend()
if isVectorialUniqueValueLegend(legend):
  print "The layer has a legend of unique values"

With the lack of API and documentation on scripting for the types of legend, we can go to IVectorialUniqueValueLegend to see what operations or methods we can use. Well, with this information we access the object legend of our layer… but… and now what?

In general, a legend has a symbols definition  and a way to see how to get a certain symbol to apply it to a feature or line of a data table associated to a layer.

For example, the single symbol legend (ISimgleSimbolLegend) has a method  getDefaultSymbol() that will return the symbol to apply to all features of our view, therefore a vector classified legend will have a method getSymbols() that will return that legend’s symbols list. Problem is what’s next that there are many symbols types, like with legends, and each one with own operations or methods. So we’ll find:

Despite there are many symbols types, all respond to a set of basic operations like:

  • getDescription()
  • getColor()
  • getSymbolForSelection(), care with this to do not get confused.

To the rest of the operations, we’ll have to see what symbol type we’re dealing, and like done with legends, we’ll have a set of functions to ask what symbol type we have.

#==========================================================
#
# Functions to dealing with basic symbol types
#
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import ISimpleFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IMarkerFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IPictureFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import ILineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import IPictureLineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IPictureMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import ISimpleMarkerSymbol
from org.gvsig.fmap.mapcontext.rendering.symbols import ITextSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text import ISimpleTextSymbol

def getSymbolName(symbol):
  return symbol.getClass().getSimpleName()

def isFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IFillSymbol.html
  return isinstance(symbol,ISimpleFillSymbol)

def isMarkerFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IMarkerFillSymbol.html
  return isinstance(symbol,IMarkerFillSymbol)

def isPictureFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IPictureFillSymbol.html
  return isinstance(symbol,IPictureFillSymbol)

def isLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/ILineSymbol.html
  return isinstance(symbol,ILineSymbol)

def isPictureLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/IPictureLineSymbol.html
  return isinstance(symbol,IPictureLineSymbol)

def isMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IMarkerSymbol.html
  return isinstance(symbol,IMarkerSymbol)

def isPictureMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IPictureMarkerSymbol.html
  return isinstance(symbol,IPictureMarkerSymbol)

def isSimpleMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/ISimpleMarkerSymbol.html
  return isinstance(symbol,ISimpleMarkerSymbol)

def isTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/symbols/ITextSymbol.html
  return isinstance(symbol,ITextSymbol)

def isSimpleTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/text/ISimpleTextSymbol.html
  return isinstance(symbol,ISimpleTextSymbol)

So we can do things like:

layer = currentLayer()
legend = layer.getLegend()
if isSingleSymbolLegend(legend):
  symbol = getDefaultSymbol()
  if isFillSymbol(symbol):
    print symbol.getFillColor()

With this, more or less we can start to investigate about what a legend offers to us, but one of the questions shown to us is How do we know what symbol is applied to each geometry?

The question has an answer easy and other hard. We’re gonna stay with the easy. To the legend we can ask what symbol is applied to a feature, getSymbolByFeature(). For example, we could do something like:

layer = currentLayer()
legend = layer.getLegend()
print 
print "Each feature symbols:"
for feature in layer.features():
  # The following line, is a hack to access the object feature of java  
  # in gvSIG 2.1 probably will not be missed.
  feature = feature() 

  symbol = legend.getSymbolByFeature(feature)
  ...

Here what we do is travel all around layer’s features, and for each feature, we ask legend what symbol would be applied to that feature.

Well,  we’m not gonna linger no more, this is just the start point to those would interest start to prove it, and if there’s any doubts, you can ask by gvSIG users’s list.

We leave here a script “complete” where is all together. The script gets the view active and tries to dump the data console of the layer symbology.

The “complete”, is why we was not exhaustive in verifying  the legends types and symbols, but we think it’s enough to start.

See you.

from gvsig import *

def main():
  #
  # To prove it we uploaded in a view a layer:
  # http://downloads.gvsig.org/download/geodata/vector/SHP2D/provincias_andalucia.zip
  # We activated it and added a unique values legend.
  #
  # This code means to be a start point, it’s not ended.
  # Not just because legends are missing
  # In many points we let na "#ALL" indicating from here you are alone
  # However, we think it’s a good start point
  # To those who want to start manipulate legends from scripting.
  #
  # In functions isXXXX we let below goes the url to javadocs of the
  # corresponding class/interface. In those you’ll see methods 
  # each class has.
  #
  layer = currentLayer()
  print layer.getName()
  #
  # Function dumpLegend is below in this script.
  dumpLegend(layer.getLegend())

  # Well, with the code above, we can see how to access information of the 
  # legend, but if we want to know what symbol corresponds with each layer element
  # we can do something like:

  legend = layer.getLegend()
  print 
  print "Each feature symbol:"
  for feature in layer.features():
  # The following line, is a hack to access the object feature of java
  # in gvSIG 2.1 probably will not be missed.
    feature = feature() 

    print feature.get(0), "(", feature.toString() ,")"
    dumpSymbol( legend.getSymbolByFeature(feature) )

#==========================================================
#
# And here is the code to do a dump in text of the 
# legend and symbols. It’s not exhaustive and surely it can be 
# improved but will Worth to see where to consult
# legend values and symbols.
#
def dumpLegend(legend):
  print getLegendName(legend)

  if isSingleSymbolLegend(legend) :
    # This legend has an unique symbol applied to all 
    # geometries.
    dumpSymbol(legend.getDefaultSymbol())
    return 

  if isClassifiedVectorLegend(legend):
    print "- Classification fields: ", legend.getClassifyingFieldNames()

  if isClassifiedLegend(legend):
    # If it is a classified legend will return a symbols list
    print "- Símbolos:"
    for symbol in legend.getSymbols():
      dumpSymbol(symbol)
      print 
    print "- Descriptions:", legend.getDescriptions()
    print "- Values:", legend.getValues()

  # Now we prove if it is another legend type, that could
  # or not be classified.
  if isVectorialIntervalLegend(legend) :
    # TODO
    print "Legend codifying missing (",getLegendName(legend),")"

  elif isVectorialUniqueValueLegend(legend) :
    # It is a classified legend with some
    # more values.
    print "- colorScheme: ", legend.getColorScheme()

  else:
    print "Don’t know what to do with this legend"

def dumpSymbol(symbol, indentacion=1, selection=False):
  spaces=("  "*indentacion)
  print spaces,"- name: ", getSymbolName(symbol)
  #
  # Attributes we can find in all symbols
  print spaces,"- description: ", symbol.getDescription()
  print spaces,"- color: ", symbol.getColor()
  print spaces,"- symbolForSelection: ", symbol.getSymbolForSelection()
  if not symbol.getSymbolForSelection() is None and not selection: 
    # We call dumpSymbol setting selection on true to avoid getting 
    # confused.

    # We comment it at the moment to avoid a large output on tests
    #dumpSymbol(symbol.getSymbolForSelection(),indentacion+1, selection=True)
    pass
  #
  # The remaining depend on symbol type
  # Careful, there’s no "else"s because can exist symbols that
  # are of many type at a time.
  #
  if isFillSymbol(symbol):
    print spaces,"- hasFill: ", symbol.hasFill()
    print spaces,"- hasOutline: ", symbol.hasOutline()
    print spaces,"- fillAlpha: ", symbol.getFillAlpha()
    print spaces,"- fillColor: ", symbol.getFillColor()
    print spaces,"- outline: ", symbol.getOutline()
    if not symbol.getOutline() is None : 
      # We comment it at the moment to avoid a large output on tests
      #dumpSymbol(symbol.getOutline(),indentacion+1, selection)
      #dumpSymbol(symbol.getOutline(),indentacion+1, selection)
      pass

  if isMarkerFillSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isPictureFillSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isLineSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isPictureLineSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isMarkerSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isPictureMarkerSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isSimpleMarkerSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isTextSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

  if isSimpleTextSymbol(symbol):
    # ALL
    print spaces, "Symbol dump codifying missing (", getSymbolName(symbol),")"

#==========================================================
#
# Basic types of legends functions
#
from org.gvsig.fmap.mapcontext.rendering.legend import ISingleSymbolLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialIntervalLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialUniqueValueLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedVectorLegend

def getLegendName(legend):
  return legend.getClass().getSimpleName()

def isSingleSymbolLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/ISingleSymbolLegend.html
  return isinstance(legend,ISingleSymbolLegend)

def isVectorialIntervalLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialIntervalLegend.html
  return isinstance(legend,IVectorialIntervalLegend)

def isVectorialUniqueValueLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialUniqueValueLegend.html
  return isinstance(legend,IVectorialUniqueValueLegend)

def isClassifiedLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedLegend.html
  return isinstance(legend,IClassifiedLegend)

def isClassifiedVectorLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedVectorLegend.html
  return isinstance(legend,IClassifiedVectorLegend)

#==========================================================
#
# Basic types of symbols functions
#
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import ISimpleFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IMarkerFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IPictureFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import ILineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import IPictureLineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IPictureMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import ISimpleMarkerSymbol
from org.gvsig.fmap.mapcontext.rendering.symbols import ITextSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text import ISimpleTextSymbol

def getSymbolName(symbol):
  return symbol.getClass().getSimpleName()

def isFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IFillSymbol.html
  return isinstance(symbol,ISimpleFillSymbol)

def isMarkerFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IMarkerFillSymbol.html
  return isinstance(symbol,IMarkerFillSymbol)

def isPictureFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IPictureFillSymbol.html
  return isinstance(symbol,IPictureFillSymbol)

def isLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/ILineSymbol.html
  return isinstance(symbol,ILineSymbol)

def isPictureLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/IPictureLineSymbol.html
  return isinstance(symbol,IPictureLineSymbol)

def isMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IMarkerSymbol.html
  return isinstance(symbol,IMarkerSymbol)

def isPictureMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IPictureMarkerSymbol.html
  return isinstance(symbol,IPictureMarkerSymbol)

def isSimpleMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/ISimpleMarkerSymbol.html
  return isinstance(symbol,ISimpleMarkerSymbol)

def isTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/symbols/ITextSymbol.html
  return isinstance(symbol,ITextSymbol)

def isSimpleTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/text/ISimpleTextSymbol.html
  return isinstance(symbol,ISimpleTextSymbol)
Posted in community, development, english, gvSIG Desktop, scripting | Leave a comment

gvSIG Latin American Conference will be held in Brazil along with MundoGEO#Connect 2014

The 6th Latin American and Caribbean gvSIG Conference will be held next year in Brazil, along with MundoGEO#Connect LatinAmerica, Conference and Trade Fair of Geomatics and Geospatial Solutions, that will take place from May 7 thru 9 May at Frei Caneca Convention Center in Sao Paulo, Brazil.

“gvSIG Association is pleased in communicating this alliance with MundoGEO. A joint celebration of the Latin American and Caribbean gvSIG Conference with MundoGEO#Connect 2014 allows us to state that, during these days, it will be held the most important Geomatics event in Latin America in 2014, “said Alvaro Anguix, CEO of gvSIG Association. “This agreement is marked by a continuous collaboration between both institutions, under the premise of joining efforts and disseminating knowledge and technological capability of Latin America. The 6th Latin American and Caribbean gvSIG Conference website will be available soon, with information about the event”, added the Director.

Latin American and Caribbean gvSIG Conference will have its sixth edition held in Brazil highlighting new technology and products to be launched in 2014. As usual in gvSIG Conferences, participation in lectures and workshops will be free in order to gather the maximum number of users and participants of the large Latin American gvSIG community.

MundoGEO team is very optimistic about this alliance, which will strengthen both events and provide the gvSIG community with the opportunity to expand their connections, by contacting other attendees of the conference and also the visitors of the Geomatics Trade Fair“, says Granemann Emerson, director of MundoGE, the company that organizes MundoGEO#Connect.

The 6th Latin American and Caribbean gvSIG Conference website will be released soon with all the information about the event. MundoGEO#Connect LatinAmerica website is already available with photos, videos, news, testimonials, information about exhibitors, location, hosting, exhibition floor, MundoGEO#Connect Awards and also the conference schedule. Information on previous editions of gvSIG Conferences are available in http://www.gvsig.org/web/community/events/jornadas-lac.

Posted in english, events | Tagged | Leave a comment

Primera incursión en la simbología desde scripting en gvSIG 2.0

Hola a todos.

El otro día un compañero escribió en la lista de usuarios de gvSIG sobre un proyecto que estaba abordando en gvSIG y precisaba acceder desde scripting a la simbología de una capa.

En principio no se ha preparado nada en el API de scripting para acceder a la parte de simbología… bueno, creo que se añadieron un par de funciones para algo muy, muy, muy básico.

La cuestión es que precisaba exportar la configuración de la simbología que tenía aplicada a una serie de capas y me preguntó cómo podría hacerlo.

Como la respuesta no era “corta” y podría servir para más usuarios de gvSIG he pensado dejarlo caer aquí, en el blog de gvSIG, antes que únicamente en la lista de usuarios.

Bueno, al grano…

Acceder a la configuración de la leyenda de una capa es relativamente simple. basta con:

layer = currentLayer()
legend = layer.getLegend()

Y esto nos devolverá un objeto leyenda de gvSIG.

El problema es que en gvSIG las leyendas son registrables. Es decir, no existe una “Leyenda”, sino que los distintos plugins de gvSIG puede registrar varias leyendas. Esto hace que a priori sea bastante complicado saber a qué operaciones va a responder la leyenda que obtenemos con la invocación al getLegend().

Voy a centrarme con los tipos básicos de leyenda que van con gvSIG 2.0 (en gvSIG 2.1 se incluyen más tipos de leyenda, pero si es necesario ya hablaremos en otro momento de ellos).

Una clasificación podría ser:

  • Leyendas vectoriales (IVectorLegend)
  • Leyendas raster (IRaterLegend)

Pero de momento solo voy a hablar de las leyendas vectoriales.

Otra clasificación podría ser:

Cada tipo de leyenda ofrece una serie operaciones, así que lo primero que deberemos hacer es determinar con qué leyenda estamos trabajando. Para ello dejo aquí unas pequeñitas funcioncitas. Son muy simples, pero lo mejor es que si las necesitamos, y mientras no estén en la librería de scripting, que nos limitemos a pegar el bloque entero en nuestro script.

#==========================================================
#
# Funciones para manejo de los tipos basicos de leyendas
#
from org.gvsig.fmap.mapcontext.rendering.legend import ISingleSymbolLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialIntervalLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialUniqueValueLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedVectorLegend

def getLegendName(legend):
  return legend.getClass().getSimpleName()

def isSingleSymbolLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/ISingleSymbolLegend.html
  return isinstance(legend,ISingleSymbolLegend)

def isVectorialIntervalLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialIntervalLegend.html
  return isinstance(legend,IVectorialIntervalLegend)

def isVectorialUniqueValueLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialUniqueValueLegend.html
  return isinstance(legend,IVectorialUniqueValueLegend)

def isClassifiedLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedLegend.html
  return isinstance(legend,IClassifiedLegend)

def isClassifiedVectorLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedVectorLegend.html
  return isinstance(legend,IClassifiedVectorLegend)

No hace falta que se entienda mucho el código, nos bastará con saber que una vez incluido en nuestro script podremos saber si nuestra leyenda es de un tipo dado con algo como:

layer = currentLayer()
legend = layer.getLegend()
if isVectorialUniqueValueLegend(legend):
  print "La capa tiene una leyenda de valores unicos"

A falta de API y documentación en scripting para los tipos de leyenda, podemos ir a IVectorialUniqueValueLegend para consultar las operaciones o métodos que podemos usar. Bueno, con esta información accedemos al objeto leyenda de nuestra capa… pero… ¿y ahora qué?

En general, una leyenda contiene una definición de símbolos y una forma de consultar cómo obtener un símbolo dado para aplicarlo a una feature o linea de la tabla de datos asociada a la capa.

Por ejemplo, la leyenda de símbolo único (ISimgleSimbolLegend) tiene un método getDefaultSymbol() que nos devolverá el símbolo a aplicar a todas las features de nuestra capa, mientras que una leyenda vectorial clasificada tendrá un método getSymbols() que nos devolverá la lista de símbolos de esa leyenda. El problema con el que nos vamos a encontrar inmediatamente es que hay muchos tipos de símbolos, al igual que pasaba con las leyendas, y cada cual con sus operaciones o métodos. Así podemos encontrarnos:

A pesar de que hay distintos tipos de símbolos, todos responden a una serie de operaciones muy básicas como:

  • getDescription()
  • getColor()
  • getSymbolForSelection(), con este tened mucho cuidado que es muy fácil quedarse buclado.

Para el resto de operaciones, tendremos que averiguar de qué tipo de símbolo se trata, y al igual que he hecho con las leyendas, tendremos una serie de funciones para preguntar cuál es el tipo de símbolo que tenemos.

#==========================================================
#
# Funciones para manejo de los tipos básicos de símbolos
#
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import ISimpleFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IMarkerFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IPictureFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import ILineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import IPictureLineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IPictureMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import ISimpleMarkerSymbol
from org.gvsig.fmap.mapcontext.rendering.symbols import ITextSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text import ISimpleTextSymbol

def getSymbolName(symbol):
  return symbol.getClass().getSimpleName()

def isFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IFillSymbol.html
  return isinstance(symbol,ISimpleFillSymbol)

def isMarkerFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IMarkerFillSymbol.html
  return isinstance(symbol,IMarkerFillSymbol)

def isPictureFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IPictureFillSymbol.html
  return isinstance(symbol,IPictureFillSymbol)

def isLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/ILineSymbol.html
  return isinstance(symbol,ILineSymbol)

def isPictureLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/IPictureLineSymbol.html
  return isinstance(symbol,IPictureLineSymbol)

def isMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IMarkerSymbol.html
  return isinstance(symbol,IMarkerSymbol)

def isPictureMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IPictureMarkerSymbol.html
  return isinstance(symbol,IPictureMarkerSymbol)

def isSimpleMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/ISimpleMarkerSymbol.html
  return isinstance(symbol,ISimpleMarkerSymbol)

def isTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/symbols/ITextSymbol.html
  return isinstance(symbol,ITextSymbol)

def isSimpleTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/text/ISimpleTextSymbol.html
  return isinstance(symbol,ISimpleTextSymbol)

Entonces podremos hacer cosas como:

layer = currentLayer()
legend = layer.getLegend()
if isSingleSymbolLegend(legend):
  symbol = getDefaultSymbol()
  if isFillSymbol(symbol):
    print symbol.getFillColor()

Con esto mas o menos ya podemos empezar a investigar sobre qué nos ofrece una leyenda, pero una de las preguntas que nos haremos llegados hasta aquí es ¿Y cómo sé qué símbolo se aplica a cada geometría?

La pregunta tiene una respuesta fácil y otra compleja. Nos vamos a quedar con la fácil. A la leyenda podemos preguntarle qué símbolo aplica dada una feature, getSymbolByFeature(). Por ejemplo, podríamos hacer algo como:

layer = currentLayer()
legend = layer.getLegend()
print 
print "Símbolos de cada feature:"
for feature in layer.features():
  # La siguiente linea, es un hack para acceder al objeto feature de java
  # en gvSIG 2.1 probablemente no hará falta.
  feature = feature() 

  symbol = legend.getSymbolByFeature(feature)
  ...

Aquí lo que hacemos es recorrernos las features de la capa, y para cada feature, le preguntamos a la leyenda cuál seria el símbolo que aplica a esa feature.

Bueno, no me voy a extender más, esto es solo el punto de partida para que a quien le interese pueda empezar a hacer pruebas, y si tiene dudas, puede preguntar por la lista de usuarios de gvSIG.

Dejo aquí un script “completo”, jejeje, donde esta todo esto junto. El script coge la capa activa e intenta hacer un volcado por la consola de los datos de la simbología de la capa.

Lo de “completo”, es por que no he sido exhaustivo en la verificación de los tipos de leyenda y símbolos, pero creo que es suficiente lo que hay para ir empezando.

Hasta la próxima.

from gvsig import *

def main():
  #
  # Para hacer las pruebas he cargado en una vista la capa:
  # http://downloads.gvsig.org/download/geodata/vector/SHP2D/provincias_andalucia.zip
  # La he puesto activa y le añadido una leyenda de valores únicos.
  #
  # El código pretende ser un punto de partida, y no está acabado.
  # No solo por que falten leyendas por tener en cuenta, si no porque
  # en muchos puntos he dejado un "#TODO" indicando que por ahí tenéis
  # que continuar vosotros. Sin embargo, creo que es un buen punto de partida
  # para alguien que quiera empezar a ver de manipular leyendas desde scripting.
  #
  # En las funciones isXXXX que hay más abajo he dejado la url a los javadocs de
  # la clase/interface correspondiente. En ellos podéis ver los métodos que tiene
  # cada clase.
  #
  layer = currentLayer()
  print layer.getName()
  #
  # La función dumpLegend está más abajo en este script.
  dumpLegend(layer.getLegend())

  # Bueno, con el código de arriba, podemos ver como acceder a la información de la 
  # leyenda, pero si queremos saber que símbolo se corresponde con que elemento de la capa
  # podemos hacer algo como:

  legend = layer.getLegend()
  print 
  print "Simbolos de cada feature:"
  for feature in layer.features():
    # La siguiente línea, es un hack para acceder al objeto feature de java
    # en gvSIG 2.1 probablemente no hará falta.
    feature = feature() 

    print feature.get(0), "(", feature.toString() ,")"
    dumpSymbol( legend.getSymbolByFeature(feature) )

#==========================================================
#
# Y aquí estaría el código para hacer un volcado en texto de la 
# leyenda y los símbolos. No es exhaustivo y seguramente se puede
# mejorar pero valdrá para ver por donde se puede consultar los
# valores de la leyenda y los símbolos.
#
def dumpLegend(legend):
  print getLegendName(legend)

  if isSingleSymbolLegend(legend) :
    # Esta leyenda tiene un único símbolo que se aplica a todas
    # las geometrias.
    dumpSymbol(legend.getDefaultSymbol())
    return 

  if isClassifiedVectorLegend(legend):
    print "- Campos de clasificacion: ", legend.getClassifyingFieldNames()

  if isClassifiedLegend(legend):
    # Si es una leyenda clasificada tendrá una lista de símbolos
    print "- Símbolos:"
    for symbol in legend.getSymbols():
      dumpSymbol(symbol)
      print 
    print "- Descripciones:", legend.getDescriptions()
    print "- Valores:", legend.getValues()

  # Ahora comprobamos si se trata de otros tipos de leyenda, que pueden
  # ser o no clasificadas.
  if isVectorialIntervalLegend(legend) :
    # TODO
    print "Falta por codificar la leyenda (",getLegendName(legend),")"

  elif isVectorialUniqueValueLegend(legend) :
    # Es una leyenda clasificada (ClassifiedLegend) con algunos
    # valores más. 
    print "- colorScheme: ", legend.getColorScheme()

  else:
    print "No se qué hacer con esta leyenda"

def dumpSymbol(symbol, indentacion=1, selection=False):
  spaces=("  "*indentacion)
  print spaces,"- name: ", getSymbolName(symbol)
  #
  # Atributos que podemos encontrar en todos los símbolos
  print spaces,"- description: ", symbol.getDescription()
  print spaces,"- color: ", symbol.getColor()
  print spaces,"- symbolForSelection: ", symbol.getSymbolForSelection()
  if not symbol.getSymbolForSelection() is None and not selection: 
    # Llamamos a dumpSymbol poniendo selección a true para evitar que se 
    # quede bucleado.

    # Lo comento de momento para evitar una salida tan larga en las pruebas
    #dumpSymbol(symbol.getSymbolForSelection(),indentacion+1, selection=True)
    pass
  #
  # El resto de atributos dependen del tipo de símbolo
  # Cuidado, no hay "else"s ya que pueden haber símbolos que
  # sean de varios tipos a la vez.
  #
  if isFillSymbol(symbol):
    print spaces,"- hasFill: ", symbol.hasFill()
    print spaces,"- hasOutline: ", symbol.hasOutline()
    print spaces,"- fillAlpha: ", symbol.getFillAlpha()
    print spaces,"- fillColor: ", symbol.getFillColor()
    print spaces,"- outline: ", symbol.getOutline()
    if not symbol.getOutline() is None : 
      # Lo comento de momento para evitar una salida tan larga en las pruebas
      #dumpSymbol(symbol.getOutline(),indentacion+1, selection)
      pass

  if isMarkerFillSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isPictureFillSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isLineSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isPictureLineSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isMarkerSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isPictureMarkerSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isSimpleMarkerSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isTextSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

  if isSimpleTextSymbol(symbol):
    # TODO
    print spaces, "Falta por codificar el volcado del simbolo (", getSymbolName(symbol),")"

#==========================================================
#
# Funciones para manejo de los tipos básicos de leyendas
#
from org.gvsig.fmap.mapcontext.rendering.legend import ISingleSymbolLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialIntervalLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IVectorialUniqueValueLegend
from org.gvsig.fmap.mapcontext.rendering.legend import IClassifiedVectorLegend

def getLegendName(legend):
  return legend.getClass().getSimpleName()

def isSingleSymbolLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/ISingleSymbolLegend.html
  return isinstance(legend,ISingleSymbolLegend)

def isVectorialIntervalLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialIntervalLegend.html
  return isinstance(legend,IVectorialIntervalLegend)

def isVectorialUniqueValueLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IVectorialUniqueValueLegend.html
  return isinstance(legend,IVectorialUniqueValueLegend)

def isClassifiedLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedLegend.html
  return isinstance(legend,IClassifiedLegend)

def isClassifiedVectorLegend(legend):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/legend/IClassifiedVectorLegend.html
  return isinstance(legend,IClassifiedVectorLegend)

#==========================================================
#
# Funciones para manejo de los tipos básicos de símbolos
#
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import ISimpleFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IMarkerFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill import IPictureFillSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import ILineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line import IPictureLineSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import IPictureMarkerSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker import ISimpleMarkerSymbol
from org.gvsig.fmap.mapcontext.rendering.symbols import ITextSymbol
from org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text import ISimpleTextSymbol

def getSymbolName(symbol):
  return symbol.getClass().getSimpleName()

def isFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IFillSymbol.html
  return isinstance(symbol,ISimpleFillSymbol)

def isMarkerFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IMarkerFillSymbol.html
  return isinstance(symbol,IMarkerFillSymbol)

def isPictureFillSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/fill/IPictureFillSymbol.html
  return isinstance(symbol,IPictureFillSymbol)

def isLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/ILineSymbol.html
  return isinstance(symbol,ILineSymbol)

def isPictureLineSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/line/IPictureLineSymbol.html
  return isinstance(symbol,IPictureLineSymbol)

def isMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IMarkerSymbol.html
  return isinstance(symbol,IMarkerSymbol)

def isPictureMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/IPictureMarkerSymbol.html
  return isinstance(symbol,IPictureMarkerSymbol)

def isSimpleMarkerSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/marker/ISimpleMarkerSymbol.html
  return isinstance(symbol,ISimpleMarkerSymbol)

def isTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.fmap.mapcontext.api/2.0.18/org.gvsig.desktop.compat.cdc/org.gvsig.fmap.mapcontext/org.gvsig.fmap.mapcontext.api/apidocs/org/gvsig/fmap/mapcontext/rendering/symbols/ITextSymbol.html
  return isinstance(symbol,ITextSymbol)

def isSimpleTextSymbol(symbol):
  # https://devel.gvsig.org/sites/org.gvsig.symbology.lib.api/2.0.18/org.gvsig.desktop.library/org.gvsig.symbology/org.gvsig.symbology.lib/org.gvsig.symbology.lib.api/apidocs/org/gvsig/symbology/fmap/mapcontext/rendering/symbol/text/ISimpleTextSymbol.html
  return isinstance(symbol,ISimpleTextSymbol)
Posted in gvSIG Desktop, scripting, spanish | 1 Comment

Las 6as Jornadas de Latinoamérica y Caribe se unen a las Jornadas MundoGEO#Connect

Aún con la resaca de las 9as Jornadas Internacionales de gvSIG y ya hablando otra vez de eventos gvSIG. La ocasión lo merece.

La pasada semana se anunció que dos de los eventos más importantes del ámbito GEO en Latinoamérica y Caribe unen fuerzas, celebrando del 7 al 9 de mayo de 2014, en São Paulo, la que puede convertirse en la cita de referencia para el próximo año.

Sin duda esta colaboración permitirá reforzar ambos eventos y reunir en unos pocos días a un gran número de especialistas de la geomática de los más diversos países de Latinoamérica y Caribe.

Otro paso más para divulgar el modelo de desarrollo defendido por el proyecto y la Asociación gvSIG, enmarcado en un proceso de apropiación y soberanía tecnológica de los pueblos de Latinoamérica presente en la agenda regional, como nuevamente quedó demostrado en la última Cumbre de Jefes de Estado de Mercosur, realizada en Montevideo el pasado 12 de julio.

En este sentido, el artículo 45 de la declaración conjunta expresa lo siguiente:

Apoyaron el desarrollo de software libre, que permitirá potenciar el desarrollo regional de soluciones en materia de Tecnología de la Información y las Comunicaciones (TICs), a fin de lograr una verdadera apropiación, promoción del libre conocimiento y transferencia tecnológica, reduciendo la dependencia de soluciones provistas por trasnacionales del sector o por empresas no dispuestas a respetar las industrias nacientes de la región.

Afirmaron el interés de promover el uso de software libre en los programas nacionales destinados a la inclusión digital.

Ratificaron la necesidad de impulsar y fomentar la concreción de normas a nivel del MERCOSUR para la efectiva implementación de políticas de fomento de uso, desarrollo, implementación, investigación y transferencia tecnológica basados en el modelo de software libre.”

Desde ya convocamos a todos los interesados en geomática libre a las 6as Jornadas de Latinoamérica y Caribe de gvSIG. En breve iremos ampliando información tanto desde la que será la web de las Jornadas LAC de gvSIG como desde la web de MundoGEO#Connect.

Posted in events, spanish | Leave a comment

Acabaron las 9as Jornadas Internacionales de gvSIG…

Del miércoles al viernes pasado tuvieron lugar las 9as Jornadas Internacionales de gvSIG, jornadas que no podemos más que calificarlas de un absoluto éxito.

Éxito de asistencia, con sesiones en las que casi era imposible encontrar un asiento libre.

Éxito de ponencias, donde el nivel medio de calidad ha sido altísimo; es un gran motivo de satisfacción, ver como el proyecto gvSIG avanza a la par que sus usuarios.

Éxito en cuanto a la gran amplitud de temas y geografías, con ponencias de varios países, asistentes de casi una veintena y temáticas que iban del sector petrolero a la gestión municipal, pasando por los más diversos sectores de uso de información geográfica.

Éxito de transferencia de conocimiento, con cuatro excelentes talleres sobre scripting, geomarketing, catastro y medio ambiente.

Y éxito, principalmente, por el ambiente de colaboración que se respiraba, por las ganas de participar en un proyecto de construcción colectiva como es gvSIG.

Desde la Asociación gvSIG no podemos más que agradecer a todos los que hacéis posible este tipo de jornadas: patrocinadores, colaboradores, medios asociados, ponentes, asistentes, profesores de talleres, equipo de organización. Jornadas que son la mejor muestra de la fortaleza del proyecto gvSIG.

Y como una imagen vale más que mil palabras, os dejamos con una muestra representativa de las Jornadas:

IMG_0201

IMG_0049IMG_0173IMG_0378IMG_0345IMG_0299IMG_0258IMG_0291

Posted in events, spanish | 3 Comments

Actualización talleres 9as Jornadas gvSIG

Se han puesto a disposición nuevos recursos necesarios para la realización de algunos de los talleres que se impartirán en las 9as Jornadas gvSIG.

Taller de geomarketing (miércoles 27, 15:30h)

Estos son los tutoriales que se usarán en el taller:

También os informamos que para la realización del taller es necesario tener instalado el plugin de análisis de redes (graph), el cual se puede instalar desde el administrador de complementos de gvSIG, conectando con el siguiente repositorio según la versión de gvSIG (instalación desde URL):

Se recomienda traerlo previamente instalado.

Taller de scripting (jueves 28, 15:30h)

Ya están disponibles los scripts que se utilizarán en el taller:

Taller de cartografía catastral (viernes 29, 9:30h)

Tutoriales que se usarán en el taller:

  1. Consulta de datos catastrales.
  2. Descarga de cartografía catastral en formato SHP.
  3. Descarga de cartografía catastral en formato DXF.
  4. Visualización de datos catastrales.
  5. Callejero.
  6. Mapa de cultivo.
  7. Cartografía Alhama.
Posted in events, gvSIG Desktop, opinion, spanish | Leave a comment

Coming soon: Additional options when exporting to KML

La opción de exportar una capa a KML permitirá las siguientes opciones:

  • Globos con los atributos. El archivo resultante mostrará en un globo una tabla con los atributos del elemento (generalmente cuando el usuario pinche sobre el elemento)
  • Etiquetas. Si la capa tiene activado el etiquetado, se mostrarán las etiquetas sobre el elemento (sin que el usuario tenga que pinchar)
  • Forzar reproyección a EPSG:4326. Aunque la vista no esté en este sistema de coordenadas, el KML resultante se reproyectará para ser visualizado correctamente en Google Earth/Maps.

Este breve vídeo muestra las opciones y un par de archivos de salida:

The export-to-KML option will provide the following options:

  • Balloons with attribute values. The resulting file will show attribute values inside a balloon (usually when the user clicks on each feature.)
  • Labels. If labels are enabled in the source vector layer, then they will be shown as floating texts using the default format in KML files.
  • Conversion to EPSG:4326. Even if the view is not in EPSG:4326, this option will create a KML file in EPSG:4326 (standard CRS for KML files, so it will be correctly visualized in Google Earth/Maps).

This short video shows these options and a couple output files:

Posted in development, english, gvSIG Desktop, gvSIG development, spanish | Tagged , , | 1 Comment

9as Jornadas gvSIG: taller de geomarketing.

El próximo jueves 28 miércoles 27 de noviembre y con motivo de las 9as Jornadas Internacionales de gvSIG se impartirá un taller de geomarketing.

Como muchos de vosotros sabréis, el geomarketing consiste en aplicar las herramientas de análisis de los Sistemas de Información Geográfica en el campo de las estrategias comerciales. Algunos de los casos de uso que resuelve el geomarketing son:

  • Ubicación óptima de un determinado tipo de comercio o servicio.
  • Análisis de viabilidad de un determinado tipo de comercio o servicio en una determinada ubicación.
  • Detección de zonas desabastecidas por una determinada red de comercios o servicios.
  • Cálculo de rutas óptimas para visitas comerciales.
  • Cálculo de áreas de servicio en base a distancias o tiempos de recorrido.

En el taller se mostrarán algunos de los geoprocesos de gvSIG que se utilizan habitualmente en esta disciplina para resolver los casos de uso mencionados. En concreto se abordarán los siguientes casos prácticos:

  1. Identificación de zonas mal abastecidas por la actual red de oficinas de correos.
  2. Identificación de la localización óptima para la implantación de una frutería.

Requisitos:

  • Software: Los ejercicios se podrán realizar indistintamente con gvSIG 1.11 o con gvSIG 1.12
  • Cartografía: Los datos necesarios para seguir los ejercicios que se plantearán en el taller se pueden descargar desde el siguiente enlace.

El taller tendrá lugar el jueves 28 miércoles 27 de noviembre a las 15:30h en el Centro Cultural y Deportivo La Pechina de Valencia, España. La inscripción es gratuita (aforo limitado).

Posted in events, gvSIG Desktop, opinion, spanish | 10 Comments

Basuras y TIC

Basuras: Desde hace unos días y en la ciudad de Madrid, los profesionales encargados de las tareas de recogida de residuos y de jardinería están en Huelga. Éste es un servicio que la ciudad de Madrid privatizó hará unos 15 años aproximadamente, bajo el principio, por todos conocidos, de que los servicios privatizados funcionan mejor que los públicos. Como no, si no paran de repetir el mismo mantra. ¿Qué hace la administración? Publicar una licitación para que las empresas concursen. ¿Y que pasó? Pues como hay que ser competitivos, sobre un presupuesto de licitación, imagino que ya ajustado, las empresas que ganaron el contrato hicieron un 33% de rebaja y claro, ahora los números no salen y manejan la eficiente propuesta de despedir a más de de mil trabajadores o sólo a 600 y que los demás se bajen el sueldo, aumenten las horas de trabajo, disminuyan sus derechos, etc. ¿Y la responsabilidad de la administración?

TIC:  Hará pocos meses, me contaron que en una reunión en una administración pública dónde hablaban del futuro TIC,  detectaron lo que parecía la nueva orientación en el sector y su explicación. Ésta consistía en determinar que esto de las TIC se mueve a gran rapidez, cáspita que descubrimiento, y que es evidente que lo que no resulta rentable en términos económicos es mantener una linea formativa entre los empleados públicos que garantice que no queden descolgados de la evolución del sector TIC, sino que lo eficiente era externalizar, eufemismo de privatizar, las necesidades TIC, porque como todo el mundo sabe, el mercado ya se encargará de proveer soluciones punteras en el plano tecnológico. ¿Qué sobre los presupuestos de licitación ya ajustados las empresas deberán hacer grandes bajas, tipo subasta? Eso desde el punto de visto de cierto modelo de administración es bueno, el mercado es sabio y la administración no ha de entrar a valorar si con esos precios hora que resulten es posible o no contratar a personal cualificado que nos permita seguir la línea de evolución en el sector TIC. Y si sucede eso. ¿La responsabilidad de la administración?

Mezcla: En ambos casos tenemos a colectivos profesionales abocados a suertes similares. Estoy seguro que muchos estaréis pensando en escenarios similares en diferentes ámbitos de profesionales , al menos en España, que es la realidad que más conozco. ¿La responsabilidad de la administración?

Posted in opinion | 1 Comment