unit uProcesarOptVarEstado;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, xMatDefs, Grids, ComCtrls, Math, utilidades,
  uFechas, uverdoc, utrazosxy, matreal, isocurvas, uEditarISONiveles, Menus,
  uSeleccionarArchivo, ExtCtrls, uparsesimres, uDTResultados;

type
  TProcesarOptVarEstado = class(TForm)
    GBRangoFechas: TGroupBox;
    DTPDesde: TDateTimePicker;
    DTPHasta: TDateTimePicker;
    LDesde: TLabel;
    LHasta: TLabel;
    SGDatos: TStringGrid;
    BGraficarValoresPorColumnas: TButton;
    BExportarExcel: TButton;
    BGraficarCurvasISONivel: TButton;
    MainMenu1: TMainMenu;
    MHerramientas: TMenuItem;
    MGraficarValoresPorColumnas: TMenuItem;
    MGraficarCurvasISONivel: TMenuItem;
    MExportarAExcel: TMenuItem;
    MEditarISONiveles: TMenuItem;
    GBVariableLibre: TGroupBox;
    CBVarLibre: TComboBox;
    RGTraduccionLibre: TRadioGroup;
    GBVariablesFijas: TGroupBox;
    CBVarsFijas: TComboBox;
    RGTraduccionFija: TRadioGroup;
    LEstado: TLabel;
    EnEstadoVarFija: TEdit;
    UDVarFija: TUpDown;
    LValorEstado: TLabel;
    BAyuda: TButton;
    DTPDesdeHoras: TDateTimePicker;
    DTPHastaHoras: TDateTimePicker;
    procedure CBVarLibreChange(Sender: TObject);
    procedure CBVarsFijasChange(Sender: TObject);
    procedure UDVarFijaClick(Sender: TObject; Button: TUDBtnType);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure DTPChange(Sender: TObject);
    procedure BAyudaClick(Sender: TObject);
    procedure BGraficarValoresPorColumnasClick(Sender: TObject);
    procedure BExportarExcelClick(Sender: TObject);
    procedure BGraficarCurvasISONivelClick(Sender: TObject);
    procedure MGraficarValoresPorColumnasClick(Sender: TObject);
    procedure MEditarISONivelesClick(Sender: TObject);
    procedure MGraficarCurvasISONivelClick(Sender: TObject);
    procedure MExportarAExcelClick(Sender: TObject);
    procedure TraduccionVarLibreChange(Sender: TObject);
    procedure TraduccionVarFijaChange(Sender: TObject);
  private
    nArch: String;
    datosOpt: DTResultadosOpt;

    //el indice de la variable fija seleccionada
    //para no estar calculandolo todo el tiempo
    iVarFija: Integer;

    //Fechas completas (año, mes, dia y hora) desde y hasta la cual se
    //van a visualizar los resultados
    desde, hasta: TDateTime;
    //las filas inicial y final de los datos para el rango de fechas seleccionado
    filaIni, filaFin: Integer;

    //las columnas en los datos originales  que hay que ver para observar la
    //variable libre para los valores dados de las otras variables
    cols: TDAofNInt;

    //para el graficador de curvas ISONivel
    //guardan los nombres de cada nivel y sus valores
    etiquetasNiveles : TDAofString;
    niveles: TDAofNReal;

    //Retorna en cols las columnas de los datos que contienen los valores de la
    //variable libre para los valores dados de las variables fijas
    //Las variables avanzan 1 lugar en su estado cada la productoria del numero
    //discretizaciones de las variables que se encuentren antes de ella en descVars
    procedure recalcCols(var cols: TDAofNInt);

    procedure llenarTabla(filaIni, filaFin: Integer; cols: TDAofNInt);
    procedure exportarAxlt; overload;
    procedure exportarAxlt(filaIni, filaFin : Integer ; cols: TDAofNInt; nombreArchivo: String); overload;
    procedure graficarValoresColumnasEnFuncT(filaIni, filaFin: Integer; cols: TDAofNInt);
    procedure graficarCurvasISONivel(filaIni, filaFin: Integer; cols: TDAofNInt);
    procedure editarISONiveles(var niveles: TDAofNReal; var etiquetasNiveles : TDAofString);
    procedure storeOpt;
    procedure loadOpt;
    function archivoInit: String;
  public
    Constructor Create(owner : TComponent ; nArch: String); reintroduce;
    class function filtrosDeArchivos: String;
    class function filtrosDeArchivosSave: String;
  end;

