// BusqDatos.cpp : implementation file
//

#include "stdafx.h"
#include "Proyecto.h"
#include "ProyectoDoc.h"
#include "ProyectoView.h"
#include "BusqDatos.h"
#include "Importar.h"
#include "CCurvatura.h"
#include <math.h>
#include "funciones.h"

#define PI 3.14159265

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// Columnas del grid que contiene los resultados obtenidos
enum En
{
	imagen = 0,
	directorio = 1,
	parecido = 2,
	numpuntos = 3
};

// Columnas del grid que posee los puntos característicos de la supuesta imagen a buscar
enum En2
{
	orden = 0,
	curvatura = 1,
	signo = 2,
	distancia = 3,
};

/////////////////////////////////////////////////////////////////////////////
// CBusqDatos dialog


CBusqDatos::CBusqDatos(CWnd* pParent /*=NULL*/)
	: CDialog(CBusqDatos::IDD, pParent)
{
	//{{AFX_DATA_INIT(CBusqDatos)
	m_ChkTodas = FALSE;
	m_TxtNPuntos = _T("");
	m_TxtOrden = _T("");
	m_TxtSigno = _T("");
	m_TxtBD = _T("");
	m_TxtCurvatura = _T("");
	m_TxtDistancia = _T("");
	m_Desc = -1;
	m_TxtMejores = _T("");
	m_TxtParecido = _T("");
	m_Parec = -1;
	m_ChkImagen = FALSE;
	m_ChkMejora = FALSE;
	m_ChkRotacion = FALSE;
	//}}AFX_DATA_INIT

	// Realizamos un enlace a la BD
	m_pBd = ((CProyectoView *) pParent)->GetDocument()->m_db;
	// Realizamos un enlace a la configuración actual
	m_Opt = ((CProyectoView *) pParent)->GetDocument()->opt;
	// Inicializo ciertas variables del programa
	total_filas = 0;
	total_analiz = 0;
	stpar = NULL;
}


void CBusqDatos::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBusqDatos)
	DDX_Control(pDX, IDC_BUT_SUBIR, m_ButSubir);
	DDX_Control(pDX, IDC_BUT_BAJAR, m_ButBajar);
	DDX_Control(pDX, IDC_IMPORTAR, m_ButImportar);
	DDX_Control(pDX, IDC_GENERAR, m_ButGenerar);
	DDX_Control(pDX, IDC_LABEL, m_Label);
	DDX_Control(pDX, IDC_BARRA, m_Barra);
	DDX_Control(pDX, IDC_EDIT_DISTANCIA, m_Distancia);
	DDX_Control(pDX, IDC_EDIT_CURVATURA, m_Curvatura);
	DDX_Control(pDX, IDC_ELIMINAR, m_ButEliminar);
	DDX_Control(pDX, IDC_CMB_SIGNO, m_CmbSigno);
	DDX_Control(pDX, IDC_EDIT_NPUNTOS, m_NPuntos);
	DDX_Control(pDX, IDC_ORDEN, m_Orden);
	DDX_Control(pDX, IDC_MARCO, m_Marco);
	DDX_Control(pDX, IDC_VISTA, m_Image);
	DDX_Control(pDX, IDC_COMBOBD, m_BD);
	DDX_Control(pDX, IDC_BUT_BUSQUEDA, m_ButBuscar);
	DDX_Control(pDX, IDC_GRID, m_Grid);
	DDX_Check(pDX, IDC_TODAS, m_ChkTodas);
	DDX_Control(pDX, IDC_GRID2, m_Grid2);
	DDX_Text(pDX, IDC_EDIT_NPUNTOS, m_TxtNPuntos);
	DDX_Text(pDX, IDC_ORDEN, m_TxtOrden);
	DDX_CBString(pDX, IDC_CMB_SIGNO, m_TxtSigno);
	DDX_CBString(pDX, IDC_COMBOBD, m_TxtBD);
	DDX_Text(pDX, IDC_EDIT_CURVATURA, m_TxtCurvatura);
	DDX_Text(pDX, IDC_EDIT_DISTANCIA, m_TxtDistancia);
	DDX_Radio(pDX, IDC_DESC, m_Desc);
	DDX_Text(pDX, IDC_EDIT_MEJORES, m_TxtMejores);
	DDX_Text(pDX, IDC_EDIT_PARECIDO, m_TxtParecido);
	DDX_Radio(pDX, IDC_PAREC, m_Parec);
	DDX_Check(pDX, IDC_CHK_IMAGEN, m_ChkImagen);
	DDX_Check(pDX, IDC_CHK_MEJORA, m_ChkMejora);
	DDX_Check(pDX, IDC_CHK_ROTACION, m_ChkRotacion);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CBusqDatos, CDialog)
	//{{AFX_MSG_MAP(CBusqDatos)
	ON_BN_CLICKED(IDC_BUT_BUSQUEDA, OnButBusqueda)
	ON_BN_CLICKED(IDC_TODAS, OnTodas)
	ON_BN_CLICKED(IDC_GENERAR, OnGenerar)
	ON_BN_CLICKED(IDC_IMPORTAR, OnImportar)
	ON_BN_CLICKED(IDC_ELIMINAR, OnEliminar)
	ON_CBN_EDITCHANGE(IDC_CMB_SIGNO, OnEditchangeCmbSigno)
	ON_CBN_SELCHANGE(IDC_CMB_SIGNO, OnSelchangeCmbSigno)
	ON_EN_CHANGE(IDC_EDIT_CURVATURA, OnChangeEditCurvatura)
	ON_EN_CHANGE(IDC_EDIT_DISTANCIA, OnChangeEditDistancia)
	ON_BN_CLICKED(IDC_ASC, OnAsc)
	ON_BN_CLICKED(IDC_DESC, OnDesc)
	ON_EN_CHANGE(IDC_EDIT_MEJORES, OnChangeEditMejores)
	ON_EN_CHANGE(IDC_EDIT_PARECIDO, OnChangeEditParecido)
	ON_BN_CLICKED(IDC_NOMBRE, OnNombre)
	ON_BN_CLICKED(IDC_NPUNTOS, OnNpuntos)
	ON_BN_CLICKED(IDC_PAREC, OnParec)
	ON_BN_CLICKED(IDC_CHK_MEJORA, OnChkMejora)
	ON_BN_CLICKED(IDC_CHK_ROTACION, OnChkRotacion)
	ON_BN_CLICKED(IDC_BUT_SUBIR, OnButSubir)
	ON_BN_CLICKED(IDC_BUT_BAJAR, OnButBajar)
	ON_BN_CLICKED(IDC_AYUDA, OnAyuda)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBusqDatos message handlers

// Función que ejecuta la hebra para buscar la imagen
UINT EjecucionHebra2(LPVOID pParam)
{
	// 'p' apunta a la ventana de BusqDatos
	CBusqDatos * p = (CBusqDatos *) pParam;

	// Inicializamos la barra de progreso y el label informativo
	p->SetDlgItemText(IDC_LABEL, "Iniciando búsqueda ...");
	p->m_Barra.SetPos(0);
	p->m_Barra.ShowWindow(SW_SHOW);
	
	// Deshabilitamos todos los botones (no se pueda pulsar nada)
	p->HabilitarControles(false);

	if (!p->m_ChkImagen)
		p->BuscarComoImagen();
	else
		p->BuscarComoPatron();

	// Mostramos los resultados sin realizar un UpdateData(true) (el 1 lo indica)
	p->MostrarResultados(1);
	
	// Borramos los resultados si no lo estaban ya
	if (p->stpar != NULL)
		delete p->stpar;
	
	// Seleccionamos el primero de los resultados en el grid (si hay alguno)
	if (p->m_Grid.GetRows() > 1)
	{
		p->m_Grid.SetRowSel(1);
		p->SelectGrid(); // Llamamos a una función que llama a OnSelChangeGrid
	}
	
	// Poner la BD en un estado consistente (Borro las tablas temporales y
	// actualizo las penalizaciones de las imágenes a 0)
	p->BorrarPuntoCons();
	p->BorrarPuntoM();
	p->m_pBd->ExecuteSQL("UPDATE Imagen SET Penalizacion = 0");
	
	// Quitamos la barra de progreso y el label informativo
	p->m_Barra.SetPos(0);
	p->m_Barra.ShowWindow(SW_HIDE);
	p->SetDlgItemText(IDC_LABEL, "");
	
	// Cambiamos el título del botón de "Cancelar" a "Buscar"
	p->SetDlgItemText(IDC_BUT_BUSQUEDA,"Buscar");

	// Habilitamos los botones
	p->m_ButBuscar.EnableWindow(true);
	p->HabilitarControles(true);

	return 0;
}

