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

<channel>
	<title>GIS &#38; Chips &#187; mapscript</title>
	<atom:link href="http://www.gisandchips.org/tag/mapscript/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gisandchips.org</link>
	<description>Geografía útil para llevar</description>
	<lastBuildDate>Tue, 29 Nov 2011 10:38:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Cartografía temática II: Cálculo de intervalos de clase con PL/R</title>
		<link>http://www.gisandchips.org/2010/02/04/cartografia-tematica-ii-calculo-de-intervalos-de-clase-con-plr/</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; title: ; notranslate">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; title: ; notranslate">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; title: ; notranslate">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; title: ; notranslate">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; title: ; notranslate">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; title: ; notranslate">
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; title: ; notranslate">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; title: ; notranslate">
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; title: ; notranslate">
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>
]]></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>7</slash:comments>
		</item>
		<item>
		<title>Creación de un mapa sensible utilizando Pl/PgSQL y PHP_Mapscript</title>
		<link>http://www.gisandchips.org/2009/11/06/creacion-de-un-mapa-sensible-utilizando-plpgsql-y-php_mapscript/</link>
		<comments>http://www.gisandchips.org/2009/11/06/creacion-de-un-mapa-sensible-utilizando-plpgsql-y-php_mapscript/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 17:46:56 +0000</pubDate>
		<dc:creator>Miguel</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[mapa]]></category>
		<category><![CDATA[mapscript]]></category>
		<category><![CDATA[mapserver]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php_mapscript]]></category>
		<category><![CDATA[Pl/pgsql]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=942</guid>
		<description><![CDATA[El objetivo no es otro que convertir nuestro mapa en algo más interactivo para el usuario, dando más información que la meramente visual. El siguiente artículo, muestra el camino para alcanzar nuestra meta,  seguramente no sea la única ni la mejor, pero nos será útil para nuestro fín. Obviaremos la construcción del mapfile, ya que [...]]]></description>
			<content:encoded><![CDATA[<p>El objetivo no es otro que convertir nuestro mapa en algo más interactivo para el usuario, dando más información que la meramente visual. El siguiente artículo, muestra el camino para alcanzar nuestra meta,  seguramente no sea la única ni la mejor, pero nos será útil para nuestro fín.</p>
<p>Obviaremos la construcción del mapfile, ya que fue abordado en otro <a href="http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/">artículo</a>, pero trabajaremos a partir de ese código.</p>
<p>Lo primero que necesitamos hacer es preparar la función en lenguaje PL/pgSQL que nos devolverá las coordenadas de los vértices que componen cada uno de los polígonos a partir de un parámetro, que en nuestro caso será el código municipal, y posteriormente se hará la conversión de esos vértices de metros a pixel con PHP.<span id="more-942"></span></p>
<pre class="brush: sql; title: ; notranslate">
CREATE OR REPLACE FUNCTION gc_listvertices(cod_municipal character varying)
RETURNS SETOF record AS
$BODY$
DECLARE
countpol bigint;
polygon geometry;
perimeter geometry;
countpoints integer;
i integer;
j integer;
point record;
BEGIN
--Teniendo en cuenta que cada municipio puede estar compuesto de varios polígonos, primero hacemos un conteo de los polígonos de cada municipio
select into countpol count(*) from (select st_dump(geometria) from municipios where codmun= cod_municipal) foo;
for j in 1..countpol loop
--Por cada municipio, nos devolverá los polígonos descompuestos. La función st_dump, lo que nos devuelve es tantas filas como polígonos contiene el municipio en cuestión, es decir nos descompone el MULTIPOLYGON en un array que contiene un único POLYGON
select into polygon geom from (select (st_dump(geometria)).path, (st_dump(geometria)).geom from municipios where codmun = cod_municipal) foo where path[1] = j;
--La función st_exteriorring nos devuelve un LINESTRING, que representa el anillo exterior del polígono dado.
--ATENCIÓN: esta función no trabaja con MULTIPOLYGON, de ahí la descomposición anterior
select into perimeter st_exteriorring(polygon);
--Contamos el número de vértices que componen el POLYGON
select into countpoints st_npoints(polygon);
for i in 1..countpoints loop
--Por último, nos guardamos en una variable, la coordenada X y la coordenada Y de cada vértice.
--ATENCIÓN: puesto que nos devuelve indiscriminadamente las coordenadas de todos los vértices de todos los polígonos que componen el municipio, se ha añadido un campo booleano que nos devuelve true en caso de ser un vértice final.
select into point st_x(st_pointn(perimeter, i)), st_y(st_pointn(perimeter, i)), (i=countpoints) as tend;
return next point;
end loop;
end loop;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION gc_listvertices(character varying) OWNER TO postgres;</pre>
<p>Ahora sólo queda hacer la conversión con PHP:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php header('Content-Type: text/html; charset=UTF-8'); ?&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Ejemplo de mapa sensible&lt;/title&gt;
&lt;style type=&quot;text/css&quot;&gt;
.munInfo{
border: 1px solid #C0C0C0;
background-color: white;
border-bottom-width: 0;
width: 170px;
height: 70px;
position: absolute;
}
&lt;/style&gt;

&lt;script&gt;
function info(nombre,area)
{
        document.getElementById('munInfo').innerHTML = &quot;Municipio=&quot;  + nombre +&quot; &lt;br&gt; Area =&quot; + area +&quot; km2&quot;;
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;?php
//Este código es el usado en un artículo anterior, pero para hacer más fluido el ejemplo, sólo se han seleccionado los municipios de la Comunidad Valenciana. Lo ideal es automatizar tanto la extensión máxima de la caja de la geometría como su equivalencia en el tamaño en pixeles del mapa. Para hacer el ejemplo más fluido se añaden estos parámetros a mano.
dl('php_mapscript.so');
$Map=ms_newMapObj(&quot;&quot;);
$Map-&gt;set(&quot;name&quot;,&quot;Mapa&quot;);
//Equivalencia en pixeles del tamaño del mapa
$Map-&gt;setSize(432,750);
//Extensión de la caja para los municipios de la Comunidad Valenciana
$Map-&gt;setExtent(626680,4191059,815673.125,4519371);
$Map-&gt;web-&gt;set(&quot;imagepath&quot;,&quot;/tmp&quot;);
$Map-&gt;web-&gt;set(&quot;imageurl&quot;,&quot;/ms_tmp&quot;);
$Layer2=ms_newLayerObj($Map);
$Layer2-&gt;set(&quot;name&quot;,&quot;Municipios&quot;);
$Layer2-&gt;set(&quot;type&quot;,MS_LAYER_POLYGON);
$status = $Layer2-&gt;set(&quot;status&quot;,MS_ON);
$Layer2-&gt;setConnectionType(MS_POSTGIS);
$Layer2-&gt;set(&quot;connection&quot;,&quot;user=****** dbname=demos host=localhost&quot;);
//La consulta ha sido modificada con respecto a la original, para mostrar sólo los municipios de la Comunidad Valenciana
$Layer2-&gt;set(&quot;data&quot;,&quot;geometria from (select geometria,gid from  ine.municipios where com = '10') as foo  using unique gid using srid=23030&quot;);
$clase = ms_newClassObj($Layer2);
$estilo = ms_newStyleObj($clase);
$estilo-&gt;color-&gt;setRGB(217,233,107);
$estilo-&gt;outlinecolor-&gt;setRGB(0,0,0);
$Image=$Map-&gt;Draw();
$url_imagen=$Image-&gt;saveWebImage();
//Añadimos que la imagen será usada como un mapa de html
echo &quot;&lt;img src=&quot;.$url_imagen.&quot; usemap='#sensible'&gt;&quot;;
echo &quot;&lt;map name='sensible'&gt;&quot;;

//Lo siguiente, es conectarse a la base de datos para consultar los municipios que vamos a mostrar en el mapa
$conn = pg_connect(&quot;host=localhost port=5432 dbname=demos user=****** password=******&quot;);
$sqlmun= &quot;select nombre04 as nombre,codmun as codmunicipal, area(geometria) as area from ine.municipios where com = '10'&quot;;
$poligono = pg_query($conn,$sqlmun);
$rowspol=pg_num_rows($poligono);
for ($h=0; $h&lt;$rowspol; $h++)
{
        $arraypol=pg_fetch_array($poligono,$h);
        $nombre=$arraypol['nombre'];
        $codmun=$arraypol['codmunicipal'];
        $area=round(($arraypol['area']/1000000),2);

        $pxmin = 626680;
        $pymin = 4191059;
        $pxmax = 815673.125;
        $pymax = 4519371;

        //distancia en metros de los ejes
        $eqx=$pxmax-$pxmin;
        $eqy=$pymax-$pymin;
//Llegados a este punto ejecutamos la función anterior que creamos en la base de datos, para que nos devuelva las coordenadas de los vértices de cada uno de los polígonos
        $sqlpolcoords=&quot;select * from ine.gc_listvertices('$codmun') as foo(x float, y float,tend boolean)&quot;;
        $polcoords= pg_query($conn,$sqlpolcoords);
        $rowspolcoords=pg_num_rows($polcoords);
        for ($j=0; $j&lt;$rowspolcoords; $j++)
        {
//Obtenemos los tres parámetros por separado que nos devuelve la función y hacemos la conversión de metros a pixel. Como he comentado anteriormente lo ideal es que esto se realice de manera automatizada, sin que introduzcamos nosotros la anchura y la altura del mapa
                $arraypolcoords=pg_fetch_array($polcoords,$j);
                $x=$arraypolcoords['x'];
                $y=$arraypolcoords['y'];
                $tend=$arraypolcoords['tend'];
                $xcal=$x-$pxmin;
                $ycal=$pymax-$y;

                $resx=round(((432*$xcal)/$eqx),0);
                $resy=round(((750*$ycal)/$eqy),0);
                $coordenadas.=$resx.&quot;,&quot;.$resy.&quot;,&quot;;
//Lo que va a hacer este parámetro es cortar cada polígono cada vez que devuelva true, de manera que en el caso de Alicante que son cuatro polígonos, los separa cada uno en un área distinta
                if($tend=='t')
                {
                        echo&quot;&lt;area shape=poly coords='$coordenadas' href=\&quot;javascript:void(0);\&quot; onClick=\&quot;munInfo('$nombre','$area');\&quot; alt='$nombre'&gt;\n&quot;;
//Para el ejemplo he creado una simple función en javascript que nos muestre el nombre y el área en un div cuando pasemos el ratón por encima de cualquier municipio.
                        $coordenadas=&quot;&quot;;
                }
        }
}
echo&quot;&lt;/map&gt;&quot;;
?&gt;
&lt;div id=&quot;munInfo&quot; class=&quot;munInfo&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>El resultado del ejemplo será este <a href="http://www.gisandchips.org/demos/mapscript/index_sense.php">mapa sensible</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/06/creacion-de-un-mapa-sensible-utilizando-plpgsql-y-php_mapscript/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Aumentar velocidad de carga de un mapfile utilizando simplificación de geometrías</title>
		<link>http://www.gisandchips.org/2009/11/05/aumentar-velocidad-de-carga-de-un-mapfile-utilizando-simplificacion-de-geometrias/</link>
		<comments>http://www.gisandchips.org/2009/11/05/aumentar-velocidad-de-carga-de-un-mapfile-utilizando-simplificacion-de-geometrias/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 11:48:58 +0000</pubDate>
		<dc:creator>pepe</dc:creator>
				<category><![CDATA[Comparativa]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[geometry simplification]]></category>
		<category><![CDATA[mapfile]]></category>
		<category><![CDATA[mapscript]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=492</guid>
		<description><![CDATA[En el anterior post creamos un mapfile dinámicamente con PHPMapScript, ahora lo que vamos a ver es como conseguir que la velocidad de carga de este mapfile se reduzca de forma considerable utilizando simplificación de geometrías mediante una función en PostGIS, esperando obtener un mapa con los municipios de toda España. Resultado esperado: El código [...]]]></description>
			<content:encoded><![CDATA[<p>En el anterior <a href="http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/" target="_blank">post</a> creamos un mapfile dinámicamente con PHPMapScript, ahora lo que vamos a ver es como conseguir que la velocidad de carga de este mapfile se reduzca de forma considerable utilizando simplificación de geometrías mediante una función en PostGIS, esperando obtener un mapa con los municipios de toda España.</p>
<p style="text-align: center;">Resultado esperado:<img class="aligncenter size-full wp-image-1082" title="4b024cb4_7df_1" src="http://www.gisandchips.org/wp-content/4b024cb4_7df_1.gif" alt="Mapa simplificado" width="300" height="300" /></p>
<p style="text-align: center;">
<p>El código de generación del mapfile será el mismo que en el  <a href="http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/" target="_blank">post</a> de creación del mapfile &#8220;al vuelo&#8221;, tan solo habría que cambiar la forma de obtener los datos, para que en lugar de obtenerlos con una simple sentencia sql, llamar a una función que obtuviera las geometrías simplificadas a costa de perder nivel de detalle (inapreciable a la vista).</p>
<p><span id="more-492"></span></p>
<p>Cuando se trata de simplificar geometrías hay que tener en cuenta la dimensión del mapa que queremos obtener para en función de esta dimensión, poder obtener de alguna forma un coeficiente de simplificación que se adecue a la simplificación que pretendemos obtener (es decir, ni que no nos haga casi simplificación, ni que simplifique demasiado).</p>
<p>Para obtener este factor de simplificación, podemos hacer varias operaciones, en este caso realizaremos una operación como la siguiente, dividiremos el resultado de restar a la xmax la xmin de la entensión de la geometria entre el ancho del mapa que queremos obtener.</p>
<p>Es decir, obtenemos la extensión de la geometría que estamos analizando , sacamos al xmax y la xmin, las restamos y el resultado lo dividimos entre el ancho del mapa que queremos obtener:</p>
<p>(xmax(extent(geometria) )- xmin(extent(geometria)))/Ancho del mapa</p>
<p>Creamos una función en sql para obtener el factor de simplificación que deseamos:</p>
<pre class="brush: php; title: ; notranslate">
create or replace function fs(float8) returns float8 AS $$
 select (xmax(extent(geometria))-xmin(extent(geometria)))/$1 from ine.municipios;
$$ LANGUAGE SQL;
</pre>
<p>Una vez que tenemos el factor de simplificación obtenido con la función anterior, ya podemos aplicar la simplificación con el factor de simplificación obtenido anteriormente.</p>
<p>Podemos hacer una comparativa del aumento de velocidad entre realizar una consulta sin simplificación y otra con la simplificación, por ejemplo para un mapa bastante grande de 4000px.</p>
<p>1ª consulta: &#8220;<strong><em>select geometria  from municipios2</em></strong>&#8221;</p>
<p>2ª consulta:&#8221;<strong><em>select st_simplify(geometria,factor_simplificacion) from municipios2</em></strong>&#8221;</p>
<p>En PostgreSQL, al ejecutar las dos sentencias podemos comparar y obtener:</p>
<p>1ª consulta</p>
<ul>
<li>Tiempo de ejecución de la consulta: <strong>50,84 segundos</strong></li>
<li>Numero de vertices: <strong>393666</strong></li>
</ul>
<p>2ª consulta</p>
<ul>
<li>Tiempo de ejecución de la consulta: <strong>19,51 segundos</strong></li>
<li>Numero de vertices: <strong>141610</strong></li>
</ul>
<p>De esta manera comprobamos que se produce un aumento en la velocidad a cambio de reducir el nivel de detalle, circunstancia que nos viene bien de cara a la publicación web, ya que no necesitamos un nivel de detalle elevado.</p>
<p>Para constaruir ahora la layer en MapScript, la sentencia SQL para obtener los datos sería como esta:</p>
<pre class="brush: php; title: ; notranslate">
$name = $Layer2-&gt;set(&quot;name&quot;,&quot;Municipios&quot;);
$type = $Layer2-&gt;set(&quot;type&quot;,MS_LAYER_POLYGON);
$status = $Layer2-&gt;set(&quot;status&quot;,MS_ON);
//Conexión con nuestra base de datos que va as er de tipo POSTGIS
$Layer2-&gt;setConnectionType(MS_POSTGIS);
//Cadena de conexión a la base de datos donde tenemos nuestros datos

//En primer lugar, debemos obtener el factor de simplificación que obtenemos mediante consulta a postgresql desde php:
$conexion = pg_pconnect(&quot;host=localhost port=5432 dbname=demos user=postgres&quot;);

$sql=&quot;select fs(&quot;.$Map-&gt;width.&quot;)&quot;;
$resultado=pg_exec($conexion,$sql);
$factor=pg_result($resultado,0,0);

$Layer2-&gt;set(&quot;connection&quot;,&quot;user=postgres dbname=demos host=localhost&quot;);
//Filtro en sql que vamos a introducir para sacar nuestros datos a mostrar, aplicando el factor obtenido anteriormente
$data=&quot;geometria from (select st_simplify(geometria,&quot;.$factor.&quot;) as geometria, nombre,provincia,gid from municipios) as foo using SRID=23030, using unique gid&quot;;
$Layer2-&gt;set(&quot;data&quot;,$data);
//Una vez definida la estructura d ela capa procedemos a definir el estilo de nuestra capa número 1
</pre>
<p>Para la comparación de velocidad de creación de un mapfile con una única capa PostGIS utilizando una sentencia SQL normal y utilizando simplificación de geometrías, utilizando para ello varios test de medición de velocidad de carga, asumimos que vamos a crear un mapa bastante grande de una dimensión de 2000&#215;2000 pixeles.</p>
<p><a href="http://www.gisandchips.org/demos/mapscript/index_norm.php" target="_blank">Sin simplificación de geometrías </a>(tal y como se hizo en el artículo anterior, pero con una sola capa y de tamaño 2000&#215;2000 píxeles)</p>
<p><a href="http://www.gisandchips.org/demos/mapscript/index_simp.php" target="_blank">Con simplificación de geometrías</a> (utilizando la función que hemos programado anteriormente)</p>
<p>Para realizar la comparativa de cargas he utilizado la herramienta <a href="http://www.websitegoodies.com/tools/speed-test.php" target="_blank">Speed-Test </a></p>
<p>El resultado que he obtenido es el siguiente:<br />
(no se aprecia mucha diferencia, pero es debido a que se ha guardado en la caché y no es significativa la diferencia)<br />
- Con la sentencia normal (sin simplificación)</p>
<table style="border: 1px solid #cccccc;" border="0">
<tbody>
<tr>
<td style="padding: 0pt 5px;"><strong>URL:</strong></td>
<td style="padding: 0pt 5px;">http://www.gisandchips.org/demos/mapscript/index_norm.php</td>
</tr>
<tr>
<td style="padding: 0pt 5px;"><strong>Load Time:</strong></td>
<td style="padding: 0pt 5px;">1.048 seconds</td>
</tr>
<tr>
<td style="padding: 0pt 5px;"><strong>Page Size:</strong></td>
<td style="padding: 0pt 5px;">0.19 kb</td>
</tr>
</tbody>
</table>
<p>- Utilizando el factor de simplificación y realizando una simplificación de las geometrías:</p>
<table style="border: 1px solid #cccccc;" border="0">
<tbody>
<tr>
<td style="padding: 0pt 5px;"><strong>URL:</strong></td>
<td style="padding: 0pt 5px;">http://www.gisandchips.org/demos/mapscript/index_simp.php</td>
</tr>
<tr>
<td style="padding: 0pt 5px;"><strong>Load Time:</strong></td>
<td style="padding: 0pt 5px;">1.013 seconds</td>
</tr>
<tr>
<td style="padding: 0pt 5px;"><strong>Page Size:</strong></td>
<td style="padding: 0pt 5px;">0.18 kb</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/05/aumentar-velocidad-de-carga-de-un-mapfile-utilizando-simplificacion-de-geometrias/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Creación de un mapfile de forma dinámica (&#8220;al vuelo&#8221;)</title>
		<link>http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/</link>
		<comments>http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 10:47:11 +0000</pubDate>
		<dc:creator>pepe</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[mapfile]]></category>
		<category><![CDATA[mapscript]]></category>
		<category><![CDATA[mapserver]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PostGIS]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://www.gisandchips.org/?p=383</guid>
		<description><![CDATA[Este artículo va encaminado a la publicación de cartografía en Internet de forma dinámica, utilizando PHPMapScript. Lo que vamos a intentar conseguir es mostrar en una página web un fichero de mapa sin la necesidad de tener un fichero .map (MapFile) asociado y complejo de mantener, simplemente realizando modificaciones en nuestro código php. Este es [...]]]></description>
			<content:encoded><![CDATA[<p>Este artículo va encaminado a la publicación de cartografía en Internet de forma dinámica, utilizando PHPMapScript.</p>
<p>Lo que vamos a intentar conseguir es mostrar en una página web un fichero de mapa sin la necesidad de tener un fichero .map (MapFile) asociado y complejo de mantener, simplemente realizando modificaciones en nuestro código php.</p>
<p>Este es el resultado que queremos obtener:</p>
<div id="attachment_1085" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-1085" title="4b025a29_5fd1_1" src="http://www.gisandchips.org/wp-content/4b025a29_5fd1_1-300x300.gif" alt="Mapa de españa" width="300" height="300" /><p class="wp-caption-text">Mapa de españa</p></div>
<p style="text-align: center">
<p>Vamos a ponernos manos a la obra para conseguirlo.</p>
<p>En primer lugar, doy por supuesto que tenemos instalado MapServer y MapScript en nuestro servidor Linux (en mi caso CentOS)  y el Servidor de Bases de Datos PostgreSQL+PostGIS y con la extensión PHP/pgSQL.</p>
<p>Creamos un fichero .php</p>
<p>Lo primero que debemos hacer es cargar la librería PHPMapScript (<em>php_mapscript.so</em>)</p>
<p><span id="more-383"></span></p>
<pre class="brush: php; title: ; notranslate">

dl('php_mapscript.so');

//Una vez cargada la librería ya se puede trabajar con las funciones propias de PHPMapScript
//Para empezar hay que crear el fichero mapa y definir las diferentes características que queremos que tenga el mapa (nombre, tamaño,

//Creamos un objeto llamado Map mediante el Constructor de MapObject

$Map=ms_newMapObj(&quot;&quot;);

//Le damos un nombre (p.e. mapa)
$Map-&gt;set(&quot;name&quot;,&quot;Mapa&quot;);

//La dimensión del mapa
$Map-&gt;setSize(600,600);

// La extensión del mapa (la podemos obtener de postgresql mediante la función de postgis st_extent
$Map-&gt;setExtent(626679.9375,4191059,815673.125,4519371);

// Se define el path de la imagen la temporal y la real que se mostrarán por web
$Map-&gt;web-&gt;set(&quot;imagepath&quot;,&quot;/tmp&quot;);
$Map-&gt;web-&gt;set(&quot;imageurl&quot;,&quot;/ms_tmp&quot;);

Una vez hemos definido las características de nuestro fichero de mapa, procedemos a incluir capas.
&lt;pre&gt;//Definimos una capa asociada a nuestro fichero de mapa anteriormente definido
// En este caso la primera capa, y que va a servir de fondo de nuestro mapa va a ser wms
// y del servicio wms que proporciona el &lt;a href=&quot;http://www.idee.es/wms/PNOA/PNOA?Request=GetCapabilities&amp;Service=WMS&quot; target=&quot;_blank&quot;&gt;PNOA&lt;/a&gt;&lt;/pre&gt;
$Layer1=ms_newLayerObj($Map);

$Layer1-&gt;set(&quot;name&quot;,&quot;ortofoto&quot;);

//Tipo Raster

$Layer1-&gt;set(&quot;type&quot;,MS_LAYER_RASTER);

$Layer1-&gt;set(&quot;status&quot;,MS_ON);//El status de la Layer, esto nos permitirá definir layers y mantenerlas ocultas dependiendo de las necesidades que tengamos
$Layer1-&gt;setConnectionType(MS_WMS);
$Layer1-&gt;set(&quot;connection&quot;,&quot;http://www.idee.es/wms/PNOA/PNOA?&quot;);
//Definimos la proyección del wms junto con el nombre de la capa wms, la versión del servidor y el formato de la imagen
&lt;pre&gt;//El que esta capa se muestre o no, no depende de nosotros, depende de una fuente externa que proporciona la capa WMS, en este caso es la del PNOA&lt;/pre&gt;
$Layer1-&gt;setProjection(&quot;init=epsg:23030&quot;);
$Layer1-&gt;setMetadata(&quot;wms_name&quot;,&quot;pnoa&quot;);
$Layer1-&gt;setMetadata(&quot;wms_server_version&quot;,&quot;1.1.1&quot;);
$Layer1-&gt;setMetadata(&quot;wms_format&quot;,&quot;image/png&quot;);

//Como segunda capa asociada a nuestro fichero de mapa anteriormente definido vamos a añadir una capa obtenida de nuestros datos en postgresql
$Layer2=ms_newLayerObj($Map);

//Vamos definiendo las características que va a tener esta nuestra primera capa
$name = $Layer2-&gt;set(&quot;name&quot;,&quot;Municipios&quot;);
$type = $Layer2-&gt;set(&quot;type&quot;,MS_LAYER_POLYGON);
$status = $Layer2-&gt;set(&quot;status&quot;,MS_ON);
//Conexión con nuestra base de datos que va as er de tipo POSTGIS
$Layer2-&gt;setConnectionType(MS_POSTGIS);
//Cadena de conexión a la base de datos donde tenemos nuestros datos
$Layer2-&gt;set(&quot;connection&quot;,&quot;user=postgres dbname=demos host=localhost&quot;);
//Filtro en sql que vamos a introducir para sacar nuestros datos a mostrar
// MUY IMPORTANTE es necesario incluir el unique gid y using srid=23030, si no no funcionará
$Layer2-&gt;set(&quot;data&quot;,&quot;geometria from ine.municipios using unique gid using srid=23030&quot; );
//Una vez definida la estructura d ela capa procedemos a definir el estilo de nuestra capa número 1

$clase = ms_newClassObj($Layer2); //Definimos la clase
$estilo = ms_newStyleObj($clase); //El estilo asociado a dicha clase
$estilo-&gt;color-&gt;setRGB(10,150,190); //Los colores
$estilo-&gt;outlinecolor-&gt;setRGB(0,0,0); //El contorno

//Una vez hemos definido las capas tenemos que indicar que se dibuje el mapa
$Image=$Map-&gt;Draw();

//Muy importante que no se nos olviden estas 2 sentencias que vienen a continuación, si no ponemos que se almacene la imagen en el path que le hemos incluido o no la mostramos por pantalla con un echo, no va a mostarse nada, y caeremos en el desanimo ya que después de definir todo correctamente la página aparece en blanco.

$url_imagen=$Image-&gt;saveWebImage();
echo &quot;&lt;img src=&quot;.$url_imagen.&quot;&gt;&quot;;
</pre>
<p>Y después de tener esto, solo hay que lanzar el navegador y et voilà!, tenemos nuestro primer mapfile utilizando PHPMapScript en nuestro navegador, puede que sea un poco lento a la hora de cargar, pero no depende tanto de nuestra capa en PostGIS sino del Servidor WMS que utilicemos como capa de fondo, que ya no depende de nosotros.</p>
<p>El resultado es este: <a href="http://www.gisandchips.org/demos/mapscript/index.php" target="_blank">http://www.gisandchips.org/demos/mapscript/index.php</a></p>
<p style="text-align: center;">
]]></content:encoded>
			<wfw:commentRss>http://www.gisandchips.org/2009/11/02/creacion-de-un-mapfile-de-forma-dinamica-al-vuelo/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

