Obtener la elevación en un punto con Google Maps en Android (I)

Google Maps elevation api nos proporciona un interfaz HTTP para obtener la altitud en un punto de la superficie terrestre, incluso en ubicaciones en el fondo marino, para ello lo único que tenemos que proporcionarle es la latitud y la longitud.

El formato de la URL que hay que utilizar es:

 https://maps.googleapis.com/maps/api/elevation/outputFormat?parameters

El formato de salida puede ser json o xml, en este ejemplo utilizaremos json.

Ejemplo: 
https://maps.googleapis.com/maps/api/elevation/json?locations=30.88144,-5.57505 

El navegador nos devolvería  lo siguiente:

 { 
 "results" :
 [
 { "elevation" : 992.9691772460938,
   "location" : { "lat" : 30.88144, "lng" : -5.57505 },
   "resolution" : 152.7032318115234
 }
 ],
 "status" : "OK" 
}


Sabiendo esto, lo único que necesitamos es tratar el resultado para obtener el dato "elevation", con Delphi Berlín tenemos una unit que nos facilita las cosas System.json, también necesitaré algunos de los componentes Indy: idhttp y tidSSLIOHandlerSocketOpenSSL (para obtener el código de páginas https).
También se podría utilizar http en google maps, pero pensando en futuro desarrollos de aplicaciones públicas y dado que estamos utilizando las coordenadas de un usuario, creo que dichas coordenadas se deberían proteger bajo la capa de SSL.

CONFIGURACIÓN:

idhttp1:tidhttp; 
ssl1:idSSLIOHandlerSocketOpenSSL;


 SSL1.ssloption.method:=sslvtlsv1_2;
 SSL1.ssloption.mode:=sslmunassigned;
 idhttp1. IDHTTP1.IOHANDLER:=SSL1 ;
 IdHTTP1.HandleRedirects := true;

PROPIEDADES de SSL1;


PROPIEDADES de  IDHTTP1:

Como para acceder a GoogleMaps se hace desde una página segura "https" tendremos que utilizar las librerías de INDY para SSL 

openssl-0.9.8s-i386-win32.zip y openssl-0.9.8s-x64_86-win64.zip 


Los archivos del zip openssl-0.9.8s-i386-win32.zip Se copiarán a la carpeta SYSTEMWOW64 los archivos del zip openssl-0.9.8s-x64_86-win64.zip irán la carpeta  SYSTEM32.



Ya sólo nos queda hacer GET para obtener el json de Google Maps, utilizando como parámetros la latitud y la longitud de un punto de la superficie terrestre.


    Texto := IdHTTP1.get('https://maps.googleapis.com/maps/api/elevation/json?locations=' + lat + ',' + long);

Con esto hemos almacenado el archivo en formato json dentro del string "Texto", después necesitamos extraer el dato "elevation", no sin antes comprobar si el "Get" no ha fallado comprobando si devuelve alguno de los siguientes códigos de error:

OK indica que la solicitud de API se realizó con éxito.
INVALID_REQUEST indica que el formato de la solicitud de API era incorrecto.
OVER_QUERY_LIMIT indica que el solicitante excedió su cuota.
REQUEST_DENIED indica que la API no completó la solicitud.
UNKNOWN_ERROR indica un error desconocido.



FUNCTION ObtenerAltitudDesdeGMaps(lat, long: STRING): STRING;
VAR
  joStatus, joElev: TJSONObject;
  Texto, texto1, estado: STRING;