BEGIN_EVENTSINK_MAP(CBusqDatos, CDialog)
    //{{AFX_EVENTSINK_MAP(CBusqDatos)
	ON_EVENT(CBusqDatos, IDC_GRID, 69 /* SelChange */, OnSelChangeGrid, VTS_NONE)
	ON_EVENT(CBusqDatos, IDC_GRID2, 69 /* SelChange */, OnSelChangeGrid2, VTS_NONE)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

// ************* //
// ** EVENTOS ** //
// ************* //

// ** Inicio ejecución ventana ** //

// Se dispara al iniciar la ejecución de la ventana
BOOL CBusqDatos::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	CenterWindow();

	// Inicializo variables
	m_TxtNPuntos = "1";
	m_ChkImagen = false;
	m_ChkRotacion = false;
	m_ChkMejora = true;
	m_Parec = 0;
	m_Desc = 0;
	m_TxtMejores = "20";
	m_TxtParecido = "0";	
	// y reflejo los cambios en las cajas de texto correspondientes
	UpdateData(false);

	// Borro de la BD los resultados obtenidos anteriormente
	BorrarResultados();

	// Cargo los grupos de imágenes y selecciono el primero de ellos
	CargarComboGruposImagenes();
	m_BD.SetCurSel(0);

	// Muestro los títulos de todos los grids
	IniciaGrid();
	IniciaGrid2();

	// Cargo las cajas de texto de curvatura, distancia y signo con los valores
	// correspondientes de la fila seleccionada en el grid de los puntos característicos
	CargarCajas();

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// ** Fin ejecución ventana ** //

// Se dispara cuando pulsamos el botón "Cerrar"
void CBusqDatos::OnCancel() 
{
	CDialog::OnCancel();
}

// Se dispara al cerrar la ventana
BOOL CBusqDatos::DestroyWindow() 
{
	BorrarResultados();

	return CDialog::DestroyWindow();
}

// ** Botones ** //

// Se dispara al pulsar el botón de "Búsqueda" o "Cancelar" (es el mismo)
void CBusqDatos::OnButBusqueda()
{
	CString nombre;

	// Obtenemos el nombre del botón
	GetDlgItemText(IDC_BUT_BUSQUEDA,nombre);
	
	if (strcmp(nombre,"Cancelar") == 0)
	{		
		// Si es "Cancelar", deshabilitamos el botón y ordenamos detener la ejecución
		m_ButBuscar.EnableWindow(false);
		ejecucion = false;
	}
	else
	{
		// Si es "Búsqueda", comenzamos la misma (lanzamos una hebra dedicada)
		ejecucion = true;
		UpdateData(true);

		// Modificamos el nombre del botón de "Buscar" a "Cancelar"
		SetDlgItemText(IDC_BUT_BUSQUEDA,"Cancelar");

		m_Image.SetBitmap(NULL);
		IniciaGrid();

		// Borramos los resultados anteriores de la Base de Datos
		BorrarResultados();
		
		// Ejecutamos la búsqueda con una hebra dedicada
		pThread = AfxBeginThread(EjecucionHebra2, this, THREAD_PRIORITY_NORMAL, 0, 0);
	}
}

// Se dispara cuando pulsamos el botón "Importar"
void CBusqDatos::OnImportar() 
{
	// Ejecutamos la ventana de Importar
	CImportar ImpDlg(this);

	ImpDlg.dir_vistas = m_Opt->dir;
	ImpDlg.workdir = m_Opt->workdir;
	if (ImpDlg.DoModal() == IDOK)
	{
		// Modificamos ciertas cosas si se ha pulsado "OK" en la ventana "Importar"
		ComprobarBotones();
		CargarCajas();
	}
}

// Se dispara cuando pulsamos el botón "Generar"
void CBusqDatos::OnGenerar() 
{
	char sorden[10];
	int i;
	
	// Generamos tantas filas como indica la caja de texto asociada a "m_TxtNPuntos"
	UpdateData(true);

	m_Grid2.SetRows(atoi(m_TxtNPuntos) + 1);

	for (i=1;i<m_Grid2.GetRows();i++)
	{
		itoa(i,sorden,10);
		m_Grid2.SetTextMatrix(i,(En2) orden, sorden);
	}

	ComprobarBotones();
	CargarCajas();
}

// Se dispara cuando pulsamos el botón "Eliminar"
void CBusqDatos::OnEliminar() 
{
	char si[10], s[10];
	int i, pos;

	if (m_Grid2.GetRows() < 2)
		return; // No hay nada que eliminar porque no hay puntos

	pos = m_Grid2.GetRow();

	if ((pos < 1) || (pos >= m_Grid2.GetRows()))
		return; // No hay nada que eliminar porque no se ha seleccionado un punto
	
	// Eliminar implica mover las filas debajo de la eliminada un lugar hacia arriba
	for (i=pos;i<m_Grid2.GetRows() - 1;i++)
	{
		itoa(i,si,10);
		m_Grid2.SetTextMatrix(i,(En2) orden, si);
		m_Grid2.SetTextMatrix(i,(En2) curvatura, m_Grid2.GetTextMatrix(i + 1,(En2) curvatura));
		m_Grid2.SetTextMatrix(i,(En2) signo, m_Grid2.GetTextMatrix(i + 1,(En2) signo));
		m_Grid2.SetTextMatrix(i,(En2) distancia, m_Grid2.GetTextMatrix(i + 1,(En2) distancia));
	}

	m_Grid2.SetRows(m_Grid2.GetRows() - 1);
	itoa(m_Grid2.GetRows() - 1,s,10);
	m_TxtNPuntos = CString(s);

	CargarCajas();
	ComprobarBotones();

	UpdateData(false);
}

// Se dispara cuando pulsamos el botón "Subir"
void CBusqDatos::OnButSubir()
{
	CString tmpcurv, tmpsigno, tmpdist;
	int fila_actual;
	
	fila_actual = m_Grid2.GetRow();
	if (fila_actual > 1)
	{
		m_Grid2.SetRedraw(false);

		// Guardo la fila anterior (porque la voy a sobreescribir)
		tmpcurv = m_Grid2.GetTextMatrix(fila_actual - 1, (En2) curvatura);
		tmpsigno = m_Grid2.GetTextMatrix(fila_actual - 1, (En2) signo);
		tmpdist = m_Grid2.GetTextMatrix(fila_actual - 1, (En2) distancia);
	
		// Escribo la fila seleccionada en la fila justo encima
		m_Grid2.SetTextMatrix(fila_actual - 1,(En2) curvatura, m_Grid2.GetTextMatrix(fila_actual,(En2) curvatura));
		m_Grid2.SetTextMatrix(fila_actual - 1,(En2) signo, m_Grid2.GetTextMatrix(fila_actual,(En2) signo));
		m_Grid2.SetTextMatrix(fila_actual - 1,(En2) distancia, m_Grid2.GetTextMatrix(fila_actual,(En2) distancia));

		// Escribo la fila guardada en la fila actual
		m_Grid2.SetTextMatrix(fila_actual,(En2) curvatura, tmpcurv);
		m_Grid2.SetTextMatrix(fila_actual,(En2) signo, tmpsigno);
		m_Grid2.SetTextMatrix(fila_actual,(En2) distancia, tmpdist);

		m_Grid2.SetRedraw(true);
		
		m_Grid2.SetRow(fila_actual - 1);
		m_Grid2.SetColSel(3);
	}
}

// Se dispara cuando pulsamos el botón "Bajar"
void CBusqDatos::OnButBajar() 
{
	CString tmpcurv, tmpsigno, tmpdist;
	int fila_actual;

	fila_actual = m_Grid2.GetRow();
	if (fila_actual < m_Grid2.GetRows() - 1)
	{
		m_Grid2.SetRedraw(false);

		// Guardo la fila anterior (porque la voy a sobreescribir)
		tmpcurv = m_Grid2.GetTextMatrix(fila_actual + 1, (En2) curvatura);
		tmpsigno = m_Grid2.GetTextMatrix(fila_actual + 1, (En2) signo);
		tmpdist = m_Grid2.GetTextMatrix(fila_actual + 1, (En2) distancia);
	
		// Escribo la fila seleccionada en la fila justo encima
		m_Grid2.SetTextMatrix(fila_actual + 1,(En2) curvatura, m_Grid2.GetTextMatrix(fila_actual,(En2) curvatura));
		m_Grid2.SetTextMatrix(fila_actual + 1,(En2) signo, m_Grid2.GetTextMatrix(fila_actual,(En2) signo));
		m_Grid2.SetTextMatrix(fila_actual + 1,(En2) distancia, m_Grid2.GetTextMatrix(fila_actual,(En2) distancia));

		// Escribo la fila guardada en la fila actual
		m_Grid2.SetTextMatrix(fila_actual,(En2) curvatura, tmpcurv);
		m_Grid2.SetTextMatrix(fila_actual,(En2) signo, tmpsigno);
		m_Grid2.SetTextMatrix(fila_actual,(En2) distancia, tmpdist);

		m_Grid2.SetRedraw(true);

		m_Grid2.SetRow(fila_actual + 1);
		m_Grid2.SetColSel(3);
	}	
}

