quinta-feira, 28 de outubro de 2010

Função para Calcular a Distancia entre Duas Coordenadas no SQL Server (Transact-SQL)

                Em sistemas de logística temos sempre que calcular a distancia entre pontos e geralmente temos tabelas com endereço dos pontos ou as coordenadas do endereço, sempre que temos que saber a distancia usamos ferramentas de roteirização para calcular o trajeto e informar a distancia. Esse tipo de solução pode ter um custo alto de processamento, velocidade e financeiro já que algumas ferramentas cobram por acesso a sua base.
                Para evitar custos desnecessários podemos fazer este calculo no banco de dados, ao invés de usar a ferramenta de roteirização. A vantagem de usar esta abordagem é que mais rápido, podemos usar o comando order by (sem precisar recorrer a código para ordenar pelo mais próximo ou mais distante) e não tem custo, porem poderemos ter problemas se os pontos estiverem muito próximos já que o calculo será feito em linha reta sem levar em consideração o trajeto.
                Primeiro vamos criar a função para calcular a distancia entre dois pares de coordenadas, estes pares devem estar em graus decimais. Esta função é a mesma que eu criei no artigo Função em Delphi para Calcular a Distância Entre Dois Pares de Coordenadas (Latitude e Longitude) convertida nas funções do Transact-SQL.
                Segue o script para criar a função:
-- =============================================
-- Author:        Wagner Carmo da Silva
-- Create date:   20/10/2010 17:24
-- Description:   Calcula a distância em quilometros
-- =============================================
CREATE FUNCTION [fun_CalcDistancia] 
(
     @latIni float, -- Latitude do ponto inicial
     @lonIni float, -- Longitude do ponto inicial
     @latFim float,-- Latitude do ponto final
     @lonFim float -- Longitude do ponto final
)
RETURNS float
AS
BEGIN
     DECLARE @Result AS FLOAT
     DECLARE @arcoA AS FLOAT
     DECLARE @arcoB AS FLOAT
     DECLARE @arcoC AS FLOAT
     DECLARE @auxPI AS FLOAT

     SET @auxPi = Pi() / 180
     SET @arcoA = (@lonFim - @lonIni) * @auxPi
     SET @arcoB = (90 - @latFim) * @auxPi
     SET @arcoC = (90 - @latIni) * @auxPi
     SET @Result = Cos(@arcoB) * Cos(@arcoC) + Sin(@arcoB) * Sin(@arcoC) * Cos(@arcoA)
     SET @Result = (40030 * ((180 / Pi()) * Acos(@Result))) /360

     RETURN Round(@Result,2)
END
                Esta função retorna o valor em quilômetros arredondando duas casas, se precisar aumentar a precisão do calculo basta alterar este trecho do código RETURN Round(@Result,2) , número 2 é a quantidade de casas decimais depois da virgula basta aumentar este número para aumentar as casas, se quiser deixar com precisão total basta remover a função round (RETURN @Result).
                Agora vou mostrar um select que mostra uso dessa função :

SELECT
     cd_Empresa,
     nr_Latitude,
     nr_Longitude,
     fun_CalcDistancia(-23.479483, -46.749340, nr_Latitude, nr_Longitude) AS nr_Distancia
FROM tbl_Empresas
ORDER BY fun_CalcDistancia(-23.479483, -46.749340, nr_Latitude, nr_Latitude)

                Repare que eu usei a função até mesmo para ordenar o resultado, neste caso ele traz o mais próximo, para inverter isto basta usar o desc depois do order by.
                Importante é não esquecer que o calculo é em linha reta, isso deve ser usado quando os pontos tem uma boa distancia, ou seja, o caminho não vai interferir muito na distancia do ponto.

Referências:

terça-feira, 19 de outubro de 2010

Função Para Converter Graus Decimais em Graus Minutos e Segundos no Javascript

                Quem trabalha com mapas vive precisando fazer conversões de coordenadas, com o crescimento das ferramentas de mapas para Web essas conversões devem ser feitas no Javascript, abaixo segue a função que eu desenvolvi para exibir as coordenadas que a ferramenta de mapa retorna em graus para exibir em graus minutos e segundos:
function showCoordenadasMinutos(gDec, x) {
    var graus;
    var minutos;
    var aux;
    var segundos;
    var milisegundos;
    var direcao;

    // Separa os graus
    graus = parseInt(gDec);

    // Pega a fração dos graus e converte em minutos
    aux = (graus - gDec) * 60;
    minutos = parseInt(aux);

    // Pega a fração dos minutos e converte em segundos
    aux = (aux - minutos) * 60;
    segundos = parseInt(aux);

    // Pega a fração dos segundos e converte em milisegundos
    milisegundos = parseInt((aux - segundos) * 60);

    // Essa parte eu verifico se é o eixo X ou Y para substituir o simbolo de negativo  pelas iniciais de norte ou sul para o eixo Y, leste ou oeste para o eixo X
    if (x) {
        // Eixo X
        if (graus < 0)
            direcao = "O";
        else
            direcao = "L";
    } else {
        // Eixo Y
        if (graus < 0)
            direcao = "S";
        else
            direcao = "N";
    }
    // Devolvo a string formatada, a função Math.abs é para retornar o valor absoluto // (retirar o valor negativo) já que estou usando a notação norte, sul, leste ou oeste
    return Math.abs(graus) + "° " + minutos + "' " + segundos + "." + milisegundos + "'' " + direcao;
}

Como eu precisava criar uma função para exibir os dados para o usuário eu substitui o valor negativo pelas inicias dos pontos cardeais e coloquei as aspas simples, se quiser deixar no padrão NMEA basta juntar o grau o minuto colocar o ponto e juntar o segundo e o milissegundos.
Se quiser usar esta função para retornar um valor de ponto flutuante no padrão NMEA substitua o retorno da função pelo debaixo :

return ((graus * 100) + minutos) + (((segundos * 100) + milisegundos) / 10000);
 

E remova o parâmetro x da função e o trecho de código que verifica qual é a direção da coordenada.

terça-feira, 24 de agosto de 2010

Lendo os Dados de uma Planilha do Excel C#

    Me deparei com uma situação onde precisava ler os dados de uma planilha de Excel, e depois de muita pesquisa segue a forma mais fácil que eu encontrei para fazer isso usando o C#, porem é necessário que o Excel esteja instalado nas maquinas onde seu programa vai executar.    
    O primeiro passo é adicionar as referências do Excel ao seu projeto, para isso clique com o botão direito em cima do seu projeto na Solution Explorer, vá até a opção Add Reference, depois na aba COM, procure pelo Microsoft Excel (versão) Object Library e depois click em OK.
    Adicione as seguintes bibliotecas ao seu fonte :
using Excel =  Microsoft.Office.Interop.Excel; //*
using System.Reflection;
    * Renomeie esta biblioteca para evitar conflitos de nome e facilitar seu uso dentro do seu programa

    Segue o código comentado para abrir o Excel,  a planilha ler os dados :
// Cria uma instancia do Excel
Excel.Application oXL = new Excel.Application();
// Objeto que vai  conter seu arquivo
Excel.Workbook oWB; 
// Caso você queira que o seu programa  mostre a planilha aberta no Excel deixa está opção como true
oXL.Visible = true; 
//Comando para abrir a  planilha, basta substituir o "endereço da planilha"
oWB = oXL.Workbooks.Open("endereço da planilha", 0, true,  5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, null, null); 
// Pega a planilha ativa, se o Excel não estiver  aberto é a primeira planilha do arquivo
Excel.Worksheet activeSheet = (Excel.Worksheet) oWB.ActiveSheet;
// Pega o  texto da célula A1
string cellA1 = (string) activeSheet.get_Range("A1", Missing.Value).Text;
// Exibe uma mensagem com o texto da célula A1
MessageBox.Show(cellA1);
    Caso você queira pegar uma planilha especifica do arquivo use o seguinte comando :
// Substitua o X pelo número da planilha, é  a ordem que aparece as abas
Excel.Worksheet activeSheet = (Excel.Worksheet) oWB.Worksheets.get_Item(X); 
   Isto é o básico para abrir e ler uma planilha no Excel, mas saiba que é possível alterar fonte, criar formula adicionar conteúdo e alterar dados.


