package yi.iu.processor.clc;

import yi.iu.processor.clc.*;

import yi.iu.processor.*;
import yi.iu.processor.building.*;
import yi.iu.processor.ort.*;
import yi.iu.processor.filter.GaussianSmooth;
import yi.iu.ui.*;
import yi.iu.processor.color.*;
import yi.util.io.*;
import yi.util.ImageUtil;
import yi.ds.Merge;

import java.awt.*;
import java.util.Vector;
import java.io.*;

/**
 * Construct line clusters based on inter-relationship and intra-relationship
 * @depracated inter-relationship part is replaced by CLC_Interrelationship
 */
public class CSOSSM extends yi.iu.processor.clc.ConsistentLineCluster
{
    public static boolean TEST=false;
    public static boolean TESTOL=false;

    static double INTERTHRSH=0.6;   //how much lines intersect will be considered as related
    //static int INTERLENTHRSH=12;
    static int INTERLENTHRSH=5;
    //static int CONINTERLENTHRSH=20;
    static int CONINTERLENTHRSH=10;
    static double INTERLOOSERATIO=2;
    public int Thuge=30;                   //the size of overlaped line cluster
    public double Tlenforollines= 0.75;    //the width of considered overlaped lines must > 0.75
    double StrictSV=0.5;
    double StrictSH=0.8;
    int Tonline=5;

    int mon1=-1;
    int mon2=-1;
    int out4test=-1;
    public int getArguNum() { return 4;}

    public void setArgument(int i, String st)
    {
        if (st.length()==0) return;
        if (i==0) mon1= Integer.valueOf(st).intValue();
        if (i==1) mon2= Integer.valueOf(st).intValue();
        if (i==2) testCluster= Integer.valueOf(st).intValue();
        if (i==3) out4test= Integer.valueOf(st).intValue();
    }

    public String getArgument(int i)
    {
        if (i==0) return (new Integer(mon1)).toString();
        if (i==1) return (new Integer(mon2)).toString();
        if (i==2) return (new Integer(testCluster)).toString();
        if (i==3) return (new Integer(out4test)).toString();
        return null;
    }

    public String getArguName(int i)
    {
        if (i==0) return "mon1";
        if (i==1) return "mon2";
        if (i==2) return "TestCluster";
        if (i==3) return "out4test";
        return null;
    }

    public int[] getProcessed(int source[], Dimension d)
    {
        return null;
    }