// Se dispara cuando pulsamos el botón "Ayuda"
void CBusqDatos::OnAyuda() 
{
	HtmlHelp(NULL, m_Opt->workdir + "\\Ayuda\\Ayuda.chm::/busqdatos.htm", HH_DISPLAY_TOPIC, 0);	
}

// ** Checkboxes ** //

// Se dispara cuando modificamos el checkbox "Todas"
void CBusqDatos::OnTodas()
{
	UpdateData(true);

	if (m_ChkTodas == 1)
		m_BD.EnableWindow(false); // Deshabilitamos el combo de los grupos de imágenes
	else
		m_BD.EnableWindow(true);  // Habilitamos el combo de los grupos de imágenes
}

// Se dispara cuando modificamos el checkbox "Con Rotación"
void CBusqDatos::OnChkRotacion() 
{
	CompruebaOpciones2();
}

// Se dispara cuando modificamos el checkbox "Con 1-Mejora"
void CBusqDatos::OnChkMejora()
{
	CompruebaOpciones();	
}

// ** Option buttons ** //

// Se dispara cuando modificamos el OptionButton "IDC_PAREC" a "Parecido"
void CBusqDatos::OnParec()
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_NPUNTOS" a "Nº Puntos"
void CBusqDatos::OnNpuntos() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_NOMBRE" a "Nombre"
void CBusqDatos::OnNombre() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_ASC" a "ASC"
void CBusqDatos::OnAsc() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_DESC" a "DESC"
void CBusqDatos::OnDesc() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// ** Combos ** //

// Se dispara cuando se seleccionamos un elemento en el combo del signo
void CBusqDatos::OnSelchangeCmbSigno() 
{
	OnEditchangeCmbSigno();
}

// Se dispara cuando se cambia el contenido del combo del signo
void CBusqDatos::OnEditchangeCmbSigno()
{
	UpdateData(true);

	m_Grid2.SetTextMatrix(atoi(m_TxtOrden), (En2) signo, m_TxtSigno);			
}

// Se dispara cuando se seleccionamos un elemento en el combo de la curvatura
void CBusqDatos::OnSelchangeCmbCurvatura() 
{
    // Disparo el evento EDITCHANGE tras la finalización del evento
	// SELCHANGE, para poder recuperar el valor real de m_TxtCurvatura.
	PostMessage(WM_COMMAND,
               MAKEWPARAM(IDC_CMB_CURVATURA, CBN_EDITCHANGE),
              (LPARAM)(GetDlgItem(IDC_CMB_CURVATURA)->m_hWnd));
}

// Se dispara cuando se seleccionamos un elemento en el combo de la distancia
void CBusqDatos::OnSelchangeCmbDistancia() 
{
    // Disparo el evento EDITCHANGE tras la finalización del evento
	// SELCHANGE, para poder recuperar el valor real de m_TxtDistancia.
	PostMessage(WM_COMMAND,
               MAKEWPARAM(IDC_CMB_DISTANCIA, CBN_EDITCHANGE),
              (LPARAM)(GetDlgItem(IDC_CMB_DISTANCIA)->m_hWnd));	
}

// ** Cajas de texto ** //

// Se dispara cuando modificamos la caja de texto de curvatura
void CBusqDatos::OnChangeEditCurvatura()
{
	UpdateData(true);
	m_Grid2.SetTextMatrix(atoi(m_TxtOrden), (En2) curvatura, m_TxtCurvatura);
}

// Se dispara cuando modificamos la caja de texto de distancia
void CBusqDatos::OnChangeEditDistancia()
{
	UpdateData(true);
	m_Grid2.SetTextMatrix(atoi(m_TxtOrden), (En2) distancia, m_TxtDistancia);
}

// Se dispara cuando modificamos la caja de texto de parecido
void CBusqDatos::OnChangeEditParecido() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// Se dispara cuando modificamos la caja de texto de mejores
void CBusqDatos::OnChangeEditMejores()
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image.SetBitmap(NULL);
}

// ** Grids ** //

// Se dispara cuando se selecciona una fila del grid 1
void CBusqDatos::OnSelChangeGrid()
{
	// Dibujamos la imagen asociada a la linea de grid marcada
	DibujarImagen();
}

// Se dispara cuando se selecciona una fila del grid 2
void CBusqDatos::OnSelChangeGrid2() 
{
	// Cargamos los valores de la linea de grid seleccionada en las cajas de texto
	CargarCajas();
}

// ******************** //
// ** PROCEDIMIENTOS ** //
// ******************** //

void CBusqDatos::BuscarComoImagen()
{
	CForma datos;	
	CString sSQL, snpuntos;
	int i, npuntos, ini, num;

	stpar = NULL;
	m_Image.SetBitmap(NULL);

	IniciaGrid();

	snpuntos = m_Grid2.GetTextMatrix(m_Grid2.GetRows() - 1, (En2) orden);
	npuntos = atoi(snpuntos);
	
	// Calculo el número de imagenes que voy a tener y actualizo la variable total_filas
	total_analiz = 0;
	total_filas = TotalImagenes(npuntos,0,m_ChkTodas);
	stpar = (StParecido *) calloc(total_filas, (size_t) (sizeof(StParecido)));

	if (!ejecucion)
		return; // Acabo la ejecución abruptamente
	
	// Pongo a 0 el campo penalizacion de todas las imágenes que voy a buscar
	ActualizarPenalizaciones(npuntos);
	
	// Elimino todos los puntos de la tabla temporal PuntoCons
	BorrarPuntoCons();
			
	// Inserto en la tabla temporal PuntoCons los puntos de las imágenes con
	// un número total de puntos mayor al de la imagen a buscar
	if (!m_ChkMejora)
		InsertarMayores(npuntos,npuntos + m_Opt->margenmay,0);
	else
		// Si habilitamos la 1-mejora, obviamos aquí las
		// imágenes con 1 punto más que la que buscamos.
		InsertarMayores(npuntos + 1, npuntos + m_Opt->margenmay,0);

	// Inserto en la tabla temporal PuntoCons los puntos de las imágenes con
	// igual número total de puntos al de la imagen a buscar	
	InsertarIguales(npuntos);

	SetDlgItemText(IDC_LABEL, "Fase 1: Imágenes mayores e iguales.");

	// Busco en los mayores o iguales
	num = BuscarImagen(npuntos,1);
	if (num == -1)
		return; // Acabo la ejecución abruptamente

	total_analiz = total_analiz + num;
	
	// Elimino todos los puntos de la tabla temporal PuntoCons
	BorrarPuntoCons();

	// Inicializo la barra de progreso de los menores
	m_Barra.SetPos(0);

	SetDlgItemText(IDC_LABEL, "Fase 2: Imágenes menores.");

	if (!m_ChkMejora)
		ini = 1;
	else
		// Si habilitamos la 1-mejora, obviamos aquí las
		// imágenes con 1 punto menos que la que buscamos.
		ini = 2;

	for (i=ini;i<=m_Opt->margenmen;i++)
	{
		m_Barra.OffsetPos((100 / (m_Opt->margenmen - i + 1)) + 1);

		// Insertamos en PuntoCons los puntos npuntos - i. Si no hay ninguno en
		// la BD, pasamos directamente al siguiente menor.
 		if (InsertarMenores(npuntos - i) != 0)
		{
			// Guardo en PuntoM la nueva imagen a buscar
			CargarMenor(npuntos - i, npuntos);
			
			// Busco en los menores
			num = BuscarImagenM(npuntos);
			if (num == -1)
				return; // Acabo la ejecución abruptamente

			total_analiz = total_analiz + num;

			// Elimino todos los puntos de la tabla temporal PuntoM
			BorrarPuntoM();
			
			// Elimino todos los puntos de la tabla temporal PuntoCons
			BorrarPuntoCons();
		}
	}

	num = 0;
	// Calcular la 1-mejora si es seleccionada
	if (m_ChkMejora)
	{
		// Inicializo la barra de progreso de la 1-Mejora
		m_Barra.SetPos(0);
		
		SetDlgItemText(IDC_LABEL, "Fase 3: 1-Mejora superior.");

		if (ExistenPuntos(npuntos + 1))
		{
			// Calcular la 1-mejora (1 punto más)
			for (i=1;i<=npuntos;i++)
			{
				InsertarMayores(npuntos, npuntos + 1,i);
				num = BuscarImagen(npuntos,0);
				if (num == -1)
					return; // Acabo la ejecución abruptamente

				BorrarPuntoCons();
				ActualizarPenalizaciones(npuntos);
				m_Barra.OffsetPos((100 / (2 * npuntos)) + 1);
			}

			total_analiz = total_analiz + num;
		}
		else
			m_Barra.SetPos(50);

		num = 0;
		SetDlgItemText(IDC_LABEL, "Fase 3: 1-Mejora inferior.");

		for (i=1;i<=npuntos;i++)
		{
			// Calcular la 1-mejora (1 punto menos)
			if (InsertarMenores(npuntos - 1) != 0)
			{
				CargarMenor1Mej(npuntos - 1,i);
				num = BuscarImagenM(npuntos);
				if (num == -1)
					return; // Acabo la ejecución abruptamente

				BorrarPuntoM();
				BorrarPuntoCons();
				ActualizarPenalizaciones(npuntos);
			}
			
			m_Barra.OffsetPos((100 / (2 * npuntos)) + 1);
		}

		total_analiz = total_analiz + num;
	}

	m_Barra.ShowWindow(SW_HIDE);
	SetDlgItemText(IDC_LABEL, "");

	GuardarResultados();
}

