package yi.iu.processor.clc;

import yi.iu.processor.ort.*;
import java.util.*;

public class CLCUtil {

  /**
   * Return the weight of a line.  Generally, the weight of a line is the length
   * of it.  However, a maximum weight is enforced to prevent that one long line
   * dominants all.  Similar to the method in ORTLine:
   *   double weightedLength(double standard, double maxWeight)
   *
   * @param len the length of the line
   * @return the weight
   */
  public static double lineWeight(double len) {
    double max_line_weight = CLCConfig.getMaxLineWeight();
    double norm_line_length = CLCConfig.getNormalLineLength();

    double weight = len/norm_line_length;
    if (weight > max_line_weight) weight = max_line_weight;
    return weight;
  }

  /**
   * Return the weighted length summary of the lines in a line cluster
   * @param lines
   * @return
   */
  public static double weightedLength(LineClusterSet lines) {
    double len = 0;
    Iterator i = lines.iterator();
    while (i.hasNext()) {
      ORTLine l = (ORTLine) i.next();
      len += lineWeight(l.Length);
    }
    return len;
  }

  /**
   * Return the coordinate of the point on the line l.  Consider l as an axis.
   * If the point is close to start point of l, the coordinate will be negative,
   * otherwise positive.  The given point must on the given line, otherwise,
   * user should call coordinateToAxis(point, line)
   * @param p
   * @param l
   * @return
   */
  public static double positionOnAxis (ORTPoint p, ORTLine l)
  {
    // the middle point of line
    ORTPoint mid_point  = l.midPoint();

    // the distance from the point to the middle point of the line
    double d = ORTPoint.distance (p, mid_point);

    if (l.Start.Col != l.End.Col) {  // not vertical
        if (l.Start.Col > mid_point.Col) {  // start on the right
            if (p.Col > mid_point.Col) return -d; // p on the right too
            else return d;
        }
        else {
            if (p.Col > mid_point.Col) return d;
            else return -d;
        }
    }
    else { // vertical
        if (l.Start.Row > mid_point.Row) {
            if (p.Row>mid_point.Row) return -d;
            else return d;
        }
        else {
            if (p.Row>mid_point.Row) return d;
            else return -d;
        }
    }

  }

  /**
   * Return the coordinate of the point with respective to the axis of given
   * line.  Consider the given line as the coordinate axis.  First the point
   * will be projected to the line, then position of the line on the axis will
   * be returned.  If user knows the given point is on the given line, call
   * positionOnAxis(point, line) instead
   * @param p
   * @param l
   * @return
   */
  public static double coordinateToAxis(ORTPoint p, ORTLine l)
  {
    // project the point the line
    double[] inter= GeometricUtil.PtLinePerpIntercept(p, l);

    // find the position of the projected point with respective to the middle
    // point of the line
    return positionOnAxis(new ORTPoint(inter[0],inter[1]), l);
  }
}