    public LineCluster[] getProcessed_ex(int source[], Dimension d, Object ref[])
    {
        int i,j;

        //get the line clusters (classified by color information) stored in lc
        CSOSSCLC csoss= new CSOSSCLC();
        LineCluster[] lc= csoss.getProcessed_ex(source, d, ref);
        int[] dominant_colors= (int[])ref[0];
        int cNum=dominant_colors.length;
        Vector lines= (Vector)ref[1];
        int[][] lineColor= (int[][])ref[2];

        if (true) {
            for (i=0;i<lc.length;i++) {
                for (j=0;j<lc[i].size();j++) {
                    ORTLine l= lc[i].getLineAt(j);
                    if (l.MidPoint.Col!=(l.Start.Col+l.End.Col)/2||l.MidPoint.Row!=(l.Start.Row+l.End.Row)/2)
                        System.err.println("wrong!"+l.MidPoint+","+l.Start+","+l.End);
                }
            }
        }
        if (mon1>=0&&mon2>=0) {
            testInter(source, d, lc[mon1], lc[mon2]);
        }
        if (testCluster>=0) lc[testCluster-1].output();

        filterSmallClusters(lc);

        //drawLineClusters("pre-merge", d, lc, testCluster);

        //get the building candidates
        Vector intersects= new Vector();

        //LineCluster[] ilcs= postMerge(source ,d, lc, lines, intersects);
        LineCluster[] ilcs;
        if (TESTOL) ilcs= new LineCluster[0];
        else ilcs= intersectClusters(source ,d, lc, lines, intersects);
        //return ilcs;

        LineCluster[] hlcs= intraClusters(source ,d, lc, lines, intersects);
        //return hlcs;
        if (TESTOL) ArgumentExperiment_ol.output(hlcs);

        int realsize=0;
        for (i=0;i<ilcs.length;i++) if (ilcs[i].size()>0) realsize++;
        LineCluster[] cans= new LineCluster[realsize+hlcs.length];
        int realcount=0;
        for (i=0;i<ilcs.length;i++) if (ilcs[i].size()>0) cans[realcount++]=ilcs[i];
        for (i=0;i<hlcs.length;i++) cans[i+realsize]=hlcs[i];


        if (TEST&&!TESTOL) {
            int[] background= yi.util.ImageUtil.makeBackground(source);
            ArgumentExperiment.rstImg= drawLineClusters_nodisplay(
                "postMerge", background, d, cans, -1);
            System.err.println("cans#:"+cans.length);
        }
        return cans;

        //drawLineClusters("postMerge", d, mlcs, testCluster);
        /*
        //mark out the intersectant points
        for (i=0;i<intersects.size();i++) {
            ORTConjLineGroup clg= (ORTConjLineGroup)intersects.elementAt(i);
            double cx= clg.JunctionPt.Col, cy= clg.JunctionPt.Row;
            int index=(int)(Math.round(cy)*d.width+Math.round(cx));
            int color=0xffffffff;
            DrawUtil.drawMark(demo,d,(int)Math.round(cx),(int)Math.round(cy),4,color);
        }
        //mark out the no.1 line cluster
        if (bCans.size()>0) {
            LineCluster lcl= (LineCluster)bCans.elementAt(0);
            for (j=0;j<lcl.size();j++) {
                ORTLine line= lcl.getLineAt(j);
                DrawUtil.ort2image(demo, d, line, 0xff00ff00, 1);
            }
        }

        //mark out the building candidates
        double bx1=1, bx2=0, by1=1, by2=0;  //the boundary for the all clusters
        for (i=0;i<bCans.size();i++) {
            LineCluster lcl= (LineCluster)bCans.elementAt(i);
            if (lcl==null||lcl.size()==0) continue;
            //find the range of the line cluster
            ORTLine line= lcl.getLineAt(0);
            double minx=line.Start.Col, miny=line.Start.Row,
                maxx=line.Start.Col, maxy=line.Start.Row;
            for (j=0;j<lcl.size();j++) {
                line= lcl.getLineAt(j);
                if (line.Start.Col<minx) minx=line.Start.Col;
                if (line.Start.Col>maxx) maxx=line.Start.Col;
                if (line.End.Col<minx) minx=line.End.Col;
                if (line.End.Col>maxx) maxx=line.End.Col;
                if (line.Start.Row<miny) miny=line.Start.Row;
                if (line.Start.Row>maxy) maxy=line.Start.Row;
                if (line.End.Row<miny) miny=line.End.Row;
                if (line.End.Row>maxy) maxy=line.End.Row;
            }
            //change the boundary
            if (i==0) {
                bx1= minx; by1= miny; bx2= maxx; by2= maxy;
            }
            else {
                if (minx<bx1) bx1=minx;
                if (maxx>bx2) bx2=maxx;
                if (miny<by1) by1=miny;
                if (maxy>by2) by2=maxy;
            }

            //draw the boundary of the cluster
            if (i==0)
                DrawUtil.drawRectangle(demo, d, minx, miny, maxx, maxy, 0xffff0000, 2);
            else
                DrawUtil.drawRectangle(demo, d, minx, miny, maxx, maxy, 0xff0000ff, 1);
        }
*/
    }