var
  ProcesarOptVarEstado: TProcesarOptVarEstado;

implementation

{$R *.dfm}

class function TProcesarOptVarEstado.filtrosDeArchivos: String;
begin
  result:= 'Archivos de Costos Futuros Hidraulicos (opt*.xlt)|opt*.xlt';
end;

class function TProcesarOptVarEstado.filtrosDeArchivosSave: String;
begin
  result:= 'Plantilla (*.xlt)|*.xlt|Archivos de Texto (*.txt)|*.txt|Todos los Archivos (*.*)|*.*';
end;

procedure TProcesarOptVarEstado.BAyudaClick(Sender: TObject);
begin
  verdoc( 'procesador-resultados-VisualizadorCostosHidraulicos', 'Ayuda del Visualizador de Costos Hidráulicos');
end;

procedure TProcesarOptVarEstado.BExportarExcelClick(Sender: TObject);
begin
  exportarAxlt;
end;

procedure TProcesarOptVarEstado.BGraficarValoresPorColumnasClick(Sender: TObject);
begin
  graficarValoresColumnasEnFuncT(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.BGraficarCurvasISONivelClick(Sender: TObject);
begin
  graficarCurvasISONivel(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.CBVarLibreChange(Sender: TObject);
var
  i, iVarLibre: Integer;
  descVarLibre: TDescVar;
begin
  //Relleno la caja de fijas
  iVarLibre:= datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex]);

  CBVarsFijas.Items.Clear;
  CBVarsFijas.Items.Capacity:= Length(datosOpt.descVars) -1;
  for i:= 0 to iVarLibre - 1 do
    CBVarsFijas.Items.Add(datosOpt.descVars[i].nombre);
  for i:= iVarLibre + 1 to high(datosOpt.descVars) do
    CBVarsFijas.Items.Add(datosOpt.descVars[i].nombre);

  descVarLibre:= datosOpt.descVars[iVarLibre];
  RGTraduccionLibre.Items.Clear;
  if descVarLibre.traduccion <> NIL then
  begin
    RGTraduccionLibre.Items.Add(descVarLibre.nombre);
    RGTraduccionLibre.Items.Add(descVarLibre.traduccion.nombre);
    if descVarLibre.mostrarTraduccion then
      RGTraduccionLibre.ItemIndex:= 1
    else
      RGTraduccionLibre.ItemIndex:= 0;
  end
  else
  begin
    RGTraduccionLibre.Items.Add(descVarLibre.nombre);
    RGTraduccionLibre.ItemIndex:= 0;
  end;
  TraduccionVarLibreChange(RGTraduccionLibre);

  if CBVarsFijas.Items.count > 0 then
  begin
    CBVarsFijas.ItemIndex:= 0;
    CBVarsFijasChange(Sender);
  end;

  recalcCols(cols);
  llenarTabla(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.CBVarsFijasChange(Sender: TObject);
var
  descVarFija: TDescVar;
begin
  iVarFija:= datosOpt.indiceDescVar(CBVarsFijas.Items[CBVarsFijas.ItemIndex]);
  descVarFija:= datosOpt.descVars[iVarFija];
  UDVarFija.Min:= 1;
  UDVarFija.Max:= descVarFija.nDiscs;
  UDVarFija.Position:= descVarFija.pos +1;

  if descVarFija.traduccion <> NIL then
  begin
    RGTraduccionFija.Items.Clear;
    RGTraduccionFija.Items.Add(descVarFija.nombre);
    RGTraduccionFija.Items.Add(descVarFija.traduccion.nombre);
    if descVarFija.mostrarTraduccion then
      RGTraduccionFija.ItemIndex:= 1
    else
      RGTraduccionFija.ItemIndex:= 0;
  end
  else
  begin
    RGTraduccionFija.Items.Clear;
    RGTraduccionFija.Items.Add(descVarFija.nombre);
    RGTraduccionFija.ItemIndex:= 0;
  end;
  TraduccionVarFijaChange(RGTraduccionFija);
end;

Constructor TProcesarOptVarEstado.Create(owner : TComponent ; nArch: String);
var
  cursorAnterior: TCursor;
begin
  inherited Create(owner);
  self.nArch:= nArch;
  cursorAnterior:= screen.Cursor;
  screen.Cursor:= crHourGlass;
  datosOpt:= DTResultadosOpt.Create(nArch);
  datosOpt.readDatosOpt;
  datosOpt.readResultadosOpt;
  screen.Cursor:= cursorAnterior;
  self.Caption:= 'Procesar Variable de Estado - ' + nArch;
end;

procedure TProcesarOptVarEstado.DTPChange(Sender: TObject);
begin
  desde:= DTPDesde.Date + frac(DTPDesdeHoras.Time);
  hasta:= DTPHasta.Date + frac(DTPHastaHoras.Time);
  datosOpt.recalcRangoFechas(desde, hasta, filaIni, filaFin);
  llenarTabla(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  storeOpt;
  ModalResult:= mrOk;
end;

procedure TProcesarOptVarEstado.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  self.Top:= 5;
  self.Left:= 5;

  SGDatos.DefaultColWidth:= SGDatos.Canvas.TextWidth('0000000000.00');//Numeros de 10 digitos y 2 posiciones decimales

  CBVarLibre.Items.Capacity:= Length(datosOpt.descVars);
  CBVarsFijas.Items.Capacity:= Length(datosOpt.descVars);
  for i:= 0 to high(datosOpt.descVars) do
  begin
    CBVarLibre.Items.Add(datosOpt.descVars[i].nombre);
    CBVarsFijas.Items.Add(datosOpt.descVars[i].nombre);
  end;

  if CBVarsFijas.items.Count = 0 then
  begin
    GBVariablesFijas.Visible:= false;
    utilidades.bajarControles(Self, GBVariablesFijas, - GBVariablesFijas.Height);
  end;

  DTPDesde.MinDate:= Int(datosOpt.datos[0][0]);
  DTPDesde.MaxDate:= Int(datosOpt.datos[datosOpt.nPuntosT - 1][0]);

  DTPHasta.MinDate:= DTPDesde.MinDate;
  DTPHasta.MaxDate:= DTPDesde.MaxDate;

  loadOpt;

  datosOpt.recalcRangoFechas(desde, hasta, filaIni, filaFin);

  CBVarLibreChange(CBVarLibre); //Fijo la libre y las fijas se fijan solas
end;

procedure TProcesarOptVarEstado.TraduccionVarFijaChange(Sender: TObject);
var
  descVarFija: TDescVar;
begin
//  iVarFija:= indiceDescVar(CBVarsFijas.Items[CBVarsFijas.ItemIndex]);
  descVarFija:= datosOpt.descVars[iVarFija];
  if RGTraduccionFija.ItemIndex = 0 then
    descVarFija.mostrarTraduccion:= false
  else if RGTraduccionFija.ItemIndex = 1 then
    descVarFija.mostrarTraduccion:= true;

  LValorEstado.Caption:= FloatToStrF(descVarFija.getDiscretizaciones[descVarFija.pos], ffFixed, 10, 2) + ' ' + descVarFija.getUnidades;
end;

procedure TProcesarOptVarEstado.TraduccionVarLibreChange(Sender: TObject);
var
  iVarLibre: Integer;
  descVarLibre: TDescVar;
  discsAMostrar: TDAofNReal;
  i: Integer;
begin
  iVarLibre:= datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex]);
  descVarLibre:= datosOpt.descVars[iVarLibre];
  if RGTraduccionLibre.ItemIndex = 0 then
    descVarLibre.mostrarTraduccion:= false
  else if RGTraduccionLibre.ItemIndex = 1 then
    descVarLibre.mostrarTraduccion:= true;

  SGDatos.Cells[0, 0]:= 'Fecha\Estado[' + descVarLibre.getUnidades + ']';
  discsAMostrar:= descVarLibre.getDiscretizaciones;
  for i := 1 to SGDatos.ColCount - 1 do
    SGDatos.Cells[i, 0]:= FloatToStrF(discsAMostrar[i - 1], ffFixed, 10, 2);
