package ip.gui.frames;

import ip.gui.*;

import java.awt.*;
import java.awt.event.ActionEvent;

import math.Mat;


public class BoundaryFrame extends MorphFrame {
    private Menu boundaryMenu = getMenu("Boundary");
    private Menu countourMenu = getMenu("Countour");

    private MenuItem grayPyramid_mi =
            addMenuItem(boundaryMenu, "[E-p]grayPyramid");
    private MenuItem diffProcess_mi =
            addMenuItem(boundaryMenu, "[E-d]iffProcess");
    private MenuItem drawFramePoints_mi =
            addMenuItem(boundaryMenu, "drawFramePoints");
    private MenuItem edge2HeightField_mi =
            addMenuItem(boundaryMenu, "Edge->height field");
    private MenuItem buildPoints_mi =
            addMenuItem(boundaryMenu, "buildPoints");

    private MenuItem houghDetect_mi =
            addMenuItem(boundaryMenu, "[E-H]houghDetect");
    private MenuItem houghDetectGray_mi =
            addMenuItem(boundaryMenu, "houghDetectGray");

    private MenuItem copyToChildFrame_mi =
            addMenuItem(getFileMenu(), "[E-C]copyToChildFrame");
    private MenuItem grabChild_mi =
            addMenuItem(getFileMenu(), "[E-G]grabChild");

    private MenuItem bugWalk_mi =
            addMenuItem(countourMenu, "[b]ug walk");
    private MenuItem printPolys_mi =
            addMenuItem(countourMenu, "printPolys...");
    private MenuItem listPolys_mi =
            addMenuItem(countourMenu, "listPolys");
    private MenuItem filterPolys_mi =
            addMenuItem(countourMenu, "filterPolys");
    private MenuItem drawPoly_mi =
            addMenuItem(countourMenu, "drawPoly");

    private MenuItem displayHoughOfRed_mi =
            addMenuItem(boundaryMenu, "[E-R]displayHoughOfRed");
    private MenuItem drawSomeBigPoints_mi =
            addMenuItem(boundaryMenu, "[E-D]drawSomeBigPoints");
    private MenuItem computeHoughAndDraw_mi =
            addMenuItem(boundaryMenu, "[E-T-C]computeHoughAndDraw");
    private MenuItem computeMagnitudeAndGradiant_mi =
            addMenuItem(boundaryMenu, "computeMagnitudeAndGradiant");

    private MenuItem houghEdge_mi =
            addMenuItem(boundaryMenu, "[E-I]houghEdge");
    private MenuItem inverseHoughToRed_mi =
            addMenuItem(boundaryMenu, "Inverse Hough To Red");
    private MenuItem singlePixelEdge_mi =
            addMenuItem(boundaryMenu, "[E-s]inglePixelEdge");

    private MenuItem print_mi = addMenuItem(getFileMenu(), "Print...");

    private Polygons polyList = new Polygons();

    private boolean drawOnlyPolys = false;


    public Polygons getPolyList() {
        return polyList;
    }

    public void setPolyList(Polygons v) {
        polyList = v;
    }

    public void actionPerformed(ActionEvent e) {


        if (match(e, edge2HeightField_mi)) {
            edge2HeightField();
            return;
        }

        if (match(e, buildPoints_mi)) {
            buildPoints();
            return;
        }
        if (match(e, drawFramePoints_mi)) {
            drawFramePoints();
            return;
        }

        if (match(e, diffProcess_mi)) {
            diffProcess();
            return;
        }
        if (match(e, computeMagnitudeAndGradiant_mi)) {
            computeMagnitudeAndGradiant();
            return;
        }
        if (match(e, listPolys_mi)) {
            polyList.listPolys();
            return;
        }
        if (match(e, filterPolys_mi)) {
            filterPolys();
            return;
        }
        if (match(e, printPolys_mi)) {
            printPolys();
            return;
        }
        if (match(e, houghDetectGray_mi)) {
            houghDetect();
            return;
        }
        if (match(e, grabChild_mi)) {
            grabChild();
            return;
        }
        if (match(e, houghDetect_mi)) {
            houghDetect();
            return;
        }
        if (match(e, computeHoughAndDraw_mi)) {
            computeHoughAndDraw();
            return;
        }
        if (match(e, drawSomeBigPoints_mi)) {
            drawSomeBigPoints();
            return;
        }
        if (match(e, inverseHoughToRed_mi)) {
            inverseHoughToRed();
            return;
        }
        if (match(e, copyToChildFrame_mi)) {
            copyToChildFrame();
            return;
        }
        if (match(e, houghEdge_mi)) {
            houghEdge();
            return;
        }
        if (match(e, displayHoughOfRed_mi)) {
            displayHoughOfRed();
            return;
        }
        if (match(e, grayPyramid_mi)) {
            grayPyramid(getKsquare());
            return;
        }
        if (match(e, singlePixelEdge_mi)) {
            singlePixelEdge();
            return;
        }
        if (match(e, drawPoly_mi)) {
            polyList.drawPolys(getGraphics());
            return;
        }
        if (match(e, bugWalk_mi)) {
            bugWalk();
            return;
        }
        if (match(e, print_mi)) {
            PrintContainer(this);
            return;
        }
        super.actionPerformed(e);
    }

    public void drawFramePoints() {
        String args[] = {""};
        DrawFrame.main(args);
    }

    /**
     edge2HeightField - input and image, output
     x,y,z points.
     */
    public void edge2HeightField() {
        int n = 1;
        for (int x = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++)
                if (getR()[x][y] == 255)
                    n++;
        System.out.println("found " + n + " points");
        float pointX[] = new float[n];
        float pointY[] = new float[n];
        float pointZ[] = new float[n];
        for (int x = 0,i = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++)
                if (getR()[x][y] == 255) {
                    pointX[i] = x / ((float) getImageWidth());
                    pointY[i] = y / ((float) getImageHeight());
                    pointZ[i] = 1f;
                }
        DrawFrame.drawPoints(pointX, pointY, pointZ);
    }


    public void grayPyramid(float k[][]) {
        setR(dilategs(erodegs(getR(), k), k));
        setR(erodegs(dilategs(getR(), k), k));
        grayResample(2);
        setR(trim(2, 2, getR()));
        copyRedToGreenAndBlue();
        short2Image();
    }

    private double radiusTable(int x) {
// wrong..measure this!
        double r0 = 1;
        double r1 = 100;
        double t = x / 100; //0..1?
        return t * r1 + (1 - t) * r0;
    }

    private void buildPoints() {
        int numberOfPoints = 100;
        int X[] = new int[numberOfPoints];
        int Y[] = new int[numberOfPoints];
        int Z[] = new int[numberOfPoints];
        double eps = (1.0 / numberOfPoints) * 2 * Math.PI;
        int n = 0;
        double radius;
        loop: for (double theta = 0; theta < 2 * Math.PI; theta += eps) {
            for (int x = 0; x < getImageWidth(); x++)
                for (int y = 0; y < getImageHeight(); y++) {
                    if (getR()[x][y] == 0) continue;
                    if (n >= numberOfPoints - 1) break loop;
                    n++;
                    radius = radiusTable(x);
                    X[n] = (int)
                            ((Math.sin(theta) * radius) - 256 / 2);
                    Y[n] = y;
                    Z[n] = (int) radius;
                }
            //stepMotorAndDigitize...
            //diffProcess();
            // send me an e-mail if you
            // want to do this....
            // I have serial-port
            // and video digitization
            // drivers in java...
            // This is used for 3D scanners!!
            // Doug Lyon
            // lyon@DocJava.com
        }
        DrawFrame f = new DrawFrame("DrawFrame");
        f.setSize(256, 256);
        f.show();
        f.setUpFrame();
        f.setPoints(X, Y, Z);
        f.addFocusListener(f);
        f.repaint();
    }

    /**
     * Process a structured illumination based
     * multi-order diffraction subimage.
     * A turntable is used to rotate the object
     * to be digitized.
     */
    private void diffProcess() {
        int x1 = 145;
        int y1 = 18;
        int x2 = 215;
        int y2 = 245;
        short threshValue = 106;
        setImageWidth(x2 - x1);
        setImageHeight(y2 - y1);
        NegateFrame nf = subFrame(this, x1, y1, getImageWidth(), getImageHeight());
        setR(Mat.copyArray(nf.getR()));
        nf.setVisible(false);
        System.out.println("Copy red to green and blue");
        int width1 = getImageWidth() - 1;
        setImageWidth(width1);
        int height1 = getImageHeight() - 1;
        setImageHeight(height1);
        copyRedToGreenAndBlue();
        setSize(getImageWidth(), getImageHeight());
        lp3();
        Mat.threshold(getR(), threshValue);
        Mat.threshold(getG(), threshValue);
        Mat.threshold(getB(), threshValue);
        skeleton();
        medianSquare2x2();
        medianSquare2x2();
        skeleton();
        thresh();
        wellConditioned();
        short2Image();

    }

    private double cos(double alpha) {
        return
                Math.cos(alpha * Math.PI / 180);
    }

    private double sin(double alpha) {
        return
                Math.sin(alpha * Math.PI / 180);
    }

    private int atan(int y, int x) {
        return (int)
                (180 * Math.atan2(y, x) / Math.PI);
    }

    //BoundaryFrame child = null;
    public void copyToChildFrame() {
        short _r[][] = new short[getImageWidth()][getImageHeight()];
        short _g[][] = new short[getImageWidth()][getImageHeight()];
        short _b[][] = new short[getImageWidth()][getImageHeight()];
        for (int x = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++) {
                _r[x][y] = getR()[x][y];
                _g[x][y] = getG()[x][y];
                _b[x][y] = getB()[x][y];
            }
        child = new TopFrame(
                "copy of BoundaryFrame",
                _r, _g, _b);
        child.setSize(getImageWidth(), getImageHeight());
    }

    public BoundaryFrame(String title) {
        super(title);
        boundaryMenu.add(countourMenu);
        getSpatialFilterMenu().add(boundaryMenu);
    }

    private int rhoStep = 1;
    private int thetaStep = 1;

    public void displayHoughOfRed() {
        setR(hough());
        setImageWidth(getR().length);
        setImageHeight(getR()[0].length);
        setSize(getImageWidth(), getImageHeight());
        copyRedToGreenAndBlue();
        short2Image();
        show();
    }

    private Point identifyLargestPoint() {
        int max = -1;
        Point p = null;
        for (int x = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++) {
                if (getG()[x][y] > max) {
                    max = getG()[x][y];
                    p = new Point(x, y);
                }
            }
        return p;
    }

    public Point[] getTheLargestPoints(int n) {
        Point points[] = new Point[n];
        for (int i = 0; i < n; i++) {
            Point p = identifyLargestPoint();
            points[i] = p;
            if (p == null) break;
            getG()[p.x][p.y] = 0;
        }
        return points;
    }

    public void drawSomeBigPoints() {
        Point points[] = getTheLargestPoints(4);
        drawThePoints(points);
        drawHoughLines(points);
    }

    public TopFrame child = null;

    public void computeHoughAndDraw() {

        copyToChildFrame();
        child.displayHoughOfRed();
        Point points[] = child.getTheLargestPoints(40);
        child.linearTransform();
        drawHoughLines(points);
        drawThePoints(points);
        copyRedToGreenAndBlue();
        short2Image();
    }


    public void andWithChild() {
        if (child == null) return;
        for (int i = 0; i < getImageWidth(); i++)
            for (int j = 0; j < getImageHeight(); j++) {
                getR()[i][j] = min(getR()[i][j], child.getR()[i][j]);
                getG()[i][j] = min(getG()[i][j], child.getG()[i][j]);
                getB()[i][j] = min(getB()[i][j], child.getB()[i][j]);
            }
    }

    private short min(short m1, short m2) {
        if (m1 < m2) return m1;
        return m2;
    }

    public void drawThePoints(Point points[]) {
        Graphics g = getGraphics();
        g.setColor(Color.white);
        int n = points.length;
        for (int i = 0; i < n; i++) {
            Point p = points[i];
            g.drawOval(p.x - 5, p.y - 5, 10, 10);
        }
    }

    public void drawHoughLines(Point points[]) {
        Graphics g = getGraphics();
        g.setColor(Color.white);
        for (int i = 0; i < points.length; i++) {
            Point p = points[i];
            int rho = p.x;
            int theta = p.y;
            int x1 = 0;
            int x2 = getImageWidth();
            int y1 = (int) ((rho - cos(theta) * x1) / sin(theta));
            int y2 = (int) ((rho - cos(theta) * x2) / sin(theta));

            if (theta == 0) {
                x1 = rho;
                x2 = rho;
                y1 = 0;
                y2 = getImageHeight();
            }
            drawLineRed(x1, y1, x2, y2);
            g.drawLine(x1, y1, x2, y2);
        }
    }

    public short[][] hough() {
        int thetaMax = 360;
        int radiusMax = (int) Math.sqrt(getImageWidth() * getImageWidth() + getImageHeight() * getImageHeight());
        short s[][] = new short[radiusMax][thetaMax];
        for (int x = 0; x < getR().length; x++) {
            for (int y = 0; y < getR()[0].length; y++) {
                if (getR()[x][y] == 0) continue;
                drawHoughLine(x, y, s);
            }
        }
        return s;
    }

    public short[][] houghGray2() {
        int thetaMax = 360;
        int radiusMax = (int) Math.sqrt(getImageWidth() * getImageWidth() + getImageHeight() * getImageHeight());
        short s[][] = new short[radiusMax][thetaMax];
        for (int x = 0; x < getR().length; x++) {
            for (int y = 0; y < getR()[0].length; y++) {
                if (getR()[x][y] == 0) continue;
                drawHoughLineGray(x, y, s);
            }
        }
        return s;
    }

    public void drawHoughLine(int x, int y,
                              short s[][]) {
        for (int theta = 0; theta < s[0].length; theta++) {
            int rho = (int) (x * cos(theta) + y * sin(theta));
            if (rho >= s.length) continue;
            if (rho < 0) continue;
            s[rho][theta]++;
        }
    }

    public void drawHoughLineGray(int x, int y,
                                  short s[][]) {
        int theta = atan(getG()[x][y], getB()[x][y]);
        if (theta < 0) return;
        if (theta > s[0].length) return;
        int rho = (int) (x * cos(theta) + y * sin(theta));
        if (rho >= s.length) return;
        if (rho < 0) return;
        s[rho][theta]++;
    }

    public void houghEdge() {
        copyToChildFrame();
        child.displayHoughOfRed();
        child.unahe();
        child.copyToChildFrame();
        child.child.thresh();
        andHough(child.child);
        short2Image();
    }

    public void houghDetect() {
        copyToChildFrame();
        child.displayHoughOfRed();
        inverseHough();
    }

    public void andHough(BoundaryFrame bf) {
        System.out.println("hough computing");

        for (int x = 0; x < getR().length; x++)
            for (int y = 0; y < getR()[0].length; y++) {
                if (getR()[x][y] == 0) continue;
                int theta = atan(y, x);
                if (theta < 0) continue;
                if (theta >= 360) continue;
                int rho = (int) (x * cos(theta) + y * sin(theta));
                if (rho >= getImageWidth()) continue;
                if (rho < 0) continue;
                if (bf.getR()[rho][theta] == 0)
                    getR()[x][y] = 0;
            }
    }


    public void inverseHoughToRed() {
        inverseHoughToRed(rhoStep, thetaStep);
        copyRedToGreenAndBlue();
        short2Image();
    }

    public void inverseHough() {
        Point points[] = child.getTheLargestPoints(10);
        child.linearTransform();
        copyToChildFrame();
        child.reinitializeRedGreenAndBlue();
        System.out.println("About to draw hough lines");
        child.drawHoughLines(points);
        System.out.println("Anding with child");
        andWithChild();
        copyRedToGreenAndBlue();
        short2Image();
        show();
    }

    private void inverseHoughToRed(int rhoStep, int thetaStep) {
        for (int hx = 0; hx < getG().length; hx++)
            for (int hy = 0; hy < getG()[0].length; hy++) {
                if (getG()[hx][hy] == 0) continue;
                int x1 = 0;
                int x2 = getImageWidth() - 1;
                int theta = hy * thetaStep;
                int rho = hx * rhoStep;
                double cosTheta = cos(theta);
                double sinTheta = sin(theta);
                int y1 = clip((rho - x1 * cosTheta) / sinTheta);
                int y2 = clip((rho - x2 * cosTheta) / sinTheta);
                drawLineRed(x1, y1, x2, y2);
            }
    }


    public void drawLineRed2(int x1, int y1, int x2, int y2) {
        double dx = Math.abs(x1 - x2);
        double dy = Math.abs(y1 - y2);
        double length = 2 * Math.sqrt(dx * dx + dy * dy);
        double eps = 1 / length;
        for (double t = 0; t < 1; t = t + eps) {
            int x = (int) ((1 - t) * x1 + t * x2);
            int y = (int) ((1 - t) * y1 + t * y2);
            if (x >= getImageWidth()) continue;
            if (y >= getImageHeight()) continue;
            if (x < 0) continue;
            if (y < 0) continue;

            getR()[x][y] = 255;
        }
    }

    private int sign(int x) {
        if (x == 0) return 0;
        if (x < 0) return -1;
        return 1;
    }

    public void grabChild() {
        MorphFrame child = (MorphFrame) super.getChild();
        if (child == null) {
            System.out.println("Child is null");
            return;
        }
        int width1 = getImageWidth();
        setImageWidth(width1);
        int height1 = getImageHeight();
        setImageHeight(height1);
        setR(child.getR());
        setG(child.getG());
        setB(child.getB());
        short2Image();
    }

// Bresenham's Algorithm;
// Adapted from Newman and Sproull,
// "Principles of Interactive Computer Graphics"
// and
// Graphics Gems Vol. 1, pp 99 by
// Paul S. Heckbert.
    public void drawLineRed(int x1, int y1, int x2, int y2) {
        int deltaX = x2 - x1;
        int deltaY = y2 - y1;
        int absDeltaX = Math.abs(deltaX);
        int absDeltaY = Math.abs(deltaY);
        int absDeltaX2 = absDeltaX * 2;
        int absDeltaY2 = absDeltaY * 2;
        int sx = sign(deltaX);
        int sy = sign(deltaY);

        int x = x1;
        int y = y1;
        // e is the error
        int e = 0;

        if (absDeltaX2 > absDeltaY2) {
            e = absDeltaY2 - absDeltaX;
            while (true) {
                setPel(x, y);
                if (x == x2) return;
                if (e >= 0) {
                    y += sy;
                    e -= absDeltaX2;
                }
                x += sx;
                e += absDeltaY2;
            }
        }
        e = absDeltaX2 - absDeltaY;
        while (true) {
            setPel(x, y);
            if (y == y2) return;
            if (e >= 0) {
                x += sx;
                e -= absDeltaY2;
            }
            y += sy;
            e += absDeltaX2;
        }
    }

    private void setPel(int x, int y) {
        if (x < 0) return;
        if (x >= getR().length) return;
        if (y < 0) return;
        if (y >= getR()[0].length) return;
        getR()[x][y] = 255;
        getG()[x][y] = 255;
        getB()[x][y] = 255;
    }

    public void testDrawLineRed() {
        reinitializeRedGreenAndBlue();
        drawLineRed(0, 0, getImageWidth(), getImageHeight());
        drawLineRed(getImageWidth(), 0, 0, getImageHeight());
        drawLineRed(getImageWidth() / 2, getImageHeight() / 2, 0, getImageHeight() / 2);
        copyRedToGreenAndBlue();
        short2Image();
    }

    private int clip(double y) {
        if (y > getImageHeight()) return getImageHeight() - 1;
        if (y < 0) return 0;
        return (int) y;
    }

    public short[][] trim(int dx, int dy, short s[][]) {
        int nw = s.length - 2 * dx;
        int nh = s[0].length - 2 * dy;
        short ns[][] = new short[nw][nh];
        for (int x = dx; x < getImageWidth() - dx; x++)
            for (int y = dy; y < getImageHeight() - dy; y++)
                ns[x - dx][y - dy] = s[x][y];
        setImageWidth(nw);
        setImageHeight(nh);
        return ns;
    }

    private void grayResample(int ratio) {
        int width1 = getImageWidth() / ratio;
        setImageWidth(width1);
        int height1 = getImageHeight() / ratio;
        setImageHeight(height1);
        setR(resampleArray(getR(), ratio));
    }


    public static void PrintContainer(Container c) {
        Toolkit tk = Toolkit.getDefaultToolkit();
        PrintJob printJob =
                tk.getPrintJob(
                        (Frame) c,
                        "print me!",
                        null);
        Graphics g = printJob.getGraphics();
        c.paint(g);
        printJob.end();
    }


    public static void main(String args[]) {
        BoundaryFrame bf = new BoundaryFrame("BoundaryFrame");
        bf.testDrawLineRed();
    }

    /**
     *  make new instances of the internal short arrays.
     */

    public void reinitializeRedGreenAndBlue() {
        setR(new short[getImageWidth()][getImageHeight()]);
        setG(new short[getImageWidth()][getImageHeight()]);
        setB(new short[getImageWidth()][getImageHeight()]);
    }


    private int pointCount() {
        int i = 0;
        for (int x = 0; x < getImageWidth(); x++)
            for (int y = 0; y < getImageHeight(); y++)
                if (getR()[x][y] != 0) i++;
        return i;
    }

    private void computeMagnitudeAndGradiant() {
        for (int x = 1; x < getImageWidth() - 1; x++)
            for (int y = 1; y < getImageHeight() - 1; y++)
                computeGradient(x, y);
        for (int x = 1; x < getImageWidth() - 1; x++)
            for (int y = 1; y < getImageHeight() - 1; y++)
                getR()[x][y] = (short) Math.sqrt(
                        getG()[x][y] * getG()[x][y] + getB()[x][y] * getB()[x][y]);
        short2Image();
    }
// abc
// hid
// gfe
    private void computeGradient(int x, int y) {
        int a1, b1, c1, d1, e1, f1, h1, g1;
        a1 = getR()[x - 1][y + 1];
        b1 = getR()[x][y + 1];
        c1 = getR()[x + 1][y + 1];
        d1 = getR()[x + 1][y];
        e1 = getR()[x + 1][y - 1];
        f1 = getR()[x][y - 1];
        g1 = getR()[x - 1][y - 1];
        h1 = getR()[x - 1][y];

        getG()[x][y] = (short) ((c1 - g1) + (e1 - a1) + 2 * (d1 - h1));
        getB()[x][y] = (short) ((c1 - g1) + (a1 - e1) + 2 * (b1 - f1));
    }


    private void singlePixelEdge() {
        colorPyramid(getKsquare());
        show();
        thresh();
        outsideContour(getKcross());
    }

    public void bugWalk() {
        polyList = new Polygons();
        System.out.println("number of points = " + pointCount());
        Timer t = new Timer();
        t.start();
        for (int x = 1; x < getImageWidth() - 1; x++)
            for (int y = 1; y < getImageHeight() - 1; y++)
                if (getR()[x][y] != 0)
                    buildPolygonList(x, y);
        t.print("poly done!");
        polyList.polyStats();
        filterPolys();
    }


    private void buildPolygonList(int x, int y) {
        Polygon p = new Polygon();
        p.addPoint(x, y);
        getR()[x][y] = 0;
        if (getR()[x + 1][y] != 0) {
            buildPolygonList(x + 1, y, p);
            polyList.addElement(p);
            return;
        }
        if (getR()[x + 1][y + 1] != 0) {
            buildPolygonList(x + 1, y + 1, p);
            polyList.addElement(p);
            return;
        }
        if (getR()[x][y + 1] != 0) {
            buildPolygonList(x, y + 1, p);
            polyList.addElement(p);
            return;
        }

    }

    private void buildPolygonList(int x, int y, Polygon p) {
        p.addPoint(x, y);
        getR()[x][y] = 0;
        try {
            if (getR()[x + 1][y] != 0) {
                buildPolygonList(x + 1, y, p);
                return;
            }
            if (getR()[x + 1][y + 1] != 0) {
                buildPolygonList(x + 1, y + 1, p);
                return;
            }
            if (getR()[x][y + 1] != 0) {
                buildPolygonList(x, y + 1, p);
                return;
            }
        } catch (Exception e) {
        }
        ;
    }

    public void printPolys() {
        Toolkit tk = Toolkit.getDefaultToolkit();
        PrintJob printJob =
                tk.getPrintJob(
                        new Frame(),
                        "print me!",
                        null);
        Graphics g = printJob.getGraphics();
        Polygon p;
        for (int i = 0; i < polyList.size(); i++) {
            p = polyList.elementAt(i);
            g.drawPolyline(p.xpoints, p.ypoints, p.npoints);
        }
        printJob.end();
    }

    public void filterPolys() {
        Timer t = new Timer();
        t.start();
        Polygon p = polyList.elementAt(0);
        Polygon pp;
        Polygons newPolys = new Polygons();
        newPolys.addElement(p);
        polyList.removeElementAt(0);
        while (polyList.size() > 0) {
            int i = nextClosestPoly(p);
            pp = polyList.elementAt(i);
            polyList.removeElementAt(i);
            pp = thinPoly(pp); // implement this for hw!
            //if (combinePolys(p,pp)) continue;

            newPolys.addElement(pp);
        }
        polyList = newPolys;
        t.print("Polys ordered");
        polyList.polyStats();
        polyList.drawPolys(getGraphics());
        //listPolys(polyList);
    }

// here is the basic idea...thin poly
// can you order the polys?
    public Polygon thinPoly(Polygon p) {
        if (p.npoints <= 2) return p;
        Polygon pp = new Polygon();
        int x0 = p.xpoints[0];
        int y0 = p.ypoints[0];
        int x1 = p.ypoints[1];
        int y1 = p.ypoints[1];
        pp.addPoint(x0, y0);
        for (int i = 1; i < p.npoints - 1; i++) {
            int xi = p.xpoints[i];
            int yi = p.ypoints[i];
            if (onLine(x0, y0, x1, y1, xi, yi) && nextTo(x1, y1, xi, yi)) {
                //System.out.println("onLine:\n"
                //  +x0+","+y0+","+x1+","+y1+","+xi+","+yi);
                x1 = xi;
                y1 = yi;
                continue;
            }
            pp.addPoint(p.xpoints[i - 1], p.ypoints[i - 1]);
            x0 = p.xpoints[i - 1];
            y0 = p.ypoints[i - 1];
            x1 = xi;
            y1 = yi;
        }
        pp.addPoint(p.xpoints[p.npoints - 1], p.ypoints[p.npoints - 1]);
        return pp;
    }

    private boolean nextTo(
            int x0, int y0,
            int x1, int y1) {
        int dx = x1 - x0;
        int dy = y1 - y0;
        return Math.sqrt(dx * dx + dy * dy) < 2;
    }

    public boolean onLine(
            int x0, int y0,
            int x1, int y1,
            int x2, int y2) {
        int dx = x1 - x0;
        int dy = y1 - y0;
        int dx2 = x2 - x0;
        int dy2 = y2 - y0;
        return Math.abs(dy * dx2 - dy2 * dx) <
                max(Math.abs(dx), Math.abs(dy));
    }

    private double max(int x, int y) {
        if (x > y) return x;
        return y;
    }

    public int nextClosestPoly(Polygon p) {
        double dMin = 10000;
        int next = 0;
        for (int i = 0; i < polyList.size(); i++) {
            Polygon pp = polyList.elementAt(i);
            if (distance(p, pp) < dMin) {
                dMin = distance(p, pp);
                next = i;
            }
        }
        return next;
    }

    public boolean combinePolys(Polygon p1, Polygon p2) {
        if (distance(p1, p2) < 2) {
            for (int i = 0; i < p2.npoints; i++)
                p1.addPoint(p2.xpoints[i], p2.ypoints[i]);
            return true;
        }
        return false;
    }

    public double distance(Polygon p1, Polygon p2) {
        double x1 = p1.xpoints[p1.npoints - 1];
        double y1 = p1.ypoints[p1.npoints - 1];
        double x2 = p2.xpoints[0];
        double y2 = p2.ypoints[0];
        double dx = x1 - x2;
        double dy = y1 - y2;
        return Math.sqrt(dx * dx + dy * dy);
    }

    public Menu getBoundaryMenu() {
        return boundaryMenu;
    }

    public void setBoundaryMenu(Menu boundaryMenu) {
        this.boundaryMenu = boundaryMenu;
    }

    public Menu getCountourMenu() {
        return countourMenu;
    }

    public void setCountourMenu(Menu countourMenu) {
        this.countourMenu = countourMenu;
    }

    public MenuItem getGrayPyramid_mi() {
        return grayPyramid_mi;
    }

    public void setGrayPyramid_mi(MenuItem grayPyramid_mi) {
        this.grayPyramid_mi = grayPyramid_mi;
    }

    public MenuItem getDiffProcess_mi() {
        return diffProcess_mi;
    }

    public void setDiffProcess_mi(MenuItem diffProcess_mi) {
        this.diffProcess_mi = diffProcess_mi;
    }

    public MenuItem getDrawFramePoints_mi() {
        return drawFramePoints_mi;
    }

    public void setDrawFramePoints_mi(MenuItem drawFramePoints_mi) {
        this.drawFramePoints_mi = drawFramePoints_mi;
    }

    public MenuItem getEdge2HeightField_mi() {
        return edge2HeightField_mi;
    }

    public void setEdge2HeightField_mi(MenuItem edge2HeightField_mi) {
        this.edge2HeightField_mi = edge2HeightField_mi;
    }

    public MenuItem getBuildPoints_mi() {
        return buildPoints_mi;
    }

    public void setBuildPoints_mi(MenuItem buildPoints_mi) {
        this.buildPoints_mi = buildPoints_mi;
    }

    public MenuItem getHoughDetect_mi() {
        return houghDetect_mi;
    }

    public void setHoughDetect_mi(MenuItem houghDetect_mi) {
        this.houghDetect_mi = houghDetect_mi;
    }

    public MenuItem getHoughDetectGray_mi() {
        return houghDetectGray_mi;
    }

    public void setHoughDetectGray_mi(MenuItem houghDetectGray_mi) {
        this.houghDetectGray_mi = houghDetectGray_mi;
    }

    public MenuItem getCopyToChildFrame_mi() {
        return copyToChildFrame_mi;
    }

    public void setCopyToChildFrame_mi(MenuItem copyToChildFrame_mi) {
        this.copyToChildFrame_mi = copyToChildFrame_mi;
    }

    public MenuItem getGrabChild_mi() {
        return grabChild_mi;
    }

    public void setGrabChild_mi(MenuItem grabChild_mi) {
        this.grabChild_mi = grabChild_mi;
    }

    public MenuItem getBugWalk_mi() {
        return bugWalk_mi;
    }

    public void setBugWalk_mi(MenuItem bugWalk_mi) {
        this.bugWalk_mi = bugWalk_mi;
    }

    public MenuItem getPrintPolys_mi() {
        return printPolys_mi;
    }

    public void setPrintPolys_mi(MenuItem printPolys_mi) {
        this.printPolys_mi = printPolys_mi;
    }

    public MenuItem getListPolys_mi() {
        return listPolys_mi;
    }

    public void setListPolys_mi(MenuItem listPolys_mi) {
        this.listPolys_mi = listPolys_mi;
    }

    public MenuItem getFilterPolys_mi() {
        return filterPolys_mi;
    }

    public void setFilterPolys_mi(MenuItem filterPolys_mi) {
        this.filterPolys_mi = filterPolys_mi;
    }

    public MenuItem getDrawPoly_mi() {
        return drawPoly_mi;
    }

    public void setDrawPoly_mi(MenuItem drawPoly_mi) {
        this.drawPoly_mi = drawPoly_mi;
    }

    public MenuItem getDisplayHoughOfRed_mi() {
        return displayHoughOfRed_mi;
    }

    public void setDisplayHoughOfRed_mi(MenuItem displayHoughOfRed_mi) {
        this.displayHoughOfRed_mi = displayHoughOfRed_mi;
    }

    public MenuItem getDrawSomeBigPoints_mi() {
        return drawSomeBigPoints_mi;
    }

    public void setDrawSomeBigPoints_mi(MenuItem drawSomeBigPoints_mi) {
        this.drawSomeBigPoints_mi = drawSomeBigPoints_mi;
    }

    public MenuItem getComputeHoughAndDraw_mi() {
        return computeHoughAndDraw_mi;
    }

    public void setComputeHoughAndDraw_mi(MenuItem computeHoughAndDraw_mi) {
        this.computeHoughAndDraw_mi = computeHoughAndDraw_mi;
    }

    public MenuItem getComputeMagnitudeAndGradiant_mi() {
        return computeMagnitudeAndGradiant_mi;
    }

    public void setComputeMagnitudeAndGradiant_mi(MenuItem computeMagnitudeAndGradiant_mi) {
        this.computeMagnitudeAndGradiant_mi = computeMagnitudeAndGradiant_mi;
    }

    public MenuItem getHoughEdge_mi() {
        return houghEdge_mi;
    }

    public void setHoughEdge_mi(MenuItem houghEdge_mi) {
        this.houghEdge_mi = houghEdge_mi;
    }

    public MenuItem getInverseHoughToRed_mi() {
        return inverseHoughToRed_mi;
    }

    public void setInverseHoughToRed_mi(MenuItem inverseHoughToRed_mi) {
        this.inverseHoughToRed_mi = inverseHoughToRed_mi;
    }

    public MenuItem getSinglePixelEdge_mi() {
        return singlePixelEdge_mi;
    }

    public void setSinglePixelEdge_mi(MenuItem singlePixelEdge_mi) {
        this.singlePixelEdge_mi = singlePixelEdge_mi;
    }

    public MenuItem getPrint_mi() {
        return print_mi;
    }

    public void setPrint_mi(MenuItem print_mi) {
        this.print_mi = print_mi;
    }

    public boolean isDrawOnlyPolys() {
        return drawOnlyPolys;
    }

    public void setDrawOnlyPolys(boolean drawOnlyPolys) {
        this.drawOnlyPolys = drawOnlyPolys;
    }

    public int getRhoStep() {
        return rhoStep;
    }

    public void setRhoStep(int rhoStep) {
        this.rhoStep = rhoStep;
    }

    public int getThetaStep() {
        return thetaStep;
    }

    public void setThetaStep(int thetaStep) {
        this.thetaStep = thetaStep;
    }

    public TopFrame getChild() {
        return child;
    }

    public void setChild(TopFrame child) {
        this.child = child;
    }


}