    public int[] getProcessedPseudoColor(int source[], Dimension d)
    {
        Object[] ref= new Object[4];
        LineCluster[] mlcs= getProcessed_ex(source, d, ref);
        int[] dominant_colors= (int[])ref[0];
        int cNum=dominant_colors.length;
        Vector lines= (Vector)ref[1];
        int[][] lineColor= (int[][])ref[2];

        if (mlcs!=null&&mlcs.length!=0) {
            int[] background= yi.util.ImageUtil.makeBackground(source);
            if (out4test>=0) mlcs[out4test].output();
            int[] img= drawLineClusters_nodisplay("postMerge", background, d, mlcs, testCluster);
            //(new DisplayFrame("clc", img, d)).show();
            return img;
        }
        else return null;
        //drawLineClusters("postMerge", background, d, mlcs, testCluster);
        //return null;
    }
/*
    public LineCluster[] postMerge(int[] img, Dimension d, LineCluster[] lcs, Vector lines, Vector intersects)
    {
        int i,j,m,n;

        int lcNum= lcs.length;  //the number of line cluster

        //the size of the line clusters
        int[] sizes= new int[lcNum];
        for (i=0;i<lcNum;i++) sizes[i]= lcs[i].size();

        //merge two clusters if most lines of one are intersect with another
        Merge merge=new Merge(lcNum);
        for (i=0;i<lcNum;i++) {
            LineCluster lc1=lcs[i];
            if (lc1.size()<TCS) continue;
            double weightedSum=lc1.weightedSize(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT);
            for (j=0;j<lcNum;j++) {
                if (i==j) continue;
                LineCluster lc2=lcs[j];
                if (lc2.size()<TCS) continue;
                int interCount=0;
                if (i==66&&j==52) {
                    interCount=0;
                }

                double weightedInter=0;
                for (m=0;m<sizes[i];m++) {
                    ORTLine l1= lc1.getLineAt(m);
                    boolean inter=false;
                    for (n=0;n<sizes[j];n++) {
                        ORTLine l2= lc2.getLineAt(n);
                        ORTLineGroup lg= Lpeg.loose_lineRelation_closeJunction(l1,l2,2,4,0.06,0.8,INTERLOOSERATIO);
                        //MaxWidthOverHeight= 2.0;   useless in junction type
                        //MinLineLength= 4.0;   if the length of any line < this value, return null
                        //MinDeltaTheta= 0.06;  [0,this]:parallel, [this,pi/2]:junction
                        //MinQuality= 0.8;  if the quaulity of the group < this value, return null
                        //LooseRatio= 2
                        if (lg==null) continue;
                        else {
                            inter=true;;
                            intersects.addElement(lg);
                            break;
                        }
                    }
                    if (inter) {
                        interCount++;
                        weightedInter+=l1.weightedLength(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT);
                    }
                }

                int lc1Num= lc1.size();
                int lc2Num= lc2.size();
                if (weightedInter>weightedSum) {
                    System.err.println("WRONG!!!: i="+i+", j="+j);
                    System.err.println("the total: "+lc1.weightedSize(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT));
                    System.err.println("but the inter:"+weightedInter);
                }

                if (weightedInter>weightedSum*INTERTHRSH) {
                    System.err.println("merge! "+i+"("+weightedInter+"/"+weightedSum+")"+j+"("+lc2Num+")");
                    merge.merge(i, j);
                }

            }
        }

        int[] mergeRst= merge.result();
        LineCluster[] newlcs= new LineCluster[lcs.length];
        for (i=0;i<newlcs.length;i++) newlcs[i]= new LineCluster();
        for (i=0;i<lcs.length;i++) {
            LineCluster lc=lcs[i];
            int newIndex=mergeRst[i];
            for (j=0;j<lc.size();j++) {
                newlcs[newIndex].insert(lc.getLineAt(j));
            }
        }

        return newlcs;
    }
*/
/**
     * Find intersection of line clusters
     * @param lcs line clusters
     * @param lines lines
     * @param intersects to return the intersects
     * @return result line clusters after merging intersecting line clusters
     */
        public LineCluster[] intersectClusters(int[] img, Dimension d, LineCluster[] lcs, Vector lines, Vector intersects)
    {
        int i,j,m,n;
        /*
        Vector nlc= new Vector();
        for (j=0;j<lcs.length;j++) {
            LineCluster lc= lcs[j];
            Vector tmp= lc.clusterByLength();
            for (int k=0;k<tmp.size();k++)
                nlc.addElement(tmp.elementAt(k));
        }
        lcs= new LineCluster[nlc.size()];
        for (i=0;i<nlc.size();i++) lcs[i]= (LineCluster)nlc.elementAt(i);
        */
        int lcNum= lcs.length;  //the number of line cluster

        //the size of the line clusters
        int[] sizes= new int[lcNum];
        for (i=0;i<lcNum;i++) sizes[i]= lcs[i].size();

        //remember whether a line is intersect with anothers
        boolean[][] bintersect= new boolean[lcNum][];
        for (i=0;i<lcNum;i++) bintersect[i]= new boolean[lcs[i].size()];

        //merge two clusters if most lines of one are intersect with another
        Merge merge=new Merge(lcNum);
        for (i=0;i<lcNum;i++) {
            LineCluster lc1=lcs[i];
            if (lc1.size()<TCS) continue;
            boolean[] tinter= new boolean[lc1.size()];
            double weightedSum=lc1.weightedSize(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT);
            for (j=0;j<lcNum;j++) {
                if (i==j) continue;
                LineCluster lc2=lcs[j];
                if (lc2.size()<TCS) continue;
                for (m=0;m<tinter.length;m++) tinter[m]=false;

                double weightedInter=0;
                int interCount=0;       // intersecting line number in cluster-i
                int intersectNum = 0;   // intersection number made by two clusters
                for (m=0;m<sizes[i];m++) {  // every line in line cluster-i
                    ORTLine l1= lc1.getLineAt(m);
                    boolean inter=false;
                    for (n=0;n<sizes[j];n++) { // every line in line cluster-j
                        ORTLine l2= lc2.getLineAt(n);
                        //MinDeltaTheta= 0.35;(20 degree) to only consider the good intersect
                        ORTLineGroup lg= Lpeg.loose_lineRelation_closeJunction(l1,l2,2,4,0.35,0.8,INTERLOOSERATIO);
                        //MaxWidthOverHeight= 2.0;   useless in junction type
                        //MinLineLength= 4.0;   if the length of any line < this value, return null
                        //MinDeltaTheta= 0.06;  [0,this]:parallel, [this,pi/2]:junction
                        //MinQuality= 0.8;  if the quaulity of the group < this value, return null
                        //LooseRatio= 3
                        if (lg==null) continue;
                        else {        // they are intersected
                            inter=true;;
                            //intersects.addElement(lg);
                            intersectNum ++;
                        }
                    }
                    if (inter) {        // this line is intersected by some line from line cluster-j
                        interCount++;
                        weightedInter+=l1.weightedLength(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT);
                        tinter[m]=true;
                    }
                }

                int lc1Num= lc1.size();
                int lc2Num= lc2.size();
                if (weightedInter>weightedSum) {
                    System.err.println("WRONG!!!: i="+i+", j="+j);
                    System.err.println("the total: "+lc1.weightedSize(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT));
                    System.err.println("but the inter:"+weightedInter);
                }

                if (TEST) {
                    if (interCount>ArgumentExperiment.maxInterSize)
                        ArgumentExperiment.maxInterSize=interCount;
                    if (weightedInter>ArgumentExperiment.maxInterSizeW)
                        ArgumentExperiment.maxInterSizeW=weightedInter;
                }

                /*
                if (interCount>lc1Num*INTERTHRSH) {
                    System.err.println("merge! "+i+"("+interCount+"/"+lc1Num+")"+j+"("+lc2Num+")");
                    merge.merge(i, j);
                }
                */

                //if (weightedInter>=weightedSum*INTERTHRSH||weightedInter>=INTERLENTHRSH) {
                //if (weightedInter>weightedSum*INTERTHRSH||interCount>10) {
                if (TEST||interCount>=INTERLENTHRSH) {
                    //test the the merged lines in the another line cluster
                    boolean[] another= new boolean[sizes[j]];
                    for (m=0;m<tinter.length;m++) {
                        if (!tinter[m]) continue;
                        ORTLine l1= lc1.getLineAt(m);
                        for (n=0;n<sizes[j];n++) {
                            ORTLine l2= lc2.getLineAt(n);
                            ORTLineGroup lg= Lpeg.loose_lineRelation_closeJunction(l1,l2,2,4,0.06,0.8,INTERLOOSERATIO);
                            if (lg!=null) {
                                another[n]=true;
                            }
                        }
                    }
                    //calculate the weighted line length in the another line cluter
                    double weightedInter2=0;
                    int interCount2=0;
                    for (n=0;n<sizes[j];n++) {
                        if (another[n]) {
                            ORTLine l2= lc2.getLineAt(n);
                            weightedInter2+= l2.weightedLength(LineCluster.STANDARDLEN, LineCluster.MAXWEIGHT);
                            interCount2++;
                        }
                    }

                    if (TEST) {
                        if (interCount+interCount2>ArgumentExperiment.maxInterCombineSize) {
                            ArgumentExperiment.maxInterCombineSize=interCount+interCount2;
                        }
                        if (weightedInter+weightedInter2>ArgumentExperiment.maxInterCombineSizeW)
                            ArgumentExperiment.maxInterCombineSizeW=weightedInter+weightedInter2;
                        if (interCount>=INTERLENTHRSH) {
                            if (interCount+interCount2>ArgumentExperiment.maxInterCombineSizeR)
                                ArgumentExperiment.maxInterCombineSizeR=interCount+interCount2;
                            if (weightedInter+weightedInter2>ArgumentExperiment.maxInterCombineSizeWR)
                                ArgumentExperiment.maxInterCombineSizeWR=weightedInter+weightedInter2;
                        }

                        ArgumentExperiment.interClusters(
                            lc1,
                            lc2,
                            tinter,
                            another,
                            interCount,
                            interCount2,
                            intersectNum);
                    }

                    if (TEST&&!(interCount>=INTERLENTHRSH)) continue;


                    //if (weightedInter2<INTERLENTHRSH && weightedInter2<weightedInter/2)
                    if (interCount+interCount2<CONINTERLENTHRSH)
                        continue;

                    if (inter_related(interCount,interCount2,lc1.size(),lc2.size())) {
                        if (VERBOSE) System.err.println("merge! "+i+"("+weightedInter+"/"+weightedSum+")"+j+"("+lc2Num+")");
                        merge.merge(i, j);
                        for (m=0;m<tinter.length;m++)
                            if (tinter[m]) bintersect[i][m]=true;
                        for (n=0;n<another.length;n++)
                            if (another[n]) bintersect[j][n]=true;
                    }
                }

            }
        }

        int[] mergeRst= merge.result();
        boolean[] roots= merge.getRoots();
        LineCluster[] newlcs= new LineCluster[lcs.length];
        for (i=0;i<newlcs.length;i++) newlcs[i]= new LineCluster();
        for (i=0;i<lcs.length;i++) {
            LineCluster lc=lcs[i];
            int newIndex=mergeRst[i];
            if (!roots[newIndex]) continue;
            for (j=0;j<lc.size();j++) {
                if (bintersect[i][j])
                    newlcs[newIndex].insert(lc.getLineAt(j));
            }
        }

        return newlcs;
    }