void CBusqDatos::BuscarComoPatron()
{
	CString snpuntos;
	int npuntos, max_puntos, i, err;
	
	stpar = NULL;
	m_Image.SetBitmap(NULL);

	IniciaGrid();

	snpuntos = m_Grid2.GetTextMatrix(m_Grid2.GetRows() - 1, (En2) orden);
	npuntos = atoi(snpuntos);
	
	// Calculo el número de imagenes que voy a tener y actualizo la variable total_filas
	total_analiz = 0;
	total_filas = TotalImagenes(-1,npuntos,m_ChkTodas);
	stpar = (StParecido *) calloc(total_filas, (size_t) (sizeof(StParecido)));

	if (!ejecucion)
		return; // Acabo la ejecución abruptamente
	
	// Busco el máximo de puntos que hay en una imagen de la Base de Datos
	max_puntos = MaximoNumPuntos(m_ChkTodas);

	m_Barra.SetPos(0);
	SetDlgItemText(IDC_LABEL, "Buscando el patrón en las imágenes ...");
	
	for (i=1;i<=max_puntos;i++)
	{
		if (!ejecucion)
			return; // Acabo la ejecución abruptamente

		m_Barra.OffsetPos((100 / max_puntos) + 1);

		// Busco el patrón en todas las imágenes
		err = BuscarPatron(npuntos, i, total_filas);
		if (err != 0)
		{
			m_Barra.ShowWindow(SW_HIDE);
			SetDlgItemText(IDC_LABEL, "");
			MostrarError(err);
			return;
		}
	}

	m_Barra.ShowWindow(SW_HIDE);
	SetDlgItemText(IDC_LABEL, "");

	GuardarResultados();
}

int CBusqDatos::BuscarImagen(int npuntos, int usarbarra)
{
	ODynaset dyna, dyna2;
	CString scurvat, sdist, ssigno, sSQL, sSQLNueva;
	int i, j, ind, pos, ipenaliz, res;
	char sorden[10];
	double parec;

	if (usarbarra == 1)
		m_Barra.SetPos(0);

	// Probamos todas las combinaciones y nos quedamos con la mejor para cada uno
	for (i=0;i<npuntos;i++)
	{
		if (!ejecucion)
			return -1;

		if (usarbarra == 1)
		{
			if (!m_ChkRotacion)
				m_Barra.SetPos(100);
			else
				m_Barra.OffsetPos((100 / npuntos) + 1);
		}

		sSQLNueva = "";
		sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,PuntoCons WHERE Nombre = INombre";

		if (m_ChkTodas == false)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
		sSQL = sSQL + " AND (";

		// Este bucle añade tantas condiciones en el WHERE como puntos tiene la imagen
		for (ind=0;ind<npuntos;ind++)
		{
			if (ind != 0)
				sSQL = sSQL + " OR ";

			pos = ((ind + i) % npuntos) + 1;
			itoa(ind + 1,sorden,10);
			scurvat = m_Grid2.GetTextMatrix(pos,(En2) curvatura);
			if (!EsNumero(scurvat,0,100))
			{
				MostrarError(1);
				return -1;
			}
			
			sdist = m_Grid2.GetTextMatrix(pos,(En2) distancia);
			if (!EsNumero(sdist,0,100))
			{
				MostrarError(2);
				return -1;			
			}
			
			ssigno = m_Grid2.GetTextMatrix(pos,(En2) signo);
			if (ssigno.GetLength() == 0)
			{
				MostrarError(3);
				return -1;			
			}

			if (strcmp(ssigno,"+") == 0)
				ssigno = CString("0");
			else
				ssigno = CString("1");
			
			if (ind == 0)
			{
				sSQL = sSQL + "(Curvatura FEQ " + scurvat + " THOLD 0 AND Distancia FEQ ";
				sSQL = sSQL + sdist + " THOLD 0 AND Signo FEQ " + ssigno;
				sSQL = sSQL + " THOLD 0 AND Orden = " + CString(sorden) + ")";			
			}
			else
			{
				sSQL = sSQL + "(Orden = " + CString(sorden) + " AND Curvatura FEQ " + scurvat + " THOLD 0";
				sSQL = sSQL + " AND Distancia FEQ " + sdist + " THOLD 0 AND Signo FEQ ";
				sSQL = sSQL + ssigno + " THOLD 0)";
			}		
		}

		// Cierro la consulta agrupando por cada imagen.
		sSQL = sSQL + ") GROUP BY Nombre ORDER BY Nombre";

		// Traduzco la sentencia FSQL a SQL y veo si hay errores
		if (!PreConsulta(&sSQL,&sSQLNueva))
		{
			MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
			return -1;
		}

		// Abro el dynaset
		oresult err = dyna.Open(*m_pBd, sSQLNueva);
		if (err != OSUCCESS)
		{
			AfxMessageBox(dyna.GetErrorText(),MB_OK);
			return -1;
		}
		
		j = 0;
		dyna.MoveFirst();
		// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
		// de si se encontró una combinación más parecida o no.
		while (!dyna.IsEOF())
		{			
			if (i == 0)
			{
				dyna.GetFieldValue("Nombre", stpar[j + total_analiz].nombre, 100);
				sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
				sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
				dyna2.Open(*m_pBd,sSQL);
				dyna2.GetFieldValue("NumPuntos",&stpar[j + total_analiz].numpuntos);
				dyna2.Close();
			}

			dyna.GetFieldValue("Parec", &parec);

			sSQL = "SELECT Penalizacion FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);
			
			dyna2.GetFieldValue("Penalizacion",&ipenaliz);
			// El parecido es el obtenido menos la penalización a aplicar
			parec = parec - ipenaliz;

			if (parec > (double) stpar[j + total_analiz].parecido)
				stpar[j + total_analiz].parecido = Redondear(parec);
			
			dyna2.Close();
			dyna.MoveNext();
			j++;
		}

		if (i == 0)
			res = j;

		dyna.Close();

		if (!m_ChkRotacion)
			i = npuntos;
	}
	
	// Borro la tabla temporal PuntoCons
	BorrarPuntoCons();

	return res;
}

