<?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 &#187; C#</title>
	<atom:link href="http://www.gisandchips.org/tag/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gisandchips.org</link>
	<description>Geografía útil para llevar</description>
	<lastBuildDate>Tue, 29 Nov 2011 10:38:56 +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>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>Procesamiento de imágenes digitales con C# (y una aplicación para el análisis de parcelas agrícolas).</title>
		<link>http://www.gisandchips.org/2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/</link>
		<comments>http://www.gisandchips.org/2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 13:05:28 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[AForge.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Mineria de datos espacial]]></category>
		<category><![CDATA[Procesamiento digital de imagenes]]></category>
		<category><![CDATA[RAPID]]></category>
		<category><![CDATA[Teledetección orientada a objetos]]></category>
		<category><![CDATA[Transformada de Hough]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1038</guid>
		<description><![CDATA[En este artículo voy a exponer una aplicación de ejemplo que he realizado con C# utilizando Aforge.NET. Dicha aplicación trata (y a veces lo consigue    ) de distinguir si una parcela dada puede ser una plantación  agrícola arbórea mediante el análisis de la Transformada de Hough, y luego se posibilita el conteo automático de [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">En este artículo voy a exponer una aplicación de ejemplo que he realizado con C# utilizando Aforge.NET. Dicha aplicación trata (y a veces lo consigue  <img src='http://www.gisandchips.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />   ) de distinguir si una parcela dada puede ser una plantación  agrícola arbórea mediante el análisis de la  Transformada de Hough, y luego se posibilita el conteo automático de los árboles. Al tratarse de un programa con finalidad didáctica los análisis se realizan para una sola parcela y por pasos muy definidos. No obstante, cabe pensar que su mayor utilidad vendría de un análisis masivo de parcelas.</p>
<h4 style="text-align: center"><a href="http://www.gisandchips.org/wp-content/hough_direcciones.jpg"><img class="size-full wp-image-1041 aligncenter" src="http://www.gisandchips.org/wp-content/hough_direcciones.jpg" alt="hough1" width="392" height="314" /></a>Imagen1</h4>
<p style="text-align: justify"><span id="more-1038"></span>En primer lugar, Aforge.NET es un Framework con distintas librerías que abarcan un amplio rango de campos relacionados con el tratamiento digital de imágenes. Se trata de un proyecto GNU GPL disponible en <a href="http://code.google.com/p/aforge/">http://code.google.com/p/aforge/</a> . Es un proyecto consolidado pero también muy prometedor, en el que Andrew Kirillov tiene un gran trabajo realizado.</p>
<p style="text-align: justify">Según vemos en la página Web entre sus librerías se encuentran:</p>
<ul style="text-align: justify">
<li><strong>AForge.Imaging</strong> &#8211; library with image      processing routines and filters;</li>
<li><strong>AForge.Vision</strong> &#8211; computer vision library;</li>
<li><strong>AForge.Neuro</strong> &#8211; neural networks computation      library;</li>
<li><strong>AForge.Genetic</strong> &#8211; evolution programming      library;</li>
<li><strong>AForge.Fuzzy</strong> &#8211; fuzzy computations library;</li>
<li><strong>AForge.MachineLearning</strong> &#8211; machine learning library;</li>
<li><strong>AForge.Robotics</strong> &#8211; library providing support of      some robotics kits;</li>
<li><strong>AForge.Video</strong> &#8211; set of libraries for video      processing</li>
<li>etc…</li>
</ul>
<p style="text-align: justify">Se me ocurre que alguien se podría plantear un <strong>AForge.GIS</strong>. Pensaremos en ello…</p>
<p style="text-align: justify">Nosotros hemos trabajado únicamente con Aforge.Imaging, pero salta a la vista la potencialidad que prácticamente todas las librerías tendrían para realizar análisis espaciales.</p>
<p style="text-align: justify">
<h3 style="text-align: justify">Introducción</h3>
<p style="text-align: justify">Actualmente, al trabajar en cuestiones de teledetección aplicada a fotografías aéreas e imágenes de satélite se esta aplicando cada vez más el paradigma del Análisis Orientado a Objetos (AOO), pasando de hablar de los valores de los píxeles, a las propiedades de los objetos. Podríamos resumirlo como: teledetección orientada a objetos.</p>
<p style="text-align: justify">No voy a tratar de hablar de análisis orientado a objetos, pues considero que hay abundante información en Internet.</p>
<p style="text-align: justify">Solamente por sentar el ejemplo que vamos a trabajar en este artículo, “Objeto” sería una parcela agrícola que podría tener múltiples “propiedades” como un área, perímetro, otros índices de forma… pero también tendría propiedades basadas en la respuesta espectral de la superficie que encierra, por ejemplo los valores de un índice de vegetación. También serían propiedades muy descriptivas de la parcela aquellas que describan la estructura generada por la distribución de los píxeles. Así pues, para una sola parcela podríamos tener muchísimas propiedades que la describieran, claro está, siempre unas lo harían mejor que otras.</p>
<p style="text-align: justify">En AForge.Imaging están disponibles distintas funciones de análisis para la extracción de estas propiedades o características a partir de una imagen, como por ejemplo la Transformada de Fourier, distintos algoritmos de detección de bordes y la que nos interesa aquí: La <strong>Transformada</strong><strong> de Hough</strong>.</p>
<p style="text-align: justify">En definitiva, hemos elaborado una aplicación de escritorio que calcula la transformada de Hough para la imagen aérea de una parcela, y después de aplicar unas sencillas reglas para decidir si se trata de una parcela agrícola y arbórea, permite contar automáticamente los árboles de dicha parcela.</p>
<p style="text-align: justify">
<h3 style="text-align: justify">La Transformada de Hough</h3>
<p style="text-align: justify">Se trata de una técnica utilizada para extraer elementos, con una forma particular, a partir de una imagen. Es comúnmente aplicada para encontrar y describir líneas rectas en una imagen, aunque también se pueden hallar círculos y otras formas. En la carpeta de ejemplos de AForge podéis encontrar el ejemplo en el que me he basado, en el cual se aplica Hough para hallar líneas y círculos dentro de una imagen.</p>
<p style="text-align: justify">Aquí no vamos a explicar los fundamentos de cálculo, sino la interpretación que podemos hacer de los resultados en nuestro caso del análisis de parcelas.</p>
<p style="text-align: justify">En concreto uno de los datos que obtenemos aplicando Hough es la inclinación de cada una de todas las líneas rectas halladas, como también la intensidad de cada línea (en nuestro caso tendrán mayor intensidad las líneas que más árboles atraviesen).</p>
<p style="text-align: justify">Solamente viendo la <strong>imagen1</strong> podríamos intuir cuales serían las inclinaciones/direcciones de las dos líneas de mayor intensidad halladas por Hough, pero como se ve en la imagen no hay una coincidencia exacta debido a pequeños detalles (los árboles no están homogéneamente separados, la parcela no es cuadrada…).</p>
<p style="text-align: justify"><strong>Nota: las líneas rojas no son las de mayor intensidad, solamente muestran las direcciones.</strong></p>
<p style="text-align: justify">En la <strong>Imagen2</strong> vemos como las direcciones principales son muy similares, y esto nos indica que difícilmente la parcela tendrá la estructura necesaria para realizar el conteo de árboles.</p>
<h4 style="text-align: center"><a href="http://www.gisandchips.org/wp-content/hough_direcciones2.jpg"><img class="size-full wp-image-1043 aligncenter" src="http://www.gisandchips.org/wp-content/hough_direcciones2.jpg" alt="hough_direcciones2" width="417" height="274" /></a>Imagen2</h4>
<h3 style="text-align: justify">Reglas de decisión</h3>
<p style="text-align: justify">Una vez calculado Hough usamos algunas estadísticas de las líneas halladas para crear reglas de decisión que ayuden a distinguir automáticamente la estructura de la parcela.</p>
<p style="text-align: justify">De un modo arbitrario a partir de las pocas parcelas vistas he decidido que serán agrícolas – arbóreas aquellas parcelas cumplan lo siguiente:</p>
<ul style="text-align: justify">
<li>aquellas parcelas que tengan una diferencia angular entre las dos direcciones principales comprendida entre 80 y 120,</li>
<li>o que el % de líneas en la 1ª dirección no sea mucho mayor que el % de la 2ª (&lt;2x)</li>
</ul>
<p style="text-align: justify">Estas reglas deberían ser más complejas y basadas en algún clasificador estadístico o matemático. Pero para ser didáctico es más que suficiente.</p>
<p style="text-align: justify">
<h3 style="text-align: justify">Rough Agricultural Plots IDentifier (RAPID)</h3>
<p style="text-align: justify">RAPID es el nombre que le hemos dado a nuestra aplicación de ejemplo. Es un identificador “basto” de parcelas agrícolas. No hay que esperar maravillas, pero veréis que acierta bastante.</p>
<p style="text-align: center"><a href="http://www.gisandchips.org/wp-content/RAPID.jpg"><img class="aligncenter size-medium wp-image-1448" src="http://www.gisandchips.org/wp-content/RAPID-300x176.jpg" alt="" width="300" height="176" /></a></p>
<h4 style="text-align: center">Imagen3</h4>
<p style="text-align: justify">La aplicación muestra una barra de tareas donde se secuencian los pasos de análisis y a medida que se realiza cada paso se activan nuevos botones.</p>
<p style="text-align: justify">Los botones son:</p>
<ul style="text-align: justify">
<li>OpenImage: permite añadir imágenes propias.</li>
<li>Binarize: binariza la imagen aplicando el umbral especificado en el cuadro de texto.</li>
<li>Calc Hough: calcula la transformada de Hough para la imagen binaria y muestra algunas estadísticas en es cuadro de la derecha. También muestra un mensaje sobre la adecuación, o no, de la parcela.</li>
<li>Count Trees: realiza el recuento de árboles de la imagen binaria y muestra el resultado en el cuadro “Trees estimation”. Este último no debería activarse en caso de que no se cumplieran las condiciones establecidas en nuestras reglas, pero se activa para facilitar todo tipo de pruebas.</li>
</ul>
<p style="text-align: justify">Por último, y para ahorrar tiempo se ha añadido una galería de imágenes de parcelas extraídas del visor del SIGPAC (<a href="http://sigpac.mapa.es/fega/visor/">http://sigpac.mapa.es/fega/visor/</a> ). He intentado que haya cierta variedad. Hay algunas parcelas donde resulta fácil el recuento (1, 2, 6, 8 ), pero también es muy interesante ver como se rechazan las otras parcelas. En algunos casos el conteo de árboles sería difícil incluso manualmente sobre la imagen.</p>
<p>En el caso de la parcela 8 de los ejemplos, vemos que RAPID hace un recuento bastante preciso de los olivos de la parcela 8 de los ejemplos (SIGPAC = 148; RAPID +/- 150, según el Threshold). Por supuesto que seríamos más precisos si elimináramos los ruidos que los bordes de la parcela introducen en el análisis.</p>
<p><a href="http://www.gisandchips.org/wp-content/parcela8_sigpac.jpg"><img class="size-medium wp-image-1449   alignleft" src="http://www.gisandchips.org/wp-content/parcela8_sigpac-242x300.jpg" alt="" width="199" height="246" /></a><a href="http://www.gisandchips.org/wp-content/parcela8_rapid.jpg"><img class="aligncenter size-medium wp-image-1450" src="http://www.gisandchips.org/wp-content/parcela8_rapid-241x300.jpg" alt="" width="202" height="251" /></a></p>
<p style="text-align: center">
<h5 style="text-align: center">Imagenes 4 y 5</h5>
<p style="text-align: justify">Podéis ajustar el umbral, y veréis como el recuento mejora en algunas imágenes. Esto también se podría automatizar.</p>
<p style="text-align: justify">Otra cuestión es que hemos trabajado sobre una imagen RGB, pero es evidente que la distinción de los árboles mejoraría mucho si dispusiéramos de una banda de infrarrojo próximo y la combináramos con las otras antes de realizar la binarización.</p>
<p style="text-align: justify">
<h3 style="text-align: justify">Algunas cosas sobre el código</h3>
<p style="text-align: justify">
<p style="text-align: justify">La mayor parte del código que he escrito se corresponde con aspectos del UI, lo que da una idea de cómo de bueno es AForge.</p>
<p style="text-align: justify">He organizado el código en un fórmulario y tres clases. Hay una clase para binarizar una imagen aplicando unos pocos filtros, otra para obtener las estadísticas de Hough y la última realiza el recuento de “blobs”, en este caso árboles.</p>
<p style="text-align: justify">Solamente me interesa destacar el uso de FilterSequence que permite predefinir el uso de varios filtros, lo cual resulta muy práctico.</p>
<pre class="brush: csharp; title: ; notranslate">

// binarization filtering sequence

FiltersSequence filter = new FiltersSequence(

new ContrastCorrection(),

new Mean(),

new GrayscaleBT709(),

new Threshold()

);
</pre>
<p style="text-align: justify">Por otra parte, si usando filtros y otras herramientas notáis que hacen justo lo contrario de lo que deberían, es porque justamente están haciendo lo contrario <img src='http://www.gisandchips.org/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  . Deberéis aplicar un Invert() al Bitmap. Esto me pasaba con el BlobCounter(), pues me devolvía la cuenta de todo lo que no eran árboles. También deberéis invertir la imagen si queréis usar filtros del tipo Erosion() o Dilatation().</p>
<p style="text-align: justify">
<p style="text-align: justify"><strong>El codigo fuente lo podeis obtener haciendo un checkout del siguiente repositorio subversion: </strong>svn co http://www.gisandchips.org/svn/rapid/</p>
<h3 style="text-align: justify">Referencias</h3>
<ul style="text-align: justify">
<li>De nuevo la página del proyecto: <a href="http://code.google.com/p/aforge/">http://code.google.com/p/aforge/</a></li>
</ul>
<ul style="text-align: justify">
<li>Para entender mejor esta técnica podéis consultar <a href="http://en.wikipedia.org/wiki/Hough_transform">http://en.wikipedia.org/wiki/Hough_transform</a></li>
</ul>
<ul style="text-align: justify">
<li>Antes del verano asistí a un curso en Valencia (Esp.) donde aprendí bastante de este tema. Como me gustó bastante os adjunto la referencia por si lo repiten de nuevo el año que viene: Teledetección aplicada a la actualización de cartografía de ocupación del suelo: técnicas de clasificación orientada a objetos. Curso teórico-práctico. <a href="http://cgat.webs.upv.es/bigfiles/c_objetos/index.html">http://cgat.webs.upv.es/bigfiles/c_objetos/index.html</a></li>
</ul>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Si quereis contactar podeis enviarme un email (asunto: gisandchips):</p>
<p>Benito M. Zaragozí</p>
<p>benito.zaragozi@ua.es</p>
<p style="text-align: justify">
<p style="text-align: justify">
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Edición de geometrías en NTS con CoordinateArrayFilter</title>
		<link>http://www.gisandchips.org/2009/11/04/edicion-de-geometrias-en-nts-con-coordinatearrayfilter/</link>
		<comments>http://www.gisandchips.org/2009/11/04/edicion-de-geometrias-en-nts-con-coordinatearrayfilter/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 11:09:09 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CoordinateArrayFilter]]></category>
		<category><![CDATA[JTS]]></category>
		<category><![CDATA[NTS]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=747</guid>
		<description><![CDATA[Java Topology Suite (JTS) es una librería que resuelve problemas complejos y en la que sus arquitectos han recurrido al uso exhaustivo de patrones de diseño de software como medio de gestionar eficientemente dicha complejidad. Como muestra baste mencionar que los desarrolladores debemos asumir desde el principio el factory pattern que implementa la clase GeometryFactory [...]]]></description>
			<content:encoded><![CDATA[<p><a title="Java Topology Suite" href="http://www.vividsolutions.com/jts/JTSHome.htm" target="_blank">Java Topology Suite</a> (JTS) es una librería que resuelve problemas complejos y en la que sus arquitectos han recurrido al uso exhaustivo de <a title="patrones de diseño de software" href="http://en.wikipedia.org/wiki/Design_pattern_(computer_science)" target="_blank">patrones de diseño de software</a> como medio de gestionar eficientemente dicha complejidad. Como muestra baste mencionar que los desarrolladores debemos asumir desde el principio el <a title="factory pattern" href="http://en.wikipedia.org/wiki/Factory_pattern" target="_blank"><em>factory pattern</em></a> que implementa la clase <em>GeometryFactory</em> que empleamos en la construcción de objetos geométricos. El hecho de que JTS haga uso de patrones de diseño es una muestra más de su fiabilidad, aunque en ocasiones (sobretodo si hay carencia de documentación) también implica un esfuerzo extra por nuestra parte a la hora de entender cómo se solucionan determinados casos de uso. Uno de esos casos en los que la solución no se evidencia a primera vista es la edición de los vértices de una geometría, así que en este  artículo os muestro código de ejemplo para el porting de JTS a C#, <a title="NetTopologySuite" href="http://code.google.com/p/nettopologysuite/" target="_blank">NetTopologySuite</a> (NTS) en su versión 1.2, que os permitirá introduciros en el manejo del interface <em>ICoordinateFilter </em>para la manipulación geométrica.<span id="more-747"></span></p>
<p>Quizá me equivoque, pero creo que no se puede calificar JTS/NTS como un &#8220;framework&#8221; para el desarrollo de herramientas de  manipulación de geometrías (e.g. aplicaciones tipo CAD). El diseño de este API promueve más bien la idea de inmutabilidad de un objeto geométrico a lo largo de su ciclo de vida (aunque no hay un mecanimo que fuerze dicha inmutabilidad), y se centra en la modelización a bajo nivel de las tareas de cálculo topológico y análisis espacial, y en la exactitud de los resultados derivados de un geoproceso, todo ello en función de las recomendaciones del <a title="OGC Simple Feature Access specification" href="http://www.opengeospatial.org/standards/sfa" target="_blank">Open Geospatial Consortium</a>.</p>
<p>Pero es probable que, en algún punto de una secuencia de geoprocesamiento, necesitemos manipular las coordenadas de una geometría (por ejemplo, forzar una corrección de forma transparente para el  usuario). Asumiendo que el array de coordenadas almacena la secuencia de vértices actual en lugar de una copia (que la propiedad <em>Coordinates </em>sea o no una copia depende de la secuencia de coordenadas empleada en la construcción de la geometría; tenéis más información sobre esto en el capítulo 8 de la <a title="JTS Developer's Guide" href="http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf" target="_blank">guía del desarrollador de JTS</a>), nada nos impide editar diréctamente los valores en ese array. También podríamos copiar dicho array, operar sobre los vértices en cuestión, instanciar una nueva geometría y desechar la antigua. Discutir sobre la idoneidad de estas soluciones no es objeto de este artículo. Lo que interesa es que sepamos que el propio API proporciona otras vías específicas para la edición de vértices.</p>
<p>En concreto, si tan sólo necesitamos operar con las coordenadas existentes (no añadir ni borrar), NTS proporciona el interfaz <em>ICoordinateFilter</em>, a partir del cual pueden derivarse clases que implementen el <a title="visitor pattern" href="http://en.wikipedia.org/wiki/Visitor_pattern"><em>visitor pattern</em></a> para operar con la lista de coordenadas de cualquier tipo de geometría. Cada desarrollador puede implementar sus propias operaciones o filtros de coordenadas a conveniencia, pero NTS ya proporciona unos cuantos: <em>UniqueCoordinateArrayFilter</em>, <em>CoordinateCountFilter </em>y, el más simple y objeto de nuestro interés,  <em>CoordinateArrayFilter</em>, que da acceso al array completo de coordenadas para su manipulación.</p>
<h2>Veamos un ejemplo</h2>
<p>Suponed que tenemos el siguiente LineString:</p>
<pre>LINESTRING (100 100,  150 180,  200 210,
            210 140,  100 110,  100 100)</pre>
<p>Si lo visualizárais en vuestro cliente favorito observaríais algo similar a esto:</p>
<p style="padding-left: 90px"><img class="size-medium wp-image-632" src="http://www.gisandchips.org/wp-content/CoordinateArrayFilter1-300x222.png" alt="LineString con autointersección" width="300" height="222" /></p>
<p>Esta geometría presenta una autointersección que NTS permite detectar de diversas formas. Nosotros nos centraremos en corregirla aplicando un criterio muy simple: intercambiaremos los valores de las coordenadas en las posiciones 0 y 4. Aquí tenéis el código fuente de esta operación de desplazamiento de vértices:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using GisSharpBlog.NetTopologySuite.Geometries;
using GisSharpBlog.NetTopologySuite.IO;
using GisSharpBlog.NetTopologySuite.Utilities;

namespace CoordFilter
{
 class Program
 {
  public static void Main(string[] args)
  {
   string wkt = &quot;LINESTRING (100 100,  150 180,  200 210, 210 140,  100 110,  100 100)&quot;;
   WKTReader r = new WKTReader();
   Geometry g = r.Read(wkt);
   //Creamos sendas copias de las coordenadas objeto de desplazamiento
   Coordinate c0 = new Coordinate(g.Coordinates[0]);
   Coordinate c4 = new Coordinate(g.Coordinates[4]);
   //Instanciamos el filtro; puesto que queremos acceso a todo el array
   //de coordenadas de nuestra geometría, indicamos el tamaño del array
   CoordinateArrayFilter filter = new CoordinateArrayFilter(g.NumPoints);
   //El método Apply vuelca el array de coordenadas de la geometría en
   //el array de coordenadas del filtro
   g.Apply(filter);
   //Realizamos la operación de desplazamiento de vértices
   //sobre el array de coordenadas del filtro
   filter.Coordinates[0].X = c4.X;
   filter.Coordinates[0].Y = c4.Y;
   filter.Coordinates[4].X = c0.X;
   filter.Coordinates[4].Y = c0.Y;
   filter.Coordinates[5].X = c4.X;
   filter.Coordinates[5].Y = c4.Y;
   //Notificamos la actualización para que el Envelope pueda recalcularse
   g.GeometryChanged();
   Console.WriteLine(g.ToText());
   Console.Write(&quot;Press any key to continue . . . &quot;);
   Console.ReadKey(true);
  }
 }
}
</pre>
<p>Si ejecutáis el código, obtendréis el siguiente resultado en WKT:</p>
<pre>LINESTRING (100 110,  150 180,  200 210,
            210 140,  100 100,  100 110)</pre>
<p>Y este sería el resultado gráfico:</p>
<p style="padding-left: 90px"><img class="size-medium wp-image-657" src="http://www.gisandchips.org/wp-content/CoordinateArrayFilter2-300x221.png" alt="LineString modificado con CoordinateArrayFilter" width="300" height="221" /></p>
<h2>¿Qué hay del modelo de precisión?</h2>
<p>Lo cierto es que la clase CoordinateArrayFilter no toma en consideración el modelo de precisión de la geometría a modificar. Entonces ¿cómo podemos controlar que, ante un desplazamiento, las coordenadas se calculen sobre el &#8220;grid&#8221; de referencia asociado a la geometría? Una opción es utilizar la clase <em>GeometryEditor</em>, lo que implica generar una nueva geometría a partir de la antigua. Pero ya que hablamos de filtros y traslado de coordenadas, ¿por qué no derivar una clase de tipo ICoordinateFilter que, dado un desplazamiento (dx, dy), mueva una geometría al completo respetando su modelo de precisión? Aquí tenéis un ejemplo:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using GisSharpBlog.NetTopologySuite.Geometries;
using GisSharpBlog.NetTopologySuite.IO;

namespace CoordFilter
{
 class Program
 {
  public static void Main(string[] args)
  {
   string wkt = &quot;LINESTRING (100.24 100.5, 150.82 180.56, 200.06 210.1, 210.44 140.82, 100.24 100.5)&quot;;
   //Asumiendo que la unidad principal es el metro, asociamos un &quot;grid&quot; centimétrico
   //a nuestro objeto GeometryFactory.
   WKTReader r = new WKTReader(new GeometryFactory(new PrecisionModel(100)));
   Geometry g = r.Read(wkt);
   //Instanciamos el filtro; puesto que queremos acceso a todo el array
   //de coordenadas de la geometría a desplazar, indicamos el tamaño del array;
   //además indicamos el modelo de precisión de dicha geometría.
   GeometryMoveFilter filter = new GeometryMoveFilter(g.NumPoints, g.Factory.PrecisionModel);
   g.Apply(filter);
   filter.Move(5.342237891, 3.865754133);
   g.GeometryChanged();
   Console.WriteLine(g.ToText());
   Console.Write(&quot;Press any key to continue . . . &quot;);
   Console.ReadKey(true);
  }

  //Clase derivada de ICoordinateFilter para el desplazamiento
  //de geometrías acorde con un modelo de precisión. El código de esta
  //clase está basado en el de la clase CoordinateArrayFilter de NTS,
  //cuyo autor es Diego Guidi.
  class GeometryMoveFilter : ICoordinateFilter
  {
   Coordinate[] pts = null;
   int n = 0;
   PrecisionModel grid = null;

   //Al igual que la clase CoordinateArrayFilter, el constructor necesita
   //el tamaño del array de coordenadas. Adicionalmente se necesita el
   //objeto PrecisionModel que define el &quot;grid&quot; de referencia
   public GeometryMoveFilter(int size, PrecisionModel model)
   {
    pts = new Coordinate[size];
    grid = model;
   }

   //Este método aplica un desplazamiento en X y en Y sobre
   //cada coordenada
   public void Move(double xOffset, double yOffset)
   {
    for(int i = 0; i &lt; n; i++)
    {
     Coordinate c = pts[i];
     //Aplicamos el desplazamiento
     c.X += xOffset;
     c.Y += yOffset;
     //Ajustamos la coordenada al &quot;grid&quot; de referencia
     grid.MakePrecise(ref c);
    }
   }

   public void Filter(Coordinate coord)
   {
    pts[n++] = coord;
   }
  }
 }
}
</pre>
<p>Si lo ejecutáis deberíais obtener el siguiente resultado:</p>
<p>LINESTRING (105.58 104.37, 156.16 184.43, 205.4 213.97, 215.78 144.69, 105.58 104.37)</p>
<p>Recordad que si estáis trabajando con NTS 1.2 hay que solucionar previamente un &#8220;bug&#8221; que afecta a la clase <em>PrecisionModel</em>. En <a title="modelos de precisión fija en NTS" href="http://www.gisandchips.org/2009/11/03/como-definir-y-usar-modelos-de-precision-fija-en-nts/" target="_blank">este artículo</a> encontraréis información sobre cómo resolverlo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/04/edicion-de-geometrias-en-nts-con-coordinatearrayfilter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo definir y usar modelos de precisión fija en NTS</title>
		<link>http://www.gisandchips.org/2009/11/03/como-definir-y-usar-modelos-de-precision-fija-en-nts/</link>
		<comments>http://www.gisandchips.org/2009/11/03/como-definir-y-usar-modelos-de-precision-fija-en-nts/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 13:14:29 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[fixed PrecisionModel]]></category>
		<category><![CDATA[JTS]]></category>
		<category><![CDATA[MakePrecise]]></category>
		<category><![CDATA[NTS]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=470</guid>
		<description><![CDATA[En JTS Topology Suite el modelo de precisión  es un mecanismo central que determina la robustez de los cálculos geométricos y topológicos. En las especificaciones técnicas de este API libre para el análisis espacial encontrareis una detallada exposición de las implicaciones del modelo de precisión, principalmente en lo que se refiere a situaciones de colapso [...]]]></description>
			<content:encoded><![CDATA[<p>En <a title="JTS Topology Suite" href="http://www.vividsolutions.com/JTS/JTSHome.htm" target="_blank">JTS Topology Suite</a> el modelo de precisión  es un mecanismo central que determina la robustez de los cálculos geométricos y topológicos. En las <a title="especificaciones técnicas" href="http://www.vividsolutions.com/jts/bin/JTS%20Technical%20Specs.pdf" target="_blank">especificaciones técnicas</a> de este API libre para el análisis espacial encontrareis una detallada exposición de las implicaciones del modelo de precisión, principalmente en lo que se refiere a situaciones de colapso dimensional. Por ejemplo, podemos encontrarnos una situación de colapso dimensional cuando a partir de una geometría topológicamente válida calculada sobre un modelo de doble precisión (i.e. un polígono calculado mediante un objeto <em>Polygonizer</em>) obtenemos su representación en WKT y al intentar renderizarlo en una aplicación externa obtenemos un error de validación topológica (i.e. el polígono contiene una autointersección).</p>
<p>Cuando nos vemos en esta coyuntura, es decir, en la necesidad de transferir geometría entre aplicaciones mediante un formato interoperable pero de precisión limitada (i.e. DXF, WKT), hay que plantearse el uso de un modelo de precisión fija, a saber, un modelo que nos permita definir un &#8220;grid&#8221; al que siempre estarán referidas nuestras coordenadas, tanto las de origen como las derivadas del cálculo. En este breve artículo tenéis ejemplos de código fuente que os orientarán sobre cómo aplicar la clase <em>PrecisionModel</em> para trabajar con un &#8220;grid&#8221; de referencia en <a title="NetTopologySuite" href="http://code.google.com/p/nettopologysuite/" target="_blank">NetTopologySuite</a> (NTS), el porting de JTS a C#, en su versión 1.2.<span id="more-470"></span></p>
<p>Definir un &#8220;grid&#8221; es sencillo. Basta con crear una instancia de la clase <em>PrecisionModel</em> y asignarlo al objeto <em>GeometryFactory</em> mediante el cual construyamos nuestras geometrías. Cada geometría así instanciada heredará una referencia a un &#8220;grid&#8221; que determinará cualquier cálculo en el que dicha geometría intervenga posteriormente. Pero, ¿cómo se especifica la precisión de dicho  &#8220;grid&#8221;? Asignando un <strong>factor de escala</strong> que equivale al denominador de la fracción deseada de la unidad principal. Por ejemplo, si la unidad principal es el metro asignaremos 100 para trabajar en centímetros (coordenadas con un máximo de 2 decimales), 1000 para trabajar en milímetros (coordenadas con un máximo de 3 decimales), 200 para trabajar con una precisión de 0.5 centímetros, &#8230;</p>
<pre class="brush: cpp; title: ; notranslate">
using System;
using GisSharpBlog.NetTopologySuite.Geometries;

namespace Grids
{
 class Program
 {
  public static void Main(string[] args)
  {
   //Definición de varios &quot;grids&quot; asumiendo que trabajamos en metros
   PrecisionModel mGrid = new PrecisionModel(PrecisionModels.Fixed); //precisión métrica
   PrecisionModel mGrid2 = new PrecisionModel(1); //equivale al anterior
   PrecisionModel cmGrid = new PrecisionModel(100); //precisión centimétrica
   PrecisionModel mmGrid = new PrecisionModel(1000); //precisión milimétrica
   PrecisionModel halfcmGrid = new PrecisionModel(200); //0.5 cm de precisión
  }
 }
}
</pre>
<p>Cuando se parte de geometrías expresadas como <a title="WKT" href="http://en.wikipedia.org/wiki/Well-known_text" target="_blank">WKT</a>, la aplicación del &#8220;grid&#8221; a la imagen en memoria de las nuevas geometrías es transparente para el programador. Basta con asignar al objeto <em>WKTReader</em> el correspondiente objeto <em>GeometryFactory</em>. Esto significa que si probáis este código:</p>
<pre class="brush: cpp; title: ; notranslate">
using System;
using GisSharpBlog.NetTopologySuite.Geometries;
using GisSharpBlog.NetTopologySuite.IO;

namespace Grids
{
 class Program
 {
  public static void Main(string[] args)
  {
   string wkt = &quot;POLYGON ((253722.078898558 4292685.50730101, 253722.07889856 4292685.50730102, 253735.282733042 4292698.56531273, 253738.905778592 4292696.94218745, 253741.840165249 4292695.62758151, 253735.276565443 4292675.86615228, 253717.38 4292636.98, 253700.54 4292646.23, 253722.078898558 4292685.50730101))&quot;;
   PrecisionModel grid = new PrecisionModel(1000); //precisión milimétrica
   GeometryFactory gf = new GeometryFactory(grid); //vinculamos el &quot;grid&quot; con un objeto GeometryFactory
   WKTReader r = new WKTReader(gf); //asociamos el objeto GeometryFactory con el intérprete de WKT
   Console.WriteLine(r.Read(wkt).ToText()); //de WKT a Geometry y de nuevo a WKT
   Console.Write(&quot;Press any key to continue . . . &quot;);
   Console.ReadKey(true);
  }
 }
}
</pre>
<p>Éste es el resultado que deberíais obtener:</p>
<pre>POLYGON ((253722.079 4292685.507, 253722.079 4292685.507,
          253735.283 4292698.565, 253738.906 4292696.942,
          253741.84 4292695.628, 253735.277 4292675.866,
          253717.38 4292636.98, 253700.54 4292646.23,
          253722.079 4292685.507))</pre>
<p>Sin embargo, puede ocurrir que nuestros datos de entrada se presenten como lista de pares (x,y). En este caso, el programador es responsable de hacer que cada coordenada se ajuste previamente a la precisión del &#8220;grid&#8221; de referencia. Esto se consigue de manera efectiva invocando al método <em>MakePrecise</em> del correspondiente objeto <em>PrecisionModel</em>. El siguiente ejemplo ilustra una solución para el polígono del ejemplo anterior, dada su lista de coordenadas.</p>
<pre class="brush: cpp; title: ; notranslate">
using System;
using GisSharpBlog.NetTopologySuite.Geometries;
using GisSharpBlog.NetTopologySuite.IO;

namespace Grids
{
 class Program
 {
  public static void Main(string[] args)
  {
   List&lt;double[]&gt; coords = new List&lt;double[]&gt;();
   coords.Add(new double[]{253722.078898558, 4292685.50730101});
   coords.Add(new double[]{253722.07889856, 4292685.50730102});
   coords.Add(new double[]{253735.282733042, 4292698.56531273});
   coords.Add(new double[]{253738.905778592, 4292696.94218745});
   coords.Add(new double[]{253741.840165249, 4292695.62758151});
   coords.Add(new double[]{253735.276565443, 4292675.86615228});
   coords.Add(new double[]{253717.38, 4292636.98});
   coords.Add(new double[]{253700.54, 4292646.23});
   coords.Add(new double[]{253722.078898558, 4292685.50730101});

   PrecisionModel grid = new PrecisionModel(1000); //precisión milimétrica
   GeometryFactory gf = new GeometryFactory(grid); //vinculamos el &quot;grid&quot; con un objeto GeometryFactory
   Geometry g = GetPolygon(coords, gf); //instanciamos el polígono a partir de la lista de coordenadas y el objeto GeometryFactory
   Console.WriteLine(g.ToText()); //mostramos el resultado en WKT
   Console.Write(&quot;Press any key to continue . . . &quot;);
   Console.ReadKey(true);
  }

  static Polygon GetPolygon(List&lt;double[]&gt; coords, GeometryFactory gf)
  {
   List&lt;Coordinate&gt; fixedCoords = new List&lt;Coordinate&gt;();
   foreach (double[] xyPair in coords)
   {
    fixedCoords.Add(GetFixedCoordinate(xyPair[0], xyPair[1], gf));
   }
   return gf.CreatePolygon(gf.CreateLinearRing(fixedCoords.ToArray()), null);
  }

  static Coordinate GetFixedCoordinate(double x, double y, GeometryFactory gf)
  {
   Coordinate c = new Coordinate(x, y);
   gf.PrecisionModel.MakePrecise(ref c); //cálculo de coordenada precisa, es decir, referida al &quot;grid&quot; del modelo de precisión milimétrica que lleva aparejado el objeto GeometryFactory
   return c;
  }
 }
}
</pre>
<p>Si ejecutáis este código deberíais obtener un resultado idéntico al anterior.</p>
<h2>¿Y si no funciona &#8230;?</h2>
<p>Como  dije al principio, podéis usar NTS 1.2 para probar estos ejemplos. Si preferís usar NTS 1.7 seguramente necesitaréis efectuar pequeños cambios en el código. De todos modos, tanto con la versión 1.2 como con la 1.7.1 hay un &#8220;bug&#8221; que hace que, independientemente del factor de escala, el modelo de precisión  fija quede referido siempre a la unidad principal, es decir, a coordenadas enteras. Este &#8220;bug&#8221; está corregido en la versión 1.7.3. Lo bueno de trabajar con software libre es que en la mayoría de casos (y éste es uno de ellos) la solución está a nuestro alcance. Así que, los que trabajéis con la versión 1.2, podéis descargar el código fuente <a title="NTS 1.2 download" href="http://sourceforge.net/projects/nts/files/NetTopologySuite/NetTopologySuite%201.2%20Final%20Release/NetTopologySuite_20feb06.zip/download">aquí</a> y modificar la línea <strong>351</strong> del fichero <strong>PrecisionModel.cs</strong>. Donde dice:</p>
<pre>return Math.Floor(((val * scale) + 0.5d) / scale);</pre>
<p>simplemente debe decir:</p>
<pre>return Math.Floor((val * scale) + 0.5d) / scale;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/03/como-definir-y-usar-modelos-de-precision-fija-en-nts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integración de R en aplicaciones de escritorio. R, Rcom y C#</title>
		<link>http://www.gisandchips.org/2009/09/21/integracion-de-r-en-aplicaciones-de-escritorio-r-rcom-y-c/</link>
		<comments>http://www.gisandchips.org/2009/09/21/integracion-de-r-en-aplicaciones-de-escritorio-r-rcom-y-c/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 12:06:06 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[.Net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[Rcom]]></category>
		<category><![CDATA[WinForms]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/wordpress/?p=66</guid>
		<description><![CDATA[Hola a todos. Con este artículo espero escribir el primero de una larga serie de artículos sobre el mundo de R. A nuestro juicio, y el de mucha más gente éste es uno de los proyectos GNU con mayor repercusión y también uno de los más prometedores para los usuarios de información geográfica (sigue siendo [...]]]></description>
			<content:encoded><![CDATA[<p>Hola a todos. Con este artículo espero escribir el primero de una larga serie de artículos sobre el mundo de R. A nuestro juicio, y el de mucha más gente éste es uno de los proyectos GNU con mayor repercusión y también uno de los más prometedores para los usuarios de información geográfica (sigue siendo prometedor, aunque ya es toda una realidad).</p>
<p>Para aquellos que no conozcan R ( <a href="http://cran.r-project.org/">http://cran.r-project.org/</a> ), podemos decir que es un lenguaje de programación a la vez que un paquete estadístico de software, desarrollado bajo licencia GNU GPL de la Free Software Foundation. Lo más interesante de R es que se puede adaptar fácilmente a nuestros intereses mediante la instalación de nuevos paquetes. Hay muchos, y suelen englobar funciones comunes a una misma área de conocimiento. En nuestro caso, existen paquetes relacionados con el tratamiento de la información espacial y más directamente, otros que se relacionan con software GIS. Por poner algunos ejemplos, podemos interactuar desde el GUI de R con SAGA GIS, Grass6, GDAL&#8230; y utilizar muchas de sus herramientas, o bien trabajar con otros paquetes propios de R.</p>
<p>En este artículo no trabajaremos desde el GUI de R. Queremos mostrar como integrar R en nuestras aplicaciones de escritorio de .NET mediante objetos COM.</p>
<p><span id="more-66"></span></p>
<p>Para poder comenzar, deberemos instalar un servidor COM disponible en <a href="http://cran.r-project.org/">http://cran.r-project.org/</a>. Entramos en la sección de software/otros/ e instalamos  <a href="http://cran.r-project.org/contrib/extra/dcom/">R-(D)COM Interface</a>. Por supuesto, también necesitamos tener instalado R 2.8.1. Por otra parte puede ser conveniente instalar un paquete de R llamado rcom con todas sus dependencias.</p>
<p>A partir de aquí, <span style="text-decoration: underline">este artículo está dividido en tres partes</span> por motivos didácticos. Primero se habla de cómo se trabaja con Rcom, después describimos cómo se usa el visor de histogramas (que es el ejemplo propuesto), y por último entramos en algunos detalles del código.</p>
<p>Para descargar el código fuente de R2csharp  podéis hacer un <em>checkout </em>del siguiente repositorio Subversion de GIS&amp;Chips:</p>
<p style="padding-left: 30px"><code>svn co http://www.gisandchips.org/svn/r2csharp</code></p>
<p style="padding-left: 30px">
<h3>Uso básico de Rcom</h3>
<p>Una vez instalado el servidor COM agregamos todas las referencias a un proyecto WindowsForm  en nuestro IDE de C# y sus correspondientes using (aquí hemos trabajado con Visual C# Express Edition).</p>
<p class="MsoNormal" style="text-align: justify;line-height: 150%">
<pre class="brush: csharp; title: ; notranslate">
using STATCONNECTORCLNTLib;
using StatConnectorCommonLib;
using STATCONNECTORSRVLib;
</pre>
<p>Con lo que podemos crear nuestro primer objeto de conexión a R, e iniciar una sesión</p>
<pre class="brush: csharp; title: ; notranslate">

//Conexión a R
StatConnector sc1 = new STATCONNECTORSRVLib.StatConnectorClass();
sc1.Init(&quot;R&quot;);
</pre>
<p>A partir de aquí trabajaremos con tres métodos para interactuar con la sesión de R. Estos son:</p>
<ul>
<li>sc1.EvaluateNoReturn(&#8220;código de R&#8221;);</li>
</ul>
<ul>
<li>sc1.Evaluate(&#8220;código de R&#8221;);</li>
</ul>
<ul>
<li>sc1.GetSymbol(&#8220;nombre de un objeto de R&#8221;);</li>
</ul>
<p>He observado que en ocasiones es indistinto el uso de las dos primeras, pero también podemos recibir una excepción en tiempo de ejecución, por lo que utilizaremos la primera para ejecutar código de R que no tiene porqué devolver ningún resultado (por ejemplo setwd(&#8216;C:/&#8217;) , asigna el directorio de trabajo de R), mientras que el resultado de sc1.evaluate() habitualmente querremos almacenarlo en un objeto para poder consultarlo (no tiene sentido hacer un getwd() para después no mostrar su valor, sc1.Evaluate(&#8220;wd&lt;-getwd()&#8221;), con esto almacenamos el wd en un objeto, el cual podemos consultar desde nuestra aplicación).</p>
<p>Por último, sc1.GetSymbol(&#8220;wd&#8221;) nos sirve para consultar un objeto creado en nuestra sesión de R y manipularlo. Por ejemplo, podríamos querer mostrar en una etiqueta lblWD la ruta del directorio de trabajo.</p>
<pre class="brush: csharp; title: ; notranslate">

string wd = (string)sc1.GetSymbol(&quot;wd&quot;);
lblWD.Text = wd;
</pre>
<p>Hasta aquí ya hemos visto todo lo necesario para interactuar con R. Pero la complejidad puede ser mayor debido a las diferencias entre tipos de datos de R y de .NET. Mientras que en R hablamos entre otros de vectores, listas, matrices y dataframes (de números, caracteres&#8230;), en .NET tendremos arrays de distintos tipos o tipos simples. Deberemos consultar el tipo antes de almacenar los datos en estructuras de .NET. Esto lo podemos hacer mediante:</p>
<pre class="brush: csharp; title: ; notranslate">

txtType.Text = sc1.GetSymbol(&quot;wd&quot;).GetType().ToString();
</pre>
<p class="MsoNormal" style="text-align: justify;line-height: 150%"><span style="font-size: 11pt;line-height: 150%;font-family: Arial">donde averiguamos que la función getwd() devuelve un string de .NET. Utilizaremos GetType() muy amenudo. Solamente hay que pensar que estructuras como un dataframe tendrán una estructura en .NET de array de arrays de&#8230; por lo que deberemos tener muy en cuenta los tipos de cada vector miembro del dataframe (podemos entender un dataframe como un conjunto de vectores relacionados; cada vector puede ser un campo de la &#8220;tabla&#8221; que es un dataframe).</span></p>
<h3>R2csharp_histoviewer</h3>
<p>Nuestra aplicación es algo más que un &#8220;!Hola mundo ¡ &#8220;. Tiene ejemplos básicos de distintas tareas habituales en R, pero en este caso realizadas desde nuestra aplicación. En esta demostración creamos un visor de histogramas con Windows Forms, que organiza la información de R de un modo claro y permite crear, mostrar, editar y eliminar dataframes de R, ejecutar una sencilla función de R (<em>&#8220;hist</em>( )<em>&#8220;</em>), y también crear y eliminar ficheros en el sistema operativo (imágenes, directorios&#8230;).</p>
<p>Podemos simular una sesión de trabajo con este visor siguiendo estos pasos (también vemos la correspondencia de las acciones en comandos de R):</p>
<p>1. Seleccionar cargar objeto para añadir uno a uno los tres ficheros de ejemplo  ( bichos.txt, spatstat.txt y usos.txt)</p>
<p align="center"><strong>read.table()</strong></p>
<p align="center"><strong> </strong></p>
<p>2. Seleccionar el objeto bichos y borrarlo <strong> </strong></p>
<p align="center"><strong>rm(bichos)</strong></p>
<p>3. Seleccionar un campo en el segundo listbox y crear su histograma      presionando el botón Hist.</p>
<p align="center"><strong>hist(objeto$campo)</strong> / nos ahorra hacer un <strong>attatch()</strong> en R</p>
<p>4. Editar una celda del campo &#8220;incendio&#8221; del objeto usos. Cambiar algún 0 por    100, y creamos de nuevo el histograma. Vemos como ha cambiado el objeto de R sin necesidad de conocer la posición del dato dentro del dataframe. (para   saber que estamos editando en el row del datagridview deberá verse un lapiz sobre el &#8220;row head&#8221;)</p>
<div id="attachment_76" class="wp-caption aligncenter" style="width: 282px"><a href="http://www.gisandchips.org/wp-content/rcom_histoviewer.jpg"><img class="size-full wp-image-76" src="http://www.gisandchips.org/wp-content/rcom_histoviewer.jpg" alt="Vista de la aplicación en funcionamiento" width="272" height="271" /></a><p class="wp-caption-text">Vista de la aplicación en funcionamiento</p></div>
<p>Evidentemente, sin que el usuario lo sepa se están realizando varios list(), se aplican filtros, se obtienen los rownames() y colnames(), y otras operaciones habituales en R que aquí no se necesitará teclear y cuyos resultados estarán siempre visibles. Lo cual hace que nuestro interfaz sea más amigable solo por esto.</p>
<h3>Algunas notas sobre el código:</h3>
<p>Entre las tareas más interesantes en el código podemos ver un ejemplo de lectura y escritura de un dataframe en un datagridview, teniendo en cuenta los dos tipos de datos devueltos (enteros y dobles). El fichero de ejemplo spatstat.txt intercala columnas de datos dobles y enteros, claro que también podría haber String [] u otros, pero confiamos en que estas mejoras las puedan realizar nuestros lectores.</p>
<p>En el flujo de trabajo habitual hay dos tipos de objetos, los que contienen nuestros datos y los que utilizamos para interactuar con R. Estos últimos los ocultamos al usuario mediante condiciones &#8220;if&#8221;.</p>
<p>A la hora de crear imágenes temporales podemos hacer que se muestren en el device de R si no especificamos ningún dispositivo de salida para hist(). Aunque me ha parecido más interesante integrar la gráfica en el formulario. Para esto hay que decir que existe un problema al usar el portapapeles de Windows para almacenar un metafile, que es el único formato que R nos permite. Se trata de una incompatibilidad del SO que no nos permitirá recuperar la imagen del clipboard para mostrarla en el picbox (podemos consultar algo acerca de esta cuestión en <a href="http://support.microsoft.com/?scid=kb%3Ben-us%3B323530&amp;x=11&amp;y=12">http://support.microsoft.com/?scid=kb%3Ben-us%3B323530&amp;x=11&amp;y=12</a> ) Por este motivo, recurrimos a crear nuestro propio directorio temporal, el cual eliminamos al cerrar el formulario.</p>
<p>Hay que decir que Rcom aporta muchas posibilidades más directas para mostrar o trabajar con los datos de R. No obstante, considero que ya es mucho trabajo conocer un lenguaje de .NET y tener conocimientos de R, como para también especializarse en todas las opciones de Rcom. Para empezar está muy bien, pero en caso de trabajar a menudo con estas herramientas debería explorarse los ejemplos de Rcom, por si resultan más funcionales.</p>
<p>Una consideración que puedo transmitir a los lectores es que no existe ningún &#8220;binding&#8221; para C# /.NET que nos evite tener que embeber código de R en nuestra aplicación, así como existe rJava (<a href="http://cran.r-project.org/web/packages/rJava/index.html">http://cran.r-project.org/web/packages/rJava/index.html</a> ). En caso de disponer de tal posibilidad la hubiésemos utilizado por múltiples motivos, sobretodo por el uso de un solo lenguaje de programación, lo que facilita la comprensión y sencillez del código y también la depuración de la aplicación.</p>
<p>No es necesario advertir que un buen conocimiento de R y las funciones que se quiera aplicar es fundamental para diseñar el mejor interfaz de usuario posible. Pero en determinados casos donde se debe efectuar análisis exploratorios de los datos el esfuerzo se verá compensado por la comodidad y la rapidez en el trabajo. Incluso pensándolo bien, en equipos de trabajo donde haya investigadores o técnicos que no dominen R la creación de un interfaz de este tipo puede ser más que interesante.</p>
<h3>Algunas referencias:</h3>
<p>En <a href="http://www.codeproject.com/">www.CodeProject.com</a> existe un ejemplo de aplicación para C# (<a href="http://www.codeproject.com/KB/cs/RtoCSharp.aspx">http://www.codeproject.com/KB/cs/RtoCSharp.aspx</a> ) donde se repasan las posibilidades básicas para interactuar con R. También hay varios ejemplos de código disponibles para VB6 en la carpeta donde se nos instala el COM Server (por defecto &#8220;C:\Archivos de programa\R\(D)COM Server\samples&#8221;). Por último, la lista de distribución de Rcom donde se tratan muchas cuestiones relacionadas está en <a href="http://mailman.csd.univie.ac.at/pipermail/rcom-l/">http://mailman.csd.univie.ac.at/pipermail/rcom-l/</a> .</p>
<h3>Datos de ejemplo:</h3>
<p><a href="http://www.gisandchips.org/wp-content/usos.txt">Descargar usos.txt</a></p>
<p><a href="http://www.gisandchips.org/wp-content/spatstat.txt">Descargar spatstat.txt</a></p>
<p><a href="http://www.gisandchips.org/wp-content/bichos.txt">Descargar bichos.txt</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Si quereis contactar podeis 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/2009/09/21/integracion-de-r-en-aplicaciones-de-escritorio-r-rcom-y-c/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Gizmo: GIS Meets Objects!</title>
		<link>http://www.gisandchips.org/2009/07/28/gizmo-gis-meets-objects/</link>
		<comments>http://www.gisandchips.org/2009/07/28/gizmo-gis-meets-objects/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 07:33:08 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Gizmo]]></category>
		<category><![CDATA[object oriented geodatabases]]></category>
		<category><![CDATA[Perst.NET]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/wordpress/?p=93</guid>
		<description><![CDATA[De acuerdo, el título parece un tanto pretencioso. Hace años que la tecnología GIS y la programación orientada a objetos confluyeron para hacernos la vida más fácil. Sin embargo, si al empezar vuestro próximo proyecto les decís a vuestros compañeros &#8220;¡eh, esta vez no hay modelo entidad-relación!&#8221; seguro que provoca sorpresa. Efectivamente, alguno de vosotros [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">De acuerdo, el título parece un tanto pretencioso. Hace años que la tecnología GIS y la programación orientada a objetos confluyeron para hacernos la vida más fácil. Sin embargo, si al empezar vuestro próximo proyecto les decís a vuestros compañeros &#8220;¡eh, esta vez no hay modelo entidad-relación!&#8221; seguro que provoca sorpresa. Efectivamente, alguno de vosotros ya se lo imagina: os voy a hablar de bases de datos geográficas orientadas a objetos.<span id="more-93"></span> Las bases de datos orientadas a objetos (OODB) constituyen uno de los campos de investigación y desarrollo más activos en la actualidad, y de hecho son, junto con la interoperabilidad, la clave que determina el futuro de la tecnología GIS. Existen diversas alternativas de OODB de código abierto. Probablemente el proyecto más activo y difundido sea <a title="DB4O" href="http://www.db4o.com/" target="_blank">DB4O</a>. No renuncio a explorar a fondo este gestor más adelante, sobre todo teniendo en cuenta que la comunidad empieza a construir utilidades para el almacenamiento de datos espaciales como <a title="MapMe" href="http://code.google.com/p/mapme/" target="_blank">MapMe</a>. Sin embargo os confieso que en algún punto se cruzó en mi camino <a title="Perst" href="http://www.mcobject.com/perst" target="_blank">Perst</a>, otro OODB bastante popular, y al indagar acerca de los métodos de indexación y comprobar que implementa R-Trees me picó la curiosidad. Muchos de vosotros sabéis que un experimento lleva a otro, y luego a otro, y así sucesivamente hasta que sin darnos cuenta tenemos un API que &#8230; ¡sirve para algo! De modo que aquí os presento <strong>Gizmo</strong>, un API con el que podéis diseñar vuestra propia geodatabase orientada a objetos. Como su propio nombre indica, Gizmo es un trasto, es rudimentario, no hace muchas cosas, pero garantiza un rato de diversión a los curiosos dispuestos a escribir unas pocas líneas en C#.<br />
Para descargar el código fuente de Gizmo podéis hacer un <em>checkout </em>del siguiente repositorio Subversion de GIS&amp;Chips:</p>
<p style="padding-left: 30px"><code>svn co http://www.gisandchips.org/svn/gizmo/release_0.1</code></p>
<p style="text-align: justify">Obtendréis una solución <a title="SharpDevelop" href="http://www.icsharpcode.net/OpenSource/SD/Default.aspx" target="_blank">SharpDevelop</a> en C# con el proyecto del API <strong>Gizmo</strong>. El proyecto compila sobre el framework .NET 2.0 e incluye los ensamblados de referencia de <a title="Perst" href="http://www.mcobject.com/perst" target="_blank">Perst.NET</a>, <a title="NetTopologySuite" href="http://code.google.com/p/nettopologysuite/" target="_blank">NetTopologySuite</a> y <a title="ProjNET" href="http://projnet.codeplex.com/" target="_blank">ProjNET</a>.</p>
<p style="text-align: justify">
<h4>Cómo diseñar nuestro propio modelo</h4>
<p style="text-align: justify">En pocas palabras, Gizmo es un conjunto de interfaces y clases que facilitan al desarrollador la definición de su propio modelo de objetos geográficos de forma que éstos puedan ser almacenados en una base de datos Perst. Como ya he dicho, esto no deja de ser un experimento: no esperéis una herramienta CASE o un interfaz amigable de diseño a base de diagramas. De momento se trata de que podáis definir vuestras clases siguiendo una lógica coherente de derivación e implementación de métodos y propiedades sin preocuparos excesivamente de cómo funciona Perst. Recordad que, al fin y al cabo, el objetivo es que podáis persistir/serializar en un fichero binario cada objeto geográfico que instanciéis, para poder recuperarlo más adelante mediante criterios espaciales gracias a los índices R-Tree. No hay tablas, ni campos, ni registros. No hay <em>Object Relational Mapping</em>. Se trata de vuestros propios objetos, tal y como los hayáis definido en vuestro modelo, con el estado en que se encontraban al serializarlos.<br />
Pero veamos un ejemplo básico de aplicación en línea de comandos con C#. Para nuestro proyecto necesitaremos sendas referencias a Gizmo y Perst.NET. Para mayor comodidad incluid el proyecto de Gizmo en vuestra solución y añadidlo como referencia en vuestro proyecto de aplicación de consola. Respecto a Perst.NET, disponéis de una copia del ensamblado en el directorio <em>lib</em> del proyecto Gizmo (<em>lib\Perst4.NET\PerstNetGenerics.dll) </em>que podéis usar para agregarlo como referencia en vuestro proyecto.</p>
<p style="text-align: justify">Construiremos un modelo muy simple en el que vamos a representar parcelas y conducciones. Esta podría ser la definición de nuestra clase <em>Parcela</em>:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using Gizmo.Core;

namespace TestGizmo
{
 public class Parcela : GizmoObject
 {
  string _id = string.Empty;
  string _cultivo = string.Empty;

  public string Id {
   get { return _id; }
  }

  public string Cultivo {
   get { return _cultivo; }
  }

  public Parcela(string wkt, int srid,
                 string id, string cultivo) : base(wkt, srid)
  {
   _id = id;
   _cultivo = cultivo;
  }
 }
}
</pre>
<p>Y esta la definición de la clase <em>Conduccion:</em></p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using Gizmo.Core;

namespace TestGizmo
{
 public class Conduccion : GizmoObject
 {
  string _id = string.Empty;
  string _categoria = string.Empty;

  public string Id {
   get { return _id; }
  }

  public string Categoria {
   get { return _categoria; }
  }

  public Conduccion(string wkt, int srid,
                    string id, string categoria) : base(wkt, srid)
  {
  _id = id;
  _categoria = categoria;
  }
 }
}
</pre>
<p style="text-align: justify">Ya tenemos la primera clave para implementar nuestro modelo con Gizmo: nuestros tipos de entidad geográfica deben derivar de la clase <em>GizmoObject</em> y pasar en el constructor dos parámetros comunes a cualquier objeto geográfico en Gizmo, a saber, la geometría (en nuestro caso en WKT) y el identificador del Sistema de Referencia espacial.</p>
<p style="text-align: justify">El siguiente paso es crear el catálogo de índices de nuestro modelo. Esto nos permitirá implementar búsquedas eficientes por atributos. Para ello definamos una clase <em>Catalogo</em>:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using Gizmo.Catalogue;
using Perst;

namespace TestGizmo
{
  public class Catalogo : GizmoCatalogue
  {
    FieldIndex&lt;string, Parcela&gt; _parcelaIdIdx = null;
    FieldIndex&lt;string, Parcela&gt; _parcelaCultIdx = null;
    FieldIndex&lt;string, Conduccion&gt; _conduccionIdIdx = null;
    FieldIndex&lt;string, Conduccion&gt; _conduccionCatIdx = null;

   public FieldIndex&lt;string, Parcela&gt; ParcelaIdIdx {
     get { return _parcelaIdIdx; }
   }

   public FieldIndex&lt;string, Parcela&gt; ParcelaCultIdx {
     get { return _parcelaCultIdx; }
   }

   public FieldIndex&lt;string, Conduccion&gt; ConduccionIdIdx {
     get { return _conduccionIdIdx; }
   }

   public FieldIndex&lt;string, Conduccion&gt; ConduccionCatIdx {
     get { return _conduccionCatIdx; }
   }

   public Catalogo(Storage db, string name) : base(db, name)
   {
     _parcelaIdIdx = db.CreateFieldIndex&lt;string, Parcela&gt;(&quot;Id&quot;, true);
     _parcelaCultIdx = db.CreateFieldIndex&lt;string, Parcela&gt;(&quot;Cultivo&quot;, false);
     _conduccionIdIdx = db.CreateFieldIndex&lt;string, Conduccion&gt;(&quot;Id&quot;, true);
     _conduccionCatIdx = db.CreateFieldIndex&lt;string, Conduccion&gt;(&quot;Categoria&quot;, false);
   }

   public Catalogo()
   {
   }
 }
}
</pre>
<p style="text-align: justify">Como podeis ver aquí la clave está en derivar de la clase <em>GizmoCatalogue</em>, crear en el constructor un índice simple de Perst para cada una de las propiedades de nuestras clases <em>Parcela</em> y <em>Conduccion</em> e implementar los <em>getters </em>correspondientes. Alguien se preguntará &#8220;¿y qué hay del índice espacial?&#8221;: bueno, precisamente de esa tarea se ocupan Gizmo y Perst en última instancia.</p>
<p style="text-align: justify">Finalicemos nuestro modelo agregando una clase <em>layer</em> para cada uno de nuestros tipos de entidad geográfica. Esta es la clase <em>CapaParcelas</em>:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using Gizmo.Core;

namespace TestGizmo
{
 public class CapaParcelas : GizmoLayer
 {
  public Catalogo _root = null;

  protected override Type CatalogueType
  {
   get { return typeof(Catalogo); }
  }

  protected override Type TargetType
  {
   get { return typeof(Parcela); }
  }

  public CapaParcelas(GizmoStore gs, string name) : base(gs, name)
  {
   this._root = (Catalogo) base.Root;
  }

  public Parcela FindById(string id)
  {
   return _root.ParcelaIdIdx.Get(id);
  }

  public Parcela[] FindByCultivo(string cultivo)
  {
   return _root.ParcelaCultIdx.Get(cultivo, cultivo);
  }
 }
}
</pre>
<p style="text-align: justify">Y aquí tenéis la clase <em>CapaConducciones</em>:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using Gizmo.Core;

namespace TestGizmo
{
 public class CapaConducciones : GizmoLayer
 {
  Catalogo _root = null;

  protected override Type CatalogueType
  {
   get { return typeof(Catalogo); }
  }

  protected override Type TargetType
  {
   get { return typeof(Conduccion); }
  }

  public CapaConducciones(GizmoStore gs, string name) : base(gs, name)
  {
   this._root = (Catalogo) base.Root;
  }

  public Conduccion FindById(string id)
  {
   return _root.ConduccionIdIdx.Get(id);
  }

  public Conduccion[] FindByCategoria(string categoria)
  {
   return _root.ConduccionCatIdx.Get(categoria, categoria);
  }
 }
}
</pre>
<p style="text-align: justify">Las clases <em>layer</em> son el mecanismo para explotar objetos geográficos del mismo tipo. La clave está en designar el tipo asociado mediante la propiedad <em>TargetType</em> e implementar métodos de recuperación de objetos (<em>FindBy&#8230;</em>) mediante los correspondientes índices del catálogo.</p>
<p style="text-align: justify">
<h4 style="text-align: justify">¡Hagamos una prueba!</h4>
<p style="text-align: justify">Ya podemos editar la función <em>Main</em> de nuestra aplicación de consola. No olvidéis añadir el correspondiente  <em>using Gizmo.Core; </em>en la cabecera de vuestro fichero <em>Program.cs</em>. En primer lugar creamos nuestra base de datos geográfica (<em>gizmo.dbs)</em>, la abrimos y creamos las capas de parcelas y conducciones.</p>
<pre class="brush: csharp; title: ; notranslate">
GizmoStore gs = new GizmoStore(&quot;gizmo.dbs&quot;);
gs.Open();
CapaParcelas cp = new CapaParcelas(gs, &quot;parcelas&quot;);
CapaConducciones cc = new CapaConducciones(gs, &quot;conducciones&quot;);
</pre>
<p style="text-align: justify">A continuación almacenamos un  par de parcelas y una conducción a partir de geometrías en WKT en el sistema de proyección UTM 30N ED50 (SRID = 23030).</p>
<pre class="brush: csharp; first-line: 5; title: ; notranslate">
string wktP0 = &quot;POLYGON((10 10, 10 20, 20 20, 20 10, 10 10))&quot;;
string wktP1 = &quot;POLYGON((30 30, 30 40, 40 40, 40 30, 30 30))&quot;;
cp.Add(new Parcela(wktP0, 23030, &quot;P0&quot;, &quot;CEREAL&quot;));
cp.Add(new Parcela(wktP1, 23030, &quot;P1&quot;, &quot;FRUTAL&quot;));
string wktC0 = &quot;LINESTRING(5 5, 45 45)&quot;;
cc.Add(new Conduccion(wktC0, 23030, &quot;C0&quot;, &quot;PRIMARIA&quot;));
</pre>
<p>Como podéis ver,  almacenamos/persistimos nuestras parcelas y conducciones a través de la <em>layer</em> correspondiente invocando el método <em>Add</em>. En la <em>layer</em> <em>CapaParcelas </em>tenemos la parcela <strong>P0</strong> con cultivo de <strong>CEREAL</strong> y la <strong>P1</strong> con cultivo de <strong>FRUTAL</strong>. Y en la <em>layer CapaConducciones </em>tenemos la tubería <strong>C0</strong> de categoría <strong>PRIMARIA</strong>. Hasta aquí todo resulta bastante sencillo. Pero ¿y si queremos saber por qué parcelas pasa la tubería <strong>C0</strong>? Pues bien, esta es la respuesta en 2 líneas:</p>
<pre class="brush: csharp; first-line: 11; title: ; notranslate">

Conduccion c0 = cc.FindById(&quot;C0&quot;);
IGizmoObject[] query = cp.FindCrossedBy(c0);
</pre>
<p>Y si imprimimos las parcelas resultantes,</p>
<pre class="brush: csharp; first-line: 13; title: ; notranslate">

foreach (IGizmoObject p in query)
{
 Console.WriteLine((p as Parcela).Id);
}
gs.Close();
</pre>
<p>el resultado que debemos obtener es <strong>P0</strong> y <strong>P1</strong>.</p>
<p>Por cierto: ¡no olvidéis cerrar vuestra base de datos! (línea de código 17).</p>
<p>Eso es todo. Espero que disfrutéis un rato con Gizmo. En futuros artículos comentaré más aspectos de este proyecto.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/07/28/gizmo-gis-meets-objects/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Simplify Workbench: banco de pruebas para geometría simplificada</title>
		<link>http://www.gisandchips.org/2009/04/29/simplify-workbench-banco-de-pruebas-para-geometria-simplificada/</link>
		<comments>http://www.gisandchips.org/2009/04/29/simplify-workbench-banco-de-pruebas-para-geometria-simplificada/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 09:40:18 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[geometry simplification]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[SharpMap]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/wordpress/?p=22</guid>
		<description><![CDATA[Optimizar nuestro cliente GIS, tanto para web como para escritorio, implica entre otras cosas afinar al máximo los rangos de escala de visualización para cada una de nuestras capas. Sin embargo puede darse el caso de que este mecanismo no sea aplicable. Ante esta situación, es importante que no renunciemos al ahorro en los tiempos [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">Optimizar nuestro cliente GIS, tanto para web como para escritorio, implica entre otras cosas afinar al máximo los rangos de escala de visualización para cada una de nuestras capas. Sin embargo puede darse el caso de que este mecanismo no sea aplicable. Ante esta situación, es importante que no renunciemos al ahorro en los tiempos de proceso, y en este sentido puede ser útil recurrir a la simplificación o generalización de la geometría.</p>
<p style="text-align: justify">Lo que aquí os ofrecemos es una herramienta que, dada una determinada entidad PostgreSQL/PostGIS, permite explorar rápidamente cuál es la relación entre tamaño de imagen, extensión del mapa, degradación visual y tiempo de proceso <span id="more-22"></span>para un máximo de 4 valores de tolerancia designados por el usuario. Se trata de una aplicación sencilla, escrita en C#, en la que el área de trabajo se divide en cuatro paneles. En cada panel podemos asignar una tolerancia, visualizar la geometría simplificada resultante, echar un vistazo a la sentencia SQL ejecutada en PostgreSQL y comprobar el tiempo de proceso transcurrido en realizar la transacción en el servidor y generar la imagen resultante en el cliente. Además, en todo momento conocemos cuál es la dimensión en píxeles de la imagen y el ancho del mapa. La instantánea inferior muestra una sesión de Simplify Workbench en la que se compara la geometría simplificada de los municipios de España procedentes de la Base de Datos de Líneas Límite a escala 1:1.000.000 del <a title="IDEE" href="http://www.idee.es" target="_blank">IDEE</a>. Se puede observar cómo el tiempo de proceso del panel C es casi 4 veces menor que el del panel A, mientras que el impacto en la visualización es casi inapreciable. Por el contrario, la reducción del tiempo de proceso en el panel D conlleva una degradación visual que, para la resolución de la imagen, no es aceptable.</p>
<div id="attachment_42" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content/simplifyworkbench3.png"><img class="size-medium wp-image-42" src="http://www.gisandchips.org/wp-content/simplifyworkbench3-300x290.png" alt="Geometría simplificada de los municipios de España en Simplify Workbench. Fuente de datos: IDEE" width="300" height="290" /></a><p class="wp-caption-text">Geometría simplificada de los municipios de España en Simplify Workbench. Fuente de datos: IDEE</p></div>
<p style="text-align: center">
<p style="text-align: justify">Podéis disponer del código fuente de Simplify Workbench bajo licencia GPL haciendo un <em>checkout </em>del siguiente repositorio Subversion de GIS&amp;Chips:</p>
<p style="text-align: justify;padding-left: 30px"><code>svn co http://www.gisandchips.org/svn/simplifyworkbench</code></p>
<p style="text-align: justify">Para los que queráis probarlo de inmediato, tened en cuenta que los datos de conexión a PostgreSQL y entidad PostGIS se configuran en el fichero XML <strong>app.config</strong> que acompaña al ejecutable. Por defecto, os proporcionamos una conexión al servidor PostgreSQL de GIS &amp; Chips para que podáis hacer tests con los municipios del IDEE. Si vais a realizar pruebas con vuestros propios datos tened en cuenta que la función de simplificación de PostGIS (<em>simplify</em> o <em>st_simplify</em>) no opera sobre geometrías en coordenadas geográficas (e.g. SRID = 4326), por lo que la aplicación no realizará el tratamiento esperado. Tampoco opera sobre entidades con sistema de referencia espacial indeterminado en la tabla <em>geometry_columns </em>(i.e. SRID = -1).</p>
<p style="text-align: justify">Si eres desarrollador y te vas a &#8216;zambullir&#8217; en el código seguramente te interesará conocer que Simplify Workbench no es más que una extensión de <a title="SharpMap" href="http://www.codeplex.com/SharpMap" target="_blank">SharpMap</a> con un interfaz gráfico en Windows.Forms. Formalmente es una solución desarrollada en el IDE de código abierto <a title="SharpDevelop" href="http://www.icsharpcode.net/OpenSource/SD/" target="_blank">SharpDevelop</a>, escrita en C# sobre el framework 2.0 de .NET. Integra tres proyectos:  <strong>SharpMap </strong>(versión 0.9), <strong>SharpMapSimplifyExtension</strong> y <strong>Simplify</strong>.</p>
<p style="text-align: justify">Seguramente alguno de vosotros ya conozca <a title="SharpMap" href="http://www.codeplex.com/SharpMap" target="_blank">SharpMap</a>. Desde que <a title="Morten Nielsen" href="http://www.sharpgis.net/" target="_blank">Morten Nielsen</a>, su creador, publicó allá por 2005-2006  este versátil renderizador de cartografía basado en GDI+, una pequeña revolución se ha producido en el ámbito de los clientes GIS libres sobre plataforma .NET y de hecho el proyecto no sólo continúa muy activo sino que ha conseguido integrar un equipo consolidado de desarrolladores en torno a un ecosistema de proyectos interrelacionados. El proyecto <strong>SharpMap</strong> de Simplify Workbench corresponde a los fuentes de la versión 0.9, la versión estable, aunque observaréis que el namespace SharpMap.Data.Providers incluye el proveedor de PostGIS (<a title="PostGIS.cs" href="http://sharpmap.codeplex.com/Wiki/View.aspx?title=PostGIS" target="_blank">PostGIS.cs</a>) y una referencia a <a title="Npgsql" href="http://npgsql.projects.postgresql.org/" target="_blank">Npgsql</a>, la librería de acceso a datos de PostgreSQL en su versión 2.0.4.</p>
<p style="text-align: justify">El proyecto <strong>SharpMapSimplifyExtension</strong> consta de dos clases: <strong>PostGISSimplify</strong> y <strong>VectorSimplifiedLayer</strong>. La primera es una derivación de la clase SharpMap.Data.Providers.PostGIS que modifica el método <em>GetGeometriesInView</em> de forma que la sentencia SQL subyacente invoque la función <em>simplify</em> de PostGIS con la tolerancia de entrada. También añade un delegado que permite recuperar mediante un evento tanto la sentencia SQL final como el ancho del <em>bounding box</em>. La segunda deriva de la clase SharpMap.Layers.VectorLayer, sobrecarga el constructor para instanciar capas vectoriales especificando una tolerancia de simplificación y modifica el método <em>Render</em>. Con estas dos simples extensiones podemos definir  una capa vectorial que muestre geometría simplificada de PostGIS sin variar sustancialmente la lógica habitual de trabajo con SharpMap, tal y como se muestra en este ejemplo:</p>
<pre class="brush: csharp; title: ; notranslate">
//
//
//
string cnstr = &quot;Server=your.pgsql.server;Port=5432;User Id=user;Password=secret;Database=yourDB&quot;;
string tableName = &quot;yourPolygons&quot;;
string geomFieldName = &quot;geometry&quot;;
string oidFieldName = &quot;oid&quot;;
//Instance of data provider for PostGIS simplified geometry
PostGISSimplify src = new PostGISSimplify(cnstr, tableName, geomFieldName, oidFieldName);
//Instance of vector layer to hold simplified PostGIS geometry
//Third parameter is an integer corresponding to tolerance in Douglas-Peucker vertex reduction algorithm
VectorSimplifiedLayer lyr = new VectorSimplifiedLayer(&quot;SIMPLIFIED_LAYER&quot;, src, 1000);
lyr.Style.EnableOutline = true;
lyr.Style.Fill = Brushes.Transparent;
//Map object, the layer container and rendering logic construct in SharpMap
Map m = new Map(new System.Drawing.Size(350, 275));
m.BackColor = Color.White;
m.Layers.Add(lyr);
//Zoom to extents internally invokes the modified GetGeometriesInView method in PostGISSimplify class
m.ZoomToExtents();
//Retrieve map image
System.Drawing.Image img = m.GetMap();
//
</pre>
<p style="text-align: justify">El proyecto <strong>Simplify</strong> incluye el formulario estructurado en cuatro paneles comentado más arriba y una clase de conveniencia, <strong>MapRenderer</strong>, que encapsula la lógica de lectura del fichero app.config, definición de layer, obtención de la imagen, recuperación de la sentencia SQL y cálculo del tiempo de proceso. En el directorio de este proyecto encontraréis también el fichero de solución de SharpDevelop (Simplify.sln).</p>
<p style="text-align: justify">Para terminar, y puesto que muchos de nosotros aquí en GIS &amp; Chips somos fans del framework de código abierto Mono, os animamos a que probéis a compilar usando esta plataforma. Sabemos positivamente que SharpMap 0.9, con pequeñas modificaciones, es compilable sobre Mono. Creemos, aunque no lo hemos comprobado, que el código de Simplify Workbench también lo es. Si alguno lo consigue nos alegrará que nos lo comente.</p>
<p style="text-align: justify">¡Disfrutad con Simplify Workbench!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/04/29/simplify-workbench-banco-de-pruebas-para-geometria-simplificada/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