end;

procedure TProcesarOptVarEstado.UDVarFijaClick(Sender: TObject;
  Button: TUDBtnType);
var
  descVarFija: TDescVar;
begin
  descVarFija:= datosOpt.descVars[iVarFija];
  descVarFija.pos:= UDVarFija.Position -1;
  if RGTraduccionFija.ItemIndex = 0 then  
    LValorEstado.Caption:= FloatToStrF(descVarFija.discretizaciones[descVarFija.pos], ffFixed, 10, 2) + ' ' + descVarFija.unidades
  else
    LValorEstado.Caption:= FloatToStrF(descVarFija.traduccion.discretizaciones[descVarFija.pos], ffFixed, 10, 2) + ' ' + descVarFija.traduccion.unidades;
  recalcCols(cols);
  llenarTabla(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.recalcCols(var cols: TDAofNInt);
var
  nombVarLibre: String;
  iVarLibre, i: Integer;
  base: Integer;
begin
  nombVarLibre:= CBVarLibre.Items[CBVarLibre.ItemIndex];
  iVarLibre:= datosOpt.indiceDescVar(nombVarLibre);

  SetLength(cols, datosOpt.descVars[iVarLibre].nDiscs);
  base:= 1;
  for i:= 0 to iVarLibre - 1 do
    base:= base + datosOpt.descVars[i].pos * datosOpt.descVars[i].incEstadoCada;

  for i:= iVarLibre + 1 to high(datosOpt.descVars) do
    base:= base + datosOpt.descVars[i].pos * datosOpt.descVars[i].incEstadoCada;

  for i:= 0 to high(cols) do
    cols[i]:= base + i * datosOpt.descVars[iVarLibre].incEstadoCada;
end;

procedure TProcesarOptVarEstado.llenarTabla(filaIni, filaFin: Integer; cols: TDAofNInt);
var
  i, j, filaTabla: Integer;
  descVarLibre: TDescVar;
  fila: TDAofString;
  discsAMostrar: TDAofNReal;
  cursorAnterior: TCursor;
begin
  cursorAnterior:= screen.Cursor;
  Screen.Cursor:= crHourGlass;

  SGDatos.RowCount:= filaFin - filaIni + 2;
  SGDatos.ColCount:= length(cols) + 1;

  descVarLibre:= datosOpt.descVars[datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex])];
  SGDatos.Cells[0, 0]:= 'Fecha\Estado[' + descVarLibre.getUnidades + ']';
  discsAMostrar:= descVarLibre.getDiscretizaciones;
  for j := 1 to SGDatos.ColCount - 1 do
    SGDatos.Cells[j, 0]:= FloatToStrF(discsAMostrar[j - 1], ffFixed, 10, 2);
  for i:= filaIni to filaFin do
  begin
    fila:= datosOpt.datosAsString[i];
    filaTabla:= i - filaIni + 1;

    SGDatos.Cells[0, filaTabla]:= fila[0];
    for j:= 0 to high(cols) do
      SGDatos.Cells[j + 1, filaTabla]:= fila[cols[j]];
  end;

  utilidades.AutoSizeCol(SGDatos, 0);
{  utilidades.AutoSizeColsToMaxCol(SGDatos);}
  utilidades.AutosizeTableWidth(SGDatos);
  Screen.Cursor:= cursorAnterior;