    /*
     * s: size of the cluster
     * t: intersecting line number
     * rules:
     *      Ninter(10) > 34% and Ninter(19)>10% => building
     *      Ninter(10) > 34% and Ninter(8) > 52% => building
    */
    boolean inter_related(int s, int t) {
        if (s>=8  && (double)s/t > 0.52) return true;
        if (s>=10 && (double)s/t > 0.34) return true;
        if (s>=19 && (double)s/t > 0.10) return true;
        return false;
    }

    boolean inter_related(int s1, int s2, int t1, int t2) {
        if (inter_related(s1, t1) || inter_related(s2, t2)) return true;
//        if (s1+s2>8 && Math.max((double)s1/t1, (double)s2/t2)>0.8) return true;
//        if (s1+s2>14 && Math.max((double)s1/t1, (double)s2/t2)>0.6) return true;
//        if (s1+s2>30 && Math.max((double)s1/t1, (double)s2/t2)>0.31) return true;
        return false;
    }

    boolean isHuge(LineCluster lc)
    {
        //if (lc.size()>=Thuge&&(lc.weightedSize()>=Thuge||lc.weightedSize()/lc.size()>=Tlenforollines)) return true;
        if (lc.size()>=Thuge||lc.weightedSize()>=Thuge) return true;
        return false;
    }