int CBusqDatos::BuscarImagenM(int npuntos)
{
	ODynaset dyna, dynaM, dyna2;
	CString sSQL, sSQLNueva;
	int i, j, res, ind, pos, icurvat, isigno, idist, ipenaliz;
	char sorden[10], scurvat[10], sdist[10], ssigno[10];
	double parec;

	dynaM.Open(*m_pBd, "SELECT * FROM PuntoM ORDER BY Orden");
	
	// Probamos todas las combinaciones y nos quedamos con la mejor para cada uno
	for (i=0;i<npuntos;i++)
	{		
		if (!ejecucion)
			return -1;
	
		dynaM.MoveFirst();
		
		sSQLNueva = "";
		sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,PuntoCons WHERE Nombre = INombre";

		if (m_ChkTodas == false)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
		sSQL = sSQL + " AND (";

		// Este bucle añade tantas condiciones en el WHERE como puntos tiene la imagen
		for (ind=0;ind<npuntos;ind++)
		{
			if (ind != 0)
				sSQL = sSQL + " OR ";

			pos = ((ind + i) % npuntos) + 1;
			itoa(ind + 1,sorden,10);
			
			dynaM.GetFieldValue("Curvatura",&icurvat);
			dynaM.GetFieldValue("Distancia",&idist);
			dynaM.GetFieldValue("Signo",&isigno);
			itoa(icurvat,scurvat,10);
			itoa(idist,sdist,10);
			itoa(isigno,ssigno,10);

			if (ind == 0)
			{
				sSQL = sSQL + "(Curvatura FEQ " + CString(scurvat) + " THOLD 0 AND Distancia FEQ ";
				sSQL = sSQL + CString(sdist) + " THOLD 0 AND Signo FEQ " + CString(ssigno);
				sSQL = sSQL + " THOLD 0 AND Orden = " + CString(sorden) + ")";			
			}
			else
			{
				sSQL = sSQL + "(Orden = " + CString(sorden) + " AND Curvatura FEQ " + CString(scurvat) + " THOLD 0";
				sSQL = sSQL + " AND Distancia FEQ " + CString(sdist) + " THOLD 0 AND Signo FEQ ";
				sSQL = sSQL + CString(ssigno) + " THOLD 0)";
			}		

			dynaM.MoveNext();
		}

		// Cierro la consulta agrupando por cada imagen.
		sSQL = sSQL + ") GROUP BY Nombre";

		// Traduzco la sentencia FSQL a SQL y veo si hay errores
		if (!PreConsulta(&sSQL,&sSQLNueva))
		{
			MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
			return -1;
		}

		// Abro el dynaset
		oresult err = dyna.Open(*m_pBd, sSQLNueva);
		if (err != OSUCCESS)
		{
			AfxMessageBox(dyna.GetErrorText(),MB_OK);
			return -1;
		}
			
		j = 0;
		dyna.MoveFirst();
		// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
		// de si se encontró una combinación más parecida o no.
		while (!dyna.IsEOF())
		{			
			if (i == 0)
			{
				dyna.GetFieldValue("Nombre", stpar[j + total_analiz].nombre, 100);
				sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
				sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
				dyna2.Open(*m_pBd,sSQL);
				dyna2.GetFieldValue("NumPuntos",&stpar[j + total_analiz].numpuntos);
				dyna2.Close();
			}

			dyna.GetFieldValue("Parec", &parec);

			sSQL = "SELECT Penalizacion FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);

			dyna2.GetFieldValue("Penalizacion",&ipenaliz);
			// El parecido es el obtenido menos la penalización a aplicar
			parec = parec - ipenaliz;

			if (parec > (double) stpar[j + total_analiz].parecido)
				stpar[j + total_analiz].parecido = Redondear(parec);
			
			dyna2.Close();
			dyna.MoveNext();
			j++;
		}

		if (i == 0)
			res = j;

		dyna.Close();

		if (!m_ChkRotacion)
			i = npuntos;
	}
	
	dynaM.Close();
	
	return res;
}

int CBusqDatos::BuscarPatron(int npuntos, int ini, int total_filas)
{
	ODynaset dyna, dyna2;
	CString sSQL, sSQLNueva, scurvat, sdist, ssigno;
	int i, j, pos, inumptos;
	double parec;
	char sorden[10], str[100], smax[10];
	
	itoa(max(npuntos,ini),smax,10);
	sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,Punto WHERE Nombre = INombre";
	sSQL = sSQL + " AND NumPuntos >= " + CString(smax);

	if (m_ChkTodas == false)
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
	sSQL = sSQL + " AND (";

	for (i=0;i<npuntos;i++)
	{
		if (i != 0)
			sSQL = sSQL + " OR ";

		pos = i + ini - 1;
		itoa(pos,sorden,10);
		scurvat = m_Grid2.GetTextMatrix(i + 1,(En2) curvatura);
			
		if (!EsNumero(scurvat,0,100))
		{
			return 1;
		}
			
		sdist = m_Grid2.GetTextMatrix(i + 1,(En2) distancia);
		if (!EsNumero(sdist,0,50000))
		{
			return 2;			
		}
			
		ssigno = m_Grid2.GetTextMatrix(i + 1,(En2) signo);
		if (ssigno.GetLength() == 0)
		{
			return 3;			
		}

		if (strcmp(ssigno,"+") == 0)
			ssigno = CString("0");
		else
			ssigno = CString("1");

		if (i == 0)
		{
			sSQL = sSQL + "(Curvatura FEQ " + scurvat + " THOLD 0";
			if (i != (npuntos - 1))
				sSQL = sSQL + " AND Distancia_real FEQ " + sdist + " THOLD 0";
			sSQL = sSQL + " AND Signo FEQ " + ssigno + " THOLD 0";
			sSQL = sSQL + " AND Orden = MOD(" + CString(sorden) + ",NumPuntos) + 1)";
		}
		else
		{
			sSQL = sSQL + "(Orden = MOD(" + CString(sorden) + ",NumPuntos) + 1";
			sSQL = sSQL + " AND Curvatura FEQ " + scurvat + " THOLD 0";
			if (i != (npuntos - 1))
				sSQL = sSQL + " AND Distancia_real FEQ " + sdist + " THOLD 0";
			sSQL = sSQL + " AND Signo FEQ " + ssigno + " THOLD 0)";
		}		
	}

	// Cierro la consulta agrupando por cada imagen.
	sSQL = sSQL + ") GROUP BY Nombre";

	// Traduzco la sentencia FSQL a SQL y veo si hay errores
	if (!PreConsulta(&sSQL,&sSQLNueva))
	{
		MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
		return 4;
	}

	// Abro el dynaset
	oresult err = dyna.Open(*m_pBd, sSQLNueva);
	if (err != OSUCCESS)
	{
		AfxMessageBox(dyna.GetErrorText(),MB_OK);
		return 4;
	}
		
	if (ini == 1)
	{
		j = 0;
		while (!dyna.IsEOF())
		{
			dyna.GetFieldValue("Nombre", stpar[j].nombre, 100); 
	
			sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);
			dyna2.GetFieldValue("NumPuntos",&inumptos);
			stpar[j].numpuntos = inumptos;
			dyna2.Close();

			dyna.MoveNext();
			j++;
		}
	}
	
	dyna.MoveFirst();
	// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
	// de si se encontró una combinación más parecida o no.
	while (!dyna.IsEOF())
	{			
		dyna.GetFieldValue("Nombre", str, 100);
		j = Posicion(stpar, CString(str), total_filas);
			
		dyna.GetFieldValue("Parec", &parec);

		if (parec > (double) stpar[j].parecido)
			stpar[j].parecido = Redondear(parec);
			
		dyna.MoveNext();
	}

	return 0;
	dyna.Close();
}

void CBusqDatos::InsertarMayores(int valor, int valor_fin, int punto)
{
	ODynaset dyna;
	CString sSQL;
	char snpuntos[10], snpuntosmax[10], snombre[100];
	int numptos;
	
	itoa(valor,snpuntos,10);
	itoa(valor_fin,snpuntosmax,10);

	// Traslado los puntos mayores de la tabla Punto a la tabla PuntoCons.
	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos > " + CString(snpuntos);
	sSQL = sSQL + " AND NumPuntos <= " + CString(snpuntosmax);
	m_pBd->ExecuteSQL(sSQL);	
	
	// Obtenemos todas las imágenes
	sSQL = "SELECT Nombre,NumPuntos FROM Imagen WHERE NumPuntos > " + CString(snpuntos);
	sSQL = sSQL + " AND NumPuntos <= " + CString(snpuntosmax);
	
	dyna.Open(*m_pBd,sSQL);

	while (!dyna.IsEOF())
	{
		dyna.GetFieldValue("NumPuntos",&numptos);
		dyna.GetFieldValue("Nombre",snombre,100);

		if (punto == 0)
		{
			// Eliminamos los puntos necesarios y reorganizamos la tabla PuntoCons
			if (m_ChkMejora)
				// Quitamos numptos - puntos de la imagen a buscar (valor - 1) 
				SuprimirPuntos(CString(snombre), numptos, valor - 1);
			else
				// Quitamos numptos - puntos de la imagen a buscar (valor) 
				SuprimirPuntos(CString(snombre), numptos, valor);
		}
		else
			SuprimirPuntoMej(CString(snombre), numptos, punto);
				
		dyna.MoveNext();
	}

	dyna.Close();
}

void CBusqDatos::InsertarIguales(int valor)
{
	CString sSQL;
	char snpuntos[10];

	itoa(valor,snpuntos,10);

	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos = " + CString(snpuntos);

	m_pBd->ExecuteSQL(sSQL);	
}