end;

procedure TProcesarOptVarEstado.MEditarISONivelesClick(Sender: TObject);
begin
  editarISONiveles(niveles, etiquetasNiveles);
end;

procedure TProcesarOptVarEstado.MExportarAExcelClick(Sender: TObject);
begin
  exportarAxlt;
end;

procedure TProcesarOptVarEstado.MGraficarValoresPorColumnasClick(Sender: TObject);
begin
  graficarValoresColumnasEnFuncT(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.MGraficarCurvasISONivelClick(Sender: TObject);
begin
  graficarCurvasISONivel(filaIni, filaFin, cols);
end;

procedure TProcesarOptVarEstado.exportarAxlt;
var
  nombreArchivo: String;
  fSelect: TSeleccionarArchivo;
begin
  fSelect:= TSeleccionarArchivo.Create(self, TProcesarOptVarEstado.filtrosDeArchivosSave, ExtractFilePath(nArch), true);
  if fSelect.ShowModal = mrOk then
  begin
    nombreArchivo:= fSelect.getFileName;
    fSelect.Free;
    exportarAxlt(filaIni, filaFin, cols, nombreArchivo);
  end
  else
    fSelect.Free;
end;

procedure TProcesarOptVarEstado.exportarAxlt(filaIni, filaFin : Integer ; cols: TDAofNInt; nombreArchivo: String);
var
  arch: TextFile;
  linea: String;
  i, j: Integer;
  descVarLibre: TDescVar;
  fila: TDAofString;

  unidadesAMostrar: String;
  discsAMostrar: TDAofNReal;
begin
  try
    AssignFile(arch, nombreArchivo);
    Rewrite(arch);

    SGDatos.RowCount:= filaFin - filaIni + 2;
    SGDatos.ColCount:= length(cols) + 1;

    descVarLibre:= datosOpt.descVars[datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex])];

    unidadesAMostrar:= descVarLibre.getUnidades;
    discsAMostrar:= descVarLibre.getDiscretizaciones;

    linea:= 'Fecha\Estado[' + unidadesAMostrar + ']' + #9;
    for j := 0 to high(cols) do
      linea:= linea + FloatToStrF(discsAMostrar[j], ffFixed, 10, 2) + #9;
    writeln(arch, linea);

    for i:= filaIni to filaFin do
    begin
      fila:= datosOpt.datosAsString[i];
      linea:= fila[0] + #9;
      for j:= 0 to high(cols) do
        linea:= linea + fila[cols[j]] + #9;
      Writeln(arch, linea);
    end;
  finally
    CloseFile(arch);
  end;
