unit ufUbicacion;

interface

uses
  uhtmlverdoc, Windows, Messages, SysUtils, Math, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,
//  jpeg,
//  uverurl,
  ExtCtrls, StdCtrls, ComCtrls, xMatDefs  ;

type

  { TfUbicacion }

  TfUbicacion = class(TForm)
    cbGrillaMapaEolico: TCheckBox;
    Panel1: TPanel;
    lbl_Lat: TLabel;
    lbl_Long: TLabel;
    lbl_longlat: TLabel;
    Shape2: TShape;
    eLatitud: TEdit;
    eLongitud: TEdit;
    ScrollBox1: TScrollBox;
    Image1: TImage;
    Shape1: TShape;
    StatusBar: TStatusBar;
    Timer1: TTimer;
    btAceptar: TButton;
    btCancelar: TButton;
    btAyuda: TButton;
    btGoGoogleMap: TButton;
    procedure cbGrillaMapaEolicoChange(Sender: TObject);
    procedure eLatitudChange(Sender: TObject);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1Paint(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Shape2MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure btAceptarClick(Sender: TObject);
    procedure btCancelarClick(Sender: TObject);
    procedure btAyudaClick(Sender: TObject);
    procedure GrillaMapaEolico;
    procedure btGoGoogleMapClick(Sender: TObject);
  private
    { Private declarations }
    flg_salir: boolean;
  public
    { Public declarations }

    Inicializado: boolean;

    Latitud, Longitud: NReal;

    strLatLon, strZona: string;

    MapaEolico_x0, MapaEolico_y0, MapaEolico_x1, MapaEolico_y1: integer;
    MapaEolico_dx, MapaEolico_dy: double;


    procedure UbicarCirculo( Latitud, Longitud: NReal );
    procedure CalcLatLong( var Latitud, Longitud: NReal; x, y: integer );
    procedure CalcXY( var X, Y : integer; Latitud, Longitud: NReal );

    // determina la Zona del Mapa Eólico.
    // retorna kFila y kColumna de 0..9.999
    // La idea es que se puede usar esta función para tener
    // los puntos de interpolación
    procedure CalcZona( var kFila, kColumna: NReal; Latitud, Longitud: NReal );

    procedure CentrarMapa;

    procedure SetDatos( Latitud, Longitud: NReal );
    procedure GetDatos( var Latitud, Longitud: NReal );


  end;


implementation

{$R *.lfm}


procedure TfUbicacion.SetDatos( Latitud, Longitud: NReal );
begin
  Self.Latitud:= Latitud;
  Self.Longitud:= Longitud;
  flg_salir:= false;
end;
procedure TfUbicacion.GetDatos( var Latitud, Longitud: NReal );
begin
  Latitud:= self.Latitud;
  Longitud:= self.Longitud;
end;


const
// definición de constantes para mapeo de posición
// sobre el mapa de Uruguay
  x1= 145.0; y1= 856.0;
  x2= 785.0; y2= 854.0;

  x3= 129.0; y3= 84.0;
  x4= 793.0; y4= 83.0;

  long1= 58.0;
  long2= 54.0;
  lat1=	30.0;
  lat2= 34.0;

  u1x= x2 - x1;
  u1y= y2 - y1;
  u2x= x4 - x3;
  u2y= y4 - y3;

  w1x= x3 - x1;
  w1y= y3 - y1;

  dux= u1x - u2x;
  duy= u1y - u2y;

  CA= w1x* duy - w1y * dux;

// Mapa Eólico
  MapaEolico_Lat0 = 30.12;
  MapaEolico_Long0 = 58.67;

  MapaEolico_Lat1= 35.01;
  MapaEolico_Long1= 52.92;



procedure TfUbicacion.CalcZona(
  var kFila, kColumna: NReal; Latitud, Longitud: NReal );
var
  x, y: integer;
begin
  CalcXY( x,y, Latitud, Longitud );
  kFila:= ( y - MapaEolico_y0 )/ MapaEolico_dy;
  if kFila < 0 then kFila:= 0;
  if kFila > 9 then kFila:= 9;
  kColumna:= ( x - MapaEolico_x0 ) / MapaEolico_dx ;
  if kColumna < 0 then kColumna:= 0;
  if kColumna >= 10 then kColumna:= 9.99;
end;



procedure TfUbicacion.CalcXY( var X, Y : integer; Latitud, Longitud: NReal );
var
  alfa, beta: NReal;
  Ax, Ay, ux, uy: NReal;

begin
  beta:= (Latitud-lat2)/(lat1- lat2);
  alfa:= (Longitud- long1)/(long2- long1);
  Ax:= x1 + beta * w1x;
  Ay:= y1 + beta * w1y;
  ux:= (1-beta) * u1x + beta * u2x;
  uy:= (1-beta) * u1y + beta * u2y;

  X:= round( Ax + alfa*ux );
  Y:= round( Ay + alfa*uy );
end;



procedure TfUbicacion.btAceptarClick(Sender: TObject);
begin
  flg_salir:= true;
 modalresult:= 1;
end;

procedure TfUbicacion.btCancelarClick(Sender: TObject);
begin
 flg_salir:= true;
 modalresult:= 2;
end;

procedure TfUbicacion.btAyudaClick(Sender: TObject);
begin
  htmlverdoc( 'ubicaciongeografica' );
end;

procedure TfUbicacion.GrillaMapaEolico;
var
  k: integer;
  c: TCanvas;
begin

  c:= Image1.Canvas;
  c.Pen.Color:= clRed;

// verticales
  for k:= 0 to 10 do
  begin
    c.MoveTo( round( MapaEolico_x0 + k*MapaEolico_dx ), MapaEolico_y0 );
    c.LineTo( round( MapaEolico_x0+ k*MapaEolico_dx ), MapaEolico_y1 );
  end;

// horizontales
  for k:= 0 to 10 do
  begin
    c.MoveTo( MapaEolico_x0, round( MapaEolico_y0 + k* MapaEolico_dy ));
    c.LineTo( MapaEolico_x1, round( MapaEolico_y0 + k* MapaEolico_dy ));
  end;
end;

procedure TfUbicacion.btGoGoogleMapClick(Sender: TObject);
var
  url: string;
begin
//  verGoogleMap(Self, Latitud, Longitud, 10 );

  (*
  url:= 'http://maps.google.com/maps/ms?ie=UTF8&hl=es&msa=0&t=h&ll=';
  url:= url+ FloatToStrF( -Latitud, ffFixed, 9, 5 );
  url:= url+','+FloatToStrF( -Longitud, ffFixed, 9, 5 );
  url:= url+'&z=1000';
  htmlverurl( url );
  *)
end;

procedure TfUbicacion.CalcLatLong( var Latitud, Longitud: NReal; x, y: integer );
var
  CB, CC, dPx, dPy, Ax, Ay, ux, uy, alfa, beta: NReal;
begin
  dPx:= x1 - x;
  dPy:= y1 - y;
  CB:= w1x*u2y+dpx*duy-( w1y*u2x+dpy*dux );
  CC:= dpx*u2y-dpy*u2x;

  if EsCero( CA ) then
    beta:= -CC / CB
  else
    beta:= (-CB + sqrt( CB*CB- 4* CA * CC ))/ ( 2* CA );

  Ax:= x1 + beta * w1x;
  Ay:= y1 + beta * w1y;

  dpx:= x - Ax;
  dpy:= y - Ay;

  ux:= (1-beta) * u1x + beta * u2x;
  uy:= (1-beta) * u1y + beta * u2y;

  alfa:= ( dpx * ux + dpy * uy ) / ( ux*ux+ uy*uy );

  Latitud:= (1-beta) * lat2 + beta * lat1;
  Longitud:= ( 1- alfa ) * long1 + alfa * long2;


 strLatLon:= AnsiToUtf8( ' Long: '+FloatToStrF( Longitud, ffFixed, 5,2 )+'º, Lat:'+FloatToStrF( Latitud, ffFixed, 5, 2 )+'º');
end;


procedure TfUbicacion.UbicarCirculo( Latitud, Longitud: NReal );
var
  X,Y: integer;
begin
  CalcXY(X, Y, Latitud, Longitud );
  shape1.Top:= Y + Image1.Top - shape1.Height div 2;
  shape1.Left:= X + Image1.Left - shape1.Width div 2;
  eLatitud.Text:= FloatToStrF( Latitud, ffFixed, 5,1 );
  eLongitud.Text:= FloatToStrF( Longitud, ffFixed, 5,1 );
end;


procedure TfUbicacion.CentrarMapa;
var
  X,Y: integer;
  sx, sy: integer;

begin
  CalcXY(x, y, latitud, longitud );
  sx:= round( (x - scrollbox1.width div 2) / Self.Image1.Width  * ScrollBox1.HorzScrollBar.Range  );
  sy:= round( (y - scrollbox1.height div 2) / Self.Image1.Height * ScrollBox1.VertScrollBar.Range );

  sx:= max( 0, min( sx, ScrollBox1.HorzScrollBar.Range ));
  sy:= max( 0, min( sy, ScrollBox1.VertScrollBar.Range ));
  ScrollBox1.HorzScrollBar.Position:= sx;
  ScrollBox1.VertScrollBar.Position:= sy;
end;


procedure TfUbicacion.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  k: integer;

begin
  CanClose:= true;
  if flg_salir then  exit;
  k:=  application.messagebox( '¿Desea guardar los cambios?', 'Confirmación', MB_YESNOCANCEL );
  case k of
  IDYES: modalresult:= 1; // salir y guardar
  IDNO: modalresult:= 2; // salir pero no guardar
  IDCANCEL: CanClose:= false;
  else
    Canclose:= false;
  end;
end;


procedure TfUbicacion.FormCreate(Sender: TObject);
begin
  inicializado:= false;
  timer1.Enabled:= true;
  strLatLon:= '';
  strZona:= '';
end;

procedure TfUbicacion.FormResize(Sender: TObject);
begin
  CentrarMapa;
end;

procedure TfUbicacion.FormShow(Sender: TObject);
begin
  Self.Timer1.Enabled:= true;
end;

procedure TfUbicacion.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  CalcLatLong( Latitud, Longitud, X, Y );
  UbicarCirculo( Latitud, Longitud );
end;

procedure TfUbicacion.Image1Paint(Sender: TObject);
begin
  if cbGrillaMapaEolico.Checked then
    GrillaMapaEolico;
end;


procedure TfUbicacion.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  tx, ty: integer;
  Latitud, Longitud: NReal;
  kFila, kColumna: NReal;
begin
  if not Inicializado  then exit;

    CalcLatLong( Latitud, Longitud, X, Y );
    CalcXY( tx, ty, Latitud, Longitud );
    CalcZona( kFila, kColumna, Latitud, Longitud );

    strZona:='Zona: '+FloatToStrF( kFila, ffFixed, 5,2 )+', '+
              FloatToStrF( kColumna, ffFixed, 5,2 );
    StatusBar.SimpleText:= strLatLon+' '+StrZona;
end;

procedure TfUbicacion.eLatitudChange(Sender: TObject);
begin

end;

procedure TfUbicacion.cbGrillaMapaEolicoChange(Sender: TObject);
begin
  Image1.invalidate;
//  Image1Paint( Sender );
end;

procedure TfUbicacion.Shape2MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  CentrarMapa;
end;

procedure TfUbicacion.Timer1Timer(Sender: TObject);

var
  clt: TColor;

begin
  Timer1.Enabled:= false;
  UbicarCirculo( Latitud, Longitud );
  CentrarMapa;

// calculamos las constantes para las zonas del mapa eólico.
  calcXY( MapaEolico_x0, MapaEolico_y0, MapaEolico_Lat0, MapaEolico_Long0 );
  calcXY( MapaEolico_x1, MapaEolico_y1, MapaEolico_Lat1, MapaEolico_Long1 );
  MapaEolico_dx:= (MapaEolico_x1 - MapaEolico_x0 ) /10;
  MapaEolico_dy:= (MapaEolico_y1- MapaEolico_y0) / 10 ;
  inicializado:= true;
end;

end.
