<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GIS &#38; Chips</title>
	<atom:link href="http://www.gisandchips.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gisandchips.org</link>
	<description>Geografía útil para llevar</description>
	<lastBuildDate>Fri, 23 Mar 2012 17:52:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Geomondrian: un servidor OLAP con soporte espacial</title>
		<link>http://www.gisandchips.org/2012/03/23/geomondrian-un-servidor-olap-con-soporte-espacial/</link>
		<comments>http://www.gisandchips.org/2012/03/23/geomondrian-un-servidor-olap-con-soporte-espacial/#comments</comments>
		<pubDate>Fri, 23 Mar 2012 17:51:02 +0000</pubDate>
		<dc:creator>jpiera</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Geomondrian]]></category>
		<category><![CDATA[OLAP]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=2066</guid>
		<description><![CDATA[OLAP es el acrónimo en inglés de procesamiento analítico en línea (On-Line Analytical Processing). Es una solución utilizada en el campo de la llamada Inteligencia Artificial (o Business Intelligence) cuyo objetivo es agilizar la consulta de grandes cantidades de datos (Wikipedia). El objetivo es generar tablas, gráficas u otro tipo de documentos que puedan ser [...]]]></description>
			<content:encoded><![CDATA[<p>OLAP es el acrónimo en inglés de <em>procesamiento analítico en línea</em> (<em>On-Line Analytical Processing</em>). Es una solución utilizada en el campo de la llamada Inteligencia Artificial (o <em>Business Intelligence</em>) cuyo objetivo es agilizar la consulta de grandes cantidades de datos (<a href="http://es.wikipedia.org/wiki/OLAP"><em>Wikipedia</em></a>). El objetivo es generar tablas, gráficas u otro tipo de documentos que puedan ser usados para facilitar la toma de decisiones.</p>
<p><a href="http://www.spatialytics.org/projects/geomondrian/"><em></em>Geomondrian</a> es un servidor OLAP con soporte espacial, lo que permite utilizar la componente espacial a la hora de realizar consultas en el almacén.</p>
<p>Este artículo describe los pasos necesarios que hay que realizar para instalar y probar un servidor <em>Geomondrian</em>  en un computador. El objetivo no es tener un sistema en producción, sino que se pueda instalar fácilmente el sistema y se pueda &#8220;jugar&#8221; un poco para ver la potencia que puede llegar a tener.</p>
<p><span id="more-2066"></span></p>
<h2>Instalación</h2>
<p>Partimos de una máquina con una Ubuntu 11.10 de 64 bits. Instalamos el <em>Tomcat 6</em> en <em>Ubuntu</em>. Para ello ejecutamos el siguiente comando:</p>
<pre class="brush: bash; title: ; notranslate">
sudo apt-get install tomcat6 tomcat6-admin
</pre>
<p>Editamos el fichero <em>/etc/tomcat6/tomcat-users.xml</em> y añadimos el usuario <em>admin</em> con contraseña <em>admin</em>:</p>
<pre class="brush: xml; title: ; notranslate">
 &lt;role rolename=&quot;manager&quot;/&gt;
 &lt;role rolename=&quot;admin&quot;/&gt;
 &lt;user username=&quot;admin&quot; password=&quot;admin&quot; roles=&quot;manager,admin&quot;/&gt;
</pre>
<p>Reiniciamos el tomcat:</p>
<pre class="brush: bash; title: ; notranslate">
sudo /etc/init.d/tomcat6 restart
</pre>
<p>En este punto ya tenemos una instancia de <em>Tomcat</em> corriendo en nuestra máquina junto con la aplicación de administración que se va a utilizar para instalar el <em>Geomondrian</em>.</p>
<p>Descargamos el <em>Geomondrian 1.0</em> desde su <a href="http://sourceforge.net/projects/geomondrian/files/geomondrian-1.x/1.0/geomondrian.war/download">página web</a>. Se trata de un archivo con extensión war, que puede ser fácilmente desplegado en <em>Tomcat</em>.</p>
<p>Abrimos un navegador y vamos a la página de administración de <em>Tomcat</em> (http://localhost:8080/manager/html). La primera vez que accedemos tenemos que escribir el nombre de usuario y la contraseña que hemos creado previamente.</p>
<p>Buscamos la opción <em>WAR file to deploy</em> y seleccionamos el archivo <em>geomondrian.war</em> que nos hemos descargado previamente. A continuación hacemos click en <em>deploy</em>.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2074" src="http://www.gisandchips.org/wp-content//geomondrian-war2.png" alt="" width="434" height="314" /></p>
<p>Si todo ha ido bien aparecerá una nueva entrada en la lista de aplicaciones que tiene el Tomcat instaladas:</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2075" src="http://www.gisandchips.org/wp-content//installed.png" alt="" width="434" height="314" /></p>
<p>Hacemos click en el enlace o bien escribimos la url http://localhost:8080/geomondrian/ y ya podemos acceder a la ventana principal del <em>Geomondrian</em>.</p>
<p>Por defecto la aplicación incluye una base de datos embebida que contiene algunos ejemplos sin información espacial. En la web de <em>Geomondrian</em> hay un script de creación de una base de datos con información espacial pero se trata de una base de datos <em>Postgis</em>, por lo que tenemos que instalar previamente <em>Postgres</em> y <em>Postgis</em>.</p>
<p>Para ello ejecutamos desde una consola el siguiente comando:</p>
<pre class="brush: bash; title: ; notranslate">
 sudo apt-get -install postgresql-9.1 postgresql-contrib-9.1 postgis postgresql-9.1-postgis
 </pre>
<p>Cambiamos el password del usuario <em>postgres</em> a <em>postgres</em>.</p>
<pre class="brush: bash; title: ; notranslate">
 sudo -u postgres psql
 postgres=# ALTER USER postgres WITH ENCRYPTED password 'postgres';
 </pre>
<p>A continuación vamos a crear una base de datos plantilla y vamos a instalar <em>Postgis</em> en ella.</p>
<pre class="brush: bash; title: ; notranslate">
sudo su postgres
createdb postgistemplate
psql -d postgistemplate -f /usr/share/postgresql/9.1/contrib/postgis-1.5/postgis.sql
psql -d postgistemplate -f /usr/share/postgresql/9.1/contrib/postgis-1.5/spatial_ref_sys.sql
</pre>
<p>Una vez que ya tenemos la base de datos plantilla con todas las funciones de <em>Postgis</em> instaladas vamos a crear una base de datos a partir de esta plantilla que será usada por el <em>Geomondrian</em>.</p>
<pre class="brush: bash; title: ; notranslate">
 createdb -T postgistemplate simple_geofoodmart
 </pre>
<p>Ahora vamos a instalar el script creación de la base de datos OLAP que hemos tenido que <a href="http://sourceforge.net/projects/geomondrian/files/geomondrian-1.x/1.0/simple_geofoodmart_sql_postgres.zip/downloadhttp://">descargar</a> previamente desde la web de <em>Geomondrian</em>. Una vez descargado, vamos al directorio donde lo hemos descargado y ejecutamos lo siguiente:</p>
<pre class="brush: bash; title: ; notranslate">
 psql -h localhost -U postgres -W -d simple_geofoodmart -f simple_geofoodmart.sql
 </pre>
<p>A continuación tenemos que editar la cadena de conexión para que el <em>Geomondrian</em> pueda conectar con la base de datos espacial. Para ello abrimos el fichero <em>/var/lib/tomcat6/webapps/geomondrian/WEB-INF/web.xml</em>, buscamos el servlet <em>GeoMDXQueryServlet</em> y editamos la propiedad <em>conectString</em>:</p>
<pre class="brush: xml; title: ; notranslate">
 &lt;servlet&gt;
 &lt;servlet-name&gt;GeoMDXQueryServlet&lt;/servlet-name&gt;
 &lt;servlet-class&gt;
 mondrian.web.servlet.MdxQueryServlet
 &lt;/servlet-class&gt;
 &lt;init-param&gt;
 &lt;param-name&gt;connectString&lt;/param-name&gt;
 &lt;param-value&gt;Provider=mondrian;Jdbc=jdbc:postgresql_postGIS://localhost/simple_geofoodmart?user=postgres&amp;amp;password=postgres;Catalog=/WEB-INF/queries/simple_geofoodmart.xml;JdbcDrivers=org.postgis.DriverWrapper;&lt;/param-value&gt;
 &lt;/init-param&gt;
 &lt;/servlet&gt;
 </pre>
<p>Llegados a este punto ya tenemos un servidor SOLAP en funcionamiento que está conectado con una base de datos con soporte espacial.</p>
<h2>Estructura de la base de datos</h2>
<p style="text-align: left">Antes de empezar a probar la base de datos, hay que entenderla. Existe poca información en la web sobre la estructura de la misma, pero se puede consultar el xml que utiliza el <em>Geomondrian</em> para explotarla que se encuentra en el fichero <em>/var/lib/tomcat6/webapps/geomondrian/WEB-INF/queries/simple_geofoodmart.xml</em>.</p>
<p>Se trata de una base de datos de ventas de supermercados que tiene un único cubo Ventas (Sales) para el que se han definido 5 dimensiones: Tienda (Store), Producto (Product), Promociones (Promotions), Clientes (Customers) y Tiempo (Time). El objetivo es estudiar las ventas en función de estas dimensiones:</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2078" src="http://www.gisandchips.org/wp-content//cubos.png" alt="" width="504" height="335" /></p>
<p>El cubo ventas, tiene 3 medidas que son Ventas (Store Sales), Coste (Store Cost) y Unidades (Unit Sales) que son las variables que van a ser estudiadas.</p>
<p>La dimensión Tienda establece una jerarquía espacial de objetos (Tienda -&gt; Ciudad -&gt;Estado -&gt; País) que tiene un atributo de tipo geométrico. Este atributo representa el polígono que describe el contorno del objeto y será estudiado en un apartado posterior.</p>
<h2>Consulta de la base de datos</h2>
<p>Desde la ventana principal del <em>Geomondrian</em>, hay que seleccionar la opción <em>JPivot pivot table with simple_geofoodmart spatial cube</em> para acceder a la consola de administración de  <em>Geomondrian</em> que contiene la base de datos espacial.</p>
<p>Lo primero que se muestra es una ventana en la que se han seleccionado dos dimensiones (Store y Product) y en la que se muestran las tres medidas que hay en el cubo.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2079" src="http://www.gisandchips.org/wp-content//main.png" alt="" width="434" height="341" /></p>
<p>Seleccionando el primer botón de la derecha se abre el navegador de OLAP que sirve para configurar el cubo.</p>
<p><img class="aligncenter size-full wp-image-2080" src="http://www.gisandchips.org/wp-content//dimension_selector.png" alt="" width="160" height="209" /></p>
<p>En esta ventana se configuran las columnas y las filas que se quieren mostrar y los filtros que hay que aplicar en alguna de las dimensiones. Los iconos que hay delante de las dimensiones las mueven de un lugar a otro. Por ejemplo, si queremos realizar un análisis por cliente y queremos que aparezca como una columna en la tabla, simplemente seleccionaremos el icono de columna que aparece delante de <em>Customers</em>.</p>
<p>En la figura se puede observar como en <em>Time</em> aparece un  <em>Year=1997</em>, lo que indica que se están filtrando registros que no sean del año 1997. Se puede pulsar en en nombre de la dimensión y se abrirá una nueva ventana donde se pueden cambiar las condiciones del filtro.</p>
<p>Sobre la tabla que muestra los resultados se pueden realizar operaciones de drill down y drill up de forma que cada vez vemos más o menos detalle. La siguiente imagen se ha generado haciendo operaciones de drill down hasta que se han visualizado las ventas de bebida de la tienda 15 de Seattle.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2081" src="http://www.gisandchips.org/wp-content//drill.png" alt="" width="407" height="383" /></p>
<p>En la imagen se puede ver como no hay datos de ejemplo para las tiendas de México y Canadá.</p>
<h2>El lenguaje MDX</h2>
<p>Otra opción interesante es la de MDX, que se puede configurar seleccionado el segundo botón de la derecha de la barra de menú. Las expresiones multidimensionales (MDX es el acrónimo de MultiDimensional eXpressions) es un lenguaje de consulta para bases de datos multidimensionales sobre cubos OLAP, se utiliza en Business Intelligence para generar reportes para la toma de decisiones basados en datos históricos, con la posibilidad de cambiar la estructura, o permitiendo rotar el cubo (<a href="http://es.wikipedia.org/wiki/Expresiones_multidimensionaleshttp://">wikipedia</a>).</p>
<p>Conociendo la sintaxis de MDX, se pueden crear cubos a medida sin necesidad de utilizar el interfaz de usuario. Además, existe una equivalencia entre la consulta que hay en la ventana de MDX y el interfaz gráfico de forma que si se modifica uno, el otro se actualiza inmediatamente.</p>
<p>La siguiente imagen muestra un ejemplo de consulta MDX desde el interfaz web de la aplicación. El interfaz permite la edición manual de la consulta.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2082" src="http://www.gisandchips.org/wp-content//mdx.png" alt="" width="556" height="397" /></p>
<h2>Gráficas</h2>
<p>También se pueden añadir gráficas para una consulta determinada. Las gráficas son interactivas, de forma que a medida que el usuario navega haciendo operaciones de drill up y del drill down, la gráfica se refresca con las dimensiones seleccionadas.</p>
<p>La siguiente imagen muestra un ejemplo de ello. Se han ido haciendo operaciones de drill down y en la gráfica han ido apareciendo nuevas columnas dinámicamente.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2084" src="http://www.gisandchips.org/wp-content//graphic.png" alt="" width="349" height="410" /></p>
<p>Existen varios tipos de gráficas que el usuario puede configurar, como la gráfica de barras, la de tartas, etc.</p>
<h2>El soporte espacial</h2>
<p>Todo lo que se ha comentado hasta este apartado es tan válido para el <em>Geomondrian</em> como para el <em>Mondrian</em> ya que, hasta este momento, no se ha hecho ninguna mención al soporte espacial en los datos.</p>
<p>En el apartado anterior se comentó la importancia del lenguaje MDX y su mapeo con el interfaz gráfico de la aplicación. En realidad, la diferencia que aporta <em>Geomondrian</em> frente al <em>Mondrian</em> es que extiende el lenguaje MDX para que se puedan utilizar operadores espaciales. A este nuevo lenguaje lo llama GeoMDX.</p>
<p>Ya hemos visto que existen algunas tablas de la base de datos que tienen un atributo de tipo geometría. Ese tipo de datos no existe en <em>Postgres</em>, y es la extensión espacial <em>Postgis</em> la que lo añade. La siguiente imagen muestra una consulta sobre la tabla de ciudades realizada con el <a href="http://www.pgadmin.org/">pgAdmin</a>.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2085" src="http://www.gisandchips.org/wp-content//geometry.png" alt="" width="555" height="355" /></p>
<p>Se puede observar como existe una columna <em>geometry</em> que tiene un valor binario que no representa nada. Si se intenta utilizar un atributo de este tipo en un <em>Mondrian</em> lo que puede ocurrir es que o bien no procese el campo al no reconocer su tipo o bien lo muestre con su valor en binario que, para un observador humano, no dice nada.</p>
<p>A continuación vamos a intentar visualizar el mismo atributo desde el <em>Geomondrian</em>. Para ello vamos a seleccionar que nos muestre los atributos de las tablas de dimensiones y vamos a hacer drill down hasta llegar al nivel de ciudad. La siguiente figura muestra el resultado de San Diego y San Francisco.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2087" src="http://www.gisandchips.org/wp-content//geometries.png" alt="" width="560" height="338" /></p>
<p>Puede observarse que no aparece un valor binario en la columna de la geometría, sino que aparece el valor de un multipolígono, que es una de las primitivas de dibujo que soporta <em>Postgis</em>. Además se puede ver cómo se pueden leer fácilmente las coordenadas de los puntos que forman el polígono que se utiliza para describir a la ciudad.</p>
<p>Este formato de mostrar las geometrías se conoce como <a href="http://en.wikipedia.org/wiki/Well-known_text">WKT</a>  y es un estándar utilizado por muchas aplicaciones GIS. Con una geometría en WKT se podría abrir una aplicación GIS y visualizar de forma gráfica las geometrías obtenidas con el <em>Geomeondrian</em>.</p>
<p>En cuando a visualización ya hemos visto como <em>Geomeondrian</em> es capaz de convertir atributos geométricos en representaciones textuales legibles por un ser humano. Pero la extensión que se hace sobre el MDX permite además poder utilizar operadores espaciales en la consulta de la base de datos.</p>
<p>La figura siguiente muestra un ejemplo de consulta para mostrar las ventas en las tiendas de estados unidos y su área de venta en kilómetros cuadrados. Para ello se utilizan algunas funciones espaciales sobre un campo de tipo geometría.</p>
<p style="text-align: center"><img class="aligncenter size-full wp-image-2088" src="http://www.gisandchips.org/wp-content//spatial.png" alt="" width="536" height="353" /></p>
<p>La función ST_textunderscore Area devuelve el área de un polígono. La función ST_textunderscore Transform hace una conversión de sistema de coordenadas desde el sistema de coordenadas origen a un sistema de coordenadas destino que es el que necesita la función del área para operar. La función ST_textunderscore UnionAgg realiza la unión de varios campos de tipo geometría en una única geometría.</p>
<h2>Conclusiones</h2>
<p>El <em>Geomondrian</em> es un servidor SOLAP que tiene un proceso de  instalación muy sencillo (simplemente hay que desplegar un war en el <em>Tomcat</em>).</p>
<p>La aplicación extiende el MDX añadiendo soporte de operaciones espaciales que abren la posibilidad de mostrar cualquier dato que se pueda calcular mediante primitivas geométricas. Los límites son los que la semántica del GeoMDX ofrezca.</p>
<p>En la implementación actual se echa de menos un visor espacial para poder visualizar en un mapa las geometrías mostradas en WKT. Aunque esta tarea es aparentemente sencilla y se podría añadir con poco esfuerzo utilizando aplicaciones web de GIS existentes que ya son capaces de representar geometrías en WKT.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2012/03/23/geomondrian-un-servidor-olap-con-soporte-espacial/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Una librería de código libre y abierto para el cálculo de métricas del paisaje</title>
		<link>http://www.gisandchips.org/2012/03/13/una-libreria-de-codigo-libre-y-abierto-para-el-calculo-de-metricas-del-paisaje/</link>
		<comments>http://www.gisandchips.org/2012/03/13/una-libreria-de-codigo-libre-y-abierto-para-el-calculo-de-metricas-del-paisaje/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 12:02:17 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Anuncio]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[fragstats]]></category>
		<category><![CDATA[GIS libre]]></category>
		<category><![CDATA[landmetrics]]></category>
		<category><![CDATA[NTS]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=2037</guid>
		<description><![CDATA[Hola a todos, Os presento un artículo de investigación que algunos miembros de GIS&#38;Chips publicamos el mes pasado en la revista “Environmental modelling &#38; software”. Trata de la creación de un API libre y abierto para el cálculo de las métricas del paisaje. La utilidad de las métricas del paisaje en distintas aplicaciones ha sido [...]]]></description>
			<content:encoded><![CDATA[<p>Hola a todos,</p>
<p>Os presento un artículo de investigación que algunos miembros de GIS&amp;Chips publicamos el mes pasado en la revista “Environmental modelling &amp; software”. Trata de la creación de un API libre y abierto para el cálculo de las métricas del paisaje.</p>
<p style="text-align: center;"><img class="size-full wp-image-2060 aligncenter" title="Póster landmetrics DIY" src="http://www.gisandchips.org/wp-content//PosterDIY_jul_2010.jpg" alt="" width="300" height="400" /></p>
<p><span id="more-2037"></span></p>
<p>La utilidad de las métricas del paisaje en distintas aplicaciones ha sido generalmente aceptada y ha provocado que existan muchos paquetes de software diseñados para proporcionar cálculos y análisis de los patrones estructurales del paisaje. Es posible obtener más información <a href="http://www.umass.edu/landeco/research/fragstats/documents/fragstats_documents.html">aqui</a></p>
<p>Tras examinar detenidamente las herramientas más utilizadas (Fragstats, V-Late, PA4, etc), se ha podido extraer una serie de puntos fuertes y débiles con la finalidad de crear una lista de las características deseables en este tipo de software. Tras dicho análisis se consideró necesario el diseño de un API sin limitaciones en los datos de entrada, capaz de calcular a partir de datos vectoriales o raster, etc. Este API debería facilitar no sólo la construcción de aplicaciones propias, sino que también debería permitir añadir nuevas métricas y la investigación de nuevos paradigmas relacionados con las métricas del paisaje. Con estas premisas se ha comenzado a desarrollar una propuesta, basada en estándares abiertos y software libre, que se ha denominado landmetrics-DIY (“Do It Yourself”). Podéis encontrar una versión alfa junto con un sencillo interfaz de usuario haciendo checkout en el siguiente repositorio subversión:</p>
<p style="text-align: center;"><a title="http://www.gisandchips.org/svn/landmetrics_diy" href="http://www.gisandchips.org/svn/landmetrics_diy">http://www.gisandchips.org/svn/landmetrics_diy</a></p>
<p>Tendréis que volver a añadir las referencias a NTS y os daréis cuenta de que el desarrollo está aún muy verde. Era solamente una primera propuesta, pero creemos que las directrices definidas en el artículo deberían marcar los criterios a seguir en el desarrollo de proyectos geoespaciales científicos de este tipo.</p>
<p>Por el momento, este API puede calcular unas 40 métricas del paisaje a partir de ficheros vectoriales Shapefile de ESRI, pero estamos trabajando para completar su contenido, siguiendo las líneas que se explica en el artículo.</p>
<p>Aquellos que estéis interesados en saber más, podéis ver el poster que hemos añadido al principio del post o podréis encontrar el artículo en <a href="http://www.sciencedirect.com/science/article/pii/S1364815211002209">ScienceDirect</a></p>
<p>Hasta pronto.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2012/03/13/una-libreria-de-codigo-libre-y-abierto-para-el-calculo-de-metricas-del-paisaje/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Proyección segura desde UTM ED50 con interfaz gráfico</title>
		<link>http://www.gisandchips.org/2011/11/28/proyeccion-segura-desde-utm-ed50-con-interfaz-grafico/</link>
		<comments>http://www.gisandchips.org/2011/11/28/proyeccion-segura-desde-utm-ed50-con-interfaz-grafico/#comments</comments>
		<pubDate>Mon, 28 Nov 2011 19:52:39 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[ed50]]></category>
		<category><![CDATA[epsg]]></category>
		<category><![CDATA[etrs89]]></category>
		<category><![CDATA[ogr2ogr]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1963</guid>
		<description><![CDATA[Seguramente muchos de vosotros habéis estado en la tesitura de tener que proyectar vuestras capas de datos gis que usan la vetusta y a extinguir proyección UTM con datum ED50. Lo de que dicha proyección &#8220;no esta de moda&#8221; no es algo causal, puesto que hay un Real Decreto, el 1071, que define como sistema [...]]]></description>
			<content:encoded><![CDATA[<p>Seguramente muchos de vosotros habéis estado en la tesitura de tener que proyectar vuestras capas de datos gis que usan la vetusta y a extinguir proyección UTM con datum ED50. Lo de que dicha proyección &#8220;no esta de moda&#8221; no es algo causal, puesto que hay un Real Decreto, el 1071, que define como sistema geodésico oficial de referencia para España aquel con el datum ETRS89 y el elipsoide SGR80. Bien es cierto que el decreto permite la ambivalencia de ambos sistemas (ETRS89 y ED50) hasta el año 2015; fecha a partir del cual diremos adiós definitivamente a ED50 (Elipsoide Hayford).<br />
Por otra parte, con el auge de los wikimaps es bastante habitual tener que realizar reproyecciones de las capas gis con ED50 &#8220;de toda la vida&#8221; al sistema geodésico mundial WGS84, que es lo que admiten casi todas las geowikis (OpenStreetMap, ikiMaps, geoNames, etc.).<br />
<div id="attachment_1989" class="wp-caption aligncenter" style="width: 496px"><p class="wp-caption-text">Reproyección mal realizada</p></div><a href="http://www.gisandchips.org/?attachment_id=1989"><img src="http://www.gisandchips.org/wp-content//ua_etrs89_mal.png" alt="Reproyección mal realizada" width="550" class="aligncenter size-full wp-image-1991" /></a><br />
<span id="more-1963"></span><br />
Pero, ¿que es lo que ocurre cuando utilizamos de forma genérica las utilidades de reproyección de los programas de GIS?. Casi todos, generan datos erróneos, que de ninguna manera se corresponden con la realidad. He encontrado translaciones en la X de más de 100 metros, y unos 50 en la Y respecto a la coordenada donde debería estar. </p>
<p>He probado diferentes métodos (sin transformación, transformación EPSG) y el resultado es muy dispar. Sólo un de los métodos funciona bien, aquel cuya transformación utiliza la rejilla en formato NTv2 del IGN, que fue creado precisamente para la transformación de datos desde ED50.<br />
<div id="attachment_1991" class="wp-caption aligncenter" style="width: 496px"><p class="wp-caption-text">Reproyección con rejilla del IGN</p></div><a href="http://www.gisandchips.org/?attachment_id=1991"><img src="http://www.gisandchips.org/wp-content//sigua_ed50.png" alt="Reproyección con rejilla IGN" width="500" class="alignnone size-full wp-image-1991" /></a><br />
Para este artículo he creído conveniente proponer un método de reprojección que no haga uso de ningún programa GIS, y que podamos lanzarlo cómodamente desde la consola (eso de &#8220;cómodamente&#8221; a alguno le sonará a coña). Lo que quería era simplemente un programa que le indicase mi dato en UTM ED50 y me lo proyecte a lo que quiera. Finalmente he decidido crear un híbrido que esté a medio camino entre el &#8220;terminal&#8221; Linux y un interfaz gráfico (en este caso &#8220;GTK&#8221;).<br />
Como no se trata de reinventar la rueda, he utilizado una herramienta con la que me siento muy cómodo y me ha sacado más de una vez de un apuro. Se trata de &#8220;ogr2ogr&#8221;, un comando que forma parte de la suite de GDAL. Este comando está diseñado para cambiar de formato nuestros datos, pero también para reproyectar. Si sintaxis está llena de modificadores que lo hacen a veces un poco críptico.<br />
Entrando en harina, sí deseamos reproyectar un fichero en ED50 a otra proyección la sintaxis es:</p>
<pre class="brush: bash; title: ; notranslate">ogr2ogr -s_srs &quot;EPSG:23030&quot; -t_srs epsg_destino destino origen</pre>
<p>Este comando tampoco solucionaría los problemas para ED50, por lo que habría que retocar el comando de esta forma para que utilice la rejilla del IGN:</p>
<pre class="brush: bash; title: ; notranslate">ogr2ogr -s_srs '+init=epsg:23030 +nadgrids=./peninsula.gsb +wktext' -t_srs epsg_destino origen destino</pre>
<p>Coincidiréis conmigo que este comando con todas sus opciones no es muy intuitivo para recordar. Por esta razón he decidido utilizar un interfaz gráfico para el terminal (sí, no habéis oído mal) que permite lanzar los típicos formularios gráficos para rellenar los datos. En definitiva, no se hace nada más que encapsular dicho comando con cuadros de diálogo que se lanzan al X-windows. Hay algunas utilidades para ello: Xdialog (x-windows), dialog (para el terminal), kdialog (para KDE). Yo voy a utilizar uno llamado &#8220;Zenity&#8221;, que está en todas las distribuciones linux.<br />
Finalmente he creado un script BASH que empotra las peticiones (selección del EPSG, de ficheros, alertas, comprobaciones, etc.) en diálogos hechos con Zenity.<br />
Este es el codigo:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
zenity --info --text=&quot;OGR2OGR Dialog \n
Autor: José Manuel Mira \n
GISandCHIPS 2011 \n
Aplicación basada en OGR2OGR para convertir \n
shapefile proyectado en UTM con datum ED50 en huso 30 (EPSG:23030) a  \n
Geodésica mundial con datum WGS84 (epsg:4326) o \n
UTM ETRS89 (epsg:25830) utilizando GDAL. \n
NOTA: Esta utilidad necesita la rejilla del IGN \n
descargable en: \n

http://www.gisandchips.org/demos/j3m/ogr/peninsula.gsb&quot;

# Comprobar que está instalado OGR2OGR
if which ogr2ogr &gt; /dev/null; then
echo &quot;GDAL está instalado&quot;
else
echo &quot;No está instalado GDAL&quot; | zenity --error --text=&quot;No está instalado GDAL. Salir \n ¿Ubuntu? sudo apt-get install gdal-bin&quot;
exit
fi
#Comprobamos que tienes la rejilla instalada en el directorio del script
if [ -f ./peninsula.gsb ]
then
  echo &quot;OK, tienes la rejilla&quot; | zenity --info --text=&quot;OK, tienes la rejilla&quot;
else
  echo &quot;Descargando rejilla ...&quot;
  wget http://www.gisandchips.org/demos/j3m/ogr/peninsula.gsb 2&gt;=1 | sed -u 's/.*\ \([0-9]\+%\)\ \+\([0-9.]\+\ [KMB\/s]\+\)$/\1\n# Downloading \2/' | zenity --progress --title=&quot;Descargando rejilla IGN ...&quot;
fi

origen=$(zenity --file-selection --title=&quot;Selecciona un shapefile en proyección ED50&quot;)
case $? in
  0)
    echo &quot;\&quot;$origen\&quot; selected.&quot;;;
  1)
    exit;;
   -1)
    exit;;
esac

# obtener extensión del fichero
ext=${origen#*.}
echo $ext
if [ $ext != 'shp' ]
then
   echo &quot;No es un shapefile. Salir&quot; | zenity --error --text=&quot;NO es un shapefile. Salir&quot;
   exit
fi

destino=$(zenity --entry --text &quot;Nombre del Shapefile de salida (sin .shp)?&quot; --entry-text &quot;destino&quot;); echo $destino
if [ $? = 1 ]
then
 exit
else
 echo $?
fi

epsg=$(zenity  --list  --text &quot;Selecciona la proyección de salida&quot; --radiolist  --column &quot;Sel&quot; --column &quot;EPSG&quot; --column &quot;Nombre&quot; TRUE 4326 &quot;Geodésica WGS84&quot; FALSE 25830 &quot;UTM ETS89 HUSO 30&quot;  FALSE 25831 &quot;UTM ETS89 HUSO 31&quot;  FALSE 25829 &quot;UTM ETS89 HUSO 29&quot;); 

echo &quot;ogr2ogr -s_srs '+init=epsg:23030 +nadgrids=./peninsula.gsb +wktext' -t_srs EPSG:&quot;${epsg} ${destino}-${epsg}.shp $origen
ogr2ogr -s_srs '+init=epsg:23030 +nadgrids=./peninsula.gsb +wktext' -t_srs EPSG:${epsg} ${destino}-${epsg}.shp $origen
zenity --info --text &quot;Shapefile ${destino}-${epsg}.shp creado satisfactoriamente&quot;
</pre>
<p>Guardamos el script como conversor.sh, le damos permisos de ejecución y lo lanzamos con </p>
<pre class="brush: bash; title: ; notranslate">sh ./conversor.sh</pre>
<p> Estos son algunos de los diálogos que aparecen:<br />
<img src="http://www.gisandchips.org/wp-content//dialogo_shapefile.png" alt="Indicar shapefile" /><br />
<img src="http://www.gisandchips.org/wp-content//dialogo_rejilla.png" alt="Descarga rejilla IGN" /><br />
<img src="http://www.gisandchips.org/wp-content//dialogo_ok.png" alt="Fin diálogo" /><br />
<img src="http://www.gisandchips.org/wp-content//dialogo_epsg.png" alt="Lista SRS" /><br />
Sí, ya se lo que estáis pensando (tanto rollo para una sola línea de comando). Es cierto, pero resulta útil y sencillo para aquellos que no se quieren complicar la vida. Además, con ligeras modificaciones lo puedo hacer extensible a las islas, otros husos, escribir un log con comandos para reutilizarlos en el futuro en modo BATCH, etc)<br />
He realizado algunas pruebas para comprobar la validez de los datos reproyectados utilizando coordenadas de vértices geodésicos y visualizadas sobre un fondo con el WMS del PNOA. El resultado salta a la vista: &#8220;lo ha cuadrado&#8221;<br />
<div id="attachment_1990" class="wp-caption aligncenter" style="width: 496px"><p class="wp-caption-text">Comparación original (EPSG:23030) y proyectada a WGS84 (EPSG:4326)</p></div><a href="http://www.gisandchips.org/?attachment_id=1990"><img src="http://www.gisandchips.org/wp-content//comparacion_23030-4326.png" alt="comparación 23030-4326" width="570" class="alignnone size-full wp-image-1990" /></a></p>
<p>Sí deseas probar el script <a href="/demos/j3m/ogr/vgeo.zip" title="Descarga vértices geodésicos">aquí</a> tienes unas shapes de prueba (vértices geodésicos en 23030) de la Comunidad Valenciana)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/11/28/proyeccion-segura-desde-utm-ed50-con-interfaz-grafico/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>GeoFOV: Incorporando el campo de visión a una geodatabase multimedia</title>
		<link>http://www.gisandchips.org/2011/11/21/geofov-incorporando-el-campo-de-vision-a-una-geodatabase-multimedia/</link>
		<comments>http://www.gisandchips.org/2011/11/21/geofov-incorporando-el-campo-de-vision-a-una-geodatabase-multimedia/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 22:56:39 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Presentación]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[campo de visión]]></category>
		<category><![CDATA[EXIF]]></category>
		<category><![CDATA[field of view]]></category>
		<category><![CDATA[GIS & Chips]]></category>
		<category><![CDATA[NTS]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1937</guid>
		<description><![CDATA[Hola a todos, quiero compartir aquí el enlace de mi segunda presentación en slideshare. Es de un taller que no se llegó a realizar pero espero que os resulte interesante. En esta presentación comento un poco cómo se utilizan los metadatos de las imágenes para generar información espacial de interés o incluso cómo puede evolucionar [...]]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, quiero compartir aquí el enlace de mi segunda presentación en slideshare. Es de un taller que no se llegó a realizar pero espero que os resulte interesante. En esta presentación comento un poco cómo se utilizan los metadatos de las imágenes para generar información espacial de interés o incluso cómo puede evolucionar el panorama de los geotags a corto plazo.</p>
<p>Más adelante, cuando tenga tiempo, colgaré una librería que he desarrollado en mi tesis y explicaré en detalle el código.</p>
<p>Hasta pronto.</p>
<div style="width:425px" id="__ss_10245372"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/BeniZaragoz/geofov-incorporando-el-campo-de-visin-en-una-multimedia-geodatabase" title="GeoFOV: Incorporando el campo de visión en una multimedia geodatabase" target="_blank">GeoFOV: Incorporando el campo de visión en una multimedia geodatabase</a></strong> <object id="__sse10245372" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=geofov-111120161539-phpapp01&#038;stripped_title=geofov-incorporando-el-campo-de-visin-en-una-multimedia-geodatabase&#038;userName=BeniZaragoz" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><param name="wmode" value="transparent"/><embed name="__sse10245372" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=geofov-111120161539-phpapp01&#038;stripped_title=geofov-incorporando-el-campo-de-visin-en-una-multimedia-geodatabase&#038;userName=BeniZaragoz" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/BeniZaragoz" target="_blank">Beni Zaragozí</a> </div>
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/11/21/geofov-incorporando-el-campo-de-vision-a-una-geodatabase-multimedia/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Presentación de RAPID para las Jornadas de Geografía 3.0</title>
		<link>http://www.gisandchips.org/2011/11/17/presentacion-de-rapid-para-las-jornadas-de-geografia-3-0/</link>
		<comments>http://www.gisandchips.org/2011/11/17/presentacion-de-rapid-para-las-jornadas-de-geografia-3-0/#comments</comments>
		<pubDate>Thu, 17 Nov 2011 11:16:24 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Presentación]]></category>
		<category><![CDATA[AForge.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Teledetección orientada a objetos]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1867</guid>
		<description><![CDATA[En este post quiero compartir la primera presentación que subo a Slideshare En ella justifico y describo el programa RAPID que ya había introducido en un post, pero con un enfoque ligeramente distinto. Mi idea es subir otras presentaciones que tengo por ahí que puedan ser de interés para G&#38;C. RAPID: Rough Agricultural Plot IDentifier. [...]]]></description>
			<content:encoded><![CDATA[<p>En este post quiero compartir la primera presentación que subo a Slideshare <img src='http://www.gisandchips.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  En ella justifico y describo el programa RAPID que ya había introducido en un post, pero con un enfoque ligeramente distinto. Mi idea es subir otras presentaciones que tengo por ahí que puedan ser de interés para G&amp;C.</p>
<div style="width:510px" id="__ss_10197659"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/BeniZaragoz/rapid-10197659" title="RAPID: Rough Agricultural Plot IDentifier. Un contador de árboles con software libre. " target="_blank">RAPID: Rough Agricultural Plot IDentifier. Un contador de árboles con software libre. </a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10197659" width="510" height="426" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/BeniZaragoz" target="_blank">Beni Zaragozí</a> </div>
</p></div>
<p>Espero que os guste. Cuando tenga un rato subo más!!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/11/17/presentacion-de-rapid-para-las-jornadas-de-geografia-3-0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Proveedor de datos SQLite</title>
		<link>http://www.gisandchips.org/2011/11/13/proveedor-de-datos-spatialite/</link>
		<comments>http://www.gisandchips.org/2011/11/13/proveedor-de-datos-spatialite/#comments</comments>
		<pubDate>Sat, 12 Nov 2011 22:25:15 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Mono]]></category>
		<category><![CDATA[SpatiaLite]]></category>
		<category><![CDATA[SQLite]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1886</guid>
		<description><![CDATA[Si habéis intentado alguna vez acceder con C# a una base de datos SQLite, ya sabréis que existe un proveedor ADO.NET de código abierto, System.Data.SQLite. Sin embargo, a los que trabajamos en Linux, Mono ya nos ofrece un proveedor integrado en la propia plataforma (Mono.Data.Sqlite), que de hecho deriva del anterior. Mejor aún, las distros [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Si habéis intentado alguna vez acceder con C# a una base de datos <a href="http://www.sqlite.org/">SQLite</a>, ya sabréis que existe un proveedor ADO.NET de código abierto, <a href="http://system.data.sqlite.org">System.Data.SQLite</a>. Sin embargo, a los que trabajamos en Linux, Mono ya nos ofrece un proveedor integrado en la propia plataforma (<a href="http://www.mono-project.com/SQLite">Mono.Data.Sqlite</a>), que de hecho deriva del anterior. Mejor aún, las distros más populares incorporan SQLite por defecto. Y si, además, hablamos de una geodatabase, no hay ningún problema: hay paquetes de <a href="http://www.gaia-gis.it/spatialite/">SpatiaLite</a> a nuestra disposición. Todo parece un camino de rosas hasta que, a pesar de tenerlo todo felizmente instalado, uno se encuentra con que no es posible cargar la librería de SpatiaLite: al ejecutar el comando &#8220;SELECT load_extension(&#8216;libspatialite.so.2&#8242;)&#8221; obtenemos un lacónico &#8220;Not authorized&#8221;. Afortunadamente hay soluciones. La que aquí os propongo consiste simplemente en que uséis el proveedor Org.Gisandchips.Sqlite.</p>
<p><span id="more-1886"></span></p>
<h2>El problema de las extensiones de SQLite</h2>
<p align="justify">SpatiaLite es fundamentalmente una librería (libspatialite) que actúa como extensión de SQLite: explota el índice R-Tree de SQLite y añade el tipo Geometry y una serie de funciones que a su vez invocan a las de GEOS y PROJ. El resultado, al igual que el tándem PostgreSQL / PostGIS, es una implementación de la especificación &#8220;Simple Features for SQL&#8221; del OGC pero sin necesidad de una infraestructura cliente-servidor. Este tipo de librerías, que contienen funciones que extienden las propias de SQLite, se cargan dinámicamente, es decir, es el desarrollador el encargado de enlazarlas en tiempo de ejecución en el ámbito de una conexión de base de datos. El problema es que este mecanismo de extensión constituye a su vez un agujero de seguridad, un &#8220;coladero&#8221; de software malicioso. Así que, por defecto, las distros de Linux proporcionan el binario de SQLite compilado de forma que no se autoriza la carga dinámica de extensiones. Supongo que al final, quienes lo necesitan, optan por compilar su propio binario de SQLite o utilizar el que proporciona SpatiaLite, donde la extensión está estáticamente enlazada. Los que trabajáis con Mono tenéis ahora otra opción más.</p>
<h2>Org.Gisandchips.Sqlite</h2>
<p align="justify">Podéis descargar el código fuente de este proveedor ADO.NET para SQLite desde el repositorio SVN de Gis&amp;Chips:</p>
<p><code>svn co http://www.gisandchips.org/svn/sqliteprovider</code></p>
<p align="justify">Para vuestra comodidad, os proporciono el fichero de proyecto MonoDevelop. Yo compilo sin problemas en una máquina Ubuntu 11.04, con Mono 2.10, MonoDevelop 2.6 y bajo el framework .NET 4.</p>
<p align="justify">Si echáis un vistazo al código comprobaréis que se trata del mismo proveedor Mono.Data.Sqlite (obtenido de la master branch del repositorio público de Mono en github) con los siguientes añadidos:</p>
<ul>
<li>Wrappers para las funciones enable_load_extension() and load_extension() del API de sqlite3.</li>
<li>Método público SqliteConnection.LoadExtension() que permite cargar dinámicamente extensiones de sqlite3.</li>
</ul>
<p align="justify">El siguiente código de ejemplo es suficientemente explicativo:</p>
<pre class="brush: csharp; title: ; notranslate">
using (var cn = new SqliteConnection (&quot;Data Source=path/file.sqlite&quot;)) {
  cn.Open ();
  cn.LoadExtension (&quot;libspatialite.so.2&quot;);
  //your sql commands follow
}
</pre>
<p align="justify">Respecto a la licencia, me remito a la de Mono (MIT), que es la más permisiva y entiendo que compatible con las instrucciones del autor original de System.Data.SQLite, Robert Simpson, quien liberó este proveedor como de dominio público. Que lo disfrutéis.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/11/13/proveedor-de-datos-spatialite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Business card de GISchips (en LaTeX)</title>
		<link>http://www.gisandchips.org/2011/11/06/business-card-de-gischips-en-latex-3/</link>
		<comments>http://www.gisandchips.org/2011/11/06/business-card-de-gischips-en-latex-3/#comments</comments>
		<pubDate>Sun, 06 Nov 2011 18:41:06 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[Business card]]></category>
		<category><![CDATA[GIS & Chips]]></category>
		<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[OpenStreetMap]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1847</guid>
		<description><![CDATA[La semana pasada estaba previsto que varios miembros de GIS&#38;Chips presentáramos un taller en una Jornada de Geografía 3.0. Además, algunos asistimos al posterior congreso nacional de geografía. Finalmente, no se pudo realizar el taller por falta de horarios, pero esperamos poder organizar algún evento propio solamente para la difusión de conocimientos de TIG libre. [...]]]></description>
			<content:encoded><![CDATA[<p>La semana pasada estaba previsto que varios miembros de GIS&amp;Chips presentáramos un taller en una Jornada de Geografía 3.0. Además, algunos asistimos al posterior congreso nacional de geografía. Finalmente, no se pudo realizar el taller por falta de horarios, pero esperamos poder organizar algún evento propio solamente para la difusión de conocimientos de TIG libre.</p>
<p>En estos eventos es habitual el intercambio de tarjetas de presentación y como no teníamos una para darnos a conocer decidimos hacer una prueba en LaTeX, que no salió del todo mal. En este post compartimos esta primera versión para que la podáis personalizar o simplemente ver como se ha hecho.</p>
<div id="attachment_1825" class="wp-caption aligncenter" style="width: 315px"><img class="size-full wp-image-1825" src="http://www.gisandchips.org/wp-content//GC_businessCard_front1.jpg" alt="" width="305" height="152" /><p class="wp-caption-text">Cara tarjeta G&amp;C, generado con el fichero &quot;G&amp;C_businessCard_front.tex&quot;.</p></div>
<p style="text-align: center">
<p><span id="more-1847"></span></p>
<h3>Características a considerar en el diseño</h3>
<p>Hace mucho tiempo di un par de cursos para el diseño de marca. Ilustrator, Freehand y Photoshop para el diseño de tarjetas, trípticos, carteles, carátulas de cds, etc. Hay que reconocer que todo esto es una profesión en sí y hay muchos detalles por conocer. En tal caso, lo que hacemos nosotros aquí es un “apaño”, por lo que nadie espere grandes cosas <img src='http://www.gisandchips.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Las características más a tener en cuenta en el diseño son el tamaño de la tarjeta, el logo, el fondo y la gama de colores. Otra cuestión a tener en cuenta es la problemática vector-raster.</p>
<p>El <strong>tamaño</strong> de la tarjeta se puede determinar por una serie de estándares, supongo que según el tamaño de los billetes de cada país <img src='http://www.gisandchips.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  (la cartera donde guardamos las tarjetas también depende de esto). Nuestra tarjeta (90x45mm) no se ajusta a ninguno de estos estándares aunque la podríamos adaptar muy fácilmente. En <a title="http://en.wikipedia.org/wiki/Business_card" href="http://en.wikipedia.org/wiki/Business_card" target="_blank">http://en.wikipedia.org/wiki/Business_card</a> encontramos los tamaños más utilizados.</p>
<p>El <strong>logo</strong> es el  que figura en el blog, diseñado por Miguel. No obstante, eliminamos el texto pues lo incluiremos entre los otros elementos de la tarjeta.</p>
<p>El <strong>fondo de la cara frontal</strong> es una nube de tags basada en la de esta página, después en Gimp le hemos añadido un degradado lineal de negro a blanco. El<strong> fondo del reverso</strong> es un mapa de <a href="http://www.openstreetmap.org/">http://www.openstreetmap.org/</a> que indica la ubicación de la sede. Para completar la ubicación se podría añadir la dirección en texto.</p>
<p>El nombre de la asociación, el lema y los datos de contacto (web y Email) aparecen en la cara frontal. El contraste blanco/negro es uno de los más recurridos y elegantes aunque esto dependerá del gusto de cada uno, además son los colores que aparecen en el blog.</p>
<p>Finalmente, la problemática raster-vector hace que no todos los programas sean igual de prácticos al combinar imágenes con texto en un marco tan pequeño. El texto podría verse mal al rasterizarse en Gimp o las imágenes verse mal por no estar bien escaladas al tamaño del papel. Para evitar problemas es recomendable preparar todos los componentes del diseño en un marco de 90x45mm. Además, conviene que el texto sea siempre vectorial.</p>
<div id="attachment_1828" class="wp-caption aligncenter" style="width: 341px"><img class="size-full wp-image-1828 " src="http://www.gisandchips.org/wp-content//GC_businessCard_back.jpg" alt="" width="331" height="165" /><p class="wp-caption-text">Reverso de la tarjeta G&amp;C, generado con el fichero &quot;G&amp;C_businessCard_back.tex&quot;.</p></div>
<h3>¿Porqué LaTeX?</h3>
<p>Seguramente, podríamos haber creado la tarjeta solamente con Gimp, Impress, Inkscape o cualquier otro software comercial… incluso en un editor de textos cualquiera. O con una máquina de escribir… No obstante, para crear la tarjeta hemos utilizado Gimp y LaTeX.</p>
<p>Básicamente, prefiero esta opción porqué es FOSS y estándar. No necesitamos conocer demasiados botones y LaTeX lleva una larga trayectoria de más de 20 años que hace pensar que la plantilla que creemos seguirá siendo funcional en el futuro. Además, ya utilizo LaTeX para hacer pósters, artículos, presentaciones, materiales docentes, el currículum y mi tesis. De este modo, la pregunta sería ¿porqué aprender otros programas?</p>
<p>Desgraciadamente, no puedo aquí hacer un tutorial de LaTeX para geógrafos pero, si necesitáis escribir un documento estructurado de grandes dimensiones (tesis) o muchos de otro tipo (informes) os animo a que le echéis un vistazo a este proyecto tan interesante pues a medio plazo os ahorrará muchos dolores de cabeza.</p>
<h3>Como está hecha</h3>
<p>Las plantillas que he encontrado en la web (buscando “Business card; LaTeX”) son más bien sosas con un estilo próximo al de la máquina de escribir y además son bastante complejas. Para evitar estos problemas hemos utilizado la clase “Beamer” de LaTeX, que permite entre otras cosas añadir una imagen de fondo y formatear el espacio de la tarjeta apropiadamente.</p>
<p>Primero, hemos utilizado Gimp para crear los fondos de la tarjeta como dos ficheros PNG. A continuación, LaTeX se ha utilizado para la composición, añadir textos y dibujos vectoriales (líneas). En el reverso de la tarjeta hemos añadido un mapa de <a href="http://www.openstreetmap.org/">http://www.openstreetmap.org/</a> para aportar una localización más detallada, aunque también se podría añadir la dirección postal.</p>
<p>La plantilla se compone de tres ficheros TeX, uno para cada cara de la tarjeta y, tras compilar las dos caras, el tercero para crear una composición de 12 tarjetas a dos caras.</p>
<p><img class="size-full wp-image-1830 alignnone" src="http://www.gisandchips.org/wp-content//GC_businessCard_x12_Página_1.jpg" alt="" width="214" height="303" /><img class="alignnone size-full wp-image-1831" src="http://www.gisandchips.org/wp-content//GC_businessCard_x12_Página_2.jpg" alt="" width="214" height="303" /></p>
<p>Esta plantilla es altamente mejorable, es una versión 0.1 para salir del paso, pero os puede dar ideas. La idea de aprovechar OSM para la localización (idea de José) es interesante y evita tener que pensar en hacer un croquis como he visto en algunas tarjetas. Además, creo que los detalles de la tarjeta (la nube de tags como fondo, el mapa…) además de quedar bastante bien aportan información extra sobre nosotros si se saben leer.</p>
<h3>Código en latex</h3>
<p>Finalmente, os paso el código de los tres ficheros de LaTeX necesarios para crear esta tarjeta. Si leéis el código veréis donde podéis introducir vuestras propias imágenes de fondo o el logo que queráis. Espero que os sea de ayuda y os genere otras ideas.</p>
<p><strong>G&#038;C_businessCard_front.tex</strong></p>
<p>
<pre class="brush: latex; title: ; notranslate">
% GIS&amp;Chips nice business card
% By Benito M. Zaragozí
% Version 0.1 released 02/11/2011
% Further releases in: www.gisandchips.org
% This template is composed by three .tex files (businessCard.tex, businessCard_back.tex and businessCardx10.tex) for preparing a basic layout.

\documentclass{beamer}
\usepackage[utf8x]{inputenc}
\usepackage[spanish]{babel}
\usepackage{hyperref}
\usepackage[absolute,showboxes,verbose,overlay]{textpos}
\usepackage{geometry}
\geometry{paperwidth=90mm, paperheight=45mm, layoutwidth=90mm, layoutheight=45mm, left=0mm, top=0mm, right=0mm, bottom=0mm}

\usetheme{default}

\setbeamertemplate{navigation symbols}{}
\setbeamertemplate{background canvas}{\includegraphics[height=\paperheight]{background.png}}

\begin{document}

\frame{
\begin{columns}
	\begin{column}{35mm}
		\includegraphics[width=44mm]{gischips_logo.png}
	\end{column}

	\begin{column}{40mm}
		\color{white}{Asociación\\ \vspace{1mm} \huge{GIS \&amp;amp; Chips}}
		\normalsize
		\vspace{1mm}
		\line(1,0){80}
		\vspace{-1mm}
		\color{white}{Geografía útil para llevar}
	\end{column}
\end{columns}

\vspace{-1mm}
\normalsize
\color{black}{\hspace{5mm}\line(1,0){220}\\ \hspace{2mm} \url{www.gisandchips.org} \hspace{3mm} \url{info@gisandchips.org}}
}
\end{document}
</pre>
</p>
<p><strong>G&#038;C_businessCard_back.tex</strong></p>
<p><strong></strong>
<pre class="brush: latex; title: ; notranslate">
% GIS&amp;Chips nice business card
% By Benito M. Zaragozí
% Version 0.1 released 02/11/2011
% Further releases in: www.gisandchips.org
% This template is composed by three .tex files (businessCard.tex, businessCard_back.tex and businessCardx10.tex) for preparing a basic layout.

\documentclass{beamer}
\usepackage[utf8x]{inputenc}
\usepackage[spanish]{babel}
\usepackage{geometry}
\geometry{margin=2mm, paperwidth=90mm, paperheight=45mm}

\usetheme{default}
\setbeamertemplate{navigation symbols}{}
\setbeamertemplate{background canvas}{\hspace{2mm} \includegraphics[height=41.5mm]{mapbackground.png}}

\begin{document}
	\frame{
		\vspace{-1.5mm}
		\colorbox{white}{GIS\&amp;amp;Chips en la Universidad de Alicante}\\
		\vspace{31mm}
		\begin{flushright}
		\colorbox{white}{\tiny {\url{www.openstreetmap.org}}}
		\end{flushright}
	}
\end{document}
</pre>
</p>
<p><strong>G&#038;C_businessCard_x12.tex</strong></p>
<p><strong></strong>
<pre class="brush: latex; title: ; notranslate">
% GIS&amp;Chips nice business card
% By Benito M. Zaragozí
% Version 0.1 released 02/11/2011
% Further releases in: www.gisandchips.org
% This template is composed by three .tex files (businessCard.tex, businessCard_back.tex and businessCardx10.tex) for preparing a basic layout.

\documentclass[10pt,a4paper]{minimal}
\usepackage{graphicx}
\usepackage[margin=1cm]{geometry}

\begin{document}
\thispagestyle{empty}
\noindent

\begin{center}
\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard.pdf} \includegraphics[scale=1]{businessCard.pdf} \vspace{1mm}

\pagebreak
%%%%%%Back with map
\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\hspace{1mm}\includegraphics[scale=1]{businessCard_back.pdf} \includegraphics[scale=1]{businessCard_back.pdf} \vspace{1mm}

\end{center}
\pagebreak
\end{document}
</pre></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/11/06/business-card-de-gischips-en-latex-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paralelización con SIMD</title>
		<link>http://www.gisandchips.org/2011/10/20/paralelizacion-con-simd/</link>
		<comments>http://www.gisandchips.org/2011/10/20/paralelizacion-con-simd/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 16:31:37 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Mono]]></category>
		<category><![CDATA[Mono.Simd]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1744</guid>
		<description><![CDATA[En este artículo os presento un test en el que medimos los tiempos que un programa escrito en C# emplea para procesar una serie de modelos digitales del terreno. El objetivo final es comparar el rendimiento de un código que hace un cálculo secuencial frente a otro que hace uso de una tecnología de paralelización [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">En este artículo os presento un test en el que medimos los tiempos que un programa escrito en C# emplea para procesar una serie de modelos digitales del terreno. El objetivo final es comparar el rendimiento de un código que hace un cálculo secuencial frente a otro que hace uso de una tecnología de paralelización de datos por hardware denominada SIMD, disponible en la mayoría de microprocesadores que usamos hoy en día. Y el resultado es muy interesante.<div id="attachment_1801" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content//SIMD_performance.png"><img src="http://www.gisandchips.org/wp-content//SIMD_performance-300x131.png" alt="SIMD performance test" width="300" height="131" class="size-medium wp-image-1801" /></a><p class="wp-caption-text">Test de rendimiento SIMD con Mono.Simd.Vector8s</p></div><span id="more-1744"></span></p>
<p style="text-align: justify">Las técnicas de computación paralela encuentran en los sistemas de información geográfica una de sus aplicaciones más elocuentes dada la naturaleza masiva de los datos geográficos, en particular si hablamos de estructuras de datos raster. No en vano, allá por el año 1997, Richard Healey, junto con otros compañeros del Dpto. de Geografía de la Universidad de Edimburgo, editó &#8220;Parallel Processing Algorithms For GIS&#8221;. El profesor Healey es un geógrafo que ya a principios de los 90 planteaba a sus alumnos problemas de geoprocesamiento paralelo que éstos habían de resolver con ADA, el único lenguaje accesible que por aquel entonces prefiguraba el paradigma OOP y permitía definir tareas concurrentes. Desde entonces se han producido muchos avances en paralelización de procesos, tanto a nivel de software como de hardware. Sin embargo, existe un tipo de paralelización que no parece haber alcanzado demasiada notoriedad en el campo de los GIS: se trata del conjunto de instrucciones <a href="http://en.wikipedia.org/wiki/SIMD">SIMD</a> (Single Instruction, Multiple Data) que permite realizar operaciones aritméticas entre pares de vectores mediante una sola instrucción. No se trata por tanto de concurrencia de procesos, sino de paralelismo a nivel de datos. Lo más curioso es que, desde 1996, los fabricantes de microprocesadores han ido incorporando extensiones que soportan en mayor o menor medida este juego de instrucciones.</p>
<p style="text-align: justify">Cualquier PC o videoconsola actual permite ejecutar instrucciones SIMD. Evidentemente los desarrolladores de juegos hace tiempo que explotan este tipo de paralelización. Sin embargo, encontrar referencias recientes a SIMD en el ámbito de la Geomática resulta más complicado: <a href="http://gisws.media.osaka-cu.ac.jp/grass04/viewpaper.php?id=15">aquí tenéis una interesante ponencia</a> de la conferencia de usuarios de GRASS del 2004. Seguramente habrá más trabajos publicados, así que hacednos saber lo que encontréis.</p>
<p style="text-align: justify">Yo sinceramente no sabía nada de esto hasta que leí <a href="http://tirania.org/blog/archive/2008/Nov-03.html">este post de Miguel de Icaza</a>, anunciando la publicación de <a href="http://docs.go-mono.com/monodoc.ashx?link=N%3aMono.Simd">Mono.Simd</a>. Este API es un paso en la estrategia de Mono por entrar de lleno en la industria del &#8220;gaming&#8221;. ¿Y para las desarrolladores de GIS? En mi opinión significa un abanico de posibilidades a la hora de paralelizar geoprocesos que queda pendiente de explorar.</p>
<p style="text-align: justify">En este artículo sólo quiero dejar constancia de un test para un caso extremo de optimización con SIMD. En la práctica carece de utilidad, mi única intención es medir diferencias de tiempo en un escenario absolutamente favorable a la paralelización mediante vectores. Dado un grid de elevaciones, donde cada valor de altitud puede representarse como un entero de 16 bits, se trata simplemente de doblar el valor de cada pixel para &#8220;exagerar&#8221; el modelo del terreno. Estas son las especificaciones de la máquina en que he realizado el test:</p>
<ul>
<li>Intel Q8300 @ 2.50GHz</li>
<li>3.9 GiB RAM</li>
<li>Ubuntu 11.04 i686</li>
<li>Mono 2.10.5</li>
</ul>
<p style="text-align: justify">El test se ha realizado sobre 4 ficheros <a href="http://en.wikipedia.org/wiki/Esri_grid">ARC/INFO ASCII GRID</a> de distintos tamaños. Para cada fichero se han tomado 5 muestras del tiempo transcurrido en el cálculo aritmético sin aceleración de hardware, pixel a pixel, tomando finalmente la mediana. La misma metodología de muestreo se ha empleado para obtener los tiempos con aceleración de hardware, es decir, empleando Mono.Simd para multiplicar los pixels de 8 en 8 mediante una única instrucción. Para ello es necesario agrupar previamente los valores de altitud y almacenar cada vector en una lista de tipo Mono.Simd.Vector8s. Estos son los resultados:</p>
<table style="height: 5px;width: 80%" border="1" cellspacing="1" cellpadding="1" align="center">
<thead>
<tr>
<th scope="col"><span class="Apple-style-span" style="font-weight: normal">File size (MiB)</span></th>
<th scope="col"><span class="Apple-style-span" style="font-weight: normal">Elapsed time (miliseconds)</span></th>
<th scope="col"><span class="Apple-style-span" style="font-weight: normal">Elapsed time with SIMD (miliseconds)</span></th>
<th scope="col"><span class="Apple-style-span" style="font-weight: normal">Time reduction</span></th>
<th scope="col"><span class="Apple-style-span" style="font-weight: normal">Performance gain</span></th>
</tr>
</thead>
<tbody>
<tr>
<td>12.0</td>
<td>49.7447</td>
<td>14.2542</td>
<td>71.3</td>
<td><span style="background-color: #ffd700"><strong>3.5x</strong></span></td>
</tr>
<tr>
<td>48.2</td>
<td>197.5251</td>
<td>56.149</td>
<td>71.6</td>
<td><span style="background-color: #ffd700"><strong>3.5x</strong></span></td>
</tr>
<tr>
<td>192.7</td>
<td>783.0778</td>
<td>216.305</td>
<td>72.4</td>
<td><span style="background-color: #ffd700"><strong>3.6x</strong></span></td>
</tr>
<tr>
<td>535.4</td>
<td>2180.8665</td>
<td>618.2225</td>
<td>71.7</td>
<td><span style="background-color: #ffd700"><strong>3.5x</strong></span></td>
</tr>
</tbody>
</table>
<p style="text-align: justify">Como veis, en todos los casos, con SIMD el proceso de cálculo se completa en torno a 3,5 veces más rápido. Esto es una buena noticia, pero no significa que este tipo de paralelismo sea la panacea. En mi opinión la conclusión es que, si con un escenario favorable se puede reducir el tiempo de proceso en más de un 70%, merece la pena explorar otros escenarios con verdadera utilidad práctica.</p>
<p style="text-align: justify">Si alguien se pregunta por la incidencia que puede tener esta mejora en el rendimiento si contabilizamos el proceso de lectura y carga en memoria de los datos, me atrevería a decir que escasa. En cualquier caso, los procesos de lectura y manejo de grandes volúmenes de información raster constituyen un problema distinto y existen diversas técnicas para su optimización.</p>
<p style="text-align: justify">Si os pica la curiosidad, podeis averiguar el conjunto de instrucciones SIMD que soporta vuestro procesador ejecutando el código de ejemplo que aparece en la documentación de la clase <a href="http://docs.go-mono.com/monodoc.ashx?link=T%3aMono.Simd.SimdRuntime">Mono.Simd.SimdRuntime</a> (es posible que tengáis que hacer algunas modificaciones). Para aquellos que quieran reproducir un test de rendimiento con sus propios ficheros ASCII GRID, aquí os dejo el código C# que he usado (por cierto, ni es óptimo ni puedo garantizar que esté libre de bugs):</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.IO;
using Mono.Simd;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics;
using System.Linq;

namespace SIMDTest
{
 class MainClass
 {
  public static void Main (string[] args)
  {
   bool useSIMD = true;
   string path = string.Empty;
   CultureInfo formatProvider = null;
   try {
    if (args.Length == 0) {
     Console.WriteLine (&quot;Usage: SIMDTest [ASC GRID file name] [specific culture name]&quot;);
     return;
    }
    if (args.Length &gt; 0)
     path = args[0];
    if (args.Length &gt; 1)
     formatProvider = CultureInfo.GetCultureInfo (args[1]);
    Console.WriteLine (&quot;Use hardware acceleration? [y / n]? : &quot;);
    ConsoleKeyInfo key = Console.ReadKey ();
    while (key.Key != ConsoleKey.Y &amp;&amp; key.Key != ConsoleKey.N) {
     Console.WriteLine (&quot;Press 'y' to use hardware acceleration, 'n' otherwise: &quot;);
     key = Console.ReadKey ();
    }
    Console.WriteLine ();
    Console.WriteLine (&quot;Processing, please wait ...&quot;);
    useSIMD = (key.Key == ConsoleKey.Y);
    ElevationModel dem = new ElevationModel(path, formatProvider);
    Stopwatch stopwatch = new Stopwatch ();
    if (useSIMD) {
     Vector8s scale = new Vector8s (2);
     foreach (IList vPage in dem.EnumerateVectors ()) {
      stopwatch.Start ();
      for (int i = 0; i &lt; vPage.Count; i ++)
       vPage[i] = vPage[i] * scale;
      stopwatch.Stop ();
     }
    } else {
     foreach (IList page in dem.EnumerateData ()) {
      stopwatch.Start ();
      for (int i = 0; i &lt; page.Count; i ++)
       page[i] = (short) (page[i] * 2);
      stopwatch.Stop ();
     }
    }
    Console.WriteLine (&quot;Time elapsed: {0}&quot;, stopwatch.Elapsed);
   } catch (Exception ex) {
    Console.WriteLine (ex.Message);
   }
  }
 }

 class ElevationModel
 {
  string _path;
  IFormatProvider _formatProvider = CultureInfo.CurrentCulture;
  short _noData = -9999;
  int BOD = 0;

  public ElevationModel (string path, IFormatProvider formatProvider)
  {
   if (string.IsNullOrEmpty (path))
    throw new ArgumentNullException ();
   else if (!File.Exists (path))
    throw new FileNotFoundException ();
   else {
    _path = path;
    if (formatProvider != null)
     _formatProvider = formatProvider;
    this.SetMetadata ();
   }
  }

  public ElevationModel (string path) : this(path, null)
  {
  }

  void SetMetadata ()
  {
   using (StreamReader reader = new StreamReader (_path)) {
    //skip GRID header
    for (int i = 0; i &lt; 5; i++)
     reader.ReadLine ();
    _noData = short.Parse (reader.ReadLine ().Split (' ')[1], _formatProvider);
    reader.BaseStream.Position = 0;
    reader.DiscardBufferedData ();
    char[] buffer = new char[512];
    reader.Read(buffer, 0, buffer.Length);
    BOD = this.GetBeginOfData (buffer);
   }
  }

  int GetBeginOfData (char[] source)
  {
   int i = 0;
   bool isNewHeaderLine = false;
   bool isNewLine = true;
   foreach (char c in source) {
    if (char.IsLetter (c) &amp;&amp; isNewLine) {
     isNewHeaderLine = true;
     isNewLine = false;
    } else if ((char.IsDigit (c) || c == '-') &amp;&amp; isNewLine &amp;&amp; !isNewHeaderLine) {
     break;
    } else if (char.IsControl (c)) {
     isNewLine = true;
     isNewHeaderLine = false;
    }
    i++;
   }
   return i;
  }

  IList&lt;short&gt; GetPage (char[] source, int sourceIndex, int sourceLength, IList pendingDigits)
  {
   IList&lt;short&gt; page = new List&lt;short&gt; ();
   for (int i = sourceIndex; i &lt; sourceLength; i++) {
    if (char.IsDigit (source[i]) || source[i] == '-')
     pendingDigits.Add (source[i]);
    else if (pendingDigits.Count &gt; 0 &amp;&amp; (char.IsWhiteSpace (source[i]) || char.IsControl (source[i]))) {
     short n = _noData;
     string s = new string(pendingDigits.ToArray ());
     if (!short.TryParse(s, NumberStyles.Integer, _formatProvider, out n))
      Console.WriteLine (&quot;Error parsing {0}&quot;, s);
     page.Add (n);
     pendingDigits.Clear ();
    }
   }
   return page;
  }

  public IEnumerable&lt;IList&lt;short&gt;&gt; EnumerateData ()
  {
   using (StreamReader reader = new StreamReader (_path)) {
    char[] buffer = new char[25000 * 1024];
    int beginOfData = 0;
    IList pendingDigits = new List ();
    int charCount = 0;
    while ((charCount = reader.Read (buffer, 0, buffer.Length)) &gt; 0) {
     if (beginOfData == 0) {
      beginOfData = this.BOD;
      yield return this.GetPage (buffer, beginOfData, charCount, pendingDigits);
     } else
      yield return this.GetPage (buffer, 0, charCount, pendingDigits);
    }
   }
  }

  IList&lt;Vector8s&gt; GetVectorPage(IList page, IList pendingValues)
  {
   List vPage = new List ();
   foreach (short n in page) {
    pendingValues.Add (n);
    if (pendingValues.Count == 8 ) {
     vPage.Add (new Vector8s (pendingValues[0], pendingValues[1],
      pendingValues[2], pendingValues[3], pendingValues[4],
      pendingValues[5], pendingValues[6], pendingValues[7]));
     pendingValues.Clear ();
    }
   }
   return vPage;
  }

  public IEnumerable&lt;IList&lt;Vector8s&gt;&gt; EnumerateVectors ()
  {
   int lastPageSize = -1;
   IList pendingValues = new List ();
   foreach (IList page in this.EnumerateData ()) {
    IList vPage = this.GetVectorPage (page, pendingValues);
    // complete last vector in last page
    if (lastPageSize != -1 &amp;&amp; vPage.Count &lt; lastPageSize) {
     if (pendingValues.Count &gt; 0 &amp;&amp; pendingValues.Count &lt; 8 ) {
      for (int i = pendingValues.Count; i &lt; 8; i++)
	pendingValues.Add(_noData);
      vPage.Add (new Vector8s (pendingValues[0], pendingValues[1],
       pendingValues[2], pendingValues[3], pendingValues[4],
       pendingValues[5], pendingValues[6], pendingValues[7]));
     }
    }
    lastPageSize = vPage.Count;
    yield return vPage;
   }
  }
 }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/10/20/paralelizacion-con-simd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Usando RSAGA para procesar un raster &#8220;grande&#8221; por partes</title>
		<link>http://www.gisandchips.org/2011/01/13/usando-rsaga-para-procesar-un-raster-grande-por-partes/</link>
		<comments>http://www.gisandchips.org/2011/01/13/usando-rsaga-para-procesar-un-raster-grande-por-partes/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 17:20:21 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[GIS libre]]></category>
		<category><![CDATA[R]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1692</guid>
		<description><![CDATA[Hola a todos, hoy propongo una de las posibles soluciones a un problema que suele aparecer trabajando con GIS: ¿qué hacer cuando queremos procesar un raster “relativamente grande” y los GIS de escritorio más populares tienen problemas de memoria o no acaban el proceso? En algunas ocasiones la solución a estos problemas sería “trocear” el [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: normal;font-size: 13px">Hola a todos, hoy propongo una de las posibles soluciones a un problema que suele aparecer trabajando con GIS: ¿qué hacer cuando queremos procesar un raster “relativamente grande” y los GIS de escritorio más populares tienen problemas de memoria o no acaban el proceso?</span></p>
<p>En algunas ocasiones la solución a estos problemas sería “trocear” el raster y procesarlo por partes. Esto lo podríamos hacer con varios software y en todos ellos sería interesante poder automatizar la tarea al máximo.</p>
<div id="attachment_1695" class="wp-caption aligncenter" style="width: 250px"><a href="http://www.gisandchips.org/wp-content/mdt1.jpg"><img class="size-medium wp-image-1695 " src="http://www.gisandchips.org/wp-content/mdt1-300x300.jpg" alt="" width="240" height="240" /></a><p class="wp-caption-text">1. Modelo digital raster</p></div>
<p>En este post propongo realizar una prueba con RSAGA, que es un modulo de R que permite acceder a las funciones disponibles en la consola de SAGA GIS. Para este post he trabajado en Windows, con R 2.10.1 y SAGA 2.0.4, aunque supongo que no habrá problemas con usar otras versiones más recientes. Además, deberéis instalar en R el paquete RSAGA.<span id="more-1692"></span></p>
<div id="attachment_1696" class="wp-caption aligncenter" style="width: 248px"><a href="http://www.gisandchips.org/wp-content/municipios1.jpg"><img class="size-medium wp-image-1696 " src="http://www.gisandchips.org/wp-content/municipios1-298x300.jpg" alt="" width="238" height="240" /></a><p class="wp-caption-text">2. Shapefile de polígonos con que trocearemos el raster</p></div>
<p>Para esta práctica podéis <a title="descargar ficheros de prueba" href="http://dl.dropbox.com/u/17558342/rsaga_tests.rar" target="_blank">descargar dos ficheros</a> (Imagenes 1 y 2), uno raster y otro vectorial (polígonos). A efectos didácticos se utilizan ficheros pequeños, pero esto resultaría más útil en caso de necesitar fragmentar más el raster. Por ejemplo, en artículos anteriores he presentado código para trabajar imágenes a nivel de parcelas agrícolas. En aquellos artículos trabajábamos las imágenes de una en una y ya estaban recortadas, pero las parcelas podrían ser miles y no queremos hacer eso a mano.</p>
<h3>Conociendo SAGA GIS</h3>
<p>Lo principal, como en tantos otros casos, sería conocer como se trocea un fichero raster con SAGA GIS. Para ello abrimos la GUI de SAGA y vamos a la pestaña “modules” que tiene forma de TOC, generalmente se encuentra a la izquierda de la ventana principal. En esta pestaña podemos encontrar las distintas librerías que agrupan módulos que se relacionan por algún motivo. Explorar estas librerías y practicar con ellas es el mejor modo de estar seguro de lo que se quiere hacer.</p>
<div id="attachment_1697" class="wp-caption aligncenter" style="width: 148px"><a href="http://www.gisandchips.org/wp-content/toc.jpg"><img class="size-medium wp-image-1697" src="http://www.gisandchips.org/wp-content/toc-172x300.jpg" alt="" width="138" height="240" /></a><p class="wp-caption-text">3. TOC de SAGA GIS donde podemos explorar las librerías y los módulos disponibles. </p></div>
<p>Finalmente, he decidido que lo mejor es empezar por separar el shapefile original por polígonos (shapes-tools/separate shapes) y después realizar un recorte por cada uno de los nuevos shapefiles (shapes-grid/clip grid with polygon). Practicar con el interfaz gráfico es un bueno modo de estar seguros de los parámetros que nos pide cada módulo.</p>
<p>Antes de empezar a usar RSAGA he tenido que averiguar los nombres exactos de los módulos y los parámetros que aceptan. Esto lo he hecho con los métodos rsaga.get.modules() y rsaga.get.usage(). Aunque generalmente se puede averiguar también viendo los nombres en el SAGA GUI o mirando en la carpeta donde se contienen las *.dll.</p>
<h3>Trabajando con RSAGA</h3>
<pre class="brush: bash; title: ; notranslate">
## Abrimos la consola de R y cargamos la librería
library(RSAGA)

## Seleccionamos el fichero raster que queremos trocear y una capa vectorial que queramos usar como límites. También especificamos el directorio donde van los outputs. Para trabajar con Windows recomiendo rutas sin espacios.
raster&lt;- file.choose()
poligonos&lt;- file.choose()
directorio &lt;-choose.dir()

## Consultamos hasta encontrar la herramienta que nos separa un shapefile en varios, obteniendo un shapefile por cada polígono, o lo que quisiéramos. Por ejemplo:
## rsaga.get.modules(&quot;shapes_grid&quot;)
## rsaga.get.usage(&quot;shapes_tools&quot;, 7)
## Se ejecuta el método con los parámetros necesarios.
rsaga.geoprocessor(lib=&quot;shapes_tools&quot;, module=7, param=list(SHAPES=poligonos, PATH=directorio, NAMING=0, FIELD=6))
</pre>
<p>Una vez ejecutado este proceso ya disponemos de un shapefile por cada polígono, esto significa que aunque el shapefile original tuviera miles de registros solamente cargaremos en memoria uno a la vez. Esto ya supone un ahorro importante de recursos.</p>
<pre class="brush: bash; title: ; notranslate">
# Listamos los nuevos shapefiles
shapefiles &lt;- list.files(directorio, full.names=T, pattern=&quot;\\.shp&quot;)
## Por último utilizamos RSAGA para realizar tantos recortes del raster como polígonos habíamos extraído
for(i in 1:length(shapefiles)){
select &lt;- shapefiles[i]&lt;/code&gt;
rsaga.geoprocessor(lib=&quot;shapes_grid&quot;, module=7, param=list(OUTPUT=select, INPUT=raster, POLYGONS=select))
}#fin bucle
</pre>
<h3>Conclusiones</h3>
<p>Tras ver este ejemplo nos queda más claro el uso de RSAGA y se visualiza bien como se podrían automatizar gran número de tareas habituales en los GIS. Intentar realizar estas tareas herramientas básicas y generales podría ser algo trabajoso.</p>
<p>En nuestro fichero de prácticas había 18 polígonos por lo que nuestro resultado es una carpeta donde encontramos guardados 18 shapefiles y 18 ficheros raster. Los recortes quedan como se puede ver en la siguiente imagen:</p>
<div id="attachment_1702" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content/recorte.jpg"><img class="size-medium wp-image-1702" src="http://www.gisandchips.org/wp-content/recorte-300x289.jpg" alt="" width="300" height="289" /></a><p class="wp-caption-text">4. Uno de los 18 raster resultantes de los recortes y al fondo el shapefile original</p></div>
<p>En caso de ser necesario, se podría realizar más tareas sobre todos estos ficheros, con este software o con otros programas. Incluso se plantea la posibilidad de usar multithreading en R para ejecutar tareas con RSAGA. Proximamente haremos alguna demostración de esto.</p>
<p>Antes de acabar, solo quiero recordar quando trabajamos con RSAGA en Windows es posible que nos afecten algunas particularidades sobre el modo en que se forman las rutas (espacios, barras de directorios…) y los mensajes de error que aparecen no son de gran ayuda.</p>
<p>——————————————————————</p>
<p>Si queréis contactar podéis enviarme un email (asunto: gisandchips):</p>
<p>Benito M. Zaragozí</p>
<p>benito.zaragozi@ua.es</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2011/01/13/usando-rsaga-para-procesar-un-raster-grande-por-partes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Digitalización web con OpenLayer y WFS-T (Geoserver)</title>
		<link>http://www.gisandchips.org/2010/09/16/digitalizacion-web-con-openlayer-y-wfs-t-geoserver/</link>
		<comments>http://www.gisandchips.org/2010/09/16/digitalizacion-web-con-openlayer-y-wfs-t-geoserver/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 16:06:40 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Digitalización]]></category>
		<category><![CDATA[OpenLayers]]></category>
		<category><![CDATA[WFS-T]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1654</guid>
		<description><![CDATA[OBJETIVO: En el contexto de la Web 2.0. cada vez son más los casos de cartografía interactiva donde continuamente se está actualizando la información. El caso más espectacular es el de OpenStreetMap, donde una legión de &#8220;mappers&#8221; interactuan con el sistema. Nuestro objetivo es mucho más modesto, pero también más fácil de implementar, y todo [...]]]></description>
			<content:encoded><![CDATA[<p>OBJETIVO:<br />
En el contexto de la Web 2.0. cada vez son más los casos de cartografía interactiva donde continuamente se está actualizando la información. El caso más espectacular es el de OpenStreetMap, donde una legión de &#8220;mappers&#8221; interactuan con el sistema. Nuestro objetivo es mucho más modesto, pero también más fácil de implementar, y todo gracias al uso de estándares y servicios de mapa libres. Perseguimos, en definitiva, una digitalización <em>on-line</em>, en todos los aspectos: creación de nuevos elementos, modificación geométrica de los ya existentes, actualización de atributos, etc. Todo ello con casi todas las ventajas de las aplicaciones de escritorio, pero con la singularidad de que cualquier usuario pueda intervenir sin apenas conocimientos. </p>
<p>Estos son los ingredientes para la receta:</p>
<ul>
<li>capas geográficas almacenadas en tablas PostgreSQL/PostGIS</li>
<li>servicio de mapas WFS-T con GeoServer</li>
<li>Diseño web con OpenLayers</li>
</ul>
<div id="attachment_1677" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content/digitalizacion.png"><img src="http://www.gisandchips.org/wp-content/digitalizacion-300x298.png" alt="Digitalizacion WFS-T" width="300" height="298" class="size-medium wp-image-1677" /></a><p class="wp-caption-text">Digitalizacion WFS-T</p></div><br />
<span id="more-1654"></span><br />
En definitiva, nuestro objetivo es ofrecer un servicio de digitalización de elementos geométricos en Internet, utilizando como framework a OpenLayers, que carga una serie de capas servidas por un servicio de mapas de elementos transaccional (WFS-T) almacenadas en una geodatabase PostGIS.</p>
<p>Tengo que reconocer que en un primer momento intenté realizar este juego con un servidor WFS-T poco conocido, pero muy ligero (funciona como CGI, al igual que MapServer), y trabaja con PostGIS, con lo que me las prometía felices, pero las pruebas fueron satisfactorias  sólo mientras  modificase o crease geometría, pero en ningún momento pude subir o modificar atributos. Para los estudiosos este motor se llama TinyOWS . Seguro que más de uno lo habrá usado satisfactoriamente, con lo que se agradecerían comentarios de como hacerlo . Me gustaba porque la instalación era muy sencilla (colocar el ejecutable en el directorio donde se ejecutan los scripts CGI, generalmente en &#8220;cgi-bin&#8221;, sin necesidad de tener instaladas otras herramientas. En este enlace tienes un precioso ejemplo de esta implementación: <a href="http://dev4.mapgears.com/bdga/bdgaWFS-T.html">http://dev4.mapgears.com/bdga/bdgaWFS-T.html</a></p>
<p>Ante este dilema opté por instalar GeoServer (versión 2.0.1) cuya experiencia está más que demostrada para tener servicios de mapa interoperables. Sí quieres ver las características de nuestro servicio consúltalas aquí</p>
<p><a href="http://www.gisandchips.org:8080/geoserver/wfs?service=wfs&amp;VERSION=1.1.1&amp;REQUEST=GetCapabilities">http://www.gisandchips.org:8080/geoserver/wfs?service=wfs&amp;VERSION=1.1.1&amp;REQUEST=GetCapabilities</a></p>
<p>De esta manera me propuse crear un servicio WFS-T sobre tres capas, cada una de una tipología distinta ( puntos, polígonos y líneas), almacenadas en sus correspondientes tablas de PostGIS:</p>
<ul>
<li>tabla &#8220;golf&#8221; para puntos de campos de golf. Ver <a href="http://www.gisandchips.org:8080/geoserver/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;TypeName=cite:golf">características.</a></li>
<li>tabla &#8220;municipios&#8221; para polígonos de términos municipales Ver <a href="http://www.gisandchips.org:8080/geoserver/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;TypeName=cite:municipios">características.</a></li>
<li>tabla &#8220;vias&#8221; para línea de una red de carreteras Ver <a href="http://www.gisandchips.org:8080/geoserver/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;TypeName=cite:vias">características.</a></li>
</ul>
<p>Para ver su potencial desarrollé tres páginas web para cada uno de los tipos de digitalización</p>
<ul>
<li>demo 1: <a href="http://www.gisandchips.org/demos/j3m/wfs/wfs_golf.html">Digitalización de Campos de golf</a></li>
<li>demo2: <a href="http://www.gisandchips.org/demos/j3m/wfs/wfs_municipios.html">Digitalización de municipios</a></li>
<li>demo 3: <a href="http://www.gisandchips.org/demos/j3m/wfs/wfs_vias.html">Digitalización de vías</a></li>
</ul>
<p><em>NOTA: Puedes probar sin miedo cualquiera de estas demos. Los datos se vuelven a cargar cada día. No te desesperes si es un poco lento el servidor web. No da más de sí.</em></p>
<p>En cada una de las demos he querido incorporar una barra de iconos para hacer uso de las siguientes herramientas:</p>
<p><div id="attachment_1673" class="wp-caption aligncenter" style="width: 212px"><a href="http://www.gisandchips.org/wp-content/panel.png"><img class="size-full wp-image-1673" src="http://www.gisandchips.org/wp-content/panel.png" alt="" width="202" height="29" /></a><p class="wp-caption-text">panel digitalización</p></div>
<ul>
<li>Consulta y edición de atributos</li>
<li>Digitalización</li>
<li>Mover elementos (o vértices en el caso de municipios y vías)</li>
<li>Borrar elementos</li>
<li>Guardar las transacciones</li>
<li>Navegación en modo Pan-zoom</li>
</ul>
<p>El código está implementado de tal forma que la digitalización forma parte de una sesión, y  sólo se validan los cambios (transacción) cuando hacemos clic en el botón &#8220;salvar&#8221;. De esta forma tengo recogido todo el abanico de posibilidades de la digitalización.</p>
<p>OPENLAYERS<br />
Este framework, de sobra conocido es el responsable de articular todos los flujos entre el cliente y la base de datos utilizando WFS-T servido por GeoServer. El código fuente de cada ejemplo lo puedes obtener del propio navegador, por lo que me centraré en desmenuzar las partes:</p>
<p>ESTILO HTML PARA MENÚS<br />
Estilo para la barra de iconos</p>
<pre class="brush: xml; title: ; notranslate">
    &lt;style&gt;
        .customEditingToolbar {
            float: right;
            right: 0px;
            height: 30px;
            width: 220px;
        }
        .customEditingToolbar div {
            float: right;
            margin: 5px;
            width: 24px;
            height: 24px;
        }
        .olControlNavigationItemActive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/editing_tool_bar.png&quot;);
            background-repeat: no-repeat;
            background-position: -103px -23px;
        }
        .olControlNavigationItemInactive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/editing_tool_bar.png&quot;);
            background-repeat: no-repeat;
            background-position: -103px -0px;
        }
        .olControlDrawFeaturePointItemInactive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/editing_tool_bar.png&quot;);
            background-repeat: no-repeat;
            background-position: -77px 0px;
        }
        .olControlDrawFeaturePointItemActive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/editing_tool_bar.png&quot;);
            background-repeat: no-repeat;
            background-position: -77px -23px ;
        }
        .olControlModifyFeatureItemActive {
            background-image: url(../../js/OpenLayers-2.8/theme/default/img/move_feature_on.png);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }
        .olControlModifyFeatureItemInactive {
            background-image: url(../../js/OpenLayers-2.8/theme/default/img/move_feature_off.png);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }
        .olControlDeleteFeatureItemActive {
            background-image: url(../../js/OpenLayers-2.8/theme/default/img/remove_point_on.png);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }
        .olControlDeleteFeatureItemInactive {
            background-image: url(../../js/OpenLayers-2.8/theme/default/img/remove_point_off.png);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }
        .olControlSelectFeatureItemInactive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/info_off.png&quot;);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }
        .olControlSelectFeatureItemActive {
            background-image: url(&quot;../../js/OpenLayers-2.8/theme/default/img/info_on.png&quot;);
            background-repeat: no-repeat;
            background-position: 0px 1px;
        }

    &lt;/style&gt;
</pre>
<p>Aplico en el código de OpenLayers los estilos que tendrá la capa WFS que vamos a cargar</p>
<pre class="brush: jscript; title: ; notranslate">
	    // Styles
            var styles = new OpenLayers.StyleMap({
                &quot;default&quot;: new OpenLayers.Style(null, {
                    rules: [
                        new OpenLayers.Rule({
                            symbolizer: {
                                &quot;Point&quot;: {
                                    pointRadius: 5,
                                    graphicName: &quot;square&quot;,
                                    fillColor: &quot;red&quot;,
                                    fillOpacity: 0.25,
                                    strokeWidth: 1,
                                    strokeOpacity: 1,
                                    strokeColor: &quot;#333333&quot;
                                }
                            }
                        })
                    ]
                }),
                &quot;select&quot;: new OpenLayers.Style({
                    strokeColor: &quot;#00ccff&quot;,
                    strokeWidth: 4
                }),
                &quot;temporary&quot;: new OpenLayers.Style(null, {
                    rules: [
                        new OpenLayers.Rule({
                            symbolizer: {
                                &quot;Point&quot;: {
                                    pointRadius: 5,
                                    graphicName: &quot;square&quot;,
                                    fillColor: &quot;white&quot;,
                                    fillOpacity: 0.25,
                                    strokeWidth: 1,
                                    strokeOpacity: 1,
                                    strokeColor: &quot;#333333&quot;
                                }

                            }
                        })
                    ]
                })
            });
</pre>
<p>En definitivo asigno un estilo para el elemento geométrico, y su comportamiento cuando es seleccionado, cuando está temporal (digitalización), o su valor por defecto.</p>
<p>CAPA WFS<br />
Definimos una capa WFS con Strategy (para indicar que conjunto de datos deben de ser cargados -ej. todos los datos, por BBOX, en clusters, por página, por filtro-)</p>
<pre class="brush: jscript; title: ; notranslate">
// Definimos una capa WFS con St
           var saveStrategy = new OpenLayers.Strategy.Save();

           wfs = new OpenLayers.Layer.Vector(&quot;golf&quot;, {
               //isBaseLayer:true,
               strategies: [new OpenLayers.Strategy.BBOX(), saveStrategy],
               projection: new OpenLayers.Projection(&quot;EPSG:23030&quot;),
               styleMap: styles,
               protocol: new OpenLayers.Protocol.WFS({
                   version: &quot;1.0.0&quot;,
                   srsName: &quot;EPSG:23030&quot;,
                   url: &quot;http://www.gisandchips.org:8080/geoserver/wfs&quot;,
                   featureType: &quot;golf&quot;,
                   featureNS: &quot;http://www.opengeospatial.net/cite&quot;,
                   geometryName: &quot;geometria&quot;,
                   schema: &quot;http://www.gisandchips.org:8080/geoserver/wfs?service=WFS&amp;version=1.0.0&amp;request=DescribeFeatureType&amp;TypeName=cite:golf&quot;,
               })
            });
 // Añadimos la capa anterior y los WMS que queramos de fondo
            map.addLayers([tiled,wfs]);
</pre>
<p>RESALTADO DE ELEMENTOS</p>
<p>El siguiente código controla el resaltado de los elementos cuando se lanzan eventos del ratón (mouseover, selección)</p>
<pre class="brush: jscript; title: ; notranslate">
		/* HIGHLIGHT */

	    // inicio highlight mouseover
            var report = function(e) {
                OpenLayers.Console.log(e.type, e.feature.id);
            };

            var highlightCtrl = new OpenLayers.Control.SelectFeature(wfs, {
                hover: true,
                highlightOnly: true,
                renderIntent: &quot;temporary&quot;,
                eventListeners: {
                    beforefeaturehighlighted: report,
                    featurehighlighted: report,
                    featureunhighlighted: report
                }
            });

            var selectCtrl = new OpenLayers.Control.SelectFeature(wfs,
                {clickout: true}
            );

            map.addControl(highlightCtrl);
            map.addControl(selectCtrl);

            highlightCtrl.activate();
            selectCtrl.activate();

	    /* END HIGHLIGHT */
</pre>
<p>SNAP O TOLERANCIAS DE CAZADO Y SPLIT (CORTES)</p>
<p>En ocasiones puede ser útil que la digitalización no sea a mano alzada (donde hagamos clic con el ratón), sino que tenga establecidas tolerancias de cazado para que cuando nos acerquemos a una línea o un polígono pueda pillar el nodo, vértice o eje. En este <a href="http://openlayers.org/dev/examples/snapping.html">enlace</a> verás un ejemplo más completo de este tema.<br />
En el caso del Split sólo tiene sentido cuando los elementos son polígonos o líneas. Esto nos permite por ejemplo crear una ruta (R1) desde cualquier punto de otra ruta existente (R2), y mientras con el snapping obtenemos la sujección al vértice o eje, la ruta ya existente (R2) se parte en dos partes.</p>
<pre class="brush: jscript; title: ; notranslate">
		/* SNAPPING */
            // Configuración del Snapping
            var snap = new OpenLayers.Control.Snapping({layer: wfs});
            map.addControl(snap);
            snap.activate();

            // Configuración del Split
            var split = new OpenLayers.Control.Split({
                layer: wfs,
                source: wfs,
                tolerance: 1000,
                deferDelete: true,
                eventListeners: {
                    aftersplit: function(event) {
                        var msg = &quot;Split resulted in &quot; + event.features.length + &quot; features.&quot;;
                        flashFeatures(event.features);
                    }
                }
            });
            map.addControl(split);
            split.activate();
</pre>
<p>PANEL Y CONTROLES</p>
<p>Como ya hemos comentado es preferible tener los iconos a mano en el mapa en vez de los típicos radio button, ya que resultan más elegantes.</p>
<pre class="brush: jscript; title: ; notranslate">
/* PANEL */
// crear un panel y añadirle iconos con funcionalidad
var panel = new OpenLayers.Control.Panel(
    {displayClass: 'customEditingToolbar'}
);

// Control para digitalizar puntos (draw)
var draw = new OpenLayers.Control.DrawFeature(
    wfs, OpenLayers.Handler.Point,
    {
        title: &quot;Draw Feature&quot;,
        displayClass: &quot;olControlDrawFeaturePoint&quot;,
        handlerOptions: {freehand: false, multi: false},
        // Muy importante: Si la capa postGIS es POINT poner multi:false.
        // Si es MULTIPOINT poner multi:true
        featureAdded: onFeatureInsert,
        //onFeatureInsert es el método que se ejecuta una vez que hemos terminado de digitalizar
    }
);

/*
En el caso de digitalizar polígonos este sería el código
            var draw = new OpenLayers.Control.DrawFeature(
                wfs, OpenLayers.Handler.Polygon,
                {
                    title: &quot;Draw Feature&quot;,
                    displayClass: &quot;olControlDrawFeaturePolygon&quot;,
                    handlerOptions: {multi: true},
                    featureAdded: onFeatureInsert,
                }
            );
*/

// Control para modificar elementos. En el caso de puntos sólo se pueden desplazar
// a otra posición
modify = new OpenLayers.Control.ModifyFeature(
    wfs, {displayClass: &quot;olControlModifyFeature&quot;, title: &quot;Modify Feature&quot;}
);

// Control para borrar elementos
var del = new DeleteFeature(wfs, {title: &quot;Delete Feature&quot;});

// Control para salvar la sesión de digitalización
var save = new OpenLayers.Control.Button({
    title: &quot;Save Changes&quot;,
    trigger: function() {
        if(modify.feature) {
            modify.selectControl.unselectAll();
        }
        saveStrategy.save();
    },
    displayClass: &quot;olControlSaveFeatures&quot;
});

/*
Control de Información. Es el típico control que una vez que seleccionas un elementos obtenemos los atributos, en este caso englobado en un popUp. Aquí hemos pensado reutilizar este formulario para actualizar datos de cada elemento (UPDATE de atributos).
*/
 selectControl = new OpenLayers.Control.SelectFeature(wfs,
 {
   onSelect: onFeatureInsert,
   onUnselect: onFeatureUnselect,
   displayClass: &quot;olControlSelectFeature&quot;,
   title: &quot;Info&quot;,
});

// Añadimos los controles al panel
panel.addControls([
    new OpenLayers.Control.Navigation({title: &quot;Pan and zoom&quot;}),
    save, del, modify, draw, selectControl
]);

// Definimos el control de navegación como el activo por defecto
panel.defaultControl = panel.controls[0];
map.addControl(panel);
</pre>
<p>FUNCIONES DE CADA CONTROL<br />
Borrar elementos</p>
<pre class="brush: jscript; title: ; notranslate">
 var DeleteFeature = OpenLayers.Class(OpenLayers.Control, {
      initialize: function(layer, options) {
          OpenLayers.Control.prototype.initialize.apply(this, [options]);
          this.layer = layer;
          this.handler = new OpenLayers.Handler.Feature(
              this, layer, {click: this.clickFeature}
          );
      },
      clickFeature: function(feature) {
          // sí no tiene fid eliminarlo
          if(feature.fid == undefined) {
              this.layer.destroyFeatures([feature]);
          } else {
              feature.state = OpenLayers.State.DELETE;
              this.layer.events.triggerEvent(&quot;afterfeaturemodified&quot;,
                                             {feature: feature});
              feature.renderIntent = &quot;select&quot;;
              this.layer.drawFeature(feature);
          }
      },
      setMap: function(map) {
          this.handler.setMap(map);
          OpenLayers.Control.prototype.setMap.apply(this, arguments);
      },
      CLASS_NAME: &quot;OpenLayers.Control.DeleteFeature&quot;
  });
</pre>
<p>Información de los elementos, actualización de atributos e inserción de nuevos elementos (geometría + atributos):</p>
<pre class="brush: jscript; title: ; notranslate">
// Funciones para cerrar el popUp
  function onPopupClose(evt) {
      selectControl.unselect(selectedFeature);
  }

// Función para cuando se quita la selección
 function onFeatureUnselect(feature) {
      map.removePopup(feature.popup);
      feature.popup.destroy();
      feature.popup = null;
  }
</pre>
<p>Función para insertar un nuevo elemento o actualizar atributos en uno ya existente</p>
<pre class="brush: jscript; title: ; notranslate">
// PopUp para insert/update
  function onFeatureInsert(feature)
  {
  		selectedFeature = feature;
                // mapeo de los atributos
		var fid = selectedFeature.id;
     	        var nombre = selectedFeature.attributes['nombre'];
     	        var municipio = selectedFeature.attributes['municipio'];
		var codive = selectedFeature.attributes['codive'];
		var hoyos = selectedFeature.attributes['hoyos'];
                // Compruebo si existe un valor para el atributo nombre.
                // Sí no tiene atributos es un &quot;INSERT&quot; y muestro el formulario para cumplimentar
		if (nombre == null)
		{
 			// formulario
	            htmlForm = &quot;&lt;div style='font-size:.8em'&gt;&quot;+
	            &quot;&lt;H2&gt;&lt;b&gt;A&amp;Ntilde;ADIR CAMPO DE GOLF&lt;/b&gt;&lt;/h2&gt;\n&quot; +
	            &quot;FID: &quot;+ fid + &quot;&lt;br/&gt;\n&quot; +
	            &quot;&lt;input type='hidden' name='fid' id='fid' value='&quot;+ fid +&quot;'&gt;&quot; +
	            //&quot;GEOMETRIA: &quot;+ feature.geometry + &quot;&lt;br/&gt;\n&quot; +
	            &quot;UBICACION: &quot;+ feature.geometry + &quot;&lt;br/&gt;\n&quot; +
	            &quot;Rellene los siguientes datos: &lt;br/&gt; \n&quot; +
	            &quot;NOMBRE:&lt;input type='text' name='nombre' id='nombre' value='Test Campo de Golf' size=20 style='background-color: #E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	            &quot;HOYOS:&lt;input type='text' name='hoyos' id='hoyos' value='18' size=2 style='background-color: #E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	            &quot;MUNICIPIO:&lt;input type='text' name='municipio' id='municipio' value='Test Municipio' size=20 style='background-color: #E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
		    &quot;IVE:&lt;input type='text' name='codive' id='codive' value='12345' size=5 style='background-color: #E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	            &quot;&lt;button onclick='onTriggerInsertar()'&gt;A&amp;ntilde;adir&lt;/button&gt;&quot; +
	            &quot;&lt;button onclick='onTriggerDelNewPoint()'&gt;Eliminar&lt;/button&gt;&lt;/div&gt;&quot;;
             }
/* Sí nombre tiene valor ofrezco los atributos en el formulario para modificarlos, añadiendo al popUp
    un botón para &quot;Actualizar&quot; el registro.
*/
                 else
            {
	         htmlForm = &quot;&lt;div style='font-size:.8em'&gt;&quot;+
	         &quot;&lt;H2&gt;&lt;b&gt;ACTUALIZAR CAMPO DE GOLF&lt;/b&gt;&lt;/h2&gt;\n&quot; +
	         &quot;FID: &quot;+ fid + &quot;&lt;br/&gt;\n&quot; +
	         &quot;&lt;input type='hidden' name='fid' id='fid' value='&quot;+ fid +&quot;'&gt;&quot; +
	         &quot;Rellene los siguientes datos: &lt;br/&gt; \n&quot; +
	         &quot;NOMBRE:&lt;input type='text' name='nombre' id='nombre' value='&quot;+ nombre + &quot;' size=20 style='background-color: #E6E6FA;color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	         &quot;HOYOS:&lt;input type='text' name='hoyos' id='hoyos' value='&quot; + hoyos + &quot;' size=2 style='background-color: #E6E6FA; color:#7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	         &quot;MUNICIPIO:&lt;input type='text' name='municipio' id='municipio' value='&quot; + municipio +&quot;' size=20 style='background-color:#E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
		 &quot;IVE:&lt;input type='text' name='codive' id='codive' value='&quot; + codive +&quot;' size=5 style='background-color:#E6E6FA; color: #7F7F7F; font-style: italic;' &gt; &lt;br/&gt;\n&quot; +
	         &quot;&lt;button onclick='onTriggerUpdate()'&gt;Actualizar&lt;/button&gt;&lt;/div&gt;&quot;;
      }
// Defino el objeto popUp
      popup = new OpenLayers.Popup.FramedCloud(&quot;info&quot;,
    		feature.geometry.getBounds().getCenterLonLat(),
         null,
         htmlForm,
         null,
         true,
         onPopupClose);

      feature.popup = popup;
      map.addPopup(popup);

  }

   // Trigger y función para pasar atributos del formulario
	var btnInsert = new OpenLayers.Control.Button({trigger: onTriggerInsertar});

	function onTriggerInsertar(fid)
	// se le pasa el fid como parametro para seleccionarlo mediante getFeatureById
	{
      //alert(&quot;has llegado a trigger insertar&quot;);
      var fid =  OpenLayers.Util.getElement('fid').value;// recojo el fid del formulario
      var miFeature = wfs.getFeatureById(fid);// hago la selección de la feature a partir del fid del form
      //alert(miFeature.id);
      // Paso atributos del formulario al elemento
		miFeature.attributes.nombre = OpenLayers.Util.getElement('nombre').value;
		miFeature.attributes.municipio = OpenLayers.Util.getElement('municipio').value;
		miFeature.attributes.hoyos = OpenLayers.Util.getElement('hoyos').value;
		miFeature.attributes.codive = OpenLayers.Util.getElement('codive').value;
		// elimina el popup
		onFeatureUnselect(miFeature);
	}
	// fin trigger insert

   // Trigger y función para pasar atributos del formulario en el update
	var btnUpdate = new OpenLayers.Control.Button({trigger: onTriggerUpdate});

	function onTriggerUpdate()
	{
      // defino miFeature como el array de elementos seleccionados, miFeature[0] será el único elemento del array
      miFeature = [selectedFeature]; //alert(miFeature.length);
      // Paso atributos del formulario al elemento
                var fid =  OpenLayers.Util.getElement('fid').value;
                miFeature[0].id = fid;
		miFeature[0].attributes.nombre = OpenLayers.Util.getElement('nombre').value;
		miFeature[0].attributes.municipio = OpenLayers.Util.getElement('municipio').value;
		miFeature[0].attributes.hoyos = OpenLayers.Util.getElement('hoyos').value;
		miFeature[0].attributes.codive = OpenLayers.Util.getElement('codive').value;
		// comprobar que se le pasan los atributos al feature. Descomentar para comprobación
		/*alert (  miFeature[0].id + &quot;,&quot; +
				   miFeature[0].attributes.nombre + &quot;,&quot; +
					miFeature[0].attributes.municipio  + &quot;,&quot; +
					miFeature[0].attributes.hoyos  + &quot;,&quot; +
					miFeature[0].attributes.codive );
               */

		miFeature[0].state = OpenLayers.State.UPDATE;
		// elimina el popup
		map.removePopup(miFeature[0].popup);
                selectControl.unselectAll();
                miFeature[0].popup = null;
	}
	// fin trigger
</pre>
<p>Faltan algunos elementos más, pero en esencia aquí está la lógica de la digitalización. Observa cada caso, puntos, polígonos y líneas para ver las diferencias existentes.</p>
<p>CONCLUSIÓN:<br />
Quizás lo más relevante de este tema es que con un sólo fichero HTML hemos abordado la complejidad de la digitalización, utilizando siempre servicios y tecnologías estándar y abiertas. Con este tipo de soluciones tan sencillas podemos acercar a un número mayor de usuarios, menos especializados quizás, pero que de otra forma se hubieran visto imposibilitados de actuar por razones técnicas, económicas o de formación. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/09/16/digitalizacion-web-con-openlayer-y-wfs-t-geoserver/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>