end;

procedure TProcesarOptVarEstado.graficarValoresColumnasEnFuncT(filaIni, filaFin: Integer; cols: TDAofNInt);
var
  trazos : TfrmDllForm;
  minY, maxY: NReal;
  colorSerie: TColor;
  iSerie, iVarLibre, iVarsFijas, nAniosOpt: Integer;
  anio1, anio2, mes, dia: Word;
  descVarLibre, descVarFija: TDescVar;
  titulo, nomSerie: String;
  nPuntos: Integer;
  iFila: Integer;
  fila: TDAofNReal;
  unidadesAMostrar: String;
  discsAMostrar: TDAofNReal;
begin
  iVarLibre:= datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex]);
  descVarLibre:= datosOpt.descVars[iVarLibre];
  nPuntos:= filaFin - filaIni + 1;
  colorSerie:= RGB(random(256), random(256), random(256));
  datosOpt.minMaxDatos(filaIni, filaFin, cols, minY, maxY);
  minY:= minY * 1.1;
  maxY:= maxY * 1.1;
  trazos:= TfrmDllForm.Create(self);
  titulo:= 'Valor por Columnas en Función del Tiempo para ' + descVarLibre.getNombre;

  unidadesAMostrar:= descVarLibre.getUnidades;
  discsAMostrar:= descVarLibre.getDiscretizaciones;

  if Length(datosOpt.descVars) > 1 then
  begin
    titulo:= titulo + ' con ';
    for iVarsFijas:= 0 to iVarLibre - 1 do
    begin
      descVarFija:= datosOpt.descVars[iVarsFijas];
      titulo:= titulo + descVarFija.getNombre + ' en ' + FloatToStrF(descVarFija.getDiscretizaciones[descVarFija.pos], fffixed, 10, 1) + ' ' + descVarFija.getUnidades + ', '
    end;
    for iVarsFijas:= iVarLibre + 1 to high(datosOpt.descVars) do
    begin
      descVarFija:= datosOpt.descVars[iVarsFijas];
      titulo:= titulo + descVarFija.getNombre + ' en ' + FloatToStrF(descVarFija.getDiscretizaciones[descVarFija.pos], fffixed, 10, 1) + ' ' + descVarFija.getUnidades + ', '
    end;
  end;

  DecodeDate(DTPDesde.DateTime, anio1, mes, dia);
  DecodeDate(DTPHasta.DateTime, anio2, mes, dia);

  nAniosOpt:= anio2 - anio1 + 1;

  nomSerie:= FloatToStrF(discsAMostrar[0], ffFixed, 10, 2) + ' ' + unidadesAMostrar;
  trazos.CrearDiagramaXY(titulo, nPuntos, false, 'Tiempo', nomSerie,
                         colorSerie, filaIni, filaFin, min(0, minY), maxY,
                         10, nAniosOpt);

	trazos.titulo(titulo);
  trazos.xlabel('Tiempo');
	trazos.ylabel('Costo');

  for iSerie:= 1 to high(cols) do
  begin
    nomSerie:= FloatToStrF(discsAMostrar[iSerie], fffixed, 10, 2) + ' ' + unidadesAMostrar;
    colorSerie:= RGB(random(256), random(256), random(256));
    trazos.CrearSerieXY(nomSerie, nPuntos, false, colorSerie);
  end;

  trazos.Show;

 	trazos.dbj_xlabel;
	trazos.dbj_ylabel;
	trazos.dbj_titulo;
	trazos.dbj_etiquetasx;
	trazos.dbj_etiquetasy;
	trazos.dbj_borde;
	trazos.Etiquetas_x(filaIni+1, filaFin +1);
	trazos.Etiquetas_y(min(0, minY), maxY);

	trazos.dbj_gridX;
	trazos.dbj_gridY;

  trazos.BringToFront;
  for iFila:= filaIni to filaFin do
  begin
    fila:= datosOpt.datos[iFila];
    trazos.tr1.PlotNuevo_x(iFila);
    for iSerie:= 1 to Length(cols) do
      trazos.tr1.PlotNuevo_y(iSerie, fila[cols[iSerie-1]]);
    Application.ProcessMessages;