    public LineCluster[] intraClusters(int[] img, Dimension d, LineCluster[] lcs, Vector lines, Vector intersects)
    {
        int i,j;

        //refine the clusters by spatial relationship, very strict!
        Vector rst = new Vector();
        for (i=0;i<lcs.length;i++) {
            if (i==203) System.err.println(String.valueOf(i)+":"+lcs[i].size());
            if (TEST) {
                if (lcs[i].size()>ArgumentExperiment.maxSize)
                    ArgumentExperiment.maxSize=lcs[i].size();
                if (lcs[i].weightedSize()>ArgumentExperiment.maxSizeW)
                    ArgumentExperiment.maxSizeW=lcs[i].weightedSize();
            }

            if (TESTOL) {
                if (lcs[i].size()>ArgumentExperiment_ol.maxSize)
                    ArgumentExperiment_ol.maxSize=lcs[i].size();
                if (lcs[i].weightedSize()>ArgumentExperiment_ol.maxSizeW)
                    ArgumentExperiment_ol.maxSizeW=lcs[i].weightedSize();
            }

            if (!TEST&&!TESTOL) {
                if (!isHuge(lcs[i])) continue;
            }
            lcs[i].refineByPerspectiveRelation();

            //Vector nlc= lcs[i].splitBySpatialRelation(StrictSV,StrictSH,0,0.5);
            //Vector nlc= lcs[i].splitBySpatialRelation(StrictSV,StrictSH,0);
            Vector nlc_0= lcs[i].splitBySpatialRelation(StrictSV,StrictSH,0);
            Vector nlc= new Vector();
            for (j=0;j<nlc_0.size();j++) {
                LineCluster lc= (LineCluster)nlc_0.elementAt(j);
                Vector tmp= lc.clusterByLength();
                for (int k=0;k<tmp.size();k++)
                    nlc.addElement(tmp.elementAt(k));
            }
            for (j=0;j<nlc.size();j++) {
                LineCluster lc= (LineCluster)nlc.elementAt(j);
                LineCluster lc0= lc.copy();
                if (TEST) {
                    if (lc.size()>ArgumentExperiment.maxSizeAfterSpatial)
                        ArgumentExperiment.maxSizeAfterSpatial= lc.size();
                    if (lc.weightedSize()>ArgumentExperiment.maxSizeAfterSpatialW)
                        ArgumentExperiment.maxSizeAfterSpatialW= lc.weightedSize();
                }

                if (!TEST&&!TESTOL)
                    if (!isHuge(lc)) continue;
                while (TEST||TESTOL||isHuge(lc)) {
                    int size1= lc.size();
                    int t_online=(int)Math.max(Tonline,Math.sqrt(size1));
                    lc.verifyByHorOverlap_1(t_online);
                    //if (lc.size()>=size1*0.8&&size1-lc.size()<5) break;
                    if (size1-lc.size()<5) break;
                }
                if (TEST) {
                    if (lc.size()>ArgumentExperiment.maxSizeAfterOverlap)
                        ArgumentExperiment.maxSizeAfterOverlap= lc.size();
                    if (lc.weightedSize()>ArgumentExperiment.maxSizeAfterOverlapW)
                        ArgumentExperiment.maxSizeAfterOverlapW= lc.weightedSize();
                }
                /*
                if (isHuge(lc)) {
                    if (VERBOSE) System.err.println("found huge #"+rst.size()+" at "+i+": "+lc.size()+"/"+lcs[i].size());
                    rst.addElement(lc);
                }
                */
                if (intra_related(lc0,lc)) {
                    if (VERBOSE) System.err.println("found intra-related #"+rst.size()+" at "+i+": "+lc.size()+"/"+lcs[i].size());
                    rst.addElement(lc);
                    System.err.println("found! "+lc0.size()+","+lc.size());

                }
                if (TESTOL) {
                    ArgumentExperiment_ol.aCluster(lc0,lc);
                }
            }
        }

        LineCluster[] newlcs= new LineCluster[rst.size()];
        for (i=0;i<newlcs.length;i++) newlcs[i]= (LineCluster)rst.elementAt(i);

        return newlcs;
    }