int CBusqDatos::InsertarMenores(int valor)
{
	CString sSQL;
	char smenor[10];
	int num;
	
	itoa(valor,smenor,10);
	
	// Introduzco en PuntoCons los puntos menores
	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos = " + CString(smenor);

	m_pBd->ExecuteSQL(sSQL);
	num = m_pBd->GetRowsProcessed();
	
	return num;
}

void CBusqDatos::SuprimirPuntos(CString nombre, int nptos, int nptosref)
{
	ODynaset dyna;
	CString sSQL, sSQL2;	
	char sidpunto[10], sordenant[10], sdist[10], spenaliz[10];
	int i, lim, idpunto, orden, dist, curvat, penaliz;

	sSQL = "SELECT IdPunto,Orden,Distancia,Curvatura FROM PuntoCons WHERE INombre = '" + nombre;
	sSQL = sSQL + "' ORDER BY Curvatura";

	lim = nptos - nptosref;
	for (i=0;i<lim;i++)
	{
		dyna.Open(*m_pBd,sSQL);
		
		// Obtenemos los datos necesarios antes de eliminar el punto
		dyna.GetFieldValue("IdPunto",&idpunto);
		dyna.GetFieldValue("Orden",&orden);
		dyna.GetFieldValue("Distancia",&dist);
		dyna.GetFieldValue("Curvatura",&curvat);

		// Eliminamos el punto
		itoa(idpunto,sidpunto,10);
		sSQL2 = "DELETE FROM PuntoCons WHERE IdPunto = " + CString(sidpunto);
		m_pBd->ExecuteSQL(sSQL2);
		
		// Añadimos la penalización a la imagen
		penaliz = ObtenerPenalizacion(curvat, nptos);
		itoa(penaliz,spenaliz,10);
		sSQL2 = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
		sSQL2 = sSQL2 + " WHERE Nombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);

		// Actualizamos la distancia en el punto anterior
		itoa(dist,sdist,10);
		if (orden == 1)
			// El anterior es el último
			itoa(nptos,sordenant,10);
		else
			// El anterior es, eso, el anterior
			itoa(orden - 1,sordenant,10);

		sSQL2 = "UPDATE PuntoCons SET Distancia = Distancia + " + CString(sdist);
		sSQL2 = sSQL2 + " WHERE Orden = " + CString(sordenant);
		sSQL2 = sSQL2 + " AND INombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);

		// Actualizamos IdPunto y Orden de todos los puntos de esa imagen
		sSQL2 = "UPDATE PuntoCons SET IdPunto = IdPunto - 1, Orden = Orden - 1";
		sSQL2 = sSQL2 + " WHERE IdPunto > " + sidpunto;
		sSQL2 = sSQL2 + " AND INombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);
		
		nptos--;
		
		dyna.Close();
	}
}

void CBusqDatos::SuprimirPuntoMej(CString nombre, int nptos, int i)
{
	ODynaset dyna;
	CString sSQL;
	char sidpunto[10], sordenant[10], sdist[10], spenaliz[10], sorden[10];
	int idpunto, orden, curvat, dist, penaliz, j;

	sSQL = "SELECT IdPunto,Orden,Distancia,Curvatura FROM PuntoCons WHERE INombre = '" + nombre;
	sSQL = sSQL + "' ORDER BY Orden";

	dyna.Open(*m_pBd,sSQL);

	for (j=1;j<i;j++)
		dyna.MoveNext();
		
	// Obtenemos los datos necesarios antes de eliminar el punto
	dyna.GetFieldValue("IdPunto",&idpunto);
	dyna.GetFieldValue("Orden",&orden);
	dyna.GetFieldValue("Curvatura",&curvat);
	dyna.GetFieldValue("Distancia",&dist);

	// Eliminamos el punto
	itoa(orden,sorden,10);
	sSQL = "DELETE FROM PuntoCons WHERE Orden = " + CString(sorden);
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);
		
	// Añadimos la penalización a la imagen
	penaliz = ObtenerPenalizacion(curvat, nptos);
	itoa(penaliz,spenaliz,10);
	sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
	sSQL = sSQL + " WHERE Nombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos la distancia en el punto anterior
	itoa(dist,sdist,10);
	if (orden == 1)
		// El anterior es el último
		itoa(nptos,sordenant,10);
	else
		// El anterior es, eso, el anterior
		itoa(orden - 1,sordenant,10);

	sSQL = "UPDATE PuntoCons SET Distancia = Distancia + " + CString(sdist);
	sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos IdPunto y Orden de todos los puntos de esa imagen
	itoa(idpunto,sidpunto,10);
	sSQL = "UPDATE PuntoCons SET IdPunto = IdPunto - 1, Orden = Orden - 1";
	sSQL = sSQL + " WHERE IdPunto > " + sidpunto;
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);
		
	nptos--;
		
	dyna.Close();
}

void CBusqDatos::CargarMenor(int nummenor, int numref)
{
	ODynaset dyna;
	CString sSQL, ssigno;
	int i, filas, iorden, dist, curvat, lim, penaliz;
	char sorden[10], sdist[10], spenaliz[10], snummenor[10], sordenant[10];

	// Introduzco los datos del grid a la tabla temporal PuntoM
	i = 1;
	filas = m_Grid2.GetRows();
	while (i < filas)
	{	
		if (strcmp(m_Grid2.GetTextMatrix(i,(En2) signo),"+") == 0)
			ssigno = "0";
		else
			ssigno = "1";
		
		// Introduzco en PuntoM los puntos menores
		sSQL = "INSERT INTO PuntoM (Orden,Signo,Distancia,Curvatura) VALUES (";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) orden) + ",";
		sSQL = sSQL + ssigno + ",";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) distancia) + ",";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) curvatura) + ")";
		m_pBd->ExecuteSQL(sSQL);
		
		i++;
	}

	lim = numref - nummenor;
	for (i=0;i<lim;i++)
	{
		dyna.Open(*m_pBd,"SELECT * FROM PuntoM ORDER BY Curvatura");
		
		// Obtenemos los datos necesarios antes de eliminar el punto
		dyna.GetFieldValue("Orden",&iorden);
		dyna.GetFieldValue("Distancia",&dist);
		dyna.GetFieldValue("Curvatura",&curvat);

		// Eliminamos el punto
		itoa(iorden,sorden,10);
		sSQL = "DELETE FROM PuntoM WHERE Orden = " + CString(sorden);
		m_pBd->ExecuteSQL(sSQL);
		
		// Añadimos la penalización a la imagen
		penaliz = ObtenerPenalizacion(curvat, numref);

		// Actualizo la penaliz en todas las imágenes de PuntoCons
		itoa(penaliz,spenaliz,10);
		itoa(nummenor,snummenor,10);
		sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
		sSQL = sSQL + " WHERE Nombre IN (SELECT INombre FROM PuntoCons";
		sSQL = sSQL + " WHERE NumPuntos = " + CString(snummenor) + ")";
		m_pBd->ExecuteSQL(sSQL);
		
		// Actualizamos la distancia en el punto anterior
		itoa(dist,sdist,10);
		if (iorden == 1)
			// El anterior es el último
			itoa(numref,sordenant,10);
		else
			// El anterior es, eso, el anterior
			itoa(iorden - 1,sordenant,10);

		sSQL = "UPDATE PuntoM SET Distancia = Distancia + " + CString(sdist);
		sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
		m_pBd->ExecuteSQL(sSQL);

		// Actualizamos Orden de todos los puntos de esa imagen
		sSQL = "UPDATE PuntoM SET Orden = Orden - 1 WHERE Orden > " + CString(sorden);
		m_pBd->ExecuteSQL(sSQL);
		
		numref--;
		
		dyna.Close();
	}
}

