//! prend le plus lointain des spots visibles
int itsHybridContinuousInteractingAntColony::antGetFarerInCloseSpot( int antId )
{
  vector<int> spotsIds = antGetCloseSpots( antId );
  
  unsigned int n = spotsIds.size();

  // si n'existe pas de spots
  if ( n == 0 ) {
    return -1;
  }
  
  double bigestDistance = distanceEuclidian( antCurrentPoint[antId], spotsPoints[spotsIds[0]] );
  int fareSpotId = 0;

  // si plus de 1 spots
  if ( n>1 ) {
    unsigned int i;
    for ( i=1; i<n; i++ ) {
      // distance entre la fourmi et ce spot
      double dist = distanceEuclidian( antCurrentPoint[antId], spotsPoints[i] );
      // si distance plus grande que la plus grande
      if ( dist > bigestDistance ) {
        bigestDistance = dist;
        fareSpotId = i;
      }
    }
  }

  return fareSpotId;
}
/********** r�up�e les indices des spots les plus proches **********/
int itsHybridContinuousInteractingAntColony::antGetCloserSpot( int antId )
{
  unsigned int n = spotsValues.size();

  // si existe des spots
  if (n==0) {
    return -1;
  }
  
  // r�erve le plus possible d'espace
  vector<int> spotsIds;
  spotsIds.reserve( n );
  
  double shortestDistance = distanceEuclidian( antCurrentPoint[antId], spotsPoints[0] );
  int closestSpotId = 0;

  // si plus de 1 spots
  if ( n>1 ) {
    unsigned int i;
    for ( i=1; i<n; i++ ) {
      // si le spot est dans la zone visible
      double dist = distanceEuclidian( antCurrentPoint[antId], spotsPoints[i] );
      if ( dist < shortestDistance ) {
        shortestDistance = dist;
        closestSpotId = i;
      }
    }
  }

  return closestSpotId;
}
/********** r�up�e les indices des spots les plus proches **********/
vector<int> itsHybridContinuousInteractingAntColony::antGetCloseSpots( int antId )
{
  unsigned int n = spotsValues.size();
  
  if ( n==0 ) {
    vector<int> nullVec;
    return nullVec;
  }
  
  // r�erve le plus possible d'espace
  vector<int> spotsIds;
  spotsIds.reserve( n );
  
  unsigned int i;
  for ( i=0; i<n; i++ ) {
    // si le spot est dans la zone visible
    /*int k = 0;
    for( int j=0; j<this->getProblem()->getDimension(); j++ ) {
      if( abs( antCurrentPoint[antId][j] - spotsPoints[i][j] ) < antMoveRange[antId][j] ) {
	k++;
      }
      }
      
    if ( k == this->getProblem()->getDimension() ) {
      spotsIds.push_back( i );
      }*/
    
    double dist = distanceEuclidian( antCurrentPoint[antId], spotsPoints[i] );
    if ( dist < antMoveRange[antId] ) {
      spotsIds.push_back( i );
    }
  }

  return spotsIds;
}
/********** d�ose un spot **********/ 
void itsHybridContinuousInteractingAntColony::antSpotLay( int antId, vector< double > point, double value )
{
  vector<int> spots = antGetCloseSpots( antId );
  
  // si pas de spots visibles
  if ( spots.size() == 0 ) {
    // d�ot d'un nouveau spot
    spotsValues.push_back( value );
    spotsPoints.push_back( point );
  } else {
    // renforcement d'un spot
    // FIXME : fonction de renforcement non lin�ire?
    int spot = antGetCloserSpot( antId );
    spotsValues[spot] += spotsValues[spot] / 2; // une moiti�en plus
    
    // baisse zone visible
    spot = antGetFarerInCloseSpot( antId );
    
    
    // FIXME il vaudrait mieux prendre la distance euclidienne au spot que de d�inir ainsi un hypercube sur chaque dimensions...
    /*for ( int i=0; i<this->getProblem()->getDimension(); i++ ) {
      antMoveRange[antId][i] = abs( spotsPoints[spot][i] - antCurrentPoint[antId][i] );
      }*/

    antMoveRange[antId] = distanceEuclidian( antCurrentPoint[antId], spotsPoints[spot] );

    printDebug( "antMoveRange", antMoveRange[0]);
  }
}
 double get_max_distance(int quarter, 
 	                Point2f point, Size size) {		
 	Point2f p1 = Point2f(0, 0);
 	Point2f p2 = Point2f(size.width, 0);
 	Point2f p3 = Point2f(size.width, size.height);
 	Point2f p4 = Point2f(0, size.height);
 	switch(quarter) {
 	case 1: 
 		return distanceEuclidian(point, p3);
 	case 2: 
 		return distanceEuclidian(point, p4);
 	case 3:
 		return distanceEuclidian(point, p2);
 	case 4: 
 		return distanceEuclidian(point, p1);
 	}
 }
  vector<Match> get_corresp_points(Mat *left_image, 
  				 Mat *right_image, 
  				 int cornercount = 12) {
  	Mat firstImg, secondImg;
  	vector<Point2f> resf;
  	vector<Match> res_matches;

  	vector<uchar> status;
  	vector<float> err;

  	cvtColor(*left_image, firstImg, CV_RGB2GRAY); 
  	cvtColor(*right_image, secondImg, CV_RGB2GRAY);

  	int width, height;
  	width = min(firstImg.cols,secondImg.cols);
  	height = min(firstImg.rows,secondImg.rows);
  	int thresh = 240;

  	firstImg = firstImg(Rect(0, 0, width, height)); 
  	secondImg = secondImg(Rect(0, 0, width, height));
  	mask = mask(Rect(0, 0, width, height));

  	blockSize = min(height/2, width/2) - 2;
  	if (blockSize < 1 ) return res_matches;

  	GoodFeaturesToTrackDetector detector(
  			cornercount,
  			qualitylevel,
  			minDistance,
  			blockSize,
  			false, k);
  	vector<KeyPoint> keypoints_1, keypoints_2;
  	detector.detect(firstImg, keypoints_1, mask);
  	detector.detect(secondImg, keypoints_2, mask);

  	SurfDescriptorExtractor extractor; 
  	Mat descriptors1, descriptors2;

  	extractor.compute(firstImg, 
  			  keypoints_1, 
  			  descriptors1);
  	extractor.compute(secondImg, 
  			  keypoints_2, 
  			  descriptors2);

  	BruteForceMatcher<L2<float>> matcher;
  	vector<DMatch> matches; 
  	matcher.match(descriptors1, descriptors2, matches);
  	double distance;
  	bool contains1 = false, contains2 = false;
  	int index;

  	for(int k = 0; k < matches.size(); k++) {
  		distance = distanceEuclidian(
  		 keypoints_1[matches[k].queryIdx].pt,
  		 keypoints_2[matches[k].trainIdx].pt) ;
  		if (distance < 50) {
  			for (int l = 0; 
  			     l < res_matches.size(); l++) {
  			  if (keypoints_1
  			      [matches[k].queryIdx].pt 
  				== res_matches[l].first_pt) {
  			    contains1 = true; 
  			    break;
  			  }
  			  if (keypoints_2
  			       [matches[k].trainIdx].pt 
  				 == res_matches[l].second_pt) {
  			    contains2 = true; 
  			    break;
  			  }
  			}
  			if (!contains1 && ! contains2) {
  			  res_matches.push_back(
  			   Match(keypoints_1
  				 [matches[k].queryIdx].pt,
  				 keypoints_2
  				 [matches[k].trainIdx].pt,
  				 distance)); 
  			}
  			contains1 = false; 
  			contains2 = false;
  		}
  	}
  	return res_matches;
  }