    boolean intra_related(LineCluster lc0, LineCluster lc1) {
        //return (lc1.size()>=20&&lc1.size()>=lc0.size()*0.4);
        //return (lc1.size()>=12&&lc1.size()>=lc0.size()*0.3);
        if (  (lc0.size()>0 &&lc1.size()>lc0.size()*.33)
            &&(lc0.size()>15&&lc1.size()>0 )) return true;
        return false;
    }

    public  void testInter(int[] source, Dimension d, LineCluster lc1, LineCluster lc2)
    {
        LineCluster[] lcs= {lc1, lc2};
        Vector intersects= new Vector();
        LineCluster[] mlcs= intersectClusters(source ,d, lcs, null, intersects);

        drawLineClusters("postMerge", d, mlcs, -1);
        //mark out the intersectant points
        int[] demo = new int[d.width*d.height];
        for (int i=0;i<source.length;i++) demo[i]=0xff000000;
        for (int i=0;i<intersects.size();i++) {
            ORTConjLineGroup clg= (ORTConjLineGroup)intersects.elementAt(i);
            double cx= clg.JunctionPt.Col, cy= clg.JunctionPt.Row;
            int index=(int)(Math.round(cy)*d.width+Math.round(cx));
            int color=0xff800000;
            DrawUtil.drawMark(demo,d,(int)Math.round(cx),(int)Math.round(cy),4,color);
        }
        drawLineClusters(demo, d, lcs, -1, 0xffffffff);
        int[] label= new int[demo.length];
        for (int i=0;i<lc1.size();i++) {
            ORTLine l= lc1.getLineAt(i);
            DrawUtil.ort2image(label, d, l, i, 1);
        }
        for (int i=0;i<lc2.size();i++) {
            ORTLine l= lc2.getLineAt(i);
            DrawUtil.ort2image(label, d, l, i, 1);
        }
        (new SegFrame("inter", demo, d.width, d.height, label)).show();
    }

    public  void testHuge(int[] source, Dimension d, LineCluster lc)
    {

        double kx1=-58.0,ky1=-49.0,kx2=-58.0,ky2=-45.0;
        for (int k=0;k<lc.size();k++) {
            ORTLine kl=(ORTLine)lc.getLineAt(k);
            if ((kl.Start.Col==kx1&&kl.Start.Row==ky1)||
                (kl.Start.Col==kx2&&kl.Start.Row==ky2)) {
                System.err.println("found at "+k+":"+kl.Start.Col+","+kl.Start.Row+","
                    +kl.Start.Col+","+kl.Start.Row);
                }
        }

        LineCluster[] lcs= {lc};
        Vector intersects= new Vector();
        LineCluster[] hlcs= intraClusters(source ,d, lcs, null, intersects);

        for (int l=0;l<hlcs.length;l++) {
            for (int k=0;k<hlcs[l].size();k++) {
                ORTLine kl=(ORTLine)hlcs[l].getLineAt(k);
                if ((kl.Start.Col==kx1&&kl.Start.Row==ky1)||
                    (kl.Start.Col==kx2&&kl.Start.Row==ky2)) {
                    System.err.println("found at "+l+"/"+k+":"+kl.Start.Col+","+kl.Start.Row+","
                        +kl.Start.Col+","+kl.Start.Row);
                    }
            }
        }

        drawLineClusters("postMerge", d, hlcs, -1);

        int[] demo = new int[d.width*d.height];
        for (int i=0;i<source.length;i++) demo[i]=0xff000000;
        drawLineClusters(demo, d, lcs, -1, 0xffffffff);
        int[] label= new int[demo.length];
        for (int i=0;i<lc.size();i++) {
            ORTLine l= lc.getLineAt(i);
            DrawUtil.ort2image(label, d, l, i, 1);
        }
        (new SegFrame("inter", demo, d.width, d.height, label)).show();
    }

