sexta-feira, 18 de maio de 2012

to_ascii funcionando no PostgreSQL

Como certa vez disse o Fabrício Lakus Brito, "lower(to_ascii()) é o que há". Infelizmente essa função não funciona mais para bancos de dados com codificação UTF-8 na versão 8.3. Encontrei no blog Florian Helmberger’s blog a descrição da situação que enfrentamos:
In the process of fixing our code for an upcoming upgrade of one database version for one of our $-projects I encountered a strange behaviour. Initiual situation:
  • we're moving from PostgreSQL 8.1.3 to the 8.3.5
  • we're moving from database encoding LATIN1 to UTF8
  • in our code we're using the TO_ASCII function a few times.
And this combination produces some headaches.
A função to_ascii deixou de funcionar. A solução apresentada nesse blog (que já foi pega de uma outra pessoa) foi:

CREATE FUNCTION to_ascii(bytea, name) RETURNS text STRICT AS 'to_ascii_encname' LANGUAGE internal;

Daí eu uso a função assim:

SELECT to_ascii(convert_to('Übermeier', 'latin1'), 'latin1');

segunda-feira, 7 de maio de 2012

Múltiplas requisições AJAX


Precisava fazer várias requisições ajax a vários servidores. Não queria me preocupar com a ordem das requisições, mas pra possibilitar que todas fossem feitas ao mesmo tempo, precisava criar um objeto XmlHttp para cada uma delas (veja http://www.ibm.com/developerworks/web/library/wa-ajaxintro3/).

Uma solução que estou testando usa closures (veja http://jibbering.com/faq/notes/closures/), que é diferente do Closure Tools (https://developers.google.com/closure/compiler/). Ainda estou aprendendo a mexer com isso, e o resultado foi (atualização 7/2/2013: veja este post: Usando o ajaxStufff):


E o arquivo ajaxStufff.js:

function assoc(xmlHttp, postQueryString, onreadystatechange, action)
{
    return (function() {
        xmlHttp.onreadystatechange=onreadystatechange;
        xmlHttp.open("POST", action, true);
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlHttp.setRequestHeader("Content-length", postQueryString.length);
        xmlHttp.setRequestHeader("Connection", "close");
        xmlHttp.send(postQueryString);
    });
}

function obterXHR() {
    try
    {
        // Firefox, Opera 8.0+, Safari
        xmlHttp=new XMLHttpRequest();
    }
    catch(e)
    {
        // Internet Explorer
        try
        {
            xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e)
        {
            try
            {
                xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e)
            {
                alert("Seu navegador não suporta AJAX!");
                return false;
            }
        }
    }
    return xmlHttp;
}

quinta-feira, 27 de outubro de 2011

PHP Cheat Sheet

Pra quem fica chateado de esquecer a ordem dos parâmetros das funções do PHP

http://www.addedbytes.com/download/php-cheat-sheet-v2/png/

quarta-feira, 24 de agosto de 2011

Função "aggregate" para cálcular mediana no PostgreSQL

O Postgres não tem uma função que calcule a mediana dos valores de um determinada coluna, ou seja, fazer algo do tipo:

SELECT median(col) FROM tabela;

Mas em http://wiki.postgresql.org/wiki/Aggregate_Median está o código necessário para isso. É pequeno e não precisa entender nada dele pra utilizar. Basta copiar e executar no seu console dentro do banco de dados onde você quer que a função funcione. Se essa função tiver que funcionar em diversos bancos, é preciso executar esse código em cada um deles.

CREATE OR REPLACE FUNCTION _final_median(numeric[])
RETURNS numeric AS
$$
SELECT AVG(val)
FROM (
SELECT val
FROM unnest($1) val
ORDER BY 1
LIMIT 2 - MOD(array_upper($1, 1), 2)
OFFSET CEIL(array_upper($1, 1) / 2.0) - 1
) sub;
$$
LANGUAGE 'sql' IMMUTABLE;

CREATE AGGREGATE median(numeric) (
SFUNC=array_append,
STYPE=numeric[],
FINALFUNC=_final_median,
INITCOND='{}'
);

segunda-feira, 15 de agosto de 2011

Calculando zoom automático em mapas

Como não consegui fazer o Open Layers funcionar passando direto a resolução do mapa, precisei calcular o zoom de maneira dinâmica.

Queria que meu mapa aparecesse em uma janela de largura 600px e altura 430px, com o zoom que fizesse uma certa feature aproveitar esse espaço da melhor maneira, ficando totalmente visível nessa área.

Encontrei a seguinte fórmula:
Map resolution = 156543.04 meters/pixel * cos(latitude) / (2 ^ zoomlevel)

Fui jogando as coisas de um lado pro outro:
(2 ^ zoomlevel) = 156543.04 meters/pixel * cos(latitude)/Map resolution

E enfim, considerando que se 2^x = a, então x = (ln a/ln 2):
zoomlevel = ln(156543.04 meters/pixel * cos(latitude)/Map resolution)/ln 2

Como latitude, usei a função st_ymin (no meu caso, seria praticamente igual a usar o st_ymax) do PostGIS, passando a feature como parâmetro. Para calcular a resolução, tive que descobrir se a feição era maior no eixo x ou no eixo y usando a seguinte query:
select st_distance_sphere(st_makepoint(st_xmax(the_geom), st_ymin(the_geom)), st_makepoint(st_xmin(the_geom), st_ymin(the_geom))) as dist_x,
st_distance_sphere(st_makepoint(st_xmin(the_geom), st_ymax(the_geom)), st_makepoint(st_xmin(the_geom), st_ymin(the_geom))) as dist_y
from <tabela> where <cláusula where>


Como já sei o tamanho da janela onde ficará o mapa (600 x 430), então se a feature é maior no eixo x, a resolução é dist_x/600. Se a feature é maior no eixo y, a resolução é dist_y/430.

Encontrei a fórmula para calcular o zoom em:
http://msdn.microsoft.com/en-us/library/aa940990.aspx

Obrigado ao Cristiano Pereira da Silva (ardagh) pela ajuda com a matemática.

quarta-feira, 6 de abril de 2011

Correspondência entre zona UTM e SRID

Estou com um DVD do IBGE onde os shapes estão na projeção UTM / SAD69. Preciso indicar o SRID ao rodar o programa shp2pgsql pra conseguir transformar em coordenadas posteriormente.
A tabela abaixo tem o SRID (da EPSG) e a zona correspondente. Listei apenas as do Brasil.

29118 - zone 18N
29119 - zone 19N
29120 - zone 20N
29121 - zone 21N
29122 - zone 22N
29177 - zone 17S
29178 - zone 18S
29179 - zone 19S
29180 - zone 20S
29181 - zone 21S
29182 - zone 22S
29183 - zone 23S
29184 - zone 24S
29185 - zone 25S

A seguinte SQL faz a conversão com base na fórmula que coloquei no post Em qual zona UTM está um determinado ponto?:
select ibge, case when latitudese < 0 then 29160+trunc((longitudes + 186) / 6) else 29100+trunc((longitudes + 186) / 6) end srid from mapas.shp_munic

Outras correspondências eu busco aqui:
http://svn.osgeo.org/metacrs/csmap/trunk/CsMapDev/Dictionaries/coordsys.asc

sexta-feira, 3 de dezembro de 2010

Municípios criados ao longo do tempo

De vez em quando aparece alguém com dúvida sobre quais municípios foram criados em 2005 e quando foi criado o município de Nazária/PI.
A navegação no site do IBGE não é fácil.
Felizmente encontrei uma página no site do DataSUS que explica tudo isso:
http://www2.datasus.gov.br/DATASUS/index.php?area=040206&item=7