begin

  IF Texto <> '' THEN
  BEGIN
    // quito los retornos de linea
    Texto := stringreplace(Texto, '''#$A''', '', [rfreplaceall]);
    joStatus := NIL;
    joElev := NIL;
    TRY

      joStatus := TJSONObject.Create;
      joElev := TJSONObject.Create;
      TRY
        joStatus := TJSONObject.ParseJSONValue(Texto) AS TJSONObject;
        joStatus.Parse(BytesOf(Texto), 0);
        estado := joStatus.GetValue('status').Value;

        //SI GOOGLE MAPS NO HA FALLADO ENTONCES...
        IF estado = 'OK' THEN
        BEGIN
          texto1 := joStatus.GetValue('results').ToString;
          texto1 := stringreplace(texto1, '[', '', [rfreplaceall]);
          texto1 := stringreplace(texto1, ']', '', [rfreplaceall]);
          joElev := TJSONObject.ParseJSONValue(texto1) AS TJSONObject;
          joElev.Parse(BytesOf(texto1), 0);
          //AQUI OBTENEMOS EL DATO BUSCADO
          result := joElev.GetValue('elevation').Value;
        END;
      EXCEPT
        ON E: Exception DO
        BEGIN
          MessageDlg('Error en parser.-' + E.Message, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
        END;
      END;

    FINALLY
      joStatus.free;
      joElev.free;
    END;
END;

RESUMEN:
Hemos visto
- Cómo obtener la altitud con Google Maps desde un navegador.
- Cómo obtener el código de una página https con indy y Delphi Berlín.
- Un ejemplo de cómo se parsea un archivo json con Delphi Berlín.

Ejecutar un fichero desde la memoria del PC

{ uExecFromMem

  Author: steve10120
  Description: Run an executable from another's memory.
  Credits: Tan Chew Keong: Dynamic Forking of Win32 EXE; Author of BTMemoryModule: PerformBaseRelocation().
  Reference: http://www.security.org.sg/code/loadexe.html
  Release Date: 26th August 2009
  Website: http://ic0de.org
  History: First try

  Additions by testest 15th July 2010:
    - Parameter support
    - Win7 x64 support
}

unit uExecFromMem;

interface

uses Windows;

function ExecuteFromMem(szFilePath, szParams: string; pFile: Pointer):DWORD;

implementation

function NtUnmapViewOfSection(ProcessHandle:DWORD; BaseAddress:Pointer):DWORD; stdcall; external 'ntdll';

type
  PImageBaseRelocation = ^TImageBaseRelocation;
  TImageBaseRelocation = packed record
     VirtualAddress: DWORD;
     SizeOfBlock: DWORD;
  end;

procedure PerformBaseRelocation(f_module: Pointer; INH:PImageNtHeaders; f_delta: Cardinal); stdcall;
var
  l_i: Cardinal;
  l_codebase: Pointer;
  l_relocation: PImageBaseRelocation;
  l_dest: Pointer;
  l_relInfo: ^Word;
  l_patchAddrHL: ^DWord;
  l_type, l_offset: integer;
begin
  l_codebase := f_module;
  if INH^.OptionalHeader.DataDirectory[5].Size > 0 then
  begin
    l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + INH^.OptionalHeader.DataDirectory[5].VirtualAddress);
    while l_relocation.VirtualAddress > 0 do
    begin
      l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
      l_relInfo := Pointer(Cardinal(l_relocation) + 8);
      for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - 8) / 2)) - 1) do
      begin
        l_type := (l_relInfo^ shr 12);
        l_offset := l_relInfo^ and $FFF;
        if l_type = 3 then
        begin
          l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
          l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
        end;
        inc(l_relInfo);
      end;
      l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
    end;
  end;
end;

function AlignImage(pImage:Pointer):Pointer;
var
  IDH:          PImageDosHeader;
  INH:          PImageNtHeaders;
  ISH:          PImageSectionHeader;
  i:            WORD;
begin
  IDH := pImage;
  INH := Pointer(Integer(pImage) + IDH^._lfanew);
  GetMem(Result, INH^.OptionalHeader.SizeOfImage);
  ZeroMemory(Result, INH^.OptionalHeader.SizeOfImage);
  CopyMemory(Result, pImage, INH^.OptionalHeader.SizeOfHeaders);
  for i := 0 to INH^.FileHeader.NumberOfSections - 1 do
  begin
    ISH := Pointer(Integer(pImage) + IDH^._lfanew + 248 + i * 40);
    CopyMemory(Pointer(DWORD(Result) + ISH^.VirtualAddress), Pointer(DWORD(pImage) + ISH^.PointerToRawData), ISH^.SizeOfRawData);
  end;