void CBusqDatos::CargarMenor1Mej(int npuntos, int numi)
{
	ODynaset dyna;
	CString sSQL, ssigno;
	int i, j, filas, iorden, dist, curvat, penaliz;
	char sorden[10], sdist[10], spenaliz[10], snpuntos[10], sordenant[10];

	// Introduzco los datos del grid a la tabla temporal PuntoM
	i = 1;
	filas = m_Grid2.GetRows();
	while (i < filas)
	{	
		if (strcmp(m_Grid2.GetTextMatrix(i,(En2) signo),"+") == 0)
			ssigno = "0";
		else
			ssigno = "1";
		
		// Introduzco en PuntoM los puntos menores
		sSQL = "INSERT INTO PuntoM (Orden,Signo,Distancia,Curvatura) VALUES (";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) orden) + ",";
		sSQL = sSQL + ssigno + ",";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) distancia) + ",";
		sSQL = sSQL + m_Grid2.GetTextMatrix(i,(En2) curvatura) + ")";
		m_pBd->ExecuteSQL(sSQL);
		
		i++;
	}

	dyna.Open(*m_pBd,"SELECT * FROM PuntoM ORDER BY Orden");
		
	for (j=1;j<numi;j++)
		dyna.MoveNext();
	
	// Obtenemos los datos necesarios antes de eliminar el punto
	dyna.GetFieldValue("Orden",&iorden);
	dyna.GetFieldValue("Distancia",&dist);
	dyna.GetFieldValue("Curvatura",&curvat);

	// Eliminamos el punto
	itoa(iorden,sorden,10);
	sSQL = "DELETE FROM PuntoM WHERE Orden = " + CString(sorden);
	m_pBd->ExecuteSQL(sSQL);
		
	// Añadimos la penalización a la imagen
	penaliz = ObtenerPenalizacion(curvat, npuntos + 1);

	// Actualizo la penalización en todas las imágenes de PuntoCons
	itoa(penaliz,spenaliz,10);
	itoa(npuntos,snpuntos,10);
	sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
	sSQL = sSQL + " WHERE Nombre IN (SELECT INombre FROM PuntoCons";
	sSQL = sSQL + " WHERE NumPuntos = " + CString(snpuntos) + ")";
	m_pBd->ExecuteSQL(sSQL);
		
	// Actualizamos la distancia en el punto anterior
	itoa(dist,sdist,10);
	if (iorden == 1)
		// El anterior es el último
		itoa(npuntos + 1,sordenant,10);
	else
		// El anterior es, eso, el anterior
		itoa(iorden - 1,sordenant,10);

	sSQL = "UPDATE PuntoM SET Distancia = Distancia + " + CString(sdist);
	sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos Orden de todos los puntos de esa imagen
	sSQL = "UPDATE PuntoM SET Orden = Orden - 1 WHERE Orden > " + CString(sorden);
	m_pBd->ExecuteSQL(sSQL);
		
	dyna.Close();
}

bool CBusqDatos::PreConsulta(CString *sSQL, CString *sSQLNueva)
{
	ODynaset dyna;
	CString sFSQL;
	char cad[4000];
	int i;

	// -- 1ª Consulta -- //
	// Creo los parámetros
	OParameterCollection params = m_pBd->GetParameters();
	params.Add("SSQL", *sSQL, OPARAMETER_INVAR, OTYPE_VARCHAR2);
	params.Add("NUMERR", 0, OPARAMETER_OUTVAR, OTYPE_NUMBER);

	// Ejecuto la sentencia del paquete FSQL_PKG
	sFSQL = "DECLARE NUMERR NUMBER(4); BEGIN NUMERR:=FSQL_PKG.FSQL2SQL(:SSQL); END;";
	m_pBd->ExecuteSQL(sFSQL);
	
	// Miro si hay errores en la ejecución de la sentencia
	params.GetParameter("NUMERR").GetValue(&i);
	if (i != 0)
		return false; // Ha sucedido un error no previsto		
		
	// Borro los parámetros
	params.Remove("SSQL");
	params.Remove("NUMERR");

	// -- 2ª Consulta -- //
	// Concateno la consulta
	dyna.Open(*m_pBd, "SELECT ATRIBUTO FROM FSQL_QUERY WHERE ATRIBUTO IS NOT NULL AND SESSIONID=USERENV('SESSIONID') ORDER BY INDICE");
	int l;
	while (!dyna.IsEOF())
	{
		dyna.GetFieldValue("ATRIBUTO",cad,4000);
		CString str(cad);
		l = str.GetLength();
		*sSQLNueva =  *sSQLNueva + " " + str;
		dyna.MoveNext();
		l++;
	}

	return true;
}

void CBusqDatos::IniciaGrid()
{
	m_Grid.SetRedraw(false);
	m_Grid.Clear();
	m_Grid.SetRows(1);
	
	m_Grid.SetColAlignment((En) imagen, 1);
	m_Grid.SetColWidth((En) imagen, 1000);
	m_Grid.SetTextMatrix(0,(En) imagen, "Imagen");

	m_Grid.SetColWidth((En) directorio, 1750);
	m_Grid.SetTextMatrix(0,(En) directorio, "Carpeta");

	m_Grid.SetColWidth((En) parecido, 1000);
	m_Grid.SetTextMatrix(0,(En) parecido, "Parecido (%)");

	m_Grid.SetColWidth((En) numpuntos, 500);
	m_Grid.SetTextMatrix(0,(En) numpuntos, "Ptos");

	m_Grid.SetRedraw(true);
}

void CBusqDatos::IniciaGrid2()
{
	m_Grid2.SetRedraw(false);
	m_Grid2.Clear();
	m_Grid2.SetRows(2);
	
	m_Grid2.SetColWidth((En2) orden, 600);
	m_Grid2.SetTextMatrix(0,(En2) orden, "Orden");

	m_Grid2.SetColWidth((En2) curvatura, 1150);
	m_Grid2.SetTextMatrix(0,(En2) curvatura, "Curvatura");

	m_Grid2.SetColWidth((En2) distancia, 1250);
	m_Grid2.SetTextMatrix(0,(En2) distancia, "Distancia");

	m_Grid2.SetColWidth((En2) signo, 600);
	m_Grid2.SetTextMatrix(0,(En2) signo, "Signo");

	m_Grid2.SetTextMatrix(1,(En2) orden, "1");
	
	// Para que el grid seleccione la fila entera y no quede feo
	m_Grid2.SetTextMatrix(1,(En2) curvatura, "");
	m_Grid2.SetTextMatrix(1,(En2) signo, "");
	m_Grid2.SetTextMatrix(1,(En2) distancia, "");
	
	m_Grid2.SetRedraw(true);
}

void CBusqDatos::GuardarResultados()
{
	CString sSQL;
	int i;
	char sparec[10], snpuntos[10];

	// Borro previamente los datos que hubiera en la tabla "Resultado"
	BorrarResultados();
		
	// Añado los nuevos datos a la tabla
	for (i=0;i<total_filas;i++)
	{
		itoa(stpar[i].parecido,sparec,10);
		itoa(stpar[i].numpuntos,snpuntos,10);
		sSQL = "INSERT INTO Resultado VALUES ('" + CString(stpar[i].nombre) + "',";
		sSQL = sSQL + CString(sparec) + "," + CString(snpuntos) + ")";
		m_pBd->ExecuteSQL(sSQL);
	}
}

void CBusqDatos::MostrarResultados(int modo)
{
	ODynaset dyna;
	CString sSQL, str;
	int i, iparec, inpuntos, pos;
	char snombre[100], sparec[10], snpuntos[10], *pdest;
	
	if (modo == 0)
		UpdateData(true);

	sSQL = "SELECT * FROM Resultado";

	if (m_TxtParecido.GetLength() != 0)
		sSQL = sSQL + " WHERE Parecido >= " + m_TxtParecido;
	else
		sSQL = sSQL + " WHERE Parecido >= 0";
	
	switch(m_Parec)
	{
	case 0:
		sSQL = sSQL + " ORDER BY Parecido";
		break;
	case 1:
		sSQL = sSQL + " ORDER BY NumPuntos";
		break;
	case 2:
		sSQL = sSQL + " ORDER BY Nombre";
		break;
	}
	
	if (m_Desc == 0)
		sSQL = sSQL + " DESC";
	else
		sSQL = sSQL + " ASC";

	if (m_TxtMejores.GetLength() != 0)
		sSQL = "SELECT * FROM (" + sSQL + ") WHERE ROWNUM <= " + m_TxtMejores;

	dyna.Open(*m_pBd,sSQL);

	i = 1;
	IniciaGrid();
	while (!dyna.IsEOF())
	{
		m_Grid.SetRows(m_Grid.GetRows() + 1);

		dyna.GetFieldValue("Nombre",snombre,100);
		dyna.GetFieldValue("Parecido",&iparec);
		dyna.GetFieldValue("NumPuntos",&inpuntos);

		pdest = strrchr(snombre, '\\');
		pos = pdest - snombre + 1;
		str = CString(snombre);
		
		m_Grid.SetTextMatrix(i, (En) imagen, str.Right(str.GetLength() - pos));
		m_Grid.SetTextMatrix(i, (En) directorio, str.Left(pos - 1));
		itoa(iparec,sparec,10);
		m_Grid.SetTextMatrix(i, (En) parecido, CString(sparec));
		itoa(inpuntos,snpuntos,10);
		m_Grid.SetTextMatrix(i, (En) numpuntos, CString(snpuntos));

		dyna.MoveNext();
		i++;
	}
}