Referências:
http://support.microsoft.com/kb/302084

sexta-feira, 23 de julho de 2010

Função C# para Copiar uma Palavra de uma Frase usando StringBuilder


    Quando temos preocupação com o uso de memória em nossas aplicações o uso do tipo String não é recomendável, devemos usar a classe StringBuilder, porem ela não tem tantas funções como tem o a classe String.
    Uma função que eu senti falta foi para copiar uma palavra de uma frase, ou um trecho delimitado por isso criei a função abaixo:
// Copia as palavra na posição e seu separador
private StringBuilder Palavra(StringBuilder pacote, char separador, int posicao)
{
    StringBuilder retorno = new StringBuilder();           
    for (int i = 0, pos = 1; i < pacote.Length; i++)
    {          
        retorno.Append(pacote[i]);
        if (pacote[i] == separador)
                {
                    if (pos == posicao)
                    {
                        retorno.Remove(retorno.Length - 1, 1);
                        break;
                    }
                    else
                    {
                        retorno.Remove(0, retorno.Length);
                        pos++;
                    }
                }
            }
            return new StringBuilder().Append(retorno);
}

    Esta função possui três parâmetros :
        - pacote: é a frase que queremos pegar uma palavra;
        - separador: caracter utilizado para separar as palavras;
        - posicao: posição da palavra dentro da frase.

        Exemplo
        Temos a seguinte frase:
StringBuilder aux = new  StringBuilder("Santos campeão da Copa do Brasil de 2010");

        Para pegar a palavra "Santos" usaremos a função da seguinte forma
Palavra(aux,' ',1);

terça-feira, 29 de junho de 2010

Livro: Visual C# 2008 do Jonh Sharp

    Terminei de ler o livro Visual C# 2008 do Jonh Sharp (traduzido), é um ótimo livro para iniciar o aprendizado da plataforma .Net utilizando o C#.
    O autor utiliza ótimos exemplos, aborda quase tudo o que envolve a plataforma .Net, porem nada muito profundo mas o suficiente para iniciar e ter base para buscar mais sobre os assuntos.
     Geralmente os livros não tem uma tradução muito boa, porem este livro a tradução é ótima, mantiveram os nomes dos exemplos sem traduzir para ficar fácil localizar as classes nos exemplos.
     Fica ai uma dica para aprender C# e .Net

sexta-feira, 19 de fevereiro de 2010

Função em Delphi para Calcular a Distância Entre Dois Pares de Coordenadas (Latitude e Longitude)


Segue uma função para calcular a distância de dois pares de coordenadas em graus decimais, resultado é dado em quilômetros.
function calcDistancia(LatIni, LonIni, LatFim, LonFim: Extended): Extended;
var
 arcoA, arcoB, arcoC : Extended;
 auxPI : Extended;
begin
   auxPi := Pi / 180;

   arcoA := (LonFim - LonIni) * auxPi;
   arcoB := (90 - LatFim) * auxPi;
   arcoC := (90 - LatIni) * auxPi;

   // cos (a) = cos (b) . cos (c)  + sen (b) . sen (c) . cos (A)
   Result := Cos(arcoB) * Cos(arcoC) + Sin(arcoB) * Sin(arcoC) * Cos(arcoA);
   Result := (40030 * ((180 / Pi) * ArcCos(Result))) / 360;
end;

Como Saber a Quantidade de Registros Duplicados (SQL SERVER)


Uma forma de localizar registros duplicados no SQL é utilizar a instrução GROUP BY e HEAVING.
Vamos imaginar uma tabela chamada Clientes com o campo CPF e você queira saber a quantidade de CPF's duplicados, para isso digite a seguinte instrução :
 
SELECT CPF, COUNT(*) FROM Clientes
GROUP BY CPF
HAVING COUNT(*) > 1
 
Esta instrução ira retorna o CPF e a quantidade de registro que ele possui, porem ele só vai trazer os CPF que tem mais de uma ocorrência, isto devido a clausula HAVING COUNT(*) > 1.