package yi.iu.processor.line;

import java.util.*;
import java.awt.*;
import yi.iu.processor.color.*;
import yi.iu.processor.ort.*;
import yi.stat.hist.*;
import yi.util.config.*;
import yi.util.io.*;

/**
 * Class LineColorPairs extracts the color pairs of a line.  There are two
 * possible ways to init the class.  One is to give the lines and the color index
 * image (which is precalculated); anther is to give the lines and the original
 * image which will be processed to get the color index image first.
 *
 * This class and the main functinality is extracted from
 * yi.iu.processor.clc.CSCLC
 *
 * Example:
 *
 *   LineColorPairs lcp = new LineColorPairs(int[] rgb, int width, int height);
 *
 *   // get the color pair indices of a line
 *   Collection color_pair_indices = lcp.getLineColorPairs(ORTLine);
 *
 *   // get the corresponding color pairs of those indices
 *   Iterator i = color_pair_indices.iterator;
 *   while (i.hasMore()) {
 *     ColorPair cp = (ColorPair)i.getNext();
 *   }
 *
 */
public class LineColorPairs implements Configurable{
  public final static int COLOR_PAIR_METHOD_1 = 1;
  public final static int COLOR_PAIR_METHOD_2 = 2;
  public final static int COLOR_PAIR_METHOD_3 = 3;
  public final static int COLOR_PAIR_METHOD_4 = 4;
  public final static int COLOR_PAIR_METHOD_5 = 5;

  public int COLOR_PAIR_METHOD = COLOR_PAIR_METHOD_2;

  boolean SHOW_STEPS = false;

  int LINEWIDTH = 3;

  /**
   * The pixel->color_index map.  Usually, the color number is small enough for
   * efficient line color calculation.  For example, use only the dominant colors
   * instead of all the colors from original image.
   */
  int[] m_colorIndexImage;

  /**
   * The real color RGB values corresponding to the color indices.  While
   * m_colorIndexImage stores the color index; this array stores the corresponding
   * real color values.
   */
  int[] m_colors;

  /**
   * The color number in the image.  Should always be m_colors.length.
   * see #m_colors.
   */
  int m_colorNum;

  /**
   * Image width
   */
  int m_imgWidth;

  /**
   * Image height
   */
  int m_imgHeight;

  public String[] getParameterNames() {
    return new String[] {
        "COLOR_PAIR_METHOD",
    };
  }


  /**
   * Init a LineColorPairs instance with a given image.  First, the dominant
   * colors are extracted as saved for later use
   * @param rgb    the image pixeles
   * @param width  the image width
   * @param height the image heigth
   * @see yi.iu.processor.color.DPU_DominantColor
   */
  public LineColorPairs(int[] rgb, int width, int height) {
    Configuration.configParameters(this);

    // use DPU_DominantColor to get the dominant colors
    DPU_DominantColor dpu_dc = new DPU_DominantColor();
    DS_DominantColor ds_dc = dpu_dc.getReusableDominantColors(rgb, width, height);
    if (SHOW_STEPS) {
      int[] dc_img = dpu_dc.getDemo(rgb, width, height);
      String img_name = Configuration.getStringParameter("SOURCE_NAME",
          "unknown");
      OutputResult.outputGIFImage(img_name + ".dc.gif", dc_img, width, height);
    }
    Collection colors = ds_dc.getDominantColors();

    m_colors = new int[colors.size()];
    {
      Iterator i = colors.iterator();
      int j = 0;
      while (i.hasNext()) {
        m_colors[j++] = CIELab.lab2rgb((CIELab)i.next());
      }
    }
    m_colorNum = m_colors.length;
    if (SHOW_STEPS) {
      int[] colors_img = yi.iu.processor.color.ColorUtil.createSpectrum(m_colors, 20, 20);
      String img_name = Configuration.getStringParameter("SOURCE_NAME",
          "unknown");
      OutputResult.outputGIFImage(img_name + ".colors.gif", colors_img, 20 * m_colorNum, 20);
    }

    m_colorIndexImage = ds_dc.getColorMap();
    m_imgHeight = height;
    m_imgWidth = width;
  }

  /**
   * Init a LineColorPairs instance with preprocessed color index image.  The
   * corresponding colors are given in the parameter colors.  The total color
   * number should be small enough for efficient line color calculation.  For
   * example, use only the dominant colors instead of all the colors from
   * original image.
   * @param color_index_image the image presented in indexed colors.
   * @param width  the image width
   * @param height the image heigth
   * @param colors the real color values refered by the color indices in the
   *               the parameter of color_index_image
   */
  public LineColorPairs(int[] color_index_image, int width, int height, int[] colors) {
    Configuration.configParameters(this);
    m_colorIndexImage = color_index_image;
    m_colors = colors;
    m_colorNum = colors.length;
    m_imgHeight = height;
    m_imgWidth = width;
  }

  /**
   * Extract the color features (color pairs) of a given line.  A window on each
   * size of the line is considered.  The numbers of pixels having the same color
   * are counted.  Those colors taken by enough pixels (no less than the given
   * threshold) are considered as possible colors on that side of the line.
   * The returning color pairs are composed of one qualified color from one side
   * of the line and another from the another side.  To improve the robustness
   * of the algorithm, the center of the windows are shifted several times
   * (specified by window_shift).  If a color is qualified in one window, then
   * it is qualified in that side of the line.
   *
   * For example, for a line (5,0)->(5,9), if windows_shift = 3, and
   * win_width = 3.  Then for the left of line, three windows are considered:
   * (3,0)->(5,9), (2,0)->(4,9), and (1,0)->(3,9).  For the right of the line:
   * (5,0)->(7,9), (6,0)->(8,9), and (7,0)->(9,9).
   *
   * See the inner class TestGetLineColorPairs for a full test example.
   *
   * @param line the line
   * @param qualify_threshold the threshold for a color to be qualified to be
   *                          one possible color on one side of the line.  It is
   *                          related to win_width.  If win_width = 3, 33% is a
   *                          good choice; if win_width = 1, 50% is a good
   *                          choice.
   * @param windows_shift the window shift step.  3 is a reasonable choice.
   * @param win_width the window width.  It is better to be a odd number. 1 and
   *                  3 are good choices.
   * @return a Set of ColorPair
   */
  public Set getLineColorPairs(ORTLine line, double qualify_threshold, int windows_shift, int win_width)
  {
    switch (COLOR_PAIR_METHOD) {
      case COLOR_PAIR_METHOD_2:
        return getLineColorPairs2(line, qualify_threshold, windows_shift, win_width);
      case COLOR_PAIR_METHOD_3:
        return getLineColorPairs3(line, qualify_threshold, windows_shift, win_width);
      case COLOR_PAIR_METHOD_4:
        return getLineColorPairs4(line, qualify_threshold, windows_shift, win_width);
      case COLOR_PAIR_METHOD_5:
        return getLineColorPairs5(line, qualify_threshold, windows_shift, win_width);
    }


    ORTLine shift= null;

    int line_thickness = (win_width - 1)/2;

    // to record the maximum value in each bin
    SimpleHistogram hist_max1 = new SimpleHistogram(m_colorNum);
    SimpleHistogram hist_max2 = new SimpleHistogram(m_colorNum);
    int window_size1 = 0, window_size2 = 0;

    //color on the +90 side
    for (int i=0; i<windows_shift; i++)    {  // loop on window shift step
      shift = line.makeNewLineByAngleShift(line_thickness + i, Math.PI/2);
      SimpleHistogram h = colorHistOnALine(shift, line_thickness);
      if (h.getTotal() > window_size1) window_size1 = h.getTotal();
      hist_max1.pickUpMaximum(h);
    }

    //color on the -90 side
    for (int i=0; i<windows_shift; i++)    {  // loop on window shift step
      shift = line.makeNewLineByAngleShift(line_thickness + i, - Math.PI/2);
      SimpleHistogram h = colorHistOnALine(shift, line_thickness);
      if (h.getTotal() > window_size2) window_size2 = h.getTotal();
      hist_max2.pickUpMaximum(h);
    }

    // filter the colors
    int threshold1 = (int)Math.ceil(window_size1 * qualify_threshold);
    java.util.List qualified_colors1 = hist_max1.passThreshold(threshold1);
    int threshold2 = (int)Math.ceil(window_size2 * qualify_threshold);
    java.util.List qualified_colors2 = hist_max2.passThreshold(threshold2);

    HashSet color_pairs = new HashSet();
    Iterator i = qualified_colors1.iterator();
    while (i.hasNext()) {
      int color_index1 = ((Integer)i.next()).intValue();
      Iterator j = qualified_colors2.iterator();
      while (j.hasNext()) {
        int color_index2 = ((Integer)j.next()).intValue();
        if (color_index1 <= color_index2) {
          color_pairs.add(new ColorPair(m_colors[color_index1], m_colors[color_index2]));
        }
        else color_pairs.add(new ColorPair(m_colors[color_index2], m_colors[color_index1]));
      }
    }

    return color_pairs;

  }

  public Set getLineColorPairs2(ORTLine line, double qualify_threshold, int windows_shift, int win_width)
  {

      ORTLine shift= null;

      int line_thickness = (win_width - 1)/2;

      // to record the maximum value in each bin
      SimpleHistogram hist_max1 = new SimpleHistogram(m_colorNum);
      SimpleHistogram hist_max2 = new SimpleHistogram(m_colorNum);
      int window_size1 = 0, window_size2 = 0;

      //color on the +90 side
      for (int i=1; i<=windows_shift; i++)    {  // loop on window shift step
        shift = line.makeNewLineByAngleShift(line_thickness + i, Math.PI/2);
        SimpleHistogram h = colorHistOnALine(shift, line_thickness);
        if (h.getTotal() > window_size1) window_size1 = h.getTotal();
        hist_max1.pickUpMaximum(h);
      }

      //color on the -90 side
      for (int i=1; i<=windows_shift; i++)    {  // loop on window shift step
        shift = line.makeNewLineByAngleShift(line_thickness + i, - Math.PI/2);
        SimpleHistogram h = colorHistOnALine(shift, line_thickness);
        if (h.getTotal() > window_size2) window_size2 = h.getTotal();
        hist_max2.pickUpMaximum(h);
      }

      // filter the colors
      int threshold1 = (int)Math.ceil(window_size1 * qualify_threshold);
      java.util.List qualified_colors1 = hist_max1.passThreshold(threshold1);
      int threshold2 = (int)Math.ceil(window_size2 * qualify_threshold);
      java.util.List qualified_colors2 = hist_max2.passThreshold(threshold2);

      HashSet color_pairs = new HashSet();

      // colors on two side
      for (Iterator i = qualified_colors1.iterator(); i.hasNext();) {
        int color_index1 = ((Integer)i.next()).intValue();
        for (Iterator j = qualified_colors2.iterator();j.hasNext();) {
          int color_index2 = ((Integer)j.next()).intValue();
          if (color_index1 <= color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index1], m_colors[color_index2]));
          }
          else color_pairs.add(new ColorPair(m_colors[color_index2], m_colors[color_index1]));
        }
      }

      return color_pairs;
  }

  public Set getLineColorPairs3(ORTLine line, double qualify_threshold, int windows_shift, int win_width)
  {

      ORTLine shift= null;

      int line_thickness = (win_width - 1)/2;

      // to record the maximum value in each bin
      SimpleHistogram hist_max1 = new SimpleHistogram(m_colorNum);
      SimpleHistogram hist_max2 = new SimpleHistogram(m_colorNum);
      int window_size1 = 0, window_size2 = 0;

      //color on the +90 side
      for (int i=1; i<=windows_shift; i++)    {  // loop on window shift step
        shift = line.makeNewLineByAngleShift(line_thickness + i, Math.PI/2);
        SimpleHistogram h = colorHistOnALine(shift, line_thickness);
        if (h.getTotal() > window_size1) window_size1 = h.getTotal();
        hist_max1.pickUpMaximum(h);
      }

      //color on the -90 side
      for (int i=1; i<=windows_shift; i++)    {  // loop on window shift step
        shift = line.makeNewLineByAngleShift(line_thickness + i, - Math.PI/2);
        SimpleHistogram h = colorHistOnALine(shift, line_thickness);
        if (h.getTotal() > window_size2) window_size2 = h.getTotal();
        hist_max2.pickUpMaximum(h);
      }

      // color on itself
      SimpleHistogram itself = colorHistOnALine(line, 0);

      // filter the colors
      int threshold1 = (int)Math.ceil(window_size1 * qualify_threshold);
      java.util.List qualified_colors1 = hist_max1.passThreshold(threshold1);
      int threshold2 = (int)Math.ceil(window_size2 * qualify_threshold);
      java.util.List qualified_colors2 = hist_max2.passThreshold(threshold2);

      int threshold = (int)Math.ceil(itself.getTotal() * qualify_threshold);
      java.util.List qualified_colors = itself.passThreshold(threshold);

      HashSet color_pairs = new HashSet();

      // colors on two side
      for (Iterator i = qualified_colors1.iterator(); i.hasNext();) {
        int color_index1 = ((Integer)i.next()).intValue();
        for (Iterator j = qualified_colors2.iterator();j.hasNext();) {
          int color_index2 = ((Integer)j.next()).intValue();
          if (color_index1 <= color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index1], m_colors[color_index2]));
          }
          else color_pairs.add(new ColorPair(m_colors[color_index2], m_colors[color_index1]));
        }
      }

      // color pairs with one color on a side and another on itself
      for (Iterator i = qualified_colors.iterator(); i.hasNext();) {
        int color_index1 = ((Integer)i.next()).intValue();
        // one side
        for (Iterator j = qualified_colors1.iterator();j.hasNext();) {
          int color_index2 = ((Integer)j.next()).intValue();
          if (color_index1 < color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index1], m_colors[color_index2]));
          }
          else if (color_index1 > color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index2],
                                          m_colors[color_index1]));
          }
        }
        // another side
        for (Iterator j = qualified_colors2.iterator();j.hasNext();) {
          int color_index2 = ((Integer)j.next()).intValue();
          if (color_index1 < color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index1], m_colors[color_index2]));
          }
          else if (color_index1 > color_index2) {
            color_pairs.add(new ColorPair(m_colors[color_index2],
                                          m_colors[color_index1]));
          }
        }
      }
      return color_pairs;
  }

  public Set getLineColorPairs4(ORTLine line, double qualify_threshold, int windows_shift, int win_width)
  {
    // calculate the histograms of middle line, shift-1, and shift+1
    SimpleHistogram histogram = colorHistOnALine(line, 0);
    ORTLine shift_left = line.makeNewLineByAngleShift(1, Math.PI/2);
    SimpleHistogram histogram_left = colorHistOnALine(shift_left, 0);
    ORTLine shift_right = line.makeNewLineByAngleShift(1, - Math.PI/2);
    SimpleHistogram histogram_right = colorHistOnALine(shift_right, 0);


    // decide which part, left or right, the middle line should belong to
    if (histogram.difference(histogram_left) <
        histogram.difference(histogram_right)) {
      histogram_left = histogram;
    }
    else if (histogram.difference(histogram_left) >
        histogram.difference(histogram_right)) {
      histogram_right = histogram;
    }

    HashSet color_pairs = new HashSet();

    try {

      // find the color candidate
      int best_candidate_left = histogram_left.getValueWithMaxCount();
      double best_candidate_score_left =
          histogram_left.getCount(best_candidate_left) /
          (double) histogram_left.getTotal();
      int best_candidate_right = histogram_right.getValueWithMaxCount();
      double best_candidate_score_right =
          histogram_right.getCount(best_candidate_right) /
          (double) histogram_right.getTotal();

      if (best_candidate_left == best_candidate_right) {
        if (best_candidate_score_left > best_candidate_score_right) {
          shift_right = line.makeNewLineByAngleShift(2, -Math.PI / 2);
          SimpleHistogram expand = colorHistOnALine(shift_right, 0);
          histogram_right.add(expand);
          best_candidate_right = histogram_right.getValueWithMaxCount();
          best_candidate_score_right = histogram_right.getCount(
              best_candidate_right) / (double) histogram_right.getTotal();
          if (best_candidate_left == best_candidate_right) {
            histogram_right.setCount(best_candidate_right, 0);
            best_candidate_right = histogram_right.getValueWithMaxCount();
            best_candidate_score_right = histogram_right.getCount(
                best_candidate_right) / (double) histogram_right.getTotal();
          }
        }
        else if (best_candidate_score_left < best_candidate_score_right) {
          shift_left = line.makeNewLineByAngleShift(2, Math.PI / 2);
          SimpleHistogram expand = colorHistOnALine(shift_left, 0);
          histogram_left.add(expand);
          best_candidate_left = histogram_left.getValueWithMaxCount();
          best_candidate_score_left =
              histogram_left.getCount(best_candidate_left) /
              (double) histogram_left.getTotal();
          if (best_candidate_left == best_candidate_right) {
            histogram_left.setCount(best_candidate_left, 0);
            best_candidate_left = histogram_left.getValueWithMaxCount();
            best_candidate_score_left =
                histogram_left.getCount(best_candidate_left) /
                (double) histogram_left.getTotal();
          }

        }
      }

      if (best_candidate_left < best_candidate_right) {
        color_pairs.add(new ColorPair(m_colors[best_candidate_left],
                                      m_colors[best_candidate_right]));
      }
      else {
        color_pairs.add(new ColorPair(m_colors[best_candidate_right],
                                      m_colors[best_candidate_left]));
      }
    }
    catch (OutOfHistRangeException e) {
      e.printStackTrace();
    }
    return color_pairs;
  }

  public Set getLineColorPairs5(ORTLine line, double qualify_threshold, int windows_shift, int win_width)
  {
    // calculate the histograms of middle line, shift-1, and shift+1
    SimpleHistogram histogram_mid = colorHistOnALine(line, 0);
    ORTLine shift_left = line.makeNewLineByAngleShift(1, Math.PI / 2);
    SimpleHistogram histogram_left = colorHistOnALine(shift_left, 0);
    ORTLine shift_right = line.makeNewLineByAngleShift(1, -Math.PI / 2);
    SimpleHistogram histogram_right = colorHistOnALine(shift_right, 0);

    Set color_pairs = new HashSet();
    try {

      // find the color candidate
      int best_candidate_left = histogram_left.getValueWithMaxCount();
      double best_candidate_score_left =
          histogram_left.getCount(best_candidate_left) /
          (double) histogram_left.getTotal();
      int best_candidate_right = histogram_right.getValueWithMaxCount();
      double best_candidate_score_right =
          histogram_right.getCount(best_candidate_right) /
          (double) histogram_right.getTotal();
      int best_candidate_mid = histogram_mid.getValueWithMaxCount();
      double best_candidate_score_mid =
          histogram_mid.getCount(best_candidate_mid) /
          (double) histogram_mid.getTotal();

      if (best_candidate_left != best_candidate_mid) {
        color_pairs.add(createOrderedColorPair(best_candidate_left,
                                               best_candidate_mid));
      }
      if (best_candidate_right != best_candidate_mid) {
        color_pairs.add(createOrderedColorPair(best_candidate_right,
                                               best_candidate_mid));
      }

      // if the best candidates are the same, use the second best
      if (color_pairs.size() == 0) {
        int the_best = best_candidate_mid; // one color for sure
        // find the second best
        histogram_left.setCount(best_candidate_left, 0);
        best_candidate_left = histogram_left.getValueWithMaxCount();
        best_candidate_score_left = best_candidate_left >= 0 ?
                  histogram_left.getCount(best_candidate_left) /
                  (double) histogram_left.getTotal() : 0;
        int second_best = best_candidate_left;
        double second_best_score = best_candidate_score_left;

        histogram_right.setCount(best_candidate_right, 0);
        best_candidate_right = histogram_right.getValueWithMaxCount();
        best_candidate_score_right = best_candidate_right >= 0 ?
            histogram_right.getCount(
            best_candidate_right) / (double) histogram_right.getTotal() : 0;
        if (best_candidate_score_right > second_best_score) {
          second_best = best_candidate_right;
          second_best_score = best_candidate_score_right;

        }

        histogram_mid.setCount(best_candidate_mid, 0);
        best_candidate_mid = histogram_mid.getValueWithMaxCount();
        best_candidate_score_mid = best_candidate_mid >= 0 ?
            histogram_mid.getCount(
            best_candidate_mid) / (double) histogram_mid.getTotal() : 0;
        if (best_candidate_score_mid > second_best_score) {
          second_best = best_candidate_mid;
          second_best_score = best_candidate_score_mid;

        }

        if (second_best_score > 0) {
          color_pairs.add(createOrderedColorPair(the_best,
                                               second_best));
        }

      }

    } catch (OutOfHistRangeException e) {
      e.printStackTrace();
    }

    if (color_pairs.size() == 0) {
      System.out.println("A line having the same colors, ignored: " + line);
    }

    return color_pairs;
  }

  /**
   * Generate a ColorPair with colors having index of c1, c2 or c2, c1 (smaller
   * first)
   * @param c1
   * @param c2
   * @return
   */
  ColorPair createOrderedColorPair(int c1, int c2) {
    if (c1 <= c2) return new ColorPair(m_colors[c1], m_colors[c2]);
    else return new ColorPair(m_colors[c2], m_colors[c1]);
  }

  /**
   * Calculate the color histogram of the pixels of a line
   * @param line the line
   * @param LineThickness the thickness of the line.  Remember 0 -> 1-pixel line,
   *                      1 -> 3-pixel line, etc.
   * @return the color histogram
   */
  SimpleHistogram colorHistOnALine(ORTLine line, int LineThickness)
  {
    SimpleHistogram hist = new SimpleHistogram(m_colorNum);
    Set points = line.getPoints(m_imgWidth, m_imgHeight, LineThickness);
    Iterator i = points.iterator();
    while (i.hasNext()) {
      Point p = (Point)i.next();
      hist.putToBin(m_colorIndexImage[p.x + p.y * m_imgWidth]);
    }
    return hist;
  }

  /**
   * To test the method {@link #pointIterator}
   */
  public static class TestGetLineColorPairs {
    /**
     * Fill a rectangle area of an array with the specified value.  The rectangle
     * is from (x1, y1) -> (x2, y2).  (x1, y1) is inclusive while (x2, y2) is
     * exclusive
     * @param array the array to be filled
     * @param w array width
     * @param h array height
     * @param x1 x of the top-left corner of the rectangle (inclusive)
     * @param y1 y of the top-left corner of the rectangle (inclusive)
     * @param x2 x of the bottem-right corner of the rectangle (exclusive)
     * @param y2 y of the bottem-right corner of the rectangle (exclusive)
     * @param value the value used to fill
     */
    static void fillRect(int[] array, int w, int h, int x1, int y1, int x2, int y2, int value) {
      for (int y=y1; y<y2; y++) {
        for (int x=x1; x<x2; x++) {
          array[y * w + x] = value;
        }
      }
    }
    public static void main(String[] args) {
      // Tets 1
      {
        int w = 100, h = 100;
        int[] color_index_img = new int[w * h];
        java.util.Arrays.fill(color_index_img, 0, w*h/2, 0);
        java.util.Arrays.fill(color_index_img, w*h/2, w*h, 1);
        int[] colors = {0xffffffff, 0xff000000};

        ORTLine l = new ORTLine(-30, -30, 30, 30);

        LineColorPairs lcp = new LineColorPairs(color_index_img, w, h, colors);
        Set color_pairs = lcp.getLineColorPairs(l, 0.3, 3, 3);

        Iterator i = color_pairs.iterator();
        while (i.hasNext()) {
          ColorPair cp = (ColorPair)i.next();
          System.out.println(cp);
        }
        System.out.println();
      }

      // Test 2
      {
        int w = 10, h = 10;
        int[] color_index_img = new int[w * h];
        // left
        fillRect(color_index_img, w, h, 0, 0, 2, h, 0);
        fillRect(color_index_img, w, h, 2, 0, 3, h/2, 0);
        fillRect(color_index_img, w, h, 2, h/2, 3, h, 1);
        fillRect(color_index_img, w, h, 3, 0, w/2, h, 1);
        // right
        fillRect(color_index_img, w, h, w/2, 0, w, 4, 2);
        fillRect(color_index_img, w, h, w/2, 4, w, h, 3);

        yi.util.io.OutputResult.print("img", color_index_img, w, h);


        int[] colors = {0xffffffff, 0xff000000, 0xffff0000, 0xff00ff00};

        ORTLine l = new ORTLine(5-5, 0-5, 5-5, 9-5);

        LineColorPairs lcp = new LineColorPairs(color_index_img, w, h, colors);
        Set color_pairs = lcp.getLineColorPairs(l, 0.3, 3, 3);

        Iterator i = color_pairs.iterator();
        while (i.hasNext()) {
          ColorPair cp = (ColorPair)i.next();
          System.out.println(cp);
        }
        System.out.println();

        ORTLine l2 = new ORTLine(0-5, 5-5, 9-5, 5-5);

        Set color_pairs2 = lcp.getLineColorPairs(l2, 0.3, 3, 3);

        i = color_pairs2.iterator();
        while (i.hasNext()) {
          ColorPair cp = (ColorPair)i.next();
          System.out.println(cp);
        }
      }
      System.out.println();

      System.exit(0);
    }
  }


}