package yi.iu.imgdb.learn.absrgn;

import yi.iu.imgdb.learn.FeatureRepresentationList;
import yi.iu.imgdb.learn.FeatureRepresentable;
import java.util.*;
import yi.iu.imgdb.learn.*;

/**
 * AbsRgnBiRelFeatures are features contains abstract region bi-relations
 */

public class AbsRgnBiRelFeatures implements FeatureRepresentable {

  /**
   * linked list of ClassifiedAbsRgn
   * AbsRgnBiRelGenerator consider the relationship between any two
   * ellipse(s).  Although eventually, ellipse
   * should be replaced by abstract regions so that the
   * feature representation considered can be represented by any kind of
   * abstract region (eg. ellipse or polygon)
   */
  LinkedList m_classifedRgns;

  static Random rand = new Random();
  public final static double NARROWED_DEV = 0.01;

  public AbsRgnBiRelFeatures(LinkedList classified_rgns) {
    m_classifedRgns = classified_rgns;
  }

  /**
   * For each pair of the abstract region, return a feature vector
   * @param processor_name
   * @param mode
   * @return
   * @throws Exception
   */
  public FeatureRepresentationList represent(String processor_name, int mode) throws Exception {
    if (mode == 0) {
      // in the returned feature vector:
      // the cluster index number of region 1, the cluster index number of region 2
      // (the value of first one is less than that of the second one).
      // the distance of the center of two regions (normalized)
      // the orientation of the line from the center of region 1 to the center
      // of region 2 (it is not good to cut the orientation around horizontal
      // angle, vertical angle, 45 degree).  Since top-bottom relation is more
      // important than left-right relation, make the cut point as 45/2~=25 degree
      FeatureRepresentationList rst = new FeatureRepresentationList(4);
      for (int i=0; i<m_classifedRgns.size(); i++) {
        for (int j=i+1; j<m_classifedRgns.size(); j++) {
          ClassifiedAbsRgn rgn1 = (ClassifiedAbsRgn)m_classifedRgns.get(i);
          ClassifiedAbsRgn rgn2 = (ClassifiedAbsRgn) m_classifedRgns.get(j);
          // make sure the cluster index of rgn1 is less than that of rgn2
          if (rgn1.clusterIndex > rgn2.clusterIndex) {
            ClassifiedAbsRgn t = rgn1;
            rgn1 = rgn2; rgn2 = t;
          }
          // index of rgn1 and rgn2
          double index1 = rgn1.clusterIndex +
              ((rand.nextDouble() >= 0.5)?1:-1) * rgn1.normDist * NARROWED_DEV;
          double index2 = rgn2.clusterIndex +
              ((rand.nextDouble() >= 0.5)?1:-1) * rgn2.normDist * NARROWED_DEV;
          double x1 = rgn1.region.getNormalizedX();
          double y1 = rgn1.region.getNormalizedY();
          double x2 = rgn2.region.getNormalizedX();
          double y2 = rgn2.region.getNormalizedY();

          double dx = x1 - x2, dy = y1 - y2;
          double dist = Math.sqrt(dx * dx + dy * dy);

          double orientation = Math.atan2(dy, dx); // return -PI, +PI
          // cut orientation at 25 degree
          if (orientation < (25.0/180*Math.PI)) orientation += Math.PI * 2;
          rst.addFeatureRepresentation(new FeatureRepresentation(new double[]{index1, index2, dist, orientation}));
        }
      }
//      yi.util.io.OutputResult.print(System.out, rst.as2DDoubleArray());
      return rst;
    }
    return null;
  }

}