<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>GIS &amp; Chips</title>
	
	<link>http://www.gisandchips.org</link>
	<description>Geografía útil para llevar</description>
	<lastBuildDate>Thu, 06 May 2010 06:51:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/GisChips" /><feedburner:info uri="gischips" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by/2.0/</creativeCommons:license><feedburner:emailServiceId>GisChips</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>OpenLayers y Panoramio</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/fJDUnTzg378/</link>
		<comments>http://www.gisandchips.org/2010/05/04/openlayers-y-panoramio/#comments</comments>
		<pubDate>Tue, 04 May 2010 09:59:47 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[OpenLayers]]></category>
		<category><![CDATA[Panoramio]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1601</guid>
		<description><![CDATA[Tras leer el excelente post de Pepe relativo a la integración de servicios de geo-localización en un ambiente Google Maps llegué a la conclusión de que resulta muy fácil aplicarlo con dicha API, pero mi inquietud me llevó a investigar en la posibilidad de integrarlo en otra API de tipo mapping de reconocido prestigio, como ]]></description>
			<content:encoded><![CDATA[<p>Tras leer el excelente <a href="/2010/03/24/api-de-google-openstreetmap-y-otros-servicios-georreferenciados/">post</a> de <a href="http://www.gisandchips.org/author/pepe/">Pepe</a> relativo a la integración de servicios de geo-localización en un ambiente <a href="/2010/03/24/api-de-google-openstreetmap-y-otros-servicios-georreferenciados/">Google Maps</a> llegué a la conclusión de que resulta muy fácil aplicarlo con dicha API, pero mi inquietud me llevó a investigar en la posibilidad de integrarlo en otra API de tipo mapping de reconocido prestigio, como es el caso de <a href="http://openlayers.org">OpenLayers</a>, que además es 100% Open Source, lo que nos permite añadir múltiples fuentes de datos (wms, wfs, gml, xml, geojson, georss, conjunto de tiles, proveedores de mapa mundiales -OpenStreetMap, GMaps, Virtual Earth, Yahoo Maps, etc.), además de esa libertad de movimientos que le confieren una cierta ventaja sobre su homónima, sin que ello suponga una crítica hacia Google Maps, que entre otras virtudes ha popularizado el uso de los servicios de mapa vía web, acercándolo a un público genérico sin apenas conocimientos.<br />
<div id="attachment_1618" class="wp-caption aligncenter" style="width: 496px"><a href="http://www.gisandchips.org/demos/j3m/panoramio/panoramio.html"><img src="http://www.gisandchips.org/wp-content/captura_panoramio2.png" alt="Openlayers con Panoramio" width="486" height="228" class="size-full wp-image-1618" /></a><p class="wp-caption-text">Openlayers con Panoramio</p></div><br />
<span id="more-1601"></span></p>
<p>A la hora de &#8220;copiar&#8221; el ejemplo descrito en dicho post para OpenLayer, no he planteado integrar todos los geoservicios, entre otras cosas porque algunos de ellos forman parte de la API casi desde su inicio, y no supone un gran esfuerzo incorporarlo, salvo el de YouTube, que no tuve tiempo de ver, aunque tampoco creo que haya muchos videos geoposicionados. Ejemplos de integración de KML en OL hay muchos en la red, al igual que de GML, GeoJSON o GeoRSS, y también de Flickr, que en el fondo es acceder a un documento XML. Para más información consultas los <a href="http://dev.openlayers.org/releases/OpenLayers-2.9/examples/">ejemplos</a> on-line del portal Openlayers.org</p>
<p>De todos los geoservicios, al que más atención ha prestado ha sido al de <a href="http://www.panoramio.com">Panoramio</a>, entre otras cosas por la ingente cantidad de fotografías georreferenciadas que integra, lo que lo hace muy atractivo para el webmaster. Como muchos sabéis este portal dispone de un <a href="http://www.panoramio.com/api/">servicio REST</a> público que nos permite ejecutar una URL con ciertos parámetros, que finalmente nos devuelve un documento estructurado en formato JSON</p>
<pre>
{
"count": 110,
"photos": [
{
"upload_date": "20 May 2007",
"owner_name": "Carlos Sieiro del Nido",
"photo_id": 2313090,
"longitude": -0.516679,
"height": 75,
"width": 100,
"photo_title": "UNIVERSIDAD DE ALICANTE-Campus de San Vicente del Raspeig.",
"latitude": 38.386611000000002,
"owner_url": "http://www.panoramio.com/user/134716",
"owner_id": 134716,
"photo_file_url": "http://mw2.google.com/mw-panoramio/photos/thumbnail/2313090.jpg",
"photo_url": "http://www.panoramio.com/photo/2313090"
},
{
"upload_date": "16 January 2007",
"owner_name": "\u00a9 www.fotoseb.es - Sebastien Pigneur Jans",
"photo_id": 453228,
"longitude": -0.51438300000000003,
"height": 66,
"width": 100,
"photo_title": "Foto Aerea Universidad Alicante 2 (Foto_Seb)",
"latitude": 38.381700000000002,
"owner_url": "http://www.panoramio.com/user/55833",
"owner_id": 55833,
"photo_file_url": "http://mw2.google.com/mw-panoramio/photos/thumbnail/453228.jpg",
"photo_url": "http://www.panoramio.com/photo/453228"
}]</pre>
<p>}</p>
<p>Como podéis ver por cada foto disponemos de un array con los datos que nos interesan, y de forma particular los siguientes:</p>
<ul>
<li> <strong>owner_name</strong>: autor</li>
<li> <strong>photo_title</strong>: título</li>
<li> <strong>latitude</strong> y <strong>longitude</strong>: coordenadas geográficas de geoposicionamiento en datum WGS 84</li>
<li> <strong>photo_id</strong>: identificador de foto</li>
<li> <strong>photo_file_url</strong>: URL de la imagen</li>
<li> <strong>photo_url</strong>: URL del recurso en la web de Panoramio</li>
</ul>
<p>Integrar Panoramio en OpenLayers no resulta tan elegante como en GM, donde sólo hay que escribir 2 líneas, pero con un poco de esfuerzo y el apoyo de la comunidad seguro que alguien es capaz de escribir una <a href="http://docs.openlayers.org/library/formats.html#creating-custom-formats">clase derivada</a> de JSON que facilite las cosas. Por ahora me limitaré a desmenuzar el código de forma secuencial para que se entienda el proceso</p>
<p>Lo primero que debemos de hacer es preparar nuestro proxy para que admita peticiones al host de Panoramio.  En este <a href="http://trac.openlayers.org/wiki/FrequentlyAskedQuestions#ProxyHost">enlace</a> explica como hacerlo</p>
<pre class="brush: jscript;">
OpenLayers.ProxyHost= &quot;/cgi-bin/proxy.cgi?url=&quot;;
</pre>
<p>Posteriormente creamos un par de variables con la URL del servicio REST y los parámetros</p>
<pre class="brush: jscript;">
url = &quot;http://www.panoramio.com/map/get_panoramas.php&quot;;
parametros = {
   order:'popularity',
   set:'full',
   from:0,
   to:20,
   minx: minx,
   miny: miny,
   maxx: maxx,
   maxy: maxy,
   size:'thumbnail'
}
</pre>
<p>Consulta la documentación de la API de Panoramio para más información. Por ahora los parámetros que más nos interesan son:</p>
<ul>
<li> “<strong>to</strong>”: indica el nº de fotografías que queremos cargar. Máximo 50</li>
<li> “<strong>minx</strong>”,”<strong>miny</strong>”,”<strong>maxx</strong>”,”<strong>maxy</strong>”: coordenadas de la BBOX donde buscará fotos. Debén de estar en coordenadas geográficas (EPSG: 4326). En mi caso los he obtenido utilizando este código:</li>
</ul>
<pre class="brush: jscript;">
// Obtener extensiones.
ext = map.getExtent();
var minx = ext.left;
var miny = ext.bottom;
var maxx = ext.right;
var maxy = ext.top; //alert (minx + &quot; &quot; + miny + &quot; &quot; + maxx + &quot; &quot; + maxy);
</pre>
<p>Por último sólo nos queda invocar a un HttpRequest de AJAX que ejecute la URL con los parámetros y los envíe a nuestra función: mostrarfotos</p>
<pre class="brush: jscript;">
OpenLayers.loadURL(url, parametros, this, mostrarfotos);
</pre>
<p><strong>Función mostrarfotos</strong><br />
Es la encargada de procesar el documento JSON que recibe como argumento</p>
<pre class="brush: jscript;">
function mostrarfotos(response) {
</pre>
<p>El documento JSON, que todavía es una cadena de texto es parseada con OpenLayers.Format.JSON, que la convierte en un objeto que ya podemos tratar:</p>
<pre class="brush: jscript;">
var json = new OpenLayers.Format.JSON();
var panoramio = json.read(response.responseText);
</pre>
<p>Creamos un array de featutes con el total de fotos  (panoramio.photos.length)</p>
<pre class="brush: jscript;">
var features = new Array(panoramio.photos.length);
</pre>
<p>Aplicamos un bucle “for” para recorrer cada fotografía.</p>
<pre class="brush: jscript;">
for (var i = 0; i &lt; panoramio.photos.length; i++)
{
</pre>
<p>Declaramos y almacenamos cada dato de la foto en una variable para recorrerla con comodidad.</p>
<pre class="brush: jscript;">
var upload_date = panoramio.photos[i].upload_date;
var owner_name = panoramio.photos[i].owner_name;
var photo_id = panoramio.photos[i].photo_id;
var longitude =panoramio.photos[i].longitude;
var latitude = panoramio.photos[i].latitude;
var pheight = panoramio.photos[i].height;
var pwidth = panoramio.photos[i].width;
var photo_title = panoramio.photos[i].photo_title;/
var owner_url = panoramio.photos[i].owner_url;
var owner_id = panoramio.photos[i].owner_id;
var photo_file_url = panoramio.photos[i].photo_file_url;
var photo_url = panoramio.photos[i].photo_url;
</pre>
<p>Opcionalmente podemos recoger todas las fotografías en código HTML para ser ubicadas en el BODY con un DIV, en forma de “galería de fotos”</p>
<pre class="brush: jscript;">
OpenLayers.Util.getElement('galeria').innerHTML +=
     &quot;&lt;a href='&quot;+ photo_url +
     &quot;'&gt;&lt;img src='&quot;+photo_file_url+&quot;' title='&quot;+
     photo_title +&quot;' /&gt;&lt;/a&gt;&amp;nbsp;&quot;;
</pre>
<p>Posteriormente en el BODY para representar esta galería sólo hay que escribir:</p>
<pre class="brush: xml;">
&lt;div id=&quot;galeria&quot;&gt;&lt;/div&gt;
</pre>
<p>Creamos un objeto point con las coordenadas de la foto</p>
<pre class="brush: jscript;">
var fpoint = new OpenLayers.Geometry.Point(longitude,latitude);
</pre>
<p>Creo un array de atributos</p>
<pre class="brush: jscript;">
var atributos = {
   'upload_date' : upload_date,
   'owner_name':owner_name,
   'photo_id':photo_id,
   'longitude':longitude,
   'latitude':latitude,
   'pheight':pheight,
   'pwidth':pwidth,
   'pheight':pheight,
   'photo_title':photo_title,
   'owner_url':owner_url,
   'owner_id':owner_id,
   'photo_file_url':photo_file_url,
   'photo_url':photo_url
}
</pre>
<p>Por cada foto creo un elemento (feature) que contiene su posición y sus atributos</p>
<pre class="brush: jscript;">
features[i] = new OpenLayers.Feature.Vector(fpoint,atributos);
</pre>
<p>Terminamos el bucle</p>
<pre class="brush: jscript;">
}
</pre>
<p>Fuera del bucle, todavía en la función mostrar foto nos queda:</p>
<p>Definir el estilo para representar la foto. Tenemos dos opciones<br />
a) Crear un icono único para cada fotografía</p>
<pre class="brush: jscript;">
// estilo punto
var panoramio_style1 = new OpenLayers.StyleMap(OpenLayers.Util.applyDefaults({
   pointRadius: 15,
   fillColor: &quot;red&quot;,
   fillOpacity: 1,
   strokeColor: &quot;black&quot;,
   externalGraphic: &quot;${photo_file_url}&quot;
}, OpenLayers.Feature.Vector.style[&quot;default&quot;]));
</pre>
<p>b) Por cada posición añadimos una miniatura de la foto.</p>
<pre class="brush: jscript;">
var panoramio_style2 = new OpenLayers.StyleMap(OpenLayers.Util.applyDefaults({
   pointRadius: 7,
   fillColor: &quot;red&quot;,
   fillOpacity: 1,
   strokeColor: &quot;black&quot;,
   externalGraphic: &quot;panoramio-marker.png&quot;
}, OpenLayers.Feature.Vector.style[&quot;default&quot;]));
</pre>
<p>Imagen: Ejemplos de estilos</p>
<div id="attachment_1613" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content/captura_panoramio_styles.png"><img class="size-medium wp-image-1613" src="http://www.gisandchips.org/wp-content/captura_panoramio_styles-300x123.png" alt="Estilos para Panoramio" width="300" height="123" /></a><p class="wp-caption-text">Estilos para Panoramio</p></div>
<p>Ahora creamos la vector layer asignándole el estilo escogido</p>
<pre class="brush: jscript;">
var vectorPano = new OpenLayers.Layer.Vector(&quot;Panoramio fotos&quot;, {
   styleMap: panoramio_style2
});
</pre>
<p>Añadimos los elementos:</p>
<pre class="brush: jscript;">
vectorPano.addFeatures(features);
</pre>
<p>Añadimos la layer al mapa</p>
<pre class="brush: jscript;">
map.addLayer(vectorPano);
</pre>
<p>Definimos para terminar la función el comportamiento del evento que se desencadenará cuando seleccionemos ( click con el ratón) cada fotografía</p>
<pre class="brush: jscript;">
selectControl = new OpenLayers.Control.SelectFeature(vectorPano,
   {onSelect: onFeatureSelect, onUnselect: onFeatureUnselect});
map.addControl(selectControl);
selectControl.activate();
}
</pre>
<p>Como ves, se ejecutará la función “onFeatureSelect” cada vez que se selecciona un feature, y “onFeatureUnselect” cuando no hay nada seleccionado.</p>
<p>Con este código tenemos toda la lógica para obtener un vector layer con su posición y atributos. Ahora sólo nos queda definir el comportamiento de los eventos. En este caso vamos a crear un “popup” por cada elemento.</p>
<pre class="brush: jscript;">
// popups
function onPopupClose(evt) {
   selectControl.unselect(selectedFeature);
}
function onFeatureSelect(feature) {
   selectedFeature = feature;

   // HTML del PopUp
      mensaje = &quot;&lt;a href='http://www.panoramio.com'&gt;&lt;img src='./panoramio_header-logo.png' alt='Panoramio' width='146' height='27' /&gt;&lt;/a&gt;&lt;br&gt;&quot;+
	      &quot;&lt;h2&gt;&quot;+ feature.attributes.photo_title + &quot;&lt;/h2&gt;&lt;p&gt;&quot; +
	      &quot;&lt;a href='&quot;+ feature.attributes.photo_url+
		  &quot;'&gt;&lt;img src='http://mw2.google.com/mw-panoramio/photos/small/&quot; +
		  feature.attributes.photo_id + &quot;.jpg' border='0' alt=''&gt;&lt;/a&gt;&lt;br&gt;&quot; +
	      &quot;autor: &lt;a href='&quot;+ feature.attributes.owner_url+&quot;'&gt;&quot;+feature.attributes.owner_name +&quot;&lt;/a&gt;&quot;;

   popup = new OpenLayers.Popup.FramedCloud(&quot;chicken&quot;,
      feature.geometry.getBounds().getCenterLonLat(),
      null,
      mensaje,
      null, true, onPopupClose);
   feature.popup = popup;
   map.addPopup(popup);
}
function onFeatureUnselect(feature) {
   map.removePopup(feature.popup);
   feature.popup.destroy();
   feature.popup = null;
}
</pre>
<p>Ya lo tenemos todo listo. Sólo nos queda verlo en un navegador. ¿A que esperas?</p>
<p><a href="http://www.gisandchips.org/demos/j3m/panoramio/panoramio.html">Ver demo en proyección Mercator con fondo de OpenStreetMap</a><br />
<a href="http://www.gisandchips.org/demos/j3m/panoramio/panoramio_4326.html">Ver demo en WGS84</a></p>
<p><strong>Nota de interés:</strong></p>
<blockquote><p>
Por último nos gustaría hacer una consideración de especial relevancia. Este código tiene sentido cuando todas las layers (WMS y vector layer de Panoramio) se encuentran en la misma proyección, en este caso se utiliza el datum WGS84 en coordenadas geográficas (EPSG: 4326). En el caso de que utilices en el mapa otra proyección debes de recordar que has de pasarle a la URL de Panoramio los parámetros de caja en WGS84, y lo mismo ocurre cuando el servicio te devuelve los puntos de cada foto, que ahora debes de hacer lo contrario, es decir, convertirla de EPSG:4326 a la proyección que estés utilizando.
</p></blockquote>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F05%2F04%2Fopenlayers-y-panoramio%2F&amp;linkname=OpenLayers%20y%20Panoramio"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=fJDUnTzg378:xMwKfT76zs8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=fJDUnTzg378:xMwKfT76zs8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=fJDUnTzg378:xMwKfT76zs8:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=fJDUnTzg378:xMwKfT76zs8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=fJDUnTzg378:xMwKfT76zs8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=fJDUnTzg378:xMwKfT76zs8:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/fJDUnTzg378" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/05/04/openlayers-y-panoramio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/05/04/openlayers-y-panoramio/</feedburner:origLink></item>
		<item>
		<title>API de Google + OpenStreetMap y otros servicios georreferenciados</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/KQh1ZXt3K_A/</link>
		<comments>http://www.gisandchips.org/2010/03/24/api-de-google-openstreetmap-y-otros-servicios-georreferenciados/#comments</comments>
		<pubDate>Wed, 24 Mar 2010 11:22:00 +0000</pubDate>
		<dc:creator>pepe</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[OpenStreetMap]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1551</guid>
		<description><![CDATA[Voy a tratar de diseñar un visor de cartografía utilizando el API de Google Maps ( si quereis saber más sobre este tema, podeis leer artículos en esta misma web que hacen referencia:  Google Web Toolkit &#38;  Google Maps, Integración  de un servicio WMS en GoogleMaps usando GWT )  con  la cartografía ]]></description>
			<content:encoded><![CDATA[<p>Voy a tratar de diseñar un visor de cartografía utilizando el <a href="http://code.google.com/intl/es/apis/maps/" target="_blank"><strong>API </strong>de <strong>Google Maps</strong></a> ( si quereis saber más sobre este tema, podeis leer artículos en esta misma web que hacen referencia:  <a title="Google Web Toolkit &amp; Google Maps" href="../2009/11/20/google-web-toolkit-google-maps/"><a href="http://www.gisandchips.org/2009/11/20/google-web-toolkit-google-maps/" target="_blank">Google Web Toolkit &amp;  Google Maps</a>,</a><a title="Integración de un servicio WMS en GoogleMaps usando GWT" href="http://www.gisandchips.org/2010/01/18/integracion-de-un-servicio-wms-en-googlemaps-usando-gwt/" target="_self"> Integración  de un servicio WMS en GoogleMaps usando GWT </a>)  con  la cartografía de <a href="http://www.openstreetmap.org" target="_blank"><strong>OpenStreetMap</strong></a> y además voy a incluir datos de servicios de tipo  georeferenciado (<a href="http://www.panoramio.com" target="_blank"><strong>panoramio</strong></a>, <a href="http://www.youtube.com" target="_blank"><strong>youtube</strong></a>, <a href="http://www.flickr.com" target="_blank"><strong>flickr</strong></a>, <strong>kml</strong>, <a href="http://es.wikipedia.org" target="_blank"><strong>wikipedia</strong></a>,&#8230;) en dicho mapa.</p>
<p><a href="http://www.gisandchips.org/wp-content/mapa.png"><img class="alignleft size-medium wp-image-1567" style="margin-left: 5px;margin-right: 5px;border: 0pt none" src="http://www.gisandchips.org/wp-content/mapa-300x170.png" alt="Muestra un curioso mapa mundial lleno de etiquetas de los servicios georreferenciados" width="300" height="170" /></a>Ya aviso que, una vez que muestro todos los servicios en el mapa,  queda  un mapa demasiado lleno de elementos, pero eso  es justo lo que  pretendo con este visor, tener todos los elementos en el mismo mapa y  que se visualicen tanto fotos, videos, artículos de la wikipedia,kml,&#8230;  a la vez, permitiéndo incluso añadir muchos más elementos.</p>
<p>En primer lugar, para mostrar el mapa de <strong>Google Maps</strong>, necesito registrar la clave previamente para el sitio web en cuestion que voy a tratar.</p>
<p><span id="more-1551"></span></p>
<p>Y una vez registrada la clave ya se puede realizar el visor,  la programación del visor sería la siguiente:</p>
<pre class="brush: php;">
//Hojas de estilo de google maps
 &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/reset-fonts-grids/reset-fonts-grids.css&quot;&gt;
 &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/base/base-min.css&quot;&gt;
 &lt;script type=&quot;text/javascript&quot; src=&quot;http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;key=clave_registrada_en_google&quot;&gt;&lt;/script&gt;

&lt;script
type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;
 google.load(&quot;maps&quot;, &quot;2.x&quot;);

 function load()
 {
 if (!GBrowserIsCompatible())
 return;

 //definicion de variable de copyright del mapa
 var copyOSM = new GCopyrightCollection(&quot;GIS&amp;Chips 2010&quot;);
 copyOSM.addCopyright(new GCopyright(1, new GLatLngBounds(new GLatLng(-90,-180), new GLatLng(90,180)), 0, &quot; &quot;));

 //definicion de las tiles de OpenStreetMap que iran por bajo del mapa
 var tilesMapnik     = new GTileLayer(copyOSM, 1, 17, {tileUrlTemplate: 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png'});
 var tilesOsmarender = new GTileLayer(copyOSM, 1, 17, {tileUrlTemplate: 'http://tah.openstreetmap.org/Tiles/tile/{Z}/{X}/{Y}.png'});
 var tilesCycle = new GTileLayer(copyOSM, 1, 17, {tileUrlTemplate: 'http://a.andy.sandbox.cloudmade.com/tiles/cycle/{Z}/{X}/{Y}.png'});

 var mapMapnik     = new GMapType([tilesMapnik],     G_NORMAL_MAP.getProjection(), &quot;Mapnik&quot;);
 var mapOsmarender = new GMapType([tilesOsmarender], G_NORMAL_MAP.getProjection(), &quot;Osmarend&quot;);
 var mapCycleMap = new GMapType([tilesCycle], G_NORMAL_MAP.getProjection(), &quot;CycleMap&quot;);

 //definicion de mapa incluyendo los tres tiles de OpenStreetMap

 var map           = new GMap2(document.getElementById(&quot;map&quot;), { mapTypes: [mapMapnik, mapOsmarender,mapCycleMap] });

 //se añaden los controles de mapa del API de Google Maps
 map.addControl(new GLargeMapControl()); //control de desplazamiento y acercamiento de gran tamaño empleado en  Google Maps.
 map.addControl(new GMapTypeControl());  //Permite alternar entre los diferentes tipos de mapas (en este caso las tres tiles)
 map.addControl(new GOverviewMapControl()); //Este control nos permite mostrar una ventana de vista rápida contraible

//Situado el centro, las coordenadas de la Universidad de Alicante
 map.setCenter( new GLatLng(38.38575, -0.51486), 16);

 map.enableScrollWheelZoom();
 map.enableContinuousZoom();

 //Se definen como GLayers los servicios georeferenciados que quiero incluir

 var wikipedia = new GLayer(&quot;org.wikipedia.es&quot;);
 var panoramio = new GLayer(&quot;com.panoramio.all&quot;);
 var youtube = new GLayer(&quot;com.youtube.all&quot;);
 var webcam = new GLayer(&quot;com.google.webcams&quot;);

 map.addOverlay(wikipedia);
 map.addOverlay(panoramio);
 map.addOverlay(youtube);
 map.addOverlay(webcam);

 //En este caso como los servicios son un xml se añaden como GGeoXML(tanto el api de flickr como cualquier KML que quiera incluir lo debo definir as�)
 var geoXmlFlickr;
 geoXmlFlickr = new GGeoXml(&quot;http://api.flickr.com/services/feeds/geo/?tags=universidad+alicante&quot;);
 map.addOverlay(geoXmlFlickr);

//Ejemplo de introducción de un KML
 var tram = new GGeoXml(&quot;http://www.sigua.ua.es/web/utils/acceso/kml/TRAM4.kml&quot;);
 map.addOverlay(tram);
 }
</pre>
<p style="text-align: center">Aqui se puede ver como se muestra en el mapa el KML importado<br />
<a href="http://www.gisandchips.org/wp-content/kml.png"><img class="size-medium wp-image-1560 aligncenter" src="http://www.gisandchips.org/wp-content/kml-300x246.png" alt="Se muestra como queda la integracion de un archivo kml con información sobre una linea de tranvia en Alicante en el mapa anteriormente desarrollado" width="300" height="246" /></a></p>
<pre class="brush: xml;">

 &lt;/script&gt;

 &lt;/head&gt;

 &lt;body onload=&quot;load()&quot; onunload=&quot;GUnload()&quot;&gt;
 &lt;div&gt;
 &lt;div role=&quot;main&quot;&gt;
 &lt;div&gt;
 &lt;div id=&quot;map&quot; style=&quot;width: 100%; height: 600px;&quot;&gt;&lt;/div&gt;

 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
</pre>
<p>El visor completo con todos los datos estaría accesible desde la siguiente URL:<br />
<a class="aligncenter" title="Mapa " href="http://www.gisandchips.org/demos/pepe/osm/test.html" target="_blank">http://www.gisandchips.org/demos/pepe/osm/test.html</a></p>
<p>Como digo, este mapa incluye tantos elementos que a veces es un poco  extraño, pero es justo lo que pretendía, incluir muchos servicios en un  mismo mapa.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F03%2F24%2Fapi-de-google-openstreetmap-y-otros-servicios-georreferenciados%2F&amp;linkname=API%20de%20Google%20%2B%20OpenStreetMap%20y%20otros%20servicios%20georreferenciados"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=KQh1ZXt3K_A:2fm8ODFp6x4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=KQh1ZXt3K_A:2fm8ODFp6x4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=KQh1ZXt3K_A:2fm8ODFp6x4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=KQh1ZXt3K_A:2fm8ODFp6x4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=KQh1ZXt3K_A:2fm8ODFp6x4:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/KQh1ZXt3K_A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/03/24/api-de-google-openstreetmap-y-otros-servicios-georreferenciados/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/03/24/api-de-google-openstreetmap-y-otros-servicios-georreferenciados/</feedburner:origLink></item>
		<item>
		<title>Cartografía temática II: Cálculo de intervalos de clase con PL/R</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/xdFOHnlbsFo/</link>
		<comments>http://www.gisandchips.org/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 14:53:22 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[cartografía temática]]></category>
		<category><![CDATA[mapscript]]></category>
		<category><![CDATA[pl/R]]></category>
		<category><![CDATA[R]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1380</guid>
		<description><![CDATA[Como ya vimos en la primera parte de esta mini-serie dedicada a la cartografía temática, hasta ahora sólo tenemos resuelta una parte, la asignación de paletas de colores para nuestros mapas o semiología cartográfica, pero queda otra parte por resolver, la lógica estadística, es decir, calcular cuales serán los valores de cada uno de los ]]></description>
			<content:encoded><![CDATA[<div id="attachment_1416" class="wp-caption aligncenter" style="width: 310px"><a href="/demos/j3m/plr/test5.php"><img class="size-medium wp-image-1416" src="http://www.gisandchips.org/wp-content/madrid-300x228.png" alt="Población por municipios de Madrid (2008)" width="300" height="228" /></a><p class="wp-caption-text">Población por municipios de Madrid (2008) </p></div>
<p>Como ya vimos en la <a href="http://www.gisandchips.org/2010/02/04/cartografia-tematica-i-phpcolorbrewer/">primera parte</a> de esta mini-serie dedicada a la cartografía temática, hasta ahora sólo tenemos resuelta una parte, la asignación de paletas de colores para nuestros mapas o semiología cartográfica, pero queda otra parte por resolver, la lógica estadística, es decir, calcular cuales serán los valores de cada uno de los intervalos de clase que intervienen en una distribución numérica.<br />
<span id="more-1380"></span><br />
Como ya es habitual en<a href="http://www.gisandchips.org"> </a><a href="http://www.gisandchips.org">www.gisandchips.org</a> tenemos una especial predilección por almacenar nuestra fuente de datos en tablas espaciales contenidas en una base de datos PostgreSQL-PostGIS, y esta vez no va a ser menos.</p>
<p>Generalmente, el cálculo de los puntos de ruptura de una distribución ha sido tratado habitualmente desde el punto de vista del cliente (<em>gvSIG, Quantum GIS, ArcGIS</em>, etc), descargándose a la aplicación  los datos oportunos (shapefiles, PostGIS, etc) para escoger posteriormente algún método de agrupamiento o clustering. Esta solución resulta apropiada cuando los datos a representar proceden de diferentes fuentes, cambios de geometría constantes realizamos muchos temáticos distintos, o cualquier otra variable a considerar. Pero sin embargo, cuando necesitamos representar la misma realidad espacial (municipios, provincias, comunidades autónomas, continentes, etc) desde diferentes aspectos (demografía, economía, agriculturas, etc) no resulta tán cómodo delegar esta función a la aplicación cliente.</p>
<p>Pongamos un ejemplo para clarificar el tema: Imaginemos que disponemos de datos de población agregados a nivel de municipios, donde existen tantas columnas como censos de población se hayan hecho, y deseamos generar en un portal de Internet mapas temáticos a requerimiento del usuario (año del censo, nº de clases, método de agrupamiento o <em>clustering </em>y paleta de colores). Crear un mapa coroplético de la población lleva implícito un conocimiento de la distribución de los datos (valores mínimos y máximos de la serie, media), y sobre todo las medidas de dispersión o de variabilidad: desviación típica, varianza, co-varianza, coeficiente de correlación de Pearson. Con estos parámetros estamos en condiciones de definir cual será el método de cálculo de intervalo de clase más apropiado para nuestra distribución, para posteriormente asignar la paleta de colores acorde al fenómeno a representar (este último aspecto ya lo tenemos solucionado con nuestra clase PHPcolorBrewer). Con una aplicación de GIS de escritorio sólo podemos realizar un mapa para visualizarlo en pantalla o imprimirlo, pero en un ambiente web(GIS) este forma de actuar carece de lógica, pues estamos limitando al usuario la posibilidad de elegir estos parámetros (método de clustering, número de clases y paleta de colores), ya que es muy complicado obtener datos de un GIS y realizar los cálculos de los intervalos de clases en la própia página web (<em>JavaScript, PHP</em>).</p>
<div id="attachment_1432" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.gisandchips.org/wp-content/plr.png"><img class="size-medium wp-image-1432" src="http://www.gisandchips.org/wp-content/plr-300x175.png" alt="Flujo cartografía temática" width="300" height="175" /></a><p class="wp-caption-text">Flujo cartografía temática</p></div>
<p>En este artículo vamos a solucionar esta cuestión proponiendo un método que nos permita desde el servidor, es decir, desde el gestor de base de datos, calcular los intervalos de clase. Para ello no nos queda más remedio que recurrir a la creación de funciones o procedimientos almacenados que contemplen dicha lógica. Realizarlo con <em>PLPg/SQL</em> es una solución, pero programar estas funciones requiere de mucho esfuerzo al no formar parte de las funciones nativas del servidor (por ejemplo, no existe una función que calcule la desviación típica). ¿Por qué no utilizamos un lenguaje especializado en el manejo estadístico? En este sentido, <em><strong>PL/R</strong></em> reúne todas las condiciones para convertirse en el lenguaje de programación elegido. Una prueba de la potencia de este lenguaje, en este caso <strong>R</strong> lo podemos ver con este ejemplo.</p>
<p><strong>Implementación en R</strong><br />
Tenemos la población activa (valores en miles) de todas las provincias españolas, obtenidas del INE, en el año 1996, disponibles en un objeto vector:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">c(126.4,137.9,570.9,192.1,409.7,60.2,251.3,325.9,2109.1,145.8,159.4,425.5,207.8,194.3,<br />
172.5,301.5,443,69,252.4,300,55.2,296.4,158.2,84.5,244.3,200.3,141.7,174.2,2180.7,<br />
475.8,438,224.6,161.4,71.2,320.8,390,104.7,144.3,328.3,56.5,646.5,36.3,242,52.8,196.5,<br />
919.6,211.6,473.9,70.2,356.7,50)</td>
</tr>
</tbody>
</table>
<p>En una sesión de R se crearía de esta manera</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">poblacion.1996 &lt;- c(126.4,137.9,570.9,192.1,409.7,60.2,251.3,325.9,2109.1,145.8,159.4,<br />
425.5,207.8,194.3,172.5,301.5,443,69,252.4,300,55.2,296.4,158.2,84.5,244.3,200.3,141.7,<br />
174.2,2180.7,475.8,438,224.6,161.4,71.2,320.8,390,104.7,144.3,328.3,56.5,646.5,36.3,<br />
242,52.8,196.5,919.6,211.6,473.9,70.2,356.7,50)</td>
</tr>
</tbody>
</table>
<p>Y se podría ver simplemente escribiendo:</p>
<pre class="brush: bash;">poblacion.1996</pre>
<p>Resultado</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">[1]  126.4  137.9  570.9  192.1  409.7   60.2  251.3  325.9 2109.1  145.8<br />
[11]  159.4  425.5  207.8  194.3  172.5  301.5  443.0   69.0  252.4  300.0<br />
[21]   55.2  296.4  158.2   84.5  244.3  200.3  141.7  174.2 2180.7  475.8<br />
[31]  438.0  224.6  161.4   71.2  320.8  390.0  104.7  144.3  328.3   56.5<br />
[41]  646.5   36.3  242.0   52.8  196.5  919.6  211.6  473.9   70.2  356.7<br />
[51]   50.0</td>
</tr>
</tbody>
</table>
<p>Para ver un sumario estadístico básico de dicho objeto escribimos:</p>
<pre class="brush: bash;">summary(poblacion.1996)</pre>
<p>Con este resultado:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">Min. 1st Qu.  Median    Mean 3rd Qu.    Max.<br />
36.3   139.8   207.8   320.8   342.5  2181.0</td>
</tr>
</tbody>
</table>
<p>Entrando ya en materia, vamos a calcular 5 clases distribuidas por el método de intervalos iguales, es decir, <em>(valor máximo- valor mínimo) / nº intervalos</em>:</p>
<pre class="brush: bash;">seq(min(poblacion.1996),max(poblacion.1996),length.out=(5+1))</pre>
<p>Resultado</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">[1]   36.30  465.18  894.06 1322.94 1751.82 2180.70</td>
</tr>
</tbody>
</table>
<p>Es decir, las clases quedarían agrupadas de esta forma:</p>
<ul>
<li>clase 1: 36.30 &#8211; 465.18</li>
<li>clase 2: 465.18 &#8211; 894.06</li>
<li>clase 3: 894.06 &#8211; 1322.94</li>
<li>clase 4: 1322.94 &#8211; 1751.82</li>
<li>clase 5: 1751.82 &#8211; 2180.70</li>
</ul>
<p>Este método, aunque sencillo de implementar (incluso desde la parte cliente) ofrece una clasificación muy distorsionada cuando los valores son muy dispares, por lo que necesitamos recurrir a otros métodos más eficientes, como son los cuantiles. En R este cálculo queda reducido a la mínima expressión:</p>
<pre class="brush: bash;">quantile(poblacion.1996)</pre>
<p>Resultado:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">0%    25%    50%    75%   100%<br />
36.3  139.8  207.8  342.5 2180.7</td>
</tr>
</tbody>
</table>
<p>Esta sería nuestra clasificación</p>
<ul>
<li>1º quantil: 36.3 &#8211; 139.8</li>
<li>2º quantil: 139.8 &#8211; 207.8</li>
<li>3º quantil: 207.8 &#8211; 342.5</li>
<li>4º quantil: 342.5 &#8211; 2180.7</li>
</ul>
<p>¡Más sencillo imposible!</p>
<p>El problema de trabajar directamente en R estriba en la dificultad para obtener datos desde otras fuentes, aunque siempre podemos recurrir a paquetes externos para traer los datos de shapefiles o tablas de PostgreSQL a R</p>
<p><strong>Implementación en PostgreSQL</strong></p>
<p>Como ya hemos visto en anteriores artículos sobre PL/R, esta lenguaje procedural es muy sencillo de utilizar. Sólo hay que copiar el código de R y realizar pequeños cambios para adaptarlo a la sintaxis de PL/R.</p>
<p>Un aspecto que debemos tener muy claro es que casi todos los cálculos en R de una distribución deben de estar dispuestos en forma de un vector. Como es lógico, PostgreSQL no soporta este tipo de dato, pero el lenguaje PL/R si que nos permite una conversión hacia el tipo de datos &#8220;array&#8221;, ofreciéndonos además una función que realiza todo el trabajo (<em>array_accum</em>)</p>
<p>Por ejemplo, si queremos obtener un array con los datos de la poblacion activa en 1996 (columna t1996t1) de la tabla ine.poblacion_activa, esta es la forma de conseguirlo con SQL:</p>
<pre class="brush: sql;">SELECT array_accum(t1996t1) FROM ine.poblacion_activa;</pre>
<p>Y este el resultado:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">{126.4,137.9,570.9,192.1,409.7,60.2,251.3,325.9,2109.1,145.8,<br />
159.4,425.5,207.8,194.3,172.5,301.5,443,69,252.4,300,55.2,296.4,<br />
158.2,84.5,244.3,200.3,141.7,174.2,2180.7,475.8,438,224.6,161.4,<br />
71.2,320.8,390,104.7,144.3,328.3,56.5,646.5,36.3,242,52.8,196.5,<br />
919.6,211.6,473.9,70.2,356.7,50}</td>
</tr>
</tbody>
</table>
<p>Con esta pequeña aclaración ya podemos utilizar cualquier columna con datos numéricos para realizar funciones de clustering. Las siguientes funciones de PL/R reproducen los cálculos realizados anteriormente con R:</p>
<p>Función para el método de intervalos iguales:</p>
<pre class="brush: sql;">
CREATE OR REPLACE FUNCTION r_equal(double precision[], integer)
RETURNS double precision[] AS
$BODY$
sort(seq(min(arg1),max(arg1),length.out=(arg2+1)))

$BODY$
LANGUAGE 'plr' VOLATILE STRICT
COST 100;
</pre>
<p>Vamos a analizar esta función.</p>
<p>Tiene dos parámetros de entrada:</p>
<ul>
<li>double precision[]: El array con los datos de entrada que queremos utilizar para calcular los intervalos, utilizando la función array_accum</li>
<li>integer: el nº de intervalos de clase que deseamos obtener</li>
</ul>
<p>El resultado (RETURNS) será siempre una estructura de tipo array.<br />
El cuerpo de la función se reduciría a una sola línea que recibe los dos argumentos de la función (arg1 y arg2):<br />
<em>sort(seq(min(arg1),max(arg1),length.out=(arg2+1)))</em></p>
<p>El uso de esta función es muy sencillo:</p>
<pre class="brush: sql;">SELECT r_equal( array_accum(t1996t1), 5 ) FROM ine.poblacion_activa;</pre>
<p>Nos devolverá el siguiente array:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">{36.3,465.18,894.06,1322.94,1751.82,2180.7}</td>
</tr>
</tbody>
</table>
<p>Para aquellos más versados en PLPg/SQL habrán advertido que realizar la función en este lenguaje requiere de algunas líneas más de código, que pueden ser bastantes más si queremos utilizar otros métodos, como el de cuantiles, que reproducimos a continuación.</p>
<pre class="brush: sql;">
CREATE OR REPLACE FUNCTION r_quantile(double precision[], integer)
RETURNS double precision[] AS
$BODY$
quantile(arg1,probs = seq(0, 1, 1/arg2))
$BODY$
LANGUAGE 'plr' VOLATILE STRICT
COST 100;
</pre>
<p>Ejemplo de uso para 5 intervalos de clase:</p>
<pre class="brush: sql;">
SELECT r_quantile(array_accum(t1996t1),5) FROM ine.poblacion_activa;</pre>
<p>Devuelve:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="576" valign="top">{36.3,104.7,174.2,251.3,409.7,2180.7}</td>
</tr>
</tbody>
</table>
<p>Ahora que tenemos implementado un método para calcular los intervalos de clase ya estamos en condiciones de desarrollar un auténtico motor de cartografía temática (corológica) en un ambiente web que combine la capacidad de cálculo de PL/R con la semiología cartográfica implementada en PHPcolorBrewer que sea capaz de &#8220;pintar&#8221; geometrias de una tabla espacial de PostGIS. El resultado de esta coctelera explosiva lo podeis ver en las siguientes demostraciones on-line:</p>
<p><a name="demos"><strong>EJEMPLOS</strong></a></p>
<p><strong>Test 1: <a href="/demos/j3m/plr/test1.php">Distribución de la población activa por provincias (valores en miles de personas)</a></strong><br />
Este sencillo ejemplo nos permite ver las posibilidades de integración de varias piezas de software (PostGIS, PL/R. PHP MapScripts y PHPcolorBrewer). Los cálculos de los intervalos de clase utilizan el método &#8220;Kmeans&#8221;, y el usuario tiene la posibilidad de cambiar la paleta de colores y el nº de clases, así como el año que desea consultar.</p>
<p><strong>Test 2: <a href="/demos/j3m/plr/test2.php">Distribución de la tasa de ocupación/desempleo por Comunidades Autónomas(valores en miles de personas)</a></strong><br />
Similar al anterior, pero aplicado a CC.AA. Ofrece la posibilidad de múltiples consultas (número de ocupados/desempleados diferenciando hombre, mujeres y total)</p>
<p><strong>Test 3: <a href="/demos/j3m/plr/test3.php">Distribución de la población activa por provincias (valores en miles de personas) según diferentes métodos de <em>clustering</em></a></strong><br />
Este ejemplo es similar al primero, pero hemos añadido la posibilidad de que el usuario selecciones el método de cálculo de intervalos de clase desea. Es sin duda, un buen ejemplo de la potencia que tiene PL/R al permitirnos elegir hasta 8 métodos diferentes:</p>
<ul>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=quantile">quantile</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=equal">equal</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=kmeans">kmeans</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=hclust.complete">hclust.complete</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=hclust.single">hclust.single</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=bclust">bclust</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=fisher">fisher</a></li>
<li><a href="/demos/j3m/plr/test3.php?paletas=YlOrRd&amp;numInt=5&amp;field=t2000t1&amp;method=jenks">jenks</a></li>
</ul>
<p><strong>Test 4: <a href="/demos/j3m/plr/test4.php">Varios mapas temáticos en una sóla página con todos los métodos anteriores</a></strong><br />
El objeto de este ejemplo es demostrar de una sóla vez como se representa un mismo fenómeno desde diferentes métodos de clustering, para ver cual es el que mejor se adapta a nuestras necesidades.</p>
<p><strong>Test 5: <a href="/demos/j3m/plr/test5.php">Mapa temático municipal sensible con HTML dinámico</a></strong><br />
Se trata del ejemplo más completo de todos, que nos permite seleccionar una provincia y ver la distribución de la población (total, hombres o mujeres) por municipio. También permite seleccionar todos los métodos indicados, así como la paleta de colores y nº de intervalos.</p>
<p><strong>Test 6: <a href="/demos/j3m/plr/test6.php">Todas las paletas PHPcolorBrewer aplicadas a un mapa temático</a></strong><br />
El objetivo de este ejemplo es demostrar en una sóla página como un mismo fenómeno es representado con todas las paleta de PHPcolorBrewer, para que el usuario seleccione la que más le convenga.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F02%2F04%2Fcartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr%2F&amp;linkname=Cartograf%C3%ADa%20tem%C3%A1tica%20II%3A%20C%C3%A1lculo%20de%20intervalos%20de%20clase%20con%20PL%2FR"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=xdFOHnlbsFo:QAY7L0KyDKU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=xdFOHnlbsFo:QAY7L0KyDKU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=xdFOHnlbsFo:QAY7L0KyDKU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=xdFOHnlbsFo:QAY7L0KyDKU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=xdFOHnlbsFo:QAY7L0KyDKU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=xdFOHnlbsFo:QAY7L0KyDKU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/xdFOHnlbsFo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/</feedburner:origLink></item>
		<item>
		<title>Cartografía temática I: PHPcolorBrewer</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/RCKF4DnrUW4/</link>
		<comments>http://www.gisandchips.org/2010/02/04/cartografia-tematica-i-phpcolorbrewer/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 14:51:30 +0000</pubDate>
		<dc:creator>jose</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[cartografía coroplética]]></category>
		<category><![CDATA[PHPcolorBrewer]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1360</guid>
		<description><![CDATA[La creación de cartografía coroplética es quizás uno de los aspectos más recurrentes que podemos encontrar en un ambiente webgis. Todos hemos visto o realizado alguna vez con nuestro programa de GIS favorito un mapa de distribución de la población o cualquier otra variable por municipios, provincias, autonomías o estados. En su preparación siempre intervienen ]]></description>
			<content:encoded><![CDATA[<p>La creación de cartografía coroplética es quizás uno de los aspectos más recurrentes que podemos encontrar en un ambiente webgis. Todos hemos visto o realizado alguna vez con nuestro programa de GIS favorito un mapa de distribución de la población o cualquier otra variable por municipios, provincias, autonomías o estados. En su preparación siempre intervienen tres elementos: una base cartográfica con datos asociados para representar, un método estadístico para agrupar los datos en intervalos de clase o conjunto de datos, y finalmente una simbología cartográfica aplicada a dichos grupos que represente de una manera clara el fenómeno que deseamos destacar. Los datos a tratar siempre serán de tipo numérico y harán referencia a datos cuantitativos.</p>
<div id="attachment_1363" class="wp-caption aligncenter" style="width: 310px"><a title="PHPcolorBrewer palette" href="http://www.gisandchips.org/demos/j3m/plr/PHPcolorBrewer/examples.palettes.PHPcolorBrewer.php" target="_blank"><img class="size-medium wp-image-1363" src="http://www.gisandchips.org/wp-content/paletas.phpColorBrewer-300x204.jpg" alt="" width="300" height="204" /></a><p class="wp-caption-text">PHPcolorBrewer palettes</p></div>
<p><strong>NOTA</strong>: La segunda parte de este artículo lo puede consultar en: <a href="/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/"> Cartografía temática II: Cálculo de intervalos de clase con Pl/R<br />
</a><br />
<span id="more-1360"></span></p>
<p>Sobre este tipo de cartografía siempre han circulado muchos tópicos del tipo: <em>&#8220;la mejor manera de representar los datos es con un mapa&#8221;</em>, con una clara alusión al uso de mapas en detrimento de largos listados o tablas cuya lectura resulta menos intuitiva que un mapa con colores degradados. También encontramos declaraciones con una percepción negativa sobre los mapas temáticos, <em>&#8220;la mejor forma de ocultar datos es con un mapa&#8221;</em>, aludiendo esta vez al hecho incuestionable de que un fenómeno dado puede dar diferentes lecturas en función del mayor o menor acierto en la elección de los intervalos de clase, en el sentido de que muchos intervalos dificultan la lectura y pocos generalizan demasiado los datos.</p>
<p>Cuando trabajamos con aplicaciones de escritorio GIS nuestra labor se reduce a indicar el fenómeno a representar, el número de intervalos y como mucho elegir una de las gamas de paletas, para finalmente obtener una distribución más o menos aceptable donde es raro que el usuario intervenga en el proceso estadístico que implica decidir las rupturas de clase. De igual forma ocurre con la gama de colores, donde solemos aceptar los predefinidos, o como mucho definimos una degradación de colores.</p>
<p>Quizás sea por deformación profesional, pero suelo advertir una cierta dejadez del usuario respecto al tratamiento de los colores que intervienen en una distribución normalizada en mucha de la cartografía coroplética existente, utilizando, en la mayoría de los casos, los valores que por defecto nos proporciona la aplicación. Para cualquiera que haya estudiado cartografía, sabe que la simbolización del color es uno de los temás más complejos, que muchas veces delegamos en la aplicación de escritorio, en la que intervienen factores tales como la representatividad de los colores, legibilidad, idoneidad en función de su uso (por ejemplo en un mapa pensado para su impresión no todos los colores son imprimibles), adecuación del número de intervalos al fenómeno estudiado, capacidad del usuario para distinguir colores, y por supuesto la elección de un sistema de agrupamiento (clustering) adecuado.</p>
<p>La doctora Cynthia A. Brewer, profesora del Departamento de Geografía en la universidad estatal de Pennsylvania (<a href="http://www.personal.psu.edu/cab38/">http://www.personal.psu.edu/cab38/</a>) ha dedicado su faceta profesional al estudio del color en la cartografía coroplética, dejando como legado una serie de paletas de colores adecuadas para la representación cartográfica que han sido bautizadas con su nombre y utilizadas en muchas publicaciones de renombre, como el Census Atlas of the United States (<a href="http://www.census.gov/population/www/cen2000/censusatlas/">http://www.census.gov/population/www/cen2000/censusatlas/</a>) e implementadas en muchas otras aplicaciones de GIS (ArcGIS)</p>
<p>Basándonos en su trabajo hemos elaborado una sencilla clase en PHP que nos permite hacer uso de dichas paletas de una manera sencilla para el usuario, susceptibles de ser utilizadas en la elaboración de cartografía coroplética.</p>
<p><a title="Descarga PHPcolorBrewer" href="http://www.gisandchips.org/demos/j3m/plr/PHPcolorBrewer.tar.gz">Descargar PHPcolorBrewer</a></p>
<p>Esta utilidad está sujeta a la <a href="http://www.gisandchips.org/demos/j3m/plr/PHPcolorBrewer/LICENSE-2.0.txt">Apache License 2.0</a></p>
<p>Esta clase consta de los siguientes métodos:</p>
<ul>
<li>listColors: Listar colores de una paleta y un nº de intervalos o clases</li>
<li>getPalettes: Obtiene un array de paletas</li>
<li>getPaletteIntervals: Obtiene un array de intervalos de una paleta. Los valores siempre estarán entre de 3 a 9</li>
<li>getPalIntColors: Obtiene un array de intervalos de una paletas. Siempre será de 3 a 9</li>
<li>getColor: Obtiene un array con el color de una paleta, un intervalo y un número.</li>
</ul>
<p>Dada la vocación web de esta clase se han creado estos métodos:</p>
<ul>
<li>comboPalettes: Utilidad HTML para listar paletas en forma de combo</li>
<li>comboNumInt: Utilidad HTML para listado del nº de intervalos de una paleta en forma de combo</li>
<li>rgb2html:  Convierte un color en formato RGB a hexadecimal para su uso en web.</li>
<li>tableColor: Crea una tabla HTML dada una paleta y un intervalo (de 3 a 9)</li>
</ul>
<p>Con el objeto de facilitar al usuario su implementación se han añadido dos scripts con ejemplos de uso:<br />
1. Listado de todas las paletas de colores: <a title="Paletas" href="/demos/j3m/plr/PHPcolorBrewer/examples.palettes.PHPcolorBrewer.php">examples.palettes.colorBrewer.php</a><br />
2. Ejemplos de uso: <a title="Ejemplos de uso" href="http://www.gisandchips.org/demos/j3m/plr/PHPcolorBrewer/examples.PHPcolorBrewer.php">examples.colorBrewer.php</a></p>
<p>Finalmente, y como ejemplo de cartografía temática les mostramos algunas demostraciones que utilizan esta utilidad, incluidos en el siguiente post: <a href="/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/#demos">Cartografía temática II: Cálculos de intervalos de clase con PL/R</a></p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F02%2F04%2Fcartografia-tematica-i-phpcolorbrewer%2F&amp;linkname=Cartograf%C3%ADa%20tem%C3%A1tica%20I%3A%20PHPcolorBrewer"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=RCKF4DnrUW4:mylFuyA34gU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=RCKF4DnrUW4:mylFuyA34gU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=RCKF4DnrUW4:mylFuyA34gU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=RCKF4DnrUW4:mylFuyA34gU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=RCKF4DnrUW4:mylFuyA34gU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=RCKF4DnrUW4:mylFuyA34gU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/RCKF4DnrUW4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/02/04/cartografia-tematica-i-phpcolorbrewer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/02/04/cartografia-tematica-i-phpcolorbrewer/</feedburner:origLink></item>
		<item>
		<title>Extracción de características estructurales de una imagen ( II ) (Semi-variograma de una imagen usando R).</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/BOzHugXkIv8/</link>
		<comments>http://www.gisandchips.org/2010/01/28/extraccion-de-caracteristicas-estructurales-de-una-imagen-ii-semi-variograma-de-una-imagen-usando-r-2/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 12:45:08 +0000</pubDate>
		<dc:creator>benizar</dc:creator>
				<category><![CDATA[Análisis]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Fields]]></category>
		<category><![CDATA[Mineria de datos espacial]]></category>
		<category><![CDATA[R]]></category>
		<category><![CDATA[Teledetección orientada a objetos]]></category>
		<category><![CDATA[Variograma]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1303</guid>
		<description><![CDATA[En este artículo usaremos una librería de R (“fields”), que contiene métodos para calcular el semi-variograma empírico de una imagen, lo cual quiere decir que calcularemos el semi-variograma de una gran cantidad de puntos. Y a partir de ahí, analizaremos la existencia de patrones espaciales en tres parcelas agrícolas arbóreas.
Figura 1: Parcelas estudiadas en este ]]></description>
			<content:encoded><![CDATA[<p>En este artículo usaremos una librería de R (“fields”), que contiene métodos para calcular el semi-variograma empírico de una imagen, lo cual quiere decir que calcularemos el semi-variograma de una gran cantidad de puntos. Y a partir de ahí, analizaremos la existencia de patrones espaciales en tres parcelas agrícolas arbóreas.</p>
<h5><strong>Figura 1: Parcelas estudiadas en este artículo.</strong></h5>
<p><strong><a href="http://www.gisandchips.org/wp-content/parcelas.jpg"><img class="aligncenter size-medium wp-image-1238" src="http://www.gisandchips.org/wp-content/parcelas-300x115.jpg" alt="" width="415" height="158" /></a></strong></p>
<p><span id="more-1303"></span></p>
<p>Espero que este sea el primero de varios posts donde aprendamos a estudiar las ortoimagenes, extrayendo características de distintos tipos como ya hicimos en un post anterior (<a href="../2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/">http://www.gisandchips.org/2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/</a> ). En aquel caso, se extrajeron algunas sencillas frecuencias a partir del cálculo de la Transformada de Hough que nos proporcionaba AForge.NET, lo cual nos servía para automatizar la decisión de si una parcela era una plantación arbórea y realizar un conteo automático del número de árboles que contenía. En dicho post, se ofrece una aplicación llamada RAPID, que incorpora una galería de imágenes de parcelas agrícolas. Hemos extraído tres de ellas para realizar los siguientes análisis. Son las siguientes:</p>
<p>Al estudiar las 3 parcelas que aparecen en la <strong>Figura 1</strong> con el RAPID: La primera es identificada totalmente como agrícola y nos permite contar con bastante certidumbre el número de árboles de un modo automático. En el caso de la segunda, su estructura en hileras no permite el conteo de árboles pues están muy juntos. Y por último, en los olivos de la tercera no se cumplía la regla de una estructura normal, aunque sí que podíamos contar los árboles. Este último caso era el único donde RAPID no podía “acertar” pues identificaba la parcela como no agrícola debido a que la diferencia angular entre las direcciones principales de la Transformada de Hough no se aproximaba a 90º.</p>
<p><strong>¿Qué es un variograma experimental?</strong> (una breve explicación para entender los resultados)</p>
<p>Los variogramas se utilizan para caracterizar la posible estructura espacial de un conjunto de datos. Podemos distinguir dos tipos de variogramas, el experimental y el modelizado. De estos nos interesa más el experimental. Este último se usa para describir los datos de una muestra, habitualmente una nube de puntos (xyz)</p>
<p>Matemáticamente el semi-variograma, o variograma/2, se puede definir como la mitad del promedio de las diferencias al cuadrado.</p>
<h5><strong><strong>Figura 2: Fórmula para calcular el semi-variograma</strong></strong></h5>
<p><strong><strong><a href="http://www.gisandchips.org/wp-content/formula_vario.jpg"><img class="aligncenter size-full wp-image-1342" src="http://www.gisandchips.org/wp-content/formula_vario.jpg" alt="" width="254" height="46" /></a><br />
</strong></strong></p>
<p>Donde Np(h) es el número de pares a la distancia h, h es el incremento.</p>
<p>Z(xi) son los valores experimentales.</p>
<p>xi localizaciones donde son medidos los valores z(xi).</p>
<p>Aplicado a imágenes, el semi-variograma (o variograma/2), mide el grado de correlación espacial entre los píxeles de una imagen. Podemos comentar varios conceptos (ver <strong>Figura 3</strong>):</p>
<ul>
<li>Sill o meseta: representa la varianza máxima.</li>
<li>Range, rango o alcance: muestra la distancia (en nuestro caso en píxeles) a la que el semi-variograma alcanza la meseta.</li>
<li>Nugget o “efecto pepita”, es la discontinuidad en el origen. Ésta es debida a que el semivariograma, en la práctica, no es nulo en el origen.</li>
</ul>
<h5><strong><strong>Figura 3: Interpretación del semivariograma</strong></strong></h5>
<p><strong><strong><a href="http://www.gisandchips.org/wp-content/variogram.jpg"><img class="aligncenter size-medium wp-image-1343" src="http://www.gisandchips.org/wp-content/variogram-300x184.jpg" alt="" width="300" height="184" /></a><br />
</strong></strong></p>
<p><strong>Ejemplos de cálculo en R</strong></p>
<p>Os aviso de que las imágenes referidas en el código estan en formato *.ppm aunque R tiene muchas librerías capaces de convertir a este formato. También podéis utilizar OpenOffice.</p>
<p>En este post, aplicamos el siguiente código para calcular el semi-variograma empírico de cada una de estas imágenes:</p>
<pre class="brush: bash;">
&lt;pre&gt;# Instalo los packages necesarios:

#-------------------------------------------------

install.packages(&quot;pixmap&quot;, dependencies= T)

install.packages(&quot;fields&quot;, dependencies= T)

# Cargo las librerias:
#-------------------------------------------------
library(pixmap)

library(fields)

# Hago una lista con las imagenes de las parcelas y las cargo todas:
#-------------------------------------------------
imag_dir &lt;- list.files(&quot;C:\\ ... \\Articulos Gisandchips\\ parcelas_ppm\\&quot;, full.names=T)

parcela1 &lt;- read.pnm(imag_dir[1])

parcela2 &lt;- read.pnm(imag_dir[2])

parcela3 &lt;- read.pnm(imag_dir[3])

# Aislamos una banda...
#-------------------------------------------------
matriz1&lt;-parcela1@green

matriz2&lt;-parcela2@green

matriz3&lt;-parcela3@green

# Calculamos el semivariograma (si queremos podemos acabar antes cambiando el alcance de 40  a 10, por ejemplo, pero los resultados pueden cambiar y quedará menos bonito (-: )
#-------------------------------------------------
vgram1_40&lt;-vgram.matrix( matriz1, R=40) # esto llevará un poco de tiempo

vgram2_40&lt;-vgram.matrix( matriz2, R=40) # esto llevará un poco de tiempo

vgram3_40&lt;-vgram.matrix( matriz3, R=40) # esto llevará un poco de tiempo

# Añadimos al Plot las matrices que acabamos de calcular
#-------------------------------------------------
plot.vgram.matrix(vgram1_40)# La matriz del variograma

plot.vgram.matrix(vgram2_40)# La matriz del variograma

plot.vgram.matrix(vgram3_40)# La matriz del variograma

# Creamos una curva que ajuste bien sobre la muestra y la añadimos al variograma
#-------------------------------------------------
polyfit1_40_20 &lt;- lm(vgram1_40$vgram ~ poly(vgram1_40$d, 20));

plot(vgram1_40$d, vgram1_40$vgram)

lines(sort(vgram1_40$d), polyfit1_40_20$fit[order(vgram1_40$d)], col=2, lwd=4)

polyfit2_40_20 &lt;- lm(vgram2_40$vgram ~ poly(vgram2_40$d, 20));

plot(vgram2_40$d, vgram2_40$vgram)

lines(sort(vgram2_40$d), polyfit2_40_20$fit[order(vgram2_40$d)], col=2, lwd=4)

polyfit3_40_20 &lt;- lm(vgram3_40$vgram ~ poly(vgram3_40$d, 20));

plot(vgram3_40$d, vgram3_40$vgram)

lines(sort(vgram3_40$d), polyfit3_40_20$fit[order(vgram3_40$d)], col=2, lwd=4)
</pre>
<p>El plot que obtenemos es el siguiente, o similar si es que hemos preferido cambiar algún parámetro:</p>
<h5><strong><strong>Figura 4: Panel donde mostramos los resultados</strong></strong></h5>
<p><strong><strong><a href="http://www.gisandchips.org/wp-content/variograma_3parcelas_polyfit.jpg"><img class="aligncenter size-medium wp-image-1344" src="http://www.gisandchips.org/wp-content/variograma_3parcelas_polyfit-299x299.jpg" alt="" width="327" height="327" /></a><br />
</strong></strong></p>
<p>En la imagen vemos las parcelas, la matriz de su variograma y el variograma, con una curva que ajustamos mucho al los datos. Es fácil interpretar que en la estructura de las parcelas se llega a apreciar cierta &#8220;ciclicidad&#8221;, ya que encontramos mesetas a distintas distancias. Cada meseta se  corresponde aproximadamente a las hileras de árboles. El alcance es el que hemos definido (40, en este caso 40 píxeles; puede que unos 20 m. en la realidad).</p>
<p>Viendo estas imágenes nos podemos dar cuenta de que es más fácil determinar una regla de clasificación que cuando lo hacíamos en el caso del RAPID. En este caso, nos fijamos en el número de máximos relativos de la función polinómica de ajuste del variograma. A simple vista, la primera parcela tiene unos 4, la segunda apenas 1 y la última 3 o 4. <strong>En este caso, podríamos citar una nueva regla para nuestro programa según la que a partir de 2 o 3 máximos relativos una parcela puede ser considerada una plantación arbórea.</strong></p>
<p>Como nos interesa automatizar la tarea creamos una función que nos cuente los máximos relativos. Aquí viene el ejemplo aplicado a la primera parcela:</p>
<pre class="brush: bash;">

# Encontrar máximos relativos en la función 1

#--------------------------------------------------

maxRelativos1=0

hMaxRelativos1=0

for(i in 1:(length(polyfit1_40_20$fitted.values)-1))

{

if (polyfit1_40_20$fitted.values[i] &gt; polyfit1_40_20$fitted.values[i+1] &amp;&amp; polyfit1_40_20$fitted.values[i] &gt; polyfit1_40_20$fitted.values[i-1])

{maxRelativos1[i]&lt;- polyfit1_40_20$fitted.values[i]

hMaxRelativos1[i]&lt;- vgram1_40$d[i]}

}

MaxRelativos1&lt;-data.frame(hMaxRelativos1,maxRelativos1)

MaxRelativos1&lt;- na.omit(MaxRelativos1)

NumMaxRelat1_40&lt;-length(rownames(MaxRelativos1))
</pre>
<p>Consultamos los vértices de la curva que hemos dibujado mediante un bucle, de modo que si el vértice <strong>i</strong> tiene un valor superior al vértice anterior y también al vértice posterior entonces es considerado un máximo relativo y queda almacenado en la lista.</p>
<h3>Algunos comentarios sobre todo esto:</h3>
<p>(1) El semivariograma implica un gran esfuerzo de cálculo por parte del ordenador. Esto hace que aún habiendo varias librerías en R que obtienen el semivariograma de una nube de puntos, sean significativamente más lentas que <strong>Fields. </strong>Además, <strong>Fields</strong> hace directamente lo que necesitábamos. No obstante, en un futuro no muy lejano, intentaré desarrollar una librería en C# para reproducir un análisis de este tipo y otras cosillas relacionadas.</p>
<p>(2) Por cuestiones de tiempo no he tratado de crear funciones para las distintas etapas de la demostración. Puede ser un buen ejercicio tratar de implementar todo esto en funciones que permitan entre sus parámetros especificar la banda con la que trabajar, el alcance del semivariograma…</p>
<p>(3) Existen más posibilidades a la hora de establecer reglas, por ejemplo podríamos explorar la distancia que separa los máximos relativos para distinguir los cultivos más intensivos de los más tradicionales. Se me ocurren muchas más posibilidades.</p>
<p>(4) Por último, aunque no le doy mucha importancia, deciros que el número de máximos relativos no es del todo correcto pues el cero siempre aparece en el conteo (sale 5, 2, 5 y no 4, 1, 4 como he dicho más arriba), esto es porqué no he trabajado bastante el bucle, pero es fácil restar 1 a la lista final.  Mi idea principal es la de explorar el concepto y dar unos ejemplos de código a modo de ideas.</p>
<h3>Referencias:</h3>
<p>Para entender bien todo esto creo que es interesante ver mi artículo anterior&#8230;</p>
<p>Solamente os remito al siguiente tutorial de Surfer. Es bastante didáctico. <a href="http://www.goldensoftware.com/variogramTutorial.pdf">http://www.goldensoftware.com/variogramTutorial.pdf</a></p>
<p>De todos modos la red está llena de materiales, apuntes de clase, libros en PDF… No tendréis problemas en encontrar información sobre los variogramas.</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>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F01%2F28%2Fextraccion-de-caracteristicas-estructurales-de-una-imagen-ii-semi-variograma-de-una-imagen-usando-r-2%2F&amp;linkname=Extracci%C3%B3n%20de%20caracter%C3%ADsticas%20estructurales%20de%20una%20imagen%20%28%20II%20%29%20%28Semi-variograma%20de%20una%20imagen%20usando%20R%29."><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=BOzHugXkIv8:X2K8gG_pLzg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=BOzHugXkIv8:X2K8gG_pLzg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=BOzHugXkIv8:X2K8gG_pLzg:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=BOzHugXkIv8:X2K8gG_pLzg:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=BOzHugXkIv8:X2K8gG_pLzg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=BOzHugXkIv8:X2K8gG_pLzg:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/BOzHugXkIv8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/01/28/extraccion-de-caracteristicas-estructurales-de-una-imagen-ii-semi-variograma-de-una-imagen-usando-r-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/01/28/extraccion-de-caracteristicas-estructurales-de-una-imagen-ii-semi-variograma-de-una-imagen-usando-r-2/</feedburner:origLink></item>
		<item>
		<title>Integración de un servicio WMS en GoogleMaps usando GWT</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/-agvgbTRmgA/</link>
		<comments>http://www.gisandchips.org/2010/01/18/integracion-de-un-servicio-wms-en-googlemaps-usando-gwt/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 22:26:00 +0000</pubDate>
		<dc:creator>jpiera</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[GoogleMaps]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[WMS]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1192</guid>
		<description><![CDATA[Este artículo es una continuación del artículo &#8220;Google Web Toolkit &#38; Google Maps&#8221; que se publicó en este mismo blog hace un par de meses. La idea de escribirlo surgió debido a una pregunta que nos hizo una lectora en la que preguntaba cómo se podía integrar un servidor WMS propio en Google Maps utilizando ]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify">Este artículo es una continuación del artículo &#8220;<a href="http://www.gisandchips.org/?p=1034">Google Web Toolkit &amp; Google Maps</a>&#8221; que se publicó en este mismo blog hace un par de meses. La idea de escribirlo surgió debido a una pregunta que nos hizo una lectora en la que preguntaba cómo se podía integrar un servidor <a href="http://es.wikipedia.org/wiki/WMS">WMS</a> propio en Google Maps utilizando GWT.</p>
<p style="text-align: justify">Este artículo explica paso a paso cómo hacerlo y para ello se ha tomado como servidor de ejemplo un <a href="http://wms.jpl.nasa.gov/wms.cgi">WMS de la NASA,</a> pero se ha escrito el código de forma que haciendo unas pocas modificaciones se puede integrar cualquier otro servidor WMS.</p>
<p style="text-align: center"><a href="http://www.gisandchips.org/wp-content/wms1.png"><img class="size-full wp-image-1196 alignnone" src="http://www.gisandchips.org/wp-content/wms1.png" alt="wms" width="300" height="200" /></a></p>
<p style="text-align: justify">Se parte de un entorno en el que se ha creado un proyecto de GWT llamado GoogleMaps-WMS utilizando para ello el entorno de desarrollo Eclipse. Además se ha creado una página de inicio y se ha añadido un mapa de GoogleMaps en el centro. Cómo crear el proyecto y cómo crear la página de inicio es algo que ya se explicó en el <a href="http://www.gisandchips.org/?p=1034">artículo anterior</a>.</p>
<p style="text-align: justify"><span id="more-1192"></span></p>
<p style="text-align: justify">Antes de empezar a ver código es necesario entender cómo funciona el sistema de tileado de GoogleMaps basado en un <a href="http://es.wikipedia.org/wiki/Quadtree">QuadTree</a>, que no es más que una estructura de datos muy utilizada para crear índices espaciales. El QuadTree  se aplica sobre un área concreta y en el caso de GoogleMaps se aplica sobre toda la superficie terrestre que varía entre la longitud  -180º a 180º y la latitud -90º a 90º (estas cifras no son del todo exactas, ya que la latitud se &#8220;acorta&#8221; unos grados en los polos)</p>
<p style="text-align: justify">El QuadTree divide  esta superficie en 4 áreas en forma rectangular de tamaño fijo, que en su conjunto pueden ser vistas como una matriz de 2&#215;2 y se les pueden dar nombres según la fila y la columna en la que están. De aquí en adelante  a esas áreas rectangulares las vamos a llamar tiles. La nomenclatura de Google es numérica y crece de Oeste a Este y de Norte a sur de forma que el tile de la parte superior izquierda es el (0,0), el tile de la parte superior derecha es el (1,0), el de la parte inferior izquierda es el (0,1) y el de la parte inferior derecha es el (1,1). Esta matriz de 2&#215;2 es la matriz de tiles para un nivel de zoom 1.</p>
<p style="text-align: justify">Cada una de esos tiles se puede descomponer a su vez en 4 partes iguales de área constante. Si dividimos los 4 tiles que hay inicialmente en 4 partes iguales obtendremos una matriz de 4&#215;4 tiles, que nombraremos matriz de tiles de nivel 2. Podemos utilizar la misma nomenclatura que hemos utilizado para los tiles de nivel de zoom 1, siendo el tile de la esquina superior izquierda el (0,0) y el tile de la esquina inferior derecha el (3,3).</p>
<p style="text-align: justify">Este proceso de descomposición de tiles en 4 tiles de un nivel inferior lo podemos realizar N veces de forma que al final tendremos una estructura de datos de N niveles en los que en cada nivel habrá 4 veces más tiles que en el nivel predecesor. En el caso de GoogleMaps cada uno de estos tiles es una imagen de 256&#215;256 píxels independientemente del nivel en el que nos encontremos, por lo que a mayor nivel de zoom más detalle tendrá la imagen. Para poder entender mejor la nomenclatura de los tiles de Google podemos consultar <a href="http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/">ésta página web</a>.</p>
<p style="text-align: justify">Una vez entendido el sistema de tileado y la nomenclatura que usa GoogleMaps, vamos a empezar a escribir código.  Existe en el API  que proporciona Google una clase llamada <a href="http://code.google.com/p/gwt-google-apis/source/browse/trunk/google-apis/src/com/google/gwt/maps/client/TileLayer.java?r=41">TileLayer</a> que representa un proveedor de tiles del que se nutrirá el mapa para poder visualizarse. Tenemos por tanto que crear una clase llamada <a href="http://www.gisandchips.org/svn/global/jpiera/GoogleMaps-WMS/src/org/gisandchips/gwt/maps/wms/client/WMSTileLayer.java">WMSTileLayer</a> que herede de TileLayer, lo que implica que hay que implementar algunos métodos:</p>
<pre class="brush: java;">
public class WMSTileLayer extends TileLayer{
public WMSTileLayer(String baseServerUrl, String layers, String styles, Projection projection){
super();
}
@Override
public String getTileURL(Point tile, int zoom) {
return null;
}
@Override
public double getOpacity() {
return 1.0;
}
@Override
public boolean isPng() {
return true;
}
</pre>
<p style="text-align: justify">En el método <span style="font-style: italic">getOpacity</span> hay que devolver la transparencia de la imagen que varía entre 0 y 1. Si queremos que la imagen se visualice en el mapa tendremos que poner el valor 1.0.</p>
<p style="text-align: justify">En el método <span style="font-style: italic">isPng</span> hay que indicar si la imagen que se devuelve es png. En nuestro caso hemos devuelto <span style="font-style: italic">true</span> ya que las imágenes devueltas las pedimos en png.</p>
<p style="text-align: justify">Pero en el tercer método de la clase es dónde está la complejidad de esta clase. El método <span style="font-style: italic">getTileURL</span> acepta como parámetros un objeto de tipo Point y un entero. El entero hace referencia el nivel de zoom mientras que el Point es una pareja de enteros que hacen referencia al nombre del tile que hay que devolver.  Si hemos entendido la estructura de QuadrTree y la nomenclatura que usa Google en los tiles podremos entender el significado de estos parámetros. A medida que el usuario se desplaza por el mapa, el componente encargado de recuperar los tiles invoca al método <span style="font-style: italic">getTileURL</span> para recuperar la URL de los tiles del área en la que se encuentra. Este método se invocará normalmente unas cuántas veces por cada vez que el usuario modifique el área del mapa que está visualizando.</p>
<p style="text-align: justify">En el ejemplo de código hemos visto cómo en la implementación del método <span style="font-style: italic">getTileURL</span> se devolvía el valor <span style="font-style: italic">null</span> y ahora lo vamos a modificar para que devuelva la URL del tile que se está pidiendo en los argumentos del método y que  tendrá que ser descargado desde un servidor WMS. Podríamos haber creado un componente específico para un servidor WMS concreto, pero en lugar de eso hemos implementado un componente algo más genérico para que se pueda utilizar con otros servidores de mapas.</p>
<p style="text-align: justify">Para ello hemos añadido a la clase <a href="http://www.gisandchips.org/svn/global/jpiera/GoogleMaps-WMS/src/org/gisandchips/gwt/maps/wms/client/WMSTileLayer.java">WMSTileLayer</a> algunos parámetros que se establecen en el constructor. Estos parámetros son la dirección del servidor WMS, la lista de capas a cargar y los estilos con los que se desea visualizar la capa. Cómo conocer los valores de la capa(s) que soporta un servidor o los valores del estilo(s) soportados está fuera del alcance de este artículo, pero bastaría con hacer la operación <span style="font-style: italic">GetCapabilities</span> sobre el servidor.</p>
<p style="text-align: justify">El código resultante quedaría del siguiente modo:</p>
<p style="text-align: justify">
<pre class="brush: java;">
public class WMSTileLayer extends TileLayer{
private String baseServerUrl;
private String layers;
private String styles;
private Projection projection;
private String getMapUrl = null;
public WMSTileLayer(String baseServerUrl, String layers, String styles, Projection projection){
super(null, 0, 20);
this.baseServerUrl = baseServerUrl;
this.layers = layers;
this.styles = styles;
//construct the base URL
String urlBase = baseServerUrl + &quot;?&quot; +
&quot;FORMAT=image/png&amp;amp;SERVICE=WMS&amp;amp;REQUEST=GetMap&amp;amp;WIDTH&quot; +
&quot;=256&amp;amp;HEIGHT=256&amp;amp;VERSION=1.1.0&amp;amp;&quot; +
&quot;STYLES=&quot; + styles + &quot;&amp;amp;&quot; +
&quot;LAYERS=&quot;+ layers + &quot;&amp;amp;&quot;;
getMapUrl = urlBase;
}
@Override
public String getTileURL(Point tile, int zoom) {
return null;
}
@Override
public double getOpacity() {
return 1.0;
}
@Override
public boolean isPng() {
return true;
}
</pre>
<p style="text-align: justify">
<p style="text-align: justify">Además de los parámetros comentados anteriormente, podemos ver que se ha incluido un cuarto parámetro llamado projection, que se utiliza para identificar la proyección y deberá ser el mismo que el utilizado para crear el componente contenedor de mapas de GoogleMaps.</p>
<p style="text-align: justify">En el constructor lo que se está haciendo es básicamente crear la URL que servirá de base para lanzar la petición <span style="font-style: italic">GetMap</span> a un servidor WMS.Todavía faltan algunos parámetros para que la petición sea completa, pero estos parámetros los vamos a añadir en el método <span style="font-style: italic">getTileURL</span> que es el último método que nos queda por ver para terminar con la explicación.</p>
<p style="text-align: justify">Para simplificar el problema, vamos a suponer que el servidor WMS que estamos utilizando soporta el sistema de coordenadas en latitud/longitud (EPSG:4326). El problema será entonces pasar un tile de GoogleMaps definido mediante un nombre y un nivel de zoom a un par de coordenadas que definan el mismo tile en latitud/longitud. Para ello utilizamos el API de GoogleMaps y una vez tengamos ese tile, creamos la Url que lo contiene, de modo que el método getTileURL quedará de la siguiente forma:</p>
<pre class="brush: java;">
@Override
public String getTileURL(Point tile, int zoom) {
//Transforma las coordenadas a coordenadas Lat/Lon
Point tileIndexLLPoint = Point.newInstance(tile.getX() * 256, (tile.getY() + 1) * 256);
Point tileIndexURPoint = Point.newInstance(((tile.getX() + 1) * 256), (tile.getY()) * 256);
LatLng llPoint = projection.fromPixelToLatLng(tileIndexLLPoint, zoom, true);
LatLng urPoint = projection.fromPixelToLatLng(tileIndexURPoint, zoom, true);
String url =  getMapUrl + &quot;SRS=EPSG:4326&amp;amp;BBOX=&quot; +
	llPoint.getLongitude() + &quot;,&quot; +
	llPoint.getLatitude() + &quot;,&quot; +
	urPoint.getLongitude() + &quot;,&quot; +
	urPoint.getLatitude();
return url;
}
</pre>
<p>En las variables <span style="font-style: italic">llPoint</span> y <span style="font-style: italic">urPoint</span> se calculan las coordenadas de la esquina inferior izquierda y de la esquina superior derecha del tile que en latitud/longitud equivale al tile de GoogleMaps. Añadiendo estas coordenadas a la URL mediante el parámetro <span style="font-style: italic">BBOX</span> y añadiendo el parámetro <span style="font-style: italic">SRS </span>se forma la URL que se devuelve en el método y que será usada por el componente gráfico para recuperar las imágenes y mostrarlas en pantalla. Ahora ya sólo falta crear un objeto <a href="http://www.gisandchips.org/svn/global/jpiera/GoogleMaps-WMS/src/org/gisandchips/gwt/maps/wms/client/WMSTileLayer.java">WMSTileLayer</a> y asociarlo al componente gráfico de GoogleMaps. La clase que hace esto es <a href="http://www.gisandchips.org/svn/global/jpiera/GoogleMaps-WMS/src/org/gisandchips/gwt/maps/wms/client/GoogleMaps_WMS.java">GoogleMaps_WMS</a>, y el código es el sigueinte:</p>
<pre class="brush: java;">
public class GoogleMaps_WMS implements EntryPoint {
 private MapWidget map;
 private String wmsURL = &quot;http://wms.jpl.nasa.gov/wms.cgi&quot;;
 private String wmsLayers = &quot;global_mosaic_base&quot;;
 private String wmsStyles = &quot;pseudo&quot;;
 private String mapName = &quot;Nasa&quot;;
 public void onModuleLoad() {
//Coordenadas centrales para posicionar el mapa
LatLng latLonCenter = LatLng.newInstance(0,0);
//Creamos el mapa con un tamaÃ±o fijo
map = new MapWidget(latLonCenter, 2);
map.setSize(&quot;520px&quot;, &quot;520px&quot;);
Projection projection = new MercatorProjection(20);
//Creamos el servicio WMS que nutrirá a GoogleMaps
MapType myWMSMap = new MapType(new TileLayer[] {
new WMSTileLayer(wmsURL, wmsLayers, wmsStyles, projection)},
projection,
mapName);
//Añadimos el servicio WMS al mapa
map.addMapType(myWMSMap);
//Añadimos algunas opciones al mapa
MapUIOptions options = MapUIOptions.newInstance(Size.newInstance(400,400));
options.setMapTypeControl(true);
map.setUI(options);
// Add the map to the HTML host page
RootPanel.get(&quot;mapContainer&quot;).add(map);
}
}
</pre>
<p>En el ejemplo, la clase tiene algunos atributos:</p>
<ul>
<li>wmsURL: para definir la URL del servicio WMS.</li>
<li>wmsLayers: lista separada por comas de las capas a mostrar.</li>
<li>wmsStyle: estilo con el que se desea mostrar la capa</li>
<li>mapName: nombre del mapa que aparecerá en el interfaz de usuario de GoogleMaps</li>
</ul>
<p>Cambiando estos atributos se puede acceder a cualquier otro servidor WMS.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2010%2F01%2F18%2Fintegracion-de-un-servicio-wms-en-googlemaps-usando-gwt%2F&amp;linkname=Integraci%C3%B3n%20de%20un%20servicio%20WMS%20en%20GoogleMaps%20usando%20GWT"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=-agvgbTRmgA:bQfhh5IbSCg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=-agvgbTRmgA:bQfhh5IbSCg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=-agvgbTRmgA:bQfhh5IbSCg:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=-agvgbTRmgA:bQfhh5IbSCg:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=-agvgbTRmgA:bQfhh5IbSCg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=-agvgbTRmgA:bQfhh5IbSCg:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/-agvgbTRmgA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2010/01/18/integracion-de-un-servicio-wms-en-googlemaps-usando-gwt/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2010/01/18/integracion-de-un-servicio-wms-en-googlemaps-usando-gwt/</feedburner:origLink></item>
		<item>
		<title>Cómo evitar la inserción de geometrías duplicadas en PostgreSQL</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/iY3-1iUr_HM/</link>
		<comments>http://www.gisandchips.org/2009/12/22/como-evitar-la-insercion-de-geometrias-duplicadas-en-postgresql/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 11:51:02 +0000</pubDate>
		<dc:creator>josetomas</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[geometrías duplicadas]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[RULE]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1171</guid>
		<description><![CDATA[Una de las tareas habituales en el tratamiento de inconsistencias cartográficas es la detección y corrección de geometrías duplicadas. En muchos casos eliminarlas es necesario para evitar incoherencias en nuestra base de datos geográfica, sobre todo en cuanto al cómputo de frecuencias, longitudes y superficies. Por otra parte la eliminación a posteriori, también plantea problemas ]]></description>
			<content:encoded><![CDATA[<p>Una de las tareas habituales en el tratamiento de inconsistencias cartográficas es la detección y corrección de geometrías duplicadas. En muchos casos eliminarlas es necesario para evitar incoherencias en nuestra base de datos geográfica, sobre todo en cuanto al cómputo de frecuencias, longitudes y superficies. Por otra parte la eliminación a posteriori, también plantea problemas de decisión que pueden complicar el código a desarrollar y desembocar en tiempos dilatados de proceso. De modo que, en ocasiones merece la pena plantearse la detección de geometrías duplicadas a priori. Implementar semejante mecanismo de control del lado del cliente puede resultar relativamente sencillo, pero lo que aquí os propongo es centralizar la lógica y evitar la inserción de geometrías duplicadas desde el lado del servidor PostgreSQL/PostGIS.<span id="more-1171"></span></p>
<p>Planteado el problema, la primera solución que viene a la mente pasa por un &#8220;trigger&#8221; que haga la llamada a la correspondiente función de evaluación y lance un mensaje de error en caso necesario. Sin embargo, si lanzar el mensaje de error no es absolutamente necesario y lo que perseguimos es que una transacción de, por ejemplo, 1000 geometrías donde 50 son duplicadas, se complete con los 950 registros válidos insertados, entonces podemos usar una regla o <a title="RULE" href="http://www.postgresql.org/docs/8.4/static/rules.html" target="_blank">RULE</a>. Cada dos por tres estoy revisitando el sistema de reglas de PostgreSQL y no deja de sorprenderme por su versatilidad y elegancia. Echad un vistazo a la solución propuesta y decidid por vosotros mismos:</p>
<pre class="brush: sql;">
CREATE OR REPLACE RULE skip_duplicate AS
 ON INSERT TO table_name
 WHERE 0 &lt;&gt; (SELECT count(*)
 FROM table_name
 WHERE geom_field ~= new.geom_field) DO INSTEAD NOTHING;
</pre>
<p>Como podéis comprobar, hay 2 claves para interpretar esta regla:</p>
<p>1) Es una regla condicional (CREATE RULE &#8230; <em>WHERE</em> &#8230; DO &#8230;), y en la condición integramos una subquery que emplea el operador de igualdad geométrica (<em>~=</em>) para evaluar si la geometría de entrada (<em>new.geom_field</em>) es un duplicado. Recordad que, para acelerar el proceso, los operadores de PostGIS explotan, si está presente, el índice GIST sobre el campo de geometría.</p>
<p>2) Con <em>INSTEAD NOTHING</em> indicamos al motor de reescritura de expresiones subyacente al sistema de reglas que, cuando se cumpla la condición anterior, simplemente vacíe la expresión entrante y no haga nada. Por tanto, la sentencia INSERT se omite y deja de formar parte de la transacción actual.</p>
<p>¡Eso es todo!</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2009%2F12%2F22%2Fcomo-evitar-la-insercion-de-geometrias-duplicadas-en-postgresql%2F&amp;linkname=C%C3%B3mo%20evitar%20la%20inserci%C3%B3n%20de%20geometr%C3%ADas%20duplicadas%20en%20PostgreSQL"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=iY3-1iUr_HM:tSdQPbTlLP8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=iY3-1iUr_HM:tSdQPbTlLP8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=iY3-1iUr_HM:tSdQPbTlLP8:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=iY3-1iUr_HM:tSdQPbTlLP8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=iY3-1iUr_HM:tSdQPbTlLP8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=iY3-1iUr_HM:tSdQPbTlLP8:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/iY3-1iUr_HM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/12/22/como-evitar-la-insercion-de-geometrias-duplicadas-en-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2009/12/22/como-evitar-la-insercion-de-geometrias-duplicadas-en-postgresql/</feedburner:origLink></item>
		<item>
		<title>Uso de “dissolve” con POSTGIS</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/vd7jO-BDAhk/</link>
		<comments>http://www.gisandchips.org/2009/12/17/uso-de-dissolve-con-postgis/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 10:36:51 +0000</pubDate>
		<dc:creator>Miguel</dc:creator>
				<category><![CDATA[Consejo práctico]]></category>
		<category><![CDATA[dissolve]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1110</guid>
		<description><![CDATA[Uno de los problemas que tuve al manejar los datos geométricos del INE fue que la capa de municipios constaba de geometría de tipo POLYGON. Lo que necesitaba conseguir era agrupar esa geometría simple y convertirla en MULTIPOLYGON. Eso me dio la idea para el siguiente consejo práctico.
Para ello una simple ojeada a la documentación ]]></description>
			<content:encoded><![CDATA[<p>Uno de los problemas que tuve al manejar los datos geométricos del INE fue que la capa de municipios constaba de geometría de tipo POLYGON. Lo que necesitaba conseguir era agrupar esa geometría simple y convertirla en MULTIPOLYGON. Eso me dio la idea para el siguiente consejo práctico.</p>
<p>Para ello una simple ojeada a la documentación de <a href="http://postgis.refractions.net/documentation/manual-1.4/">POSTGIS</a> y encontré la función que necesitaba, <strong><a href="http://postgis.refractions.net/documentation/manual-1.4/ST_Union.html">st_union</a></strong>. Esta función nos une la geometría en función de un atributo seleccionado.</p>
<p>Voy a mostrar un ejemplo sencillo, pero muy pedagógico.  En este ejemplo partimos de tres polígonos simples,  su geometría es de tipo POLYGON y quiero unirlos por un atributo común, en su caso el código.</p>
<p><img class="alignnone size-full wp-image-1127" src="http://www.gisandchips.org/wp-content/polygon.PNG" alt="poligonos" width="417" height="313" /><br />
<span id="more-1110"></span><br />
Vemos en la imagen anterior los 3 polígonos, dos de los cuales tienen el mismo atributo (campo código).</p>
<p>La SQL quedaría de la siguiente manera:</p>
<pre class="brush: sql;">select st_union(geometria) from poligonos group by codigo;</pre>
<p>El problema viene con el resultado de esa consulta, y es la heterogeneidad del tipo de geometría:</p>
<p><img class="alignnone size-full wp-image-1133" src="http://www.gisandchips.org/wp-content/stunion.PNG" alt="stunion" width="467" height="58" /></p>
<p>Para que eso no ocurra, añadimos la función<strong> <a href="http://postgis.refractions.net/documentation/manual-1.4/ST_Multi.html">st_multi</a></strong>, y conseguimos una homogeneidad del tipo de geometría, convirtiendo todas las geometrías en MULTIPOLYGON:</p>
<pre class="brush: sql;">select st_multi(st_union(geometria)) from poligonos group by codigo;</pre>
<p><img class="alignnone size-full wp-image-1135" src="http://www.gisandchips.org/wp-content/stmultiunion.PNG" alt="stmultiunion" width="478" height="55" /></p>
<p>En caso de que los polígonos sean adyacentes, pasaría a ser un único polígono, es decir,  elimina la frontera entre ambos.</p>
<p><img class="alignnone size-full wp-image-1142" src="http://www.gisandchips.org/wp-content/polygon21.PNG" alt="polygon2" width="479" height="485" /></p>
<p>Ahora comprobamos que al usar <strong>st_union</strong>, simplemente nos ha creado un polígono a partir de un atributo común, manteniendo la geometría de tipo POLYGON y en este caso ya no hace falta usar st_multi.</p>
<p><img class="alignnone size-full wp-image-1140" src="http://www.gisandchips.org/wp-content/stunion2.PNG" alt="stunion2" width="470" height="54" /><!--more--></p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2009%2F12%2F17%2Fuso-de-dissolve-con-postgis%2F&amp;linkname=Uso%20de%20%26%238220%3Bdissolve%26%238221%3B%20con%20POSTGIS"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vd7jO-BDAhk:e5sBJBVzbxU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vd7jO-BDAhk:e5sBJBVzbxU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vd7jO-BDAhk:e5sBJBVzbxU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vd7jO-BDAhk:e5sBJBVzbxU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vd7jO-BDAhk:e5sBJBVzbxU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vd7jO-BDAhk:e5sBJBVzbxU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/vd7jO-BDAhk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/12/17/uso-de-dissolve-con-postgis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2009/12/17/uso-de-dissolve-con-postgis/</feedburner:origLink></item>
		<item>
		<title>Google Web Toolkit &amp; Google Maps</title>
		<link>http://feedproxy.google.com/~r/GisChips/~3/7qJ3XT12Gr0/</link>
		<comments>http://www.gisandchips.org/2009/11/20/google-web-toolkit-google-maps/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 14:40:09 +0000</pubDate>
		<dc:creator>jpiera</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=1034</guid>
		<description><![CDATA[Google Web Toolkit (GWT) es un framework creado por Google que permite al programador hacer aplicaciones web utilizando el lenguaje de programación Java. Existe un plugin de Eclipse que se utiliza para facilitar la generación de aplicaciones GWT donde se puede depurar código utilizando el depurador de código del entorno. Una vez que la aplicación ]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/intl/es-ES/webtoolkit/">Google Web Toolkit</a> (GWT) es un framework creado por Google que permite al programador hacer aplicaciones web utilizando el lenguaje de programación Java. Existe un plugin de Eclipse que se utiliza para facilitar la generación de aplicaciones GWT donde se puede depurar código utilizando el depurador de código del entorno. Una vez que la aplicación esta depurada, se tiene que pasar por el compilador GWT que genera código HTML y Javascript. La idea es poder generar páginas que utilicen la tecnología Ajax (HTML + Javascript asíncrono), sin ser necesario escribir ni una sola línea de Javascript.</p>
<p><a href="http://maps.google.es">Google Maps</a> es un servicio de mapas que ofrece Google que tiene un <a href="http://code.google.com/intl/es-ES/apis/maps/documentation/v3/">API</a> que permite integrarlo en cualquier página web utilizando Javascript. Pero si estamos utilizando GWT, existe además un jar que contiene un API para Java lo que permite a un programador de GWT poder integrar la tecnología de Google Maps en sus páginas web. Este artículo explica ese API y mediante ejemplos.<span id="more-1034"></span></p>
<p>En este tutorial vamos a crear un proyecto de GWT y le vamos a añadir un mapa de Google Maps. Partiremos de un entorno en el que se ha instalado un Eclipse y se ha instalado el plugin de GWT. A continuación hay que crear un proyecto del tipo &#8220;Google -&gt; Web Application Project&#8221; que tiene que tener un nombre (GoogleMapsDemo) y un paquete raíz(org.gisandchips.gwt.maps). No es necesario utilizar los mismos nombres que se usan en el ejemplo, pero si se hace así se podrá seguir este tutorial sin la necesidad modificar nada.</p>
<p style="text-align: center">
<p><a href="http://www.gisandchips.org/wp-content/Pantallazo-New-Web-Application-Project-.png"><img class="size-full wp-image-1035 alignnone" src="http://www.gisandchips.org/wp-content/Pantallazo-New-Web-Application-Project-.png" alt="Pantallazo-New Web Application Project" width="300" height="260" /></a></p>
<p>El wizard de creación de un proyecto GWT crea un proyecto que se puede ejecutar: para ello seleccionamos la opción &#8220;Run -&gt; Debug Configurations -&gt; Web Application&#8221; y seleccionaremos GoogleMapsDemo que es el lanzador que ha creado el wizard por nosotros. Pulsamos en &#8220;Debug&#8221; y si todo va bien se abrirá un navegador que muestra un formulario con un único campo de texto y un botón para enviar.</p>
<p>Podemos rellenar el campo de texto con cualquier valor y al pulsar el botón se abrirá una ventana dónde el servidor nos da la bienvenida. ¿Y qué tiene esto de especial? Lo que realmente ha ocurrido es que el cliente ha enviado una petición asíncrona (¡el famoso Ajax!) y ha esperado a que el servidor le devuelva una respuesta para mostrarla.</p>
<p><a href="http://www.gisandchips.org/wp-content/Screenshot-Web-Application-Starter-Project-.png"><img class="size-full wp-image-1074 alignnone" src="http://www.gisandchips.org/wp-content/Screenshot-Web-Application-Starter-Project-.png" alt="Screenshot-Web Application Starter Project" width="400" height="300" /></a></p>
<p>Ahora que ya sabemos crear y ejecutar una aplicación en GWT vamos a crear una aplicación utilizando Google Maps. Primero hay que <a href="http://code.google.com/p/gwt-google-apis/downloads/list">descargarse</a> la librería de Google Maps para GWT desde la página web de Google (gwt-maps-XXX), hay que descomprimirla, y hay que copiar el jar gwt-maps a la carpeta &#8220;war -&gt; WEB-INF -&gt; lib&#8221; de nuestro proyecto. A continuación hay que modificar el path del proyecto (&#8220;Project -&gt; Properties -&gt; Java Build Path -&gt; Libraries -&gt; Add Jars&#8221;) y añadir la librería que acabamos de bajar.</p>
<p>Con esto ya tenemos acceso desde el Eclipse a las clases de Google Maps, pero para tener acceso en tiempo de ejecución tenemos que editar el fichero &#8220;org.gisandchips.gwt.maps.GoogleMapsDemo.gwt.xml&#8221; y añadir una línea para incluir la dependencia en el proyecto. Al final el fichero quedará de esta forma:</p>
<pre class="brush: xml;">

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE module PUBLIC &quot;-//Google Inc.//DTD Google Web Toolkit 1.7.1//EN&quot; &quot;http://google-web-toolkit.googlecode.com/svn/tags/1.7.1/distro-source/core/src/gwt-module.dtd&quot;&gt;
&lt;module rename-to='googlemapsdemo'&gt;
 &lt;!-- Inherit the core Web Toolkit stuff.                        --&gt;
 &lt;inherits name='com.google.gwt.user.User'/&gt;

 &lt;!-- Inherit the default GWT style sheet.  You can change       --&gt;
 &lt;!-- the theme of your GWT application by uncommenting          --&gt;
 &lt;!-- any one of the following lines.                            --&gt;
 &lt;inherits name='com.google.gwt.user.theme.standard.Standard'/&gt;
 &lt;!-- &lt;inherits name='com.google.gwt.user.theme.chrome.Chrome'/&gt; --&gt;
 &lt;!-- &lt;inherits name='com.google.gwt.user.theme.dark.Dark'/&gt;     --&gt;

 &lt;!-- Other module inherits                                      --&gt;

 &lt;!-- Specify the app entry point class.                         --&gt;
 &lt;entry-point class='org.gisandchips.gwt.maps.client.GoogleMapsDemo'/&gt;

 &lt;!-- Load the Google Maps GWT bindings from the gwt-google-apis project --&gt;
 &lt;!-- Added by projectCreator if you use the -addModule argument --&gt;
 &lt;inherits name=&quot;com.google.gwt.maps.GoogleMaps&quot; /&gt;
 &lt;script src=&quot;http://maps.google.com/maps?gwt=1&amp;amp;file=api&amp;amp;v=2&amp;amp;sensor=false&quot; /&gt;
&lt;/module&gt;
</pre>
<p>Tal y como se indica en el fichero XML, la clase &#8220;org.gisandchips.gwt.maps.client.GoogleMapsDemo&#8221; es la que contiene el punto de entrada a la aplicación, por lo tanto es aquí donde hay que introducir el código Java que generará la página web. Por otra parte, el fichero &#8220;GoogleMapsDemo.html&#8221; que hay en la carpeta war es el que contiene el HTML de entrada y que habrá que editar para personalizar una nuestra página de inicio. En nuestro caso vamos a modificar el título y a añadir una etiqueta donde se situará el mapa. El &#8220;body&#8221; del documento quedaría de la siguiente forma:</p>
<pre class="brush: xml;">

&lt;body&gt;

 &lt;!-- OPTIONAL: include this if you want history support --&gt;
 &lt;iframe src=&quot;javascript:''&quot; id=&quot;__gwt_historyFrame&quot; tabIndex='-1' style=&quot;position:absolute;width:0;height:0;border:0&quot;&gt;&lt;/iframe&gt;

 &lt;h1&gt;Mi primer ejemplo con GWT y Google Maps&lt;/h1&gt;

 &lt;table align=&quot;center&quot;&gt;
 &lt;tr&gt;
 &lt;td id=&quot;mapContainer&quot;&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/table&gt;
 &lt;/body&gt;
</pre>
<p>A continuación hay que editar la clase &#8220;org.gisandchips.gwt.maps.client.GoogleMapsDemo&#8221;. Eliminamos todo el código del método &#8220;onModuleLoad&#8221; y añadimos el siguiente código java:</p>
<pre class="brush: java;">

public void onModuleLoad() {
 MapWidget mapWidget = new MapWidget();
 mapWidget.setSize(&quot;1000&quot;, &quot;500&quot;);

 RootPanel.get(&quot;mapContainer&quot;).add(mapWidget);

}
</pre>
<p>Ahora ya podemos lanzar el proyecto una vez más para ver los resultados. Se abrirá el navegador y tendremos que ver una página web con un mapa en el centro donde podremos hacer panning y desplazarnos.</p>
<p><a href="http://www.gisandchips.org/wp-content/Screenshot-Web-Application-Starter-Project-1.png"><img class="size-full wp-image-1091 alignnone" src="http://www.gisandchips.org/wp-content/Screenshot-Web-Application-Starter-Project-1.png" alt="Screenshot-Web Application Starter Project" width="500" height="350" /></a></p>
<p>Ahora que sabemos cómo introducir un mapa de todo el planeta en nuestra aplicación, vamos a modificar algunas de las propiedades del objeto &#8220;MapWidget&#8221; que es el que representa al mapa. Primero vamos a añadir algunos componentes al mapa mediante el método &#8220;addControl&#8221;.</p>
<p>Podemos introducir una barra de navegación que permitirá hacer zoom añadiendo un objeto de tipo &#8220;LargeMapControl&#8221;. También podemos añadir un combo que permitirá seleccionar los distintos formatos de GoogleMaps utilizando el objeto &#8220;MenuMapTypeControl&#8221;.  El método &#8220;onModuleLoad&#8221; quedaría así:</p>
<pre class="brush: java;">
public void onModuleLoad() {
MapWidget mapWidget = new MapWidget();
mapWidget.setSize(&quot;1000&quot;, &quot;500&quot;);

//Añadimos la barra de navegación
mapWidget.addControl(new LargeMapControl());

//Añadimos el combo con los formatos
mapWidget.addControl(new MenuMapTypeControl());

RootPanel.get(&quot;mapContainer&quot;).add(mapWidget);
}
</pre>
<p>Ahora volvemos ejecutar la aplicación y podremos ver los nuevos componentes introducidos en el mapa.</p>
<p>Llagados a esta punto ya hemos comentado los pasos básicos que hay que hacer para integrar un mapa de Google Maps en una web realizada mediante GWT. En los próximos artículos veremos cómo se pueden hacer búsquedas en el mapa y cómo se puede personalizar.</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2009%2F11%2F20%2Fgoogle-web-toolkit-google-maps%2F&amp;linkname=Google%20Web%20Toolkit%20%26amp%3B%20Google%20Maps"><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=7qJ3XT12Gr0:rqJrPSfOZYY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=7qJ3XT12Gr0:rqJrPSfOZYY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=7qJ3XT12Gr0:rqJrPSfOZYY:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=7qJ3XT12Gr0:rqJrPSfOZYY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=7qJ3XT12Gr0:rqJrPSfOZYY:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=7qJ3XT12Gr0:rqJrPSfOZYY:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/7qJ3XT12Gr0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/20/google-web-toolkit-google-maps/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2009/11/20/google-web-toolkit-google-maps/</feedburner:origLink></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://feedproxy.google.com/~r/GisChips/~3/vXyIogXDZFY/</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 ]]></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;">

// 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">
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.gisandchips.org%2F2009%2F11%2F11%2Fprocesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas%2F&amp;linkname=Procesamiento%20de%20im%C3%A1genes%20digitales%20con%20C%23%20%28y%20una%20aplicaci%C3%B3n%20para%20el%20an%C3%A1lisis%20de%20parcelas%20agr%C3%ADcolas%29."><img src="http://www.gisandchips.org/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vXyIogXDZFY:gaI2NMbmaBU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/GisChips?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vXyIogXDZFY:gaI2NMbmaBU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/GisChips?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vXyIogXDZFY:gaI2NMbmaBU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vXyIogXDZFY:gaI2NMbmaBU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/GisChips?d=TzevzKxY174" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/GisChips?i=vXyIogXDZFY:gaI2NMbmaBU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/GisChips?a=vXyIogXDZFY:gaI2NMbmaBU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/GisChips?d=dnMXMwOfBR0" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/GisChips/~4/vXyIogXDZFY" height="1" width="1"/>]]></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>2</slash:comments>
		<feedburner:origLink>http://www.gisandchips.org/2009/11/11/procesamiento-de-imagenes-digitales-con-c-y-una-aplicacion-para-el-analisis-de-parcelas-agricolas/</feedburner:origLink></item>
	</channel>
</rss>