    public static void main(String[] args)
    {
LineCluster lc0= new LineCluster(66,56,112);
lc0.insert(new ORTLine(-152.0,24.0,-153.0,59.0));
lc0.insert(new ORTLine(-154.0,21.0,-154.0,40.0));
lc0.insert(new ORTLine(-125.0,42.0,-126.0,27.0));
lc0.insert(new ORTLine(-170.0,37.0,-170.0,52.0));
lc0.insert(new ORTLine(-137.0,14.0,-137.0,28.0));
lc0.insert(new ORTLine(-42.0,-63.0,-42.0,-57.0));
lc0.insert(new ORTLine(-53.0,-31.0,-53.0,-37.0));
lc0.insert(new ORTLine(-61.0,-33.0,-61.0,-25.0));
lc0.insert(new ORTLine(-59.0,-26.0,-59.0,-34.0));
lc0.insert(new ORTLine(-72.0,-29.0,-72.0,-21.0));
lc0.insert(new ORTLine(-51.0,-39.0,-51.0,-30.0));
lc0.insert(new ORTLine(-75.0,-27.0,-75.0,-18.0));
lc0.insert(new ORTLine(-87.0,-22.0,-88.0,-13.0));
lc0.insert(new ORTLine(-84.0,-24.0,-84.0,-16.0));
lc0.insert(new ORTLine(-126.0,-22.0,-126.0,-28.0));
lc0.insert(new ORTLine(-123.0,-28.0,-123.0,-23.0));
lc0.insert(new ORTLine(-99.0,-17.0,-99.0,-10.0));
lc0.insert(new ORTLine(-96.0,-19.0,-97.0,-11.0));
lc0.insert(new ORTLine(-137.0,-17.0,-137.0,-22.0));
lc0.insert(new ORTLine(-140.0,-21.0,-140.0,-16.0));
lc0.insert(new ORTLine(-145.0,-17.0,-146.0,-13.0));
lc0.insert(new ORTLine(-108.0,-8.0,-108.0,-16.0));
lc0.insert(new ORTLine(-12.0,-44.0,-12.0,-54.0));
lc0.insert(new ORTLine(-44.0,-16.0,-44.0,-6.0));
lc0.insert(new ORTLine(-84.0,-4.0,-84.0,5.0));
lc0.insert(new ORTLine(-11.0,-3.0,-10.0,5.0));
lc0.insert(new ORTLine(-13.0,4.0,-13.0,-1.0));
lc0.insert(new ORTLine(-56.0,-33.0,-55.0,-23.0));
lc0.insert(new ORTLine(-124.0,-2.0,-124.0,-10.0));
lc0.insert(new ORTLine(-126.0,-9.0,-126.0,0.0));
lc0.insert(new ORTLine(-23.0,-48.0,-24.0,-37.0));
lc0.insert(new ORTLine(-96.0,1.0,-97.0,8.0));
lc0.insert(new ORTLine(-74.0,3.0,-75.0,-8.0));
lc0.insert(new ORTLine(-111.0,-15.0,-112.0,-4.0));
lc0.insert(new ORTLine(-146.0,-1.0,-146.0,3.0));
lc0.insert(new ORTLine(-102.0,3.0,-102.0,8.0));
lc0.insert(new ORTLine(-140.0,3.0,-140.0,-4.0));
lc0.insert(new ORTLine(-137.0,-4.0,-137.0,3.0));
lc0.insert(new ORTLine(-131.0,13.0,-130.0,17.0));
lc0.insert(new ORTLine(-72.0,15.0,-72.0,24.0));
lc0.insert(new ORTLine(-108.0,14.0,-108.0,3.0));
lc0.insert(new ORTLine(-14.0,-53.0,-14.0,-41.0));
lc0.insert(new ORTLine(-69.0,19.0,-68.0,25.0));
lc0.insert(new ORTLine(-98.0,19.0,-99.0,23.0));
lc0.insert(new ORTLine(-72.0,-10.0,-72.0,2.0));
lc0.insert(new ORTLine(-140.0,21.0,-140.0,13.0));
lc0.insert(new ORTLine(-119.0,27.0,-118.0,32.0));
lc0.insert(new ORTLine(-111.0,4.0,-111.0,18.0));
lc0.insert(new ORTLine(-55.0,44.0,-55.0,34.0));
lc0.insert(new ORTLine(-146.0,58.0,-146.0,53.0));
lc0.insert(new ORTLine(-121.0,65.0,-121.0,70.0));
lc0.insert(new ORTLine(-119.0,69.0,-119.0,65.0));
lc0.insert(new ORTLine(-64.0,65.0,-65.0,59.0));
lc0.insert(new ORTLine(-67.0,58.0,-67.0,67.0));
lc0.insert(new ORTLine(-146.0,73.0,-147.0,77.0));
lc0.insert(new ORTLine(-86.0,-47.0,-87.0,-37.0));
lc0.insert(new ORTLine(-84.0,-37.0,-83.0,-46.0));
lc0.insert(new ORTLine(-36.0,-45.0,-36.0,-36.0));
lc0.insert(new ORTLine(-34.0,-37.0,-34.0,-44.0));
lc0.insert(new ORTLine(-98.0,-41.0,-99.0,-32.0));
lc0.insert(new ORTLine(-96.0,-32.0,-96.0,-40.0));
lc0.insert(new ORTLine(-40.0,-40.0,-40.0,-30.0));
lc0.insert(new ORTLine(-110.0,-35.0,-111.0,-27.0));
lc0.insert(new ORTLine(-108.0,-27.0,-107.0,-35.0));
lc0.insert(new ORTLine(-67.0,-33.0,-67.0,-26.0));
lc0.insert(new ORTLine(-65.0,-27.0,-65.0,-32.0));
lc0.insert(new ORTLine(-80.0,-28.0,-80.0,-20.0));
lc0.insert(new ORTLine(-78.0,-21.0,-78.0,-27.0));
lc0.insert(new ORTLine(-14.0,-28.0,-14.0,-19.0));
lc0.insert(new ORTLine(-11.0,-19.0,-11.0,-28.0));
lc0.insert(new ORTLine(-20.0,-14.0,-20.0,-25.0));
lc0.insert(new ORTLine(-36.0,-21.0,-36.0,-13.0));
lc0.insert(new ORTLine(-33.0,-12.0,-33.0,-21.0));
lc0.insert(new ORTLine(-53.0,-16.0,-53.0,-7.0));
lc0.insert(new ORTLine(-51.0,-8.0,-51.0,-15.0));
lc0.insert(new ORTLine(-121.0,-12.0,-121.0,-6.0));
lc0.insert(new ORTLine(-118.0,-6.0,-118.0,-11.0));
lc0.insert(new ORTLine(-67.0,-11.0,-67.0,-3.0));
lc0.insert(new ORTLine(-65.0,-4.0,-65.0,-10.0));
lc0.insert(new ORTLine(-80.0,-7.0,-80.0,1.0));
lc0.insert(new ORTLine(-78.0,0.0,-78.0,-6.0));
lc0.insert(new ORTLine(-35.0,3.0,-35.0,13.0));
lc0.insert(new ORTLine(-33.0,12.0,-33.0,4.0));
lc0.insert(new ORTLine(-121.0,7.0,-121.0,13.0));
lc0.insert(new ORTLine(-118.0,12.0,-119.0,8.0));
lc0.insert(new ORTLine(-126.0,8.0,-126.0,18.0));
lc0.insert(new ORTLine(-123.0,17.0,-123.0,9.0));
lc0.insert(new ORTLine(-80.0,15.0,-80.0,23.0));
lc0.insert(new ORTLine(-78.0,22.0,-78.0,16.0));
lc0.insert(new ORTLine(-50.0,39.0,-50.0,32.0));
lc0.insert(new ORTLine(-110.0,42.0,-111.0,52.0));
lc0.insert(new ORTLine(-126.0,46.0,-126.0,55.0));
lc0.insert(new ORTLine(-140.0,48.0,-140.0,57.0));
lc0.insert(new ORTLine(-137.0,56.0,-137.0,49.0));
lc0.insert(new ORTLine(-110.0,63.0,-111.0,73.0));

LineCluster lc1= null;

        CSOSSM csossm= new CSOSSM();
        Dimension d= new Dimension(640, 480);
        int[] source = new int[d.width*d.height];
        for (int i=0;i<source.length;i++) source[i]=0xff000000;
        if (lc1!=null) csossm.testInter(source, d, lc0, lc1);
        else csossm.testHuge(source, d, lc0);
    }
}