
#ifndef __MLISTECOUPLES__
#define __MLISTECOUPLES__

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <list>

#include "MListePI.h"
#include "MDetecteur.h"

using namespace std;

class MCouple
{
protected:
	float x1,y1,x2,y2;
	float score;		//score ZNCC
	float scoreSM;

	//utilise par les algo qui conservent les meilleurs appariements
	int selected; //-1: non defini, 0: non selectionne, 1: selectionne
	
public:
	MCouple() {}
	MCouple(float inX1,float inY1,float inX2,float inY2,float inScore)
			{x1=inX1;y1=inY1;x2=inX2;y2=inY2;score=inScore;scoreSM=0;selected=-1;}
	float getScore()	{return score;}
	float getScoreSM()	{return scoreSM;}
	void setScoreSM(float inScoreSM)	{scoreSM=inScoreSM;}
	float getX1() {return x1;}
	float getY1() {return y1;}
	float getX2() {return x2;}
	float getY2() {return y2;}
	void setX1(float xx1) {x1=xx1;}
	void setY1(float yy1) {y1=yy1;}
	void setX2(float xx2) {x2=xx2;}
	void setY2(float yy2) {y2=yy2;}

	int getSelected(void) {return selected;}
	void setSelected(int s) {selected=s;}
	void select(void) {selected=1;}
	void deselect(void) {selected=0;}
	bool NotSelected(void) {return (selected!=1);}
	bool Selected(void) {return (selected==1);}
	
	friend float Distance1(MCouple& c1,MCouple& c2) {return sqrt((c1.x1-c2.x1)*(c1.x1-c2.x1)+(c1.y1-c2.y1)*(c1.y1-c2.y1));}
	friend float Distance2(MCouple& c1,MCouple& c2) {return sqrt((c1.x2-c2.x2)*(c1.x2-c2.x2)+(c1.y2-c2.y2)*(c1.y2-c2.y2));}
};

typedef list< MCouple > TlistMCouple;

class MListeCouples
{
protected:
	TlistMCouple listeCouples;
	int nbCouples;

	int nbSelected;	//nombre de couples marques selectionnes
	
public:

  MListeCouples() {nbCouples=0;nbSelected=0;}

  //La méthode Apparie crée la liste de couples, conserve les meilleurs appariements
  //et calcule une localisation subpixellique des points retenus
  void Apparie(MListePI& ListePI1,MDetecteur& Detecteur1,MListePI& ListePI2,MDetecteur& Detecteur2,int xROI,int yROI,float ScoreMin);
  
	//Creation de tous les couples a partir de 2 listes de points d'interet
	//le precalcul ZNCC doit avoir ete fait
	//la recherche de couples se fait dans une region d'interet rectangulaire de dimensions largeur=2*xROI+1, hauteur=2*yROI+1
	void CreateSansZones(MListePI& ListePI1,MListePI& ListePI2,int xROI,int yROI,float ScoreMin);
  //la même fonction avec optimisation (il vaut mieux appeler celle-la
	int Create(MListePI& ListePI1,MListePI& ListePI2,int xROI,int yROI,float ScoreMin);

	//Ajout d'un couple dans la liste
	void Add(int x1,int y1,int x2,int y2,float score)
					{Add(float(x1),float(y1),float(x2),float(y2),score);}
	void Add(float x1,float y1,float x2,float y2,float score)
					{MCouple c=MCouple(x1,y1,x2,y2,score);listeCouples.push_front(c);nbCouples++;}

	//Vide la liste
	void Empty();
	
	//Supprime tous les couples contenant un des 2 points (x1,y1) ou (x2,y2)
	void Remove(float x1,float y1,float x2,float y2);
	//Supprime tous les couples (non marques selected) contenant un des 2 points (x1,y1) ou (x2,y2)
	void RemoveNotSelected(float x1,float y1,float x2,float y2);

  //Recherche un couple dont le premier point est (x1,y1). Renvoie 0 si non trouve
	MCouple* FindPoint1(float x1,float y1);
	
	//Recherche du couple Co avec le score le plus eleve. Le couple Co est marque "selected"
	//tous les couples restant qui contenaient un des 2 points de Co sont supprimés
	//S'il n'y a plus de couple, la fonction renvoie 0
  int SelectBest();
	
  //Conserve seulement les meilleurs couples
  //renvoie le nombre de couples conserves
	int KeepBest();
	
	//Calcul plus precis des coordonnees des 2 points du couple
	//On doit fournir les detecteurs ayant servi a calculer chacun des 2 points
  void RaffineCoords(MDetecteur& Detecteur1,MDetecteur& Detecteur2);
	
  //Nombre de couples
  int getNbCouples(void) {return listeCouples.size();}
  //Nombre de couples avec drapeau selected a 1
  int getNbCouplesSelected(void);

  //Acces a la liste des couples
  TlistMCouple* getListe(void) {return &listeCouples;}

  //Positionnement du drapeau selected pour tous les couples de la liste
  void SetSelectedAll(int inS);

	//Lectures de 4 couples donnés par leur numéro dans la liste
	void GetCoords4Couples(int n0,int n1,int n2,int n3,float* x1,float* y1,float *x2,float* y2);
	//Lectures des coords d'un couple donné par son numéro dans la liste
	void GetCoords(int n0,float& x1,float& y1,float& x2,float& y2);

  //----------------------------------------------------------------------------------------------------
	//Methode de relaxation (Zhengyou ZHANG)
	//la liste ne doit pas avoir ete modifiee entre l'appel de Create et l'appel des fonctions qui suivent

	//Calcul du strength of match pour un couple donne.
	float CalculeSM(MCouple& Couple);
	//Calcul des scoreSM pour tous les couples de la liste
  void CalculeSM();
	//Suppression de certains couples de la liste
	//renvoie 0 quand il n'est plus possible d'optimiser (plus de couples a supprimer)
	int IterationOptimiseSM();
	//Boucle d'optimisation complete : en sortie on obtient une liste d'appariements definitifs
	//la methode renvoie le nombre de couples retenus
	int OptimiseSM();
};

#endif