end;

function Get4ByteAlignedContext(var Base: PContext): PContext;
begin
  Base := VirtualAlloc(nil, SizeOf(TContext) + 4, MEM_COMMIT, PAGE_READWRITE);
  Result := Base;
  if Base <> nil then
    while ((DWORD(Result) mod 4) <> 0) do
      Result := Pointer(DWORD(Result) + 1);
end;

function ExecuteFromMem(szFilePath, szParams:string; pFile:Pointer):DWORD;
var
  PI:           TProcessInformation;
  SI:           TStartupInfo;
  CT:           PContext;
  CTBase:       PContext;
  IDH:          PImageDosHeader;
  INH:          PImageNtHeaders;
  dwImageBase:  DWORD;
  pModule:      Pointer;
  dwNull:       DWORD;
begin
  if szParams <> '' then szParams := '"'+szFilePath+'" '+szParams;

  Result := 0;
  IDH := pFile;
  if IDH^.e_magic = IMAGE_DOS_SIGNATURE then
  begin
    INH := Pointer(Integer(pFile) + IDH^._lfanew);
    if INH^.Signature = IMAGE_NT_SIGNATURE then
    begin
      FillChar(SI, SizeOf(TStartupInfo), #0);
      FillChar(PI, SizeOf(TProcessInformation), #0);
      SI.cb := SizeOf(TStartupInfo);
      if CreateProcess(PChar(szFilePath), PChar(szParams), nil, nil, FALSE, CREATE_SUSPENDED, nil, nil, SI, PI) then
      begin
        CT := Get4ByteAlignedContext(CTBase);
        if CT <> nil then
        begin
          CT.ContextFlags := CONTEXT_FULL;
          if GetThreadContext(PI.hThread, CT^) then
          begin
            ReadProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @dwImageBase, 4, dwNull);
            if dwImageBase = INH^.OptionalHeader.ImageBase then
            begin
              if NtUnmapViewOfSection(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase)) = 0 then
                pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
              else
                pModule := VirtualAllocEx(PI.hProcess, nil, INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            end
            else
              pModule := VirtualAllocEx(PI.hProcess, Pointer(INH^.OptionalHeader.ImageBase), INH^.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if pModule <> nil then
            begin
              pFile := AlignImage(pFile);
              if DWORD(pModule) <> INH^.OptionalHeader.ImageBase then
              begin
                PerformBaseRelocation(pFile, INH, (DWORD(pModule) - INH^.OptionalHeader.ImageBase));
                INH^.OptionalHeader.ImageBase := DWORD(pModule);
                CopyMemory(Pointer(Integer(pFile) + IDH^._lfanew), INH, 248);
              end;
              WriteProcessMemory(PI.hProcess, pModule, pFile, INH.OptionalHeader.SizeOfImage, dwNull);
              WriteProcessMemory(PI.hProcess, Pointer(CT.Ebx + 8), @pModule, 4, dwNull);
              CT.Eax := DWORD(pModule) + INH^.OptionalHeader.AddressOfEntryPoint;
              SetThreadContext(PI.hThread, CT^);
              ResumeThread(PI.hThread);
              Result := PI.hThread;

FreeMem(pFile);  // IMPORTANTE YA QUE EVITA UN MEMORY LEAK
            end;
          end;
          VirtualFree(CTBase, 0, MEM_RELEASE);
        end;
        if Result = 0 then
          TerminateProcess(PI.hProcess, 0);
      end;
    end;
  end;
end;

end.

Si queréis saber más sobre cómo programar con Delphi, aquí tenéis una buena ayuda