//    sleep(10);
  end;
end;

procedure PlotIsoCurvas(
  Titulo: string;
  xlabel: string;
  ylabel: string;
  M: TMatR; vx, vy: TVectR;
  niveles: array of NReal;
  etiquetas: array of string );
var
  trx: TfrmDllForm;
  IsoScanner: TIsoScannerMatricial;
  px, py: NReal;
  pol: TPoligonalXY;
  res: boolean;
  ramaDirecta: boolean;
  plabel_x, plabel_y: NReal;
  knivel: integer;
  lblxy: TLabelXY;
  color: TColor;

begin
  trx:=TfrmDllForm.Create(ProcesarOptVarEstado);

	trx.CrearDiagramaXY(
		titulo, // Nombres
		512, // MaxNPuntos
		true, // ciruclar
		'x', // nombre_sx
		'', // nombre_sy1: pchar;
		clRed, //	color_sy1: TColor;
		vx.e(1), vx.e(vx.n), //	x1, x2,
		vy.e(1), vy.e(vy.n), //y1, y2
    vx.n-1,vy.n-1    // NDivX, NDivY
	);

	trx.show;
	trx.dbj_gridx ;
	trx.dbj_gridy;
	trx.dbj_borde;
	trx.titulo( titulo  );
	trx.etiquetas_x( vx.e(1), vx.e(vx.n) );
	trx.etiquetas_y( vy.e(1), vy.e(vy.n) );
	trx.xlabel( xlabel );
	trx.ylabel( ylabel );

  for knivel:= 0 to high( niveles ) do
  begin
    IsoScanner:= TIsoScannerMatricial.create( m, vx, vy, niveles[ knivel ] );
    color:= paleta1[ knivel+1 ];
    pol:= TPoligonalxy.Create( trx.tr1, 'p', false, color );
    ramaDirecta:= true;
    plabel_y:= 100000;

    repeat
       res:=IsoScanner.GetPunto(px, py );  {pedimos un punto a iso90}
       if IsoScanner.Estado = Reversa then
          ramaDirecta:= not ramaDirecta;

       if res then   {Si el punto es valido lo dibuja}
       begin
          if py < plabel_y then   {elige el punto más bajo}
          begin
              plabel_x:= px;
              plabel_y:= py;          {para poner la etiqueta}
          end;
          if ramaDirecta then
            pol.nuevoPunto( px, py)
          else
            pol.nuevoPuntoAlInicio( px, py );
        end;

       if IsoScanner.Estado = Semiactivo then   {termino con una curva}
       begin
          pol.Replot;
          pol:= TPoligonalxy.Create( trx.tr1, 'p', false, color );
          ramaDirecta:= true;
          // labelXY(0,plabel.x,plabel.y,luxs); {etiqueta la curva}
          lblxy:= TLabelXY.Create( trx.tr1, 'l', plabel_x, plabel_y, etiquetas[knivel], color, 10 );
          plabel_y:= 10000;
       end;
    until IsoScanner.Estado = fin;       {hasta terminar}
    trx.tr1.RePlot;
    IsoScanner.Free;
  end;
end;

procedure TProcesarOptVarEstado.graficarCurvasISONivel(filaIni, filaFin: Integer; cols: TDAofNInt);
var
  mat: TMatR;
  x, y : TVectR;

  nPuntosT: Integer;
  titulo: String;

  iVarsFijas: Integer;
  descVarFija: TDescVar;

  iVarLibre: Integer;
  descVarLibre: TDescVar;
  iFila, iColumna, iFilaMat: Integer;
  fila: TDAofNReal;
  filaMat: TVectR;

  unidadesAMostrar: String;
  discsAMostrar: TDAofNReal;
begin
  iVarLibre:= datosOpt.indiceDescVar(CBVarLibre.Items[CBVarLibre.ItemIndex]);
  descVarLibre:= datosOpt.descVars[iVarLibre];
  nPuntosT:= filaFin - filaIni + 1;

  unidadesAMostrar:= descVarLibre.getUnidades;
  discsAMostrar:= descVarLibre.getDiscretizaciones;

  x:= TVectR.Create_Init(nPuntosT);
  for iFila:= 1 to x.n do
    x.pon_e(iFila, filaIni + iFila - 1);
  y:= TVectR.Create_FromDAofR(discsAMostrar);
  mat:= TMatR.Create_Init(x.n, y.n);

  for iFila:= filaIni to filaFin do
  begin
    iFilaMat:= iFila - filaIni + 1;
    fila:= datosOpt.datos[iFila];
    filaMat:= mat.Fila(iFilaMat);
    for iColumna:= 0 to high(cols) do
      filaMat.pon_e(iColumna + 1, fila[cols[iColumna]]);
  end;

  titulo:= 'Curvas ISONivel para ' + descVarLibre.getNombre;
  if Length(datosOpt.descVars) > 1 then
  begin
    titulo:= titulo  + ' con ';
    for iVarsFijas:= 0 to iVarLibre - 1 do
    begin
      descVarFija:= datosOpt.descVars[iVarsFijas];
      titulo:= titulo + descVarFija.getNombre + ' en ' + FloatToStrF(descVarFija.getDiscretizaciones[descVarFija.pos], fffixed, 10, 1) + ' ' + descVarFija.getUnidades + ', '
    end;
    for iVarsFijas:= iVarLibre + 1 to high(datosOpt.descVars) do
    begin
      descVarFija:= datosOpt.descVars[iVarsFijas];
      titulo:= titulo + descVarFija.getNombre + ' en ' + FloatToStrF(descVarFija.getDiscretizaciones[descVarFija.pos], fffixed, 10, 1) + ' ' + descVarFija.getUnidades + ', '
    end;
  end;

  PlotIsoCurvas(titulo,
                'Paso de Tiempo', 'Estado ' + descVarLibre.getNombre + '[' + unidadesAMostrar + ']',
                mat, x, y,
                niveles, etiquetasNiveles);
end;

procedure TProcesarOptVarEstado.editarISONiveles(var niveles: TDAofNReal; var etiquetasNiveles : TDAofString);
var
  form: TEditarISONiveles;
begin
  form:= TEditarISONiveles.Create(self, niveles, etiquetasNiveles);
  if form.ShowModal = mrOk then
  begin
    niveles:= form.getNiveles;
    etiquetasNiveles:= form.getEtiquetasNiveles;
  end;
  form.Free;
end;

procedure TProcesarOptVarEstado.storeOpt;
var
  f: TextFile;
  i: Integer;
begin
  try
    AssignFile(f, archivoInit);
    rewrite(f);
    writeln(f, 'varLibre= ', CBVarLibre.Items[CBVarLibre.ItemIndex]);
    writeln(f, 'varFija= ', CBVarsFijas.Items[CBVarsFijas.ItemIndex]);
    writeln(f, 'desde= ', DateTimeToIsoStr(desde));
    writeln(f, 'hasta= ', DateTimeToIsoStr(hasta));
    writeln(f, 'Iso-Niveles');
    writeln(f, 'n= ', length(etiquetasNiveles));
    for i:= 0 to high(etiquetasNiveles) do
    begin
      writeln(f, 'etiqueta= ', etiquetasNiveles[i]);
      writeln(f, 'valor= ', niveles[i]);
    end;
    for i:= 0 to high(datosOpt.descVars) do
      datosOpt.descVars[i].storeOpt(f);
  finally
    CloseFile(f);
  end;
end;

procedure TProcesarOptVarEstado.loadOpt;
var
  f: TextFile;
  i: Integer;
  val: String;

procedure defInit;
begin
  CBVarLibre.ItemIndex:= 0;
  CBVarsFijas.Items.Delete(0);

  desde:= datosOpt.datos[0][0];
  hasta:= datosOpt.datos[datosOpt.nPuntosT - 1][0];
  //niveles:=[250, 400, 1200, 2000, 63.87, 71.2, 163.08, 122.3, 89.36, 216.5];
  SetLength(niveles, 10);
  niveles[0]:= 250;
  niveles[1]:= 400;
  niveles[2]:= 1200;
  niveles[3]:= 2000;
  niveles[4]:= 63.87;
  niveles[5]:= 71.2;
  niveles[6]:= 163.08;
  niveles[7]:= 122.3;
  niveles[8]:= 89.36;
  niveles[9]:= 216.5;

  //etiquetasNiveles= ['F1', 'F2', 'F3', 'F4', '5ta','6ta', 'CTR', 'PTI', 'SB', 'TGAA'];
  SetLength(etiquetasNiveles, length(niveles));
  etiquetasNiveles[0]:= 'F1';
  etiquetasNiveles[1]:= 'F2';
  etiquetasNiveles[2]:= 'F3';
  etiquetasNiveles[3]:= 'F4';
  etiquetasNiveles[4]:= '5ta';
  etiquetasNiveles[5]:='6ta';
  etiquetasNiveles[6]:= 'CTR';
  etiquetasNiveles[7]:= 'PTI';
  etiquetasNiveles[8]:= 'SB';
  etiquetasNiveles[9]:= 'TGAA';
end;

begin
  if FileExists(archivoInit) then
  begin
    try
      try
        AssignFile(f, archivoInit);
        Reset(f);
        //varLibre
        readln(f, val);
        val:= copy(val, pos('= ', val) + 2, MAXINT);
        CBVarLibre.ItemIndex:= CBVarLibre.Items.IndexOf(val);
        CBVarsFijas.Items.Delete(CBVarsFijas.Items.IndexOf(val));

        //varFija
        readln(f, val);
        val:= copy(val, pos('= ', val) + 2, MAXINT);
        CBVarsFijas.ItemIndex:= CBVarsFijas.Items.IndexOf(val);

        //desde
        readln(f, val);
        val:= copy(val, pos('= ', val) + 2, MAXINT);
        desde:= IsoStrToDateTime(val);

        //hasta
        readln(f, val);
        val:= copy(val, pos('= ', val) + 2, MAXINT);
        hasta:= IsoStrToDateTime(val);

        //IsoNiveles
        readln(f, val);
        //n
        readln(f, val);
        val:= copy(val, pos('= ', val) + 2, MAXINT);
        SetLength(etiquetasNiveles, StrToInt(val));
        SetLength(niveles, StrToInt(val));
        for i:= 0 to high(etiquetasNiveles) do
        begin
          //etiqueta
          readln(f, val);
          val:= copy(val, pos('= ', val) + 2, MAXINT);
          etiquetasNiveles[i]:= val;

          //valor
          readln(f, val);
          val:= copy(val, pos('= ', val) + 2, MAXINT);
          niveles[i]:= StrToFloat(val);
        end;

        for i:= 0 to high(datosOpt.descVars) do
          datosOpt.descVars[i].loadOpt(f);
      except
        on e : Exception do
        begin
          defInit;
        end;
      end;
    finally
      CloseFile(f);
    end;
  end
  else
  begin
    defInit;
  end;
  DTPDesde.DateTime:= desde;
  DTPDesdeHoras.DateTime:= desde;
  DTPHasta.DateTime:= hasta;
  DTPHastaHoras.DateTime:= hasta;
end;

function TProcesarOptVarEstado.archivoInit: String;
var
  ext: String;
begin
  ext:= ExtractFileExt(nArch);
  result:= Copy(nArch, 1, pos(ext, nArch) - 1) + '_init.vpo'; 
end;

end.