void CBusqDatos::ActualizarPenalizaciones(int valor)
{
	CString sSQL;
	char ssup[10], sinf[10];

	itoa(valor - m_Opt->margenmen,sinf,10);
	itoa(valor + m_Opt->margenmay,ssup,10);

	sSQL = "UPDATE Imagen SET Penalizacion = 0 WHERE NumPuntos >= ";
	sSQL = sSQL + CString(sinf) + " AND NumPuntos <= " + CString(ssup);
	m_pBd->ExecuteSQL(sSQL);
}

int CBusqDatos::ObtenerPenalizacion(int curvat, int numptos)
{
	int res;
	double penaliz_base;

	penaliz_base = (1.0 / (double) numptos) * 100.0;
	res = Aproximar(penaliz_base + (((double) curvat / 100.0) * (double) m_Opt->factor_penal));
	
	return res;
}

void CBusqDatos::BorrarPuntoCons()
{
	CString sSQL;

	sSQL = "DELETE FROM PuntoCons";
	m_pBd->ExecuteSQL(sSQL);
}

void CBusqDatos::BorrarPuntoM()
{
	CString sSQL;

	sSQL = "DELETE FROM PuntoM";
	m_pBd->ExecuteSQL(sSQL);
}

void CBusqDatos::BorrarResultados()
{
	m_pBd->ExecuteSQL("DELETE FROM Resultado");
}

void CBusqDatos::DibujarImagen()
{
	HBITMAP hbm;
	CString simage, sdir;

	m_Image.SetBitmap(NULL);
	simage = m_Grid.GetTextMatrix(m_Grid.GetRow(), (En) imagen);
	sdir = m_Grid.GetTextMatrix(m_Grid.GetRow(), (En) directorio);
	
	hbm = (HBITMAP) LoadImage (NULL, sdir + "\\" + simage, IMAGE_BITMAP, 200, 150, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
	if (hbm == 0x00000000) // Si no encuentra la imagen ...
	{
		simage = m_Opt->workdir + ".\\Novista.bmp";
		hbm = (HBITMAP) LoadImage (NULL, simage, IMAGE_BITMAP, 200, 150, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
	}

	m_Image.MoveWindow(468,250,0,0,true);
	m_Image.SetBitmap(hbm);
}

void CBusqDatos::CargarCajas()
{
	char s[10];
	
	if (m_Grid2.GetRow() == 0)
	{
		m_TxtOrden = "";
		m_TxtCurvatura = "";
		m_TxtDistancia = "";
		m_TxtSigno = "";
	}
	else
	{
		m_TxtOrden = m_Grid2.GetTextMatrix(m_Grid2.GetRow(), (En2) orden);
		m_TxtCurvatura = m_Grid2.GetTextMatrix(m_Grid2.GetRow(), (En2) curvatura);
		m_TxtDistancia = m_Grid2.GetTextMatrix(m_Grid2.GetRow(), (En2) distancia);
		m_TxtSigno = m_Grid2.GetTextMatrix(m_Grid2.GetRow(), (En2) signo);
	}
	
	itoa(m_Grid2.GetRows() - 1,s,10);
	m_TxtNPuntos = CString(s);

	UpdateData(false);
}

void CBusqDatos::ComprobarBotones()
{
	if (m_Grid2.GetRow() == 0)
	{
		m_ButEliminar.EnableWindow(false);
		m_ButBuscar.EnableWindow(false);
		m_Curvatura.EnableWindow(false);
		m_Distancia.EnableWindow(false);
		m_CmbSigno.EnableWindow(false);
	}
	else
	{
		m_ButEliminar.EnableWindow(true);
		m_ButBuscar.EnableWindow(true);
		m_Curvatura.EnableWindow(true);
		m_Distancia.EnableWindow(true);
		m_CmbSigno.EnableWindow(true);
	}
}

void CBusqDatos::CompruebaOpciones()
{
	UpdateData(true);

	if ((m_ChkMejora) && (m_ChkRotacion))
		m_ChkRotacion = false;

	UpdateData(false);
}

void CBusqDatos::CompruebaOpciones2()
{
	UpdateData(true);

	if ((m_ChkMejora) && (m_ChkRotacion))
		m_ChkMejora = false;

	UpdateData(false);
}

void CBusqDatos::HabilitarControles(bool modo)
{
	m_ButEliminar.EnableWindow(modo);
	m_ButGenerar.EnableWindow(modo);
	m_ButImportar.EnableWindow(modo);
	m_Curvatura.EnableWindow(modo);
	m_Distancia.EnableWindow(modo);
	m_CmbSigno.EnableWindow(modo);
	m_ButSubir.EnableWindow(modo);
	m_ButBajar.EnableWindow(modo);
}

void CBusqDatos::CargarComboGruposImagenes()
{
	ODynaset dynaBD;
	char cad[100];
	int i = 0;
	
	// Borro el posible contenido anterior del combo
	m_BD.ResetContent();

	// Abro un dynaset para cargar el combo con los grupos de imágenes
	dynaBD.Open(*m_pBd,"SELECT Nombre FROM Grupo ORDER BY Nombre");
		
	if (!dynaBD.IsEOF())
	{
		while (!dynaBD.IsEOF())
		{			
			dynaBD.GetFieldValue("nombre", cad,100);
			CString str(cad);
			m_BD.InsertString(i, str);

			dynaBD.MoveNext();
			i++;
		}
	}
	
	dynaBD.Close();
}

void CBusqDatos::SelectGrid()
{
	OnSelChangeGrid(); // Llamamos a OnSelChangeGrid
}

int CBusqDatos::MaximoNumPuntos(int todas)
{
	ODynaset dyna;
	CString sSQL;
	int imaximo;

	sSQL = "SELECT Max(Orden) AS MaxPunto FROM Punto,Imagen ";
	sSQL = sSQL + "WHERE Nombre = INombre";
	if (todas == 0)
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";

	dyna.Open(*m_pBd,sSQL);
	dyna.GetFieldValue("MaxPunto",&imaximo);

	return imaximo;
}

int CBusqDatos::TotalImagenes(int valor, int npuntos, int todas)
{
	ODynaset dyna;
	CString sSQL;
	char ssup[10], sinf[10], snpuntos[10];
	int cont;
	
	if (valor != -1)
	{
		itoa(valor - m_Opt->margenmen,sinf,10);
		itoa(valor + m_Opt->margenmay,ssup,10);

		sSQL = "SELECT Count(Nombre) AS Cont FROM Imagen WHERE NumPuntos >= ";
		sSQL = sSQL + CString(sinf) + " AND NumPuntos <= " + CString(ssup);

		if (todas == 0)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
	}
	else
	{
		itoa(npuntos,snpuntos,10);
		sSQL = "SELECT Count(Nombre) AS Cont FROM Imagen ";
		sSQL = sSQL + "WHERE NumPuntos >= " + CString(snpuntos);

		if (todas == 0)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
	}

	dyna.Open(*m_pBd,sSQL);
	dyna.GetFieldValue("Cont",&cont);

	return cont;
}

int CBusqDatos::Posicion(StParecido *parec, CString str, int total_filas)
{
	int res;
	bool fin = false;

	res = 0;
	while ((res < total_filas) && (!fin))
	{
		if (strcmp(str,parec[res].nombre) == 0)
			fin = true;
		else
			res++;
	}

	return res;
}

bool CBusqDatos::ExistenPuntos(int npuntos)
{
	ODynaset dyna;
	CString sSQL;
	char snpuntos[10];
	bool res;
	
	itoa(npuntos,snpuntos,10);
	sSQL = "SELECT Nombre FROM Imagen WHERE NumPuntos = " + CString(snpuntos);

	if (m_ChkTodas == 0)
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";

	dyna.Open(*m_pBd,sSQL);
	res = !dyna.IsEOF();
	dyna.Close();

	return (res);
}

bool CBusqDatos::EsNumero(CString s, int a, int b)
{
	bool ok = true;
	int i;
	
	if (s.GetLength() == 0)
		return false;

	i=0;
	while ((i<s.GetLength()) && (ok))
	{
		if ((s.GetAt(i) < '0') || (s.GetAt(i) > '9'))
			ok = false;
		else if ((i == 0) && (s.GetAt(i) == '0') && (s.GetLength() != 1))
			ok = false;

		i++;
	}

	if (ok)
	{
		if ((atoi(s) < a) || (atoi(s) > b))
			ok = false;
	}
	
	return ok;
}

void CBusqDatos::MostrarError(int error)
{
	switch(error)
	{
	case 1:
		MessageBox("Algún valor de curvatura no es válido.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 2:
		MessageBox("Algún valor de distancia no es válido.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 3:
		MessageBox("Algún valor de signo no es válido", "Fuzzy Finder", MB_ICONERROR);
		break;
	}
}