/*
 * VennDiagram.java
 *
 * Created on July 12, 2009, 1:31 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 *
 * @author Khalegh
 */

import java.io.PrintWriter;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.geom.*;

public class VennDiagram {
    private static int figNo = 0;
    private int [][] matrix;
    private VennPoint [][] points;
    private int [][] xfigPoints;
    private int pointsCount;
    private int rows;
    private int cols;
    private int n;
    private double radious;
    private double step;
    private double rowSpace;
    private double sxOrigin;
    private double syOrigin;
    private int colorMode = 0;
    private double ratio;
    private double [][][] sectorPoints;
    private int [] secPointsLen;
    private int totalBalanced;
    
    /** Creates a new instance of VennDiagram */
    public VennDiagram(int [][] x, int cMode) {
        colorMode = cMode;
        rows = x.length + 2;
        cols = x[0].length;
        
        n = rows - 1;
        
        matrix = new int[rows][cols];
        for (int i = 0; i < rows - 2; i++) {
            int count = 1;
            for (int j = 0; j < cols; j++) {
                if (x[i][j] == 1) {
                    matrix[i + 1][j] = count++;
                } else {
                    matrix[i + 1][j] = 0;
                }
            }
        }
        
        points = new VennPoint[n - 1][];
        for (int i = 0; i < n - 1; i++) {
            int count = BinomialCoeff.biCoeff(n, i + 1) / n;
            points[i] = new VennPoint[count];
        }
        
        totalBalanced = 0;
        radious = 10.0;
        makePoints();
        balancePoints(0);
        figNo++;
    }
    
    public int [][] getBalancedMatrix() {
        int cols;
        int [][] x;
        int max = 0;
        int rows = points.length;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < points[i].length; j++) {
                int x1 = (int) points[i][j].x;
                if (x1 > max)
                    max = x1;
            }
        }
        cols = max + 1;
        x = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < points[i].length; j++) {
                int col = (int) points[i][j].x;
                x[i][col] = 1;
            }
        }
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                System.out.print(x[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("----------------------------");
        return x;
    }
    
    private int nextOne(int row, int col, int hDir, int vDir) {
        int count = 1;
        col = (cols + col + hDir) % cols;
        while (matrix[row + vDir][col] == 0 && count <= cols) {
            count++;
            col = (cols + col + hDir) % cols;
        }
        return count;
    }
    
    private void makePoints() {
        int [][] nIndex = { {-1, -1, 1, 1}, {-1, 1, -1, 1} };
        double midRow = (rows - 3) / 2.0;
        for (int i = 1; i < rows - 1; i++) {
            for (int j = 0; j < cols; j++) {
                if (matrix[i][j] != 0) {
                    int r = i - 1;
                    int c = matrix[i][j] - 1;
                    double x = j;
                    double y = midRow - i + 1;
                    points[r][c] = new VennPoint(x, y);
                    for (int k = 0; k < 4; k++) {
                        int vDir = nIndex[0][k];
                        int hDir = nIndex[1][k];
                        int dLen = nextOne(i, j, hDir, vDir);
                        int zLen = nextOne(i, j, hDir, 0);
                        int len = (dLen < zLen) ? dLen : zLen;
                        int dir = (dLen < zLen) ? vDir : 0;
                        points[r][c].nextPoints[0][k] = dir;
                        int nextIndex = (cols + j + len * hDir) % cols;
                        points[r][c].nextPoints[1][k] = matrix[i + dir][nextIndex] - 1;
                        points[r][c].nextLen[k] = len;
                    }
                }
            }
        }
    }
    
    private void balancePoints(int k) {
        int rc = (n - 3) / 2;
        
        for (int i = rc; i >= 0; i--) {
            for (int j = 0; j < points[i].length; j++) {
                balancePoint(i, j, 1);
            }
        }
        
        for (int i = rc - 1; i >= 0; i--) {
            for (int j = 0; j < points[i].length; j++) {
                balancePoint(n - 2 - i, j, -1);
            }
        }
    }
    
    private void balancePoint(int r, int c, int dir) {
        int left = 1 + dir;
        int right = 2 + dir;
        VennPoint point = points[r][c];
        double xl, yl, xr, yr;
        if (point.nextPoints[0][left] == dir || point.nextPoints[0][right] == dir) {
            int nLeft = 1 - dir;
            int nRight = 2 - dir;
            
            VennPoint leftPoint = points[r + point.nextPoints[0][left]][point.nextPoints[1][left]];
            VennPoint rightPoint = points[r + point.nextPoints[0][right]][point.nextPoints[1][right]];
            VennPoint nLeftPoint = points[r + point.nextPoints[0][nLeft]][point.nextPoints[1][nLeft]];
            VennPoint nRightPoint = points[r + point.nextPoints[0][nRight]][point.nextPoints[1][nRight]];
            
            if (point.nextPoints[0][left] == 0) {
                xl = getBalancedX(point.x - point.nextLen[left], leftPoint.y, point.x, point.y, -dir);
                yl = getBalancedY(point.x - point.nextLen[left], leftPoint.y, point.x, point.y, -dir);
            } else {
                xl = point.x - point.nextLen[left];
                yl = leftPoint.y;
            }
            if (point.nextPoints[0][right] == 0) {
                xr = getBalancedX(point.x, point.y, point.x + point.nextLen[right], rightPoint.y, -dir);
                yr = getBalancedY(point.x, point.y, point.x + point.nextLen[right], rightPoint.y, -dir);
            } else {
                xr = point.x + point.nextLen[right];
                yr = rightPoint.y;
            }
            
            double x = getBalancedX(xl, yl, xr, yr, dir);
            point.y = getBalancedY(xl, yl, xr, yr, dir);
            
            double mx = x - point.x;
//            if (mx != 0) {
//                totalBalanced++;
//            }
            point.nextLen[right] -= mx;
            point.nextLen[left] += mx;
            if (point.nextPoints[0][right] == 0) {
                rightPoint.nextLen[left] -= mx;
            } else {
                rightPoint.nextLen[nLeft] -= mx;
            }
            
            if (point.nextPoints[0][left] == 0) {
                leftPoint.nextLen[right] += mx;
            } else {
                leftPoint.nextLen[nRight] += mx;
            }
            
            if (nRightPoint != point) {
                point.nextLen[nRight] -= mx;
                if (point.nextPoints[0][nRight] == 0) {
                    nRightPoint.nextLen[nLeft] -= mx;
                } else {
                    nRightPoint.nextLen[left] -= mx;
                }
            }
            if (nLeftPoint != point) {
                point.nextLen[nLeft] += mx;
                if (point.nextPoints[0][nLeft] == 0) {
                    nLeftPoint.nextLen[nRight] += mx;
                } else {
                    nLeftPoint.nextLen[right] += mx;
                }
            }
            if (x < 0) {
                x += cols;
            }
            if (x >= cols) {
                x -= cols;
            }
            point.x = x;
        }
    }
    
    private double getBalancedX(double xl, double yl, double xr, double yr, int dir){
        return (xl - dir * yl + xr + dir * yr) / 2.0;
    }
    
    private double getBalancedY(double xl, double yl, double xr, double yr, int dir) {
        return (yl - dir * xl + yr + dir * xr) / 2.0;
    }
    
    private double polarX(double teta, double phi){
        return radious * Math.cos(teta)/Math.tan(Math.PI/4 - phi/2);
    }
    
    private double polarY(double teta, double phi){
        return radious * Math.sin(teta)/Math.tan(Math.PI/4 - phi/2);
    }
    
    private double getPhi(double y) {
        return y * rowSpace;
    }
    
    private double abs(double x) {
        return (x >= 0) ? x : -x;
    }
    
    private void savePoint(int l , double x, double y) {
        double teta = x * step + l * 2 * Math.PI / n;;
        double phi = getPhi(y) ;
        int px = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
        int py = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);
        xfigPoints[pointsCount][0] = px;
        xfigPoints[pointsCount][1] = py;
        pointsCount++;
    }
    
    private void drawBox(PrintWriter file, double radious , double ratio, int margin) {
        int x1 = (int) (5000 - radious * ratio + margin);
        int y1 = x1;
        int x2 = (int) (5000 + radious * ratio - margin);
        int y2 = x2;
        file.println("2 2 0 2  0 7 50 -1 -1 0.000 0 0 0 0 0 5");
        file.print(x1 + " " + y1 + " ");
        file.print(x1 + " " + y2 + " ");
        file.print(x2 + " " + y2 + " ");
        file.print(x2 + " " + y1 + " ");
        file.println(x1 + " " + y1 + " ");
    }
    
    public void createXFigDiagram() {
        int [] colors = {0, 1, 2, 3, 4, 5, 6};
        PrintWriter file = null;
        String fileName = String.format("SSM_7Venn_%02d.fig", figNo);
        
        try {
            file = new PrintWriter(fileName);
        } catch (java.io.IOException e) {
            
        }
        
        //Writing the file header information
        file.println("#FIG 3.2");
        file.println("Landscape");
        file.println("Center");
        file.println("Inches");
        file.println("Letter");
        file.println("100.00");
        file.println("Single");
        file.println("-2");
        file.println("1200 2");
        
        xfigPoints = new int[400][2];
        double sectorLen = points[0][0].nextLen[1];
        double secHeight = points[0][0].y - points[n-2][0].y;
        rowSpace = 1 / (sectorLen);
        step = 2 * Math.PI /(n * sectorLen);

        double height = points[0][0].y + sectorLen * 0.5;
        double radious = 10 * polarX(0, getPhi(height));
        
        ratio = 2500.0 / radious;
        drawBox(file, radious, ratio, 200);
        
        for (int sec = 0; sec < n; sec++) {
            pointsCount = 0;
            int i = 0;
            int j = 0;
            int dir = -1;
            double x = points[0][0].x;
            double y = points[0][0].y;
            double nx, ny;
            
            do {
                savePoint(sec, x , y);
                
                if (points[i][j].nextPoints[0][2 - dir] != 0) {
                    nx = x + points[i][j].nextLen[2 - dir];
                    j = points[i][j].nextPoints[1][2 - dir];
                    i = i - dir;
                    ny = points[i][j].y;
                    double d = nx - x;
                    if ( d > 1.0) {
                        for ( double k = 1.0; k < d; k++) {
                            savePoint(sec, x + k , y + dir * k);
                        }
                    }
                } else {
                    nx = x + points[i][j].nextLen[2 - dir];
                    ny = points[i][points[i][j].nextPoints[1][2 - dir]].y;
                    double mx = getBalancedX(x, y, nx, ny, dir);
                    double my = getBalancedY(x, y, nx, ny, dir);
                    
                    double d1 = abs(my - y);
                    double d2 = abs(my - ny);
                    double d = (d1 <= d2) ? d1 : d2;
                    
                    x += d1 - d;
                    y += dir * (d1 - d);
                    for (int k = 1; k < 2; k++) {
                        savePoint(sec, x + k * d / 3, y + dir * k * d / 3);
                    }
                    savePoint(sec, mx, my);
                    dir = -dir;
                    for (int k = 2; k < 3; k++) {
                        savePoint(sec, mx + k * d / 3, my + dir * k * d / 3);
                    }
                    
                    j = points[i][j].nextPoints[1][2 + dir];
                }
                x = nx;
                y = ny;
            } while(i != 0 || j != 0 || dir == 1);
            
            int color = (colorMode == 0) ? 0 : colors[sec];
            file.print("3 1 0 2 " + color + " 7 50 -1 -1 0.000 0 0 0 " + pointsCount);
            for (i = 0; i < pointsCount; i++) {
                if (i % 6 == 0) {
                    file.println();
                    file.print("\t");
                }
                file.print(xfigPoints[i][0] + " " + xfigPoints[i][1] + " ");
            }
            for (i = 0; i < pointsCount; i++) {
                if (i % 6 == 0) {
                    file.println();
                    file.print("\t");
                }
                file.print("1.000 ");
            }
            file.println();
        }
        file.close();
    }
    
    private class VennPanel extends JPanel {
        private void drawLine(Graphics2D g, double xb, double yb, double xe, double ye, int slope) {
            
            double x1 = xb, y1 = yb;
            double x2, y2;
            double lineStep = 0.01;
            double px1, py1, px2, py2;
            double phi, t;
            
            t =  xb * step;
            phi = getPhi(yb);
            px1 = polarX(t, phi);
            py1 = polarY(t, phi);
            while (x1 < xe ) {
                x2 = x1 + lineStep;
                y2 = y1 + slope * lineStep;
                t =  x2 * step;
                phi = getPhi(y2);
                px2 = polarX(t, phi);
                py2 = polarY(t, phi);
                g.draw(new Line2D.Double(sxOrigin + px1, syOrigin + py1, sxOrigin + px2, syOrigin + py2));
                px1 = px2;
                py1 = py2;
                x1 = x2;
                y1 = y2;
            }
        }
        
        public void paintComponent(Graphics g) {
            Graphics2D g2D = (Graphics2D) g;
            BasicStroke thick = new BasicStroke(2.0f);
            
            Color [] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.BLUE, Color.CYAN, Color.GREEN, Color.ORANGE};
            double originX = 50.0;
            double originY = getHeight()/2 + 250;
            double unitLen = 10.0;
            double sectorLen = points[0][0].nextLen[1];
            step = 2 * Math.PI /(n * sectorLen);
            double startX = 0.0;
            double vSpace = points[0][0].y - points[n-2][0].y;
            rowSpace = 1 / sectorLen;
            sxOrigin = 650.0;
            syOrigin = 500.0;
            
            g2D.setStroke(thick);
            for (int sec = 0; sec < n; sec++) {
                for (int i = 0; i < points.length; i++) {
                    for (int j = 0; j < points[i].length; j++) {
                        double x1 = points[i][j].x + startX;
                        double y1 = points[i][j].y;
                        
                        if (j == 0) {
                            
                        }
                        for (int k = 0; k <= 1; k++) {
                            int index = 2 * k + 1;
                            double x2 = x1 + points[i][j].nextLen[index];
                            double y2 = points[i + points[i][j].nextPoints[0][index]][points[i][j].nextPoints[1][index]].y;
                            if (points[i][j].nextPoints[0][index] == 0) {
                                double mx = getBalancedX(x1, y1, x2, y2, 2 - index);
                                double my = getBalancedY(x1, y1, x2, y2, 2 - index);
                                double d1 = abs(my - y1);
                                double d2 = abs(my - y2);
                                double d = (d1 <= d2) ? d1 : d2;
                                
                                drawLine(g2D, x1, y1, mx, my, 2 - index);
                                drawLine(g2D, mx, my, x2, y2, index - 2);
                            } else {
                                drawLine(g2D, x1, y1, x2, y2, 2 - index);
                            }
                        }
                    }
                }
                startX += sectorLen;
            }
        }
        
    }
    
    public JPanel createVennDiagram() {
        return new VennPanel();
    }
    
    public void createArcDiagram() {
        int [] colors = {0, 1, 2, 3, 4, 5, 6};
        PrintWriter file = null;
        String fileName = String.format("Arc/SSM_7Venn_%02d.fig", figNo);
        
        try {
            file = new PrintWriter(fileName);
        } catch (java.io.IOException e) {
            
        }
        
        //Writing the file header information
        file.println("#FIG 3.2");
        file.println("Landscape");
        file.println("Center");
        file.println("Inches");
        file.println("Letter");
        file.println("100.00");
        file.println("Single");
        file.println("-2");
        file.println("1200 2");
        
        double sectorLen = points[0][0].nextLen[1];
        double secHeight = points[0][0].y - points[n-2][0].y;
        rowSpace = 1 / (sectorLen);
        step = 2 * Math.PI /(n * sectorLen);
        
        double height = points[0][0].y + sectorLen / 3.0;
        double radious = 10 * polarX(0, getPhi(height));
        
        ratio = 2000.0 / radious;
        drawBox(file, radious, ratio, 200);
        
        for (int sec = 0; sec < n; sec++) {
            int i = 0;
            int j = 0;
            int dir = -1;
            double x = points[0][0].x;
            double y = points[0][0].y;
            double nx, ny;
            
            do {
                
                if (points[i][j].nextPoints[0][2 - dir] != 0) {
                    nx = x + points[i][j].nextLen[2 - dir];
                    j = points[i][j].nextPoints[1][2 - dir];
                    i = i - dir;
                    ny = points[i][j].y;
                    saveLine(file, sec, x, y, nx, ny, dir);
                } else {
                    nx = x + points[i][j].nextLen[2 - dir];
                    ny = points[i][points[i][j].nextPoints[1][2 - dir]].y;
                    double mx = getBalancedX(x, y, nx, ny, dir);
                    double my = getBalancedY(x, y, nx, ny, dir);

                    double d1 = abs(my - y);
                    double d2 = abs(my - ny);
                    double d = (d1 <= d2) ? d1 : d2;
                    double sx = x, sy = y;
                    double ex = nx, ey = ny;
                    
                    if (d1 - d != 0) {
                        sx = x + d1 - d;
                        sy = y + dir * (d1 - d);
                        saveLine(file, sec, x, y, sx, sy, dir);
                    }
                    else if (d2 - d != 0) {
                        ex = nx - (d2 - d);
                        ey = ny + dir * (d2 - d);
                    }
                    saveArc(file, sec, sx, sy, mx, my - 2 * dir * d / 3, ex, ey, dir);
                    dir = -dir;
                    if (d2 - d != 0) {
                        saveLine(file, sec, ex, ey, nx, ny, dir);
                    }
                    j = points[i][j].nextPoints[1][2 + dir];
                }
                x = nx;
                y = ny;
            } while(i != 0 || j != 0 || dir == 1);
            
        }
        file.close();        
    }

    private void saveLine(PrintWriter file, int curve, double x1, double y1, double x2, double y2, int dir) {
        double teta, phi;
        double d = x2 - x1;
        double dx = 0.5;
        int points = (int) (Math.ceil(d / dx)) + 1;
        file.println("2 1 0 2 0 7 50 -1 -1 0.000 0 0 0 0 0 " + points);
        double sx = x1;
        double sy = y1;
        do {
            teta = sx * step + curve * 2 * Math.PI / n;;
            phi = getPhi(sy) ;
            int fx1 = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
            int fy1 = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);        
            file.print(fx1 + " " + fy1 + " ");        
            
            sx += dx;
            sy += dir * dx;
        }
        while (sx < x2);
        teta = x2 * step + curve * 2 * Math.PI / n;;
        phi = getPhi(y2) ;
        int fx1 = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
        int fy1 = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);
        file.println(fx1 + " " + fy1);
    }
    
    private void saveArc(PrintWriter file, int curve, double x1, double y1, double x2, double y2, double x3, double y3, int dir) {
        double t;
        if (dir == -1) {
            t = x1;
            x1 = x3;
            x3 = t;
            t = y1;
            y1 = y3;
            y3 = t;
        }
        double a, b1, b2;
        double teta = x1 * step + curve * 2 * Math.PI / n;;
        double phi = getPhi(y1) ;
        int sx1 = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
        int sy1 = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);
        
        teta = x2 * step + curve * 2 * Math.PI / n;;
        phi = getPhi(y2) ;
        int sx2 = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
        int sy2 = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);

        teta = x3 * step + curve * 2 * Math.PI / n;;
        phi = getPhi(y3) ;
        int sx3 = (int)( 5000 + 10 * polarX(teta, phi) * ratio);
        int sy3 = (int) ( 5000 + 10 * polarY(teta, phi) * ratio);

	 a = (sx1 - sx2) * (sy2 - sy3) - (sy1 - sy2) * (sx2 - sx3);
	 b1 = (sx1 - sx2) * (sx1 + sx2) + (sy1 - sy2) * (sy1 + sy2);
	 b2 = (sx2 - sx3) * (sx2 + sx3) + (sy2 - sy3) * (sy2 + sy3);
	 double x = (b1 * (sy2 - sy3) - b2 * (sy1 - sy2)) / (2 * a);
	 double y = (b2 * (sx1 - sx2) - b1 * (sx2 - sx3)) / (2 * a);
        
        
        file.print("5 1 0 2 0 7 50 -1 -1 0.000 0 0 0 0 ");
        file.println(String.format("%.3f %.3f ", x, y) + sx1 + " " + sy1 + " " + sx2 + " " + sy2 + " " + sx3 + " " + sy3);        
    }
        
    private void createCylindricalDiagram() {
        sectorPoints = new double[n][20][2];
        secPointsLen = new int[n];
        
        double sectorLen = points[0][0].nextLen[1];

        double height = points[0][0].y + sectorLen * 0.5;
        double radious = 10 * polarX(0, getPhi(height));
        
        ratio = 4136.0 / radious;

        int secNo = 0;
        secPointsLen[secNo] = 0;
        pointsCount = 0;
        int i = 0;
        int j = 0;
        int dir = 1;
        double x = points[0][0].x;
        double y = points[0][0].y;
        double nx, ny;
        double x0 = points[0][0].x;
        double mx;
        double my;
        double tempX, tempY;
        
        do {
            sectorPoints[secNo][secPointsLen[secNo]][0] = x;
            sectorPoints[secNo][secPointsLen[secNo]][1] = y;
            secPointsLen[secNo]++;
            
            if (points[i][j].nextPoints[0][2 - dir] != 0) {
                nx = x + points[i][j].nextLen[2 - dir];
                j = points[i][j].nextPoints[1][2 - dir];
                i = i - dir;
                ny = points[i][j].y;
                if (nx - x0 > (secNo + 1) * sectorLen && secNo < n - 1) {
                    tempX = x0 + (secNo + 1) * sectorLen;
                    tempY = ny - dir * (nx - x0 - (secNo + 1) * sectorLen );
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                    secNo++;
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                }
            } else {
                nx = x + points[i][j].nextLen[2 - dir];
                ny = points[i][points[i][j].nextPoints[1][2 - dir]].y;
                mx = getBalancedX(x, y, nx, ny, dir);
                my = getBalancedY(x, y, nx, ny, dir);
                
                if (mx - x0 > (secNo + 1) * sectorLen && secNo < n - 1) {
                    tempX = x0 + (secNo + 1) * sectorLen;
                    tempY = my - dir * (mx - x0 - (secNo + 1) * sectorLen);
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                    secNo++;
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                }
                sectorPoints[secNo][secPointsLen[secNo]][0] = mx;
                sectorPoints[secNo][secPointsLen[secNo]][1] = my;
                secPointsLen[secNo]++;
                if (nx - x0 > (secNo + 1) * sectorLen && secNo < n - 1){
                    tempX = x0 + (secNo + 1) * sectorLen;
                    tempY = ny + dir * (nx - x0 - (secNo + 1) * sectorLen);
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                    secNo++;
                    sectorPoints[secNo][secPointsLen[secNo]][0] = tempX;
                    sectorPoints[secNo][secPointsLen[secNo]][1] = tempY;
                    secPointsLen[secNo]++;
                }
                dir = -dir;
                
                j = points[i][j].nextPoints[1][2 + dir];
            }
            x = nx;
            y = ny;
        } while(i != 0 || j != 0 || dir == -1);
        sectorPoints[secNo][secPointsLen[secNo]][0] = x;
        sectorPoints[secNo][secPointsLen[secNo]][1] = y;
        secPointsLen[secNo]++;
    }
    
    public void createCylindrical() {
        double sectorLen = points[0][0].nextLen[1];
        double ratio = 12.0 / sectorLen;
        createCylindricalDiagram();
        int [] colors = {0, 1, 2, 3, 4, 5, 31};
        PrintWriter file = null;
        String fileName = String.format("Cylindrical_%02d.fig", figNo);
        
        try {
            file = new PrintWriter(fileName);
        } catch (java.io.IOException e) {
            
        }
        
        //Writing the file header information
        file.println("#FIG 3.2");
        file.println("Landscape");
        file.println("Center");
        file.println("Inches");
        file.println("Letter");
        file.println("100.00");
        file.println("Single");
        file.println("-2");
        file.println("1200 2");
        
        int curvePoints = 0;
        for (int i = 0; i < n; i++) {
            curvePoints += secPointsLen[i];
        }
        curvePoints -= n - 1;
        
        int x;
        int y;
        for (int curve = 0; curve < n; curve++) {
            file.println("2 1 0 2  " + colors[curve] + " 7 50 -1 -1 0.000 0 0 0 0 0 " + curvePoints);
            double offset = curve * sectorLen;
            x = (int) (2000 + 100 * ratio * (sectorPoints[curve][0][0] - offset));
            y = (int) (3000 - 100 * ratio * sectorPoints[curve][0][1]);
            file.print(x + " " + y + " ");
            for (int sec = curve; sec < n ; sec++) {
                for (int i = 1; i < secPointsLen[sec]; i++) {
                    x = (int) (2000 + 100 * ratio * (sectorPoints[sec][i][0] - offset));
                    y = (int) (3000 - 100 * ratio * sectorPoints[sec][i][1]);
                    file.print(x + " " + y + " ");
                }
            }
            
            offset = (n - curve) * sectorLen;
            for (int sec = 0; sec < curve; sec++) {
                for (int i = 1; i < secPointsLen[sec]; i++) {
                    x = (int) (2000 + 100 * ratio * (sectorPoints[sec][i][0] + offset));
                    y = (int) (3000 - 100 * ratio * sectorPoints[sec][i][1]);
                    file.print(x + " " + y + " ");
                }
            }
            file.println();
        }
        
        file.close();
    }
    
    public int getTotalBalanced() {
        totalBalanced = 0;
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length - 1; j++) {
                for (int k = j + 1; k < points[i].length; k++) {
                    if (points[i][j].y != points[i][k].y) {
                        totalBalanced++;
                    }
                }
            }
        }
        return totalBalanced;
    }
    
}
