package yi.iu.processor.ort;

import yi.iu.processor.*;
import yi.iu.ui.DisplayFrame;
import yi.iu.ui.SegFrame;

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

public class Lpeg extends yi.iu.processor.ImageProcessor
{
    boolean _CollinearToReal = false;   //Consider Collinear lines as real lines when forming junctions
    double  _MaxWidthOverHeight = 2.0;  //Max(Width/Height) for Overlap. = Min(Width/Height) for NonOverlap. Parallel
    double _MinLineLength      = 8.0;   //Minimum acceptable line length
    double _MinDeltaTheta      = 0.06;  //The angle between two lines. This parameter decides which lines maybe parallel/collinear,
    double _MinQuality		= 0.8;      //Minimum acceptable Quality level
    int _OutPutStatus 	= -1;  /* All */
        //0: NonOverlapping Parallel lines only,
        //1: Junctions only,
        //2: NonOverlapping Parallel lines/Collinear lines only,
        //3: Junctions/Collinear lines only
        //junctions: L junctions, V junctions, T junctions, Lambda junctions

    int _draw_type=1;

    static double PIBY2= Math.PI/2;     //1.570796

    public int getArguNum() { return 1;}

    public void setArgument(int i, String st)
    {
        if (st.length()==0) return;
        else if (i==0) _draw_type= Integer.valueOf(st).intValue();
    }

    public String getArgument(int i)
    {
        if (i==0)  return (new Integer(_draw_type)).toString();
        return null;
    }

    public String getArguName(int i)
    {
        if (i==0) return "draw type";
        return null;
    }



    public int[] getProcessed(int source[], Dimension d)
    {
        // This method is derived from class yi.iu.processor.ImageProcessor
        // to do: code goes here
        return null;
    }

    public int[] getProcessedPseudoColor(int source[], Dimension d)
    {
        Vector[] rst= lpeg(source,d,_CollinearToReal,_MaxWidthOverHeight,_MinLineLength,
                        _MinDeltaTheta,_MinQuality,_OutPutStatus);
        if (rst==null) return null;

        Vector ID_ListORTLine=rst[0];
        Vector ID_ListORTParallelNOV=rst[1];
        Vector ID_ListORTParallelOV=rst[2];
        Vector ID_ListORTCollinear=rst[3];
        Vector ID_ListORTLJunction=rst[4];
        Vector ID_ListORTVJunction=rst[5];
        Vector ID_ListORTTJunction=rst[6];
        Vector ID_ListORTLambdaJunction=rst[7];

        //draw an image
        char[][] label= new char[d.height][d.width];
        Vector ID_draw=rst[_draw_type];
        if (_draw_type==0)
            DrawUtil.ort2image( label, ID_draw, 1, 5);
        else
            DrawUtil.linegroup2image( label, ID_draw, 1);
        int[] label_1= yi.util.ImageUtil.twoD2oneD(label);
        int[] img= yi.util.ImageUtil.makeNewImageFromLabel(label_1);
        (new SegFrame("line_id", img, d.width, d.height, label_1)).show();

        //(new DisplayFrame("rst", img, d.width, d.height)).show();
        return img;
    }


    //decide the relationship between two lines.
    //given two lines, and return a line group which indicate the relationship
    static public ORTLineGroup lineRelation(ORTLine Line1, ORTLine Line2,
        double MaxWidthOverHeight,  // = 2.0;   when the WidthOverHeight > this value, the line group will be discard
        double MinLineLength,       // = 8.0;   if the length of any line < this value, return null
        double MinDeltaTheta,       // = 0.06;  [0,this]:parallel, [this,PI/2]:junction
        double MinQuality)          //	= 0.8;  if the quaulity of the group < this value, return null
    {
            if (MaxWidthOverHeight < 0.0) {
                    System.err.print("Error: Minimum Width/Height must be >= 0.0\n");
                    return(null);
            }
            if (MinLineLength < 4.0) {
                    System.err.print("Error: MinLineLength must be  >= 4.0\n");
                    return(null);
            }
            if (Line1.Length<MinLineLength||Line2.Length<MinLineLength) return null;

            double MinDeltaThetaPC= MinDeltaTheta, MinDeltaThetaJ= MinDeltaTheta;
            if (MinDeltaThetaPC > 0.1) {
                    System.err.print("Error: MinDeltaThetaParallel/Collinear must be <= 0.1radians\n");
                    return(null);
            }
            if (MinDeltaThetaJ > 0.1) {
                    System.err.print("Error: MinDeltaThetaJunctions must be <= 0.1radians\n");
                    return(null);
            }

            double MinQualityPC= MinQuality, MinQualityJ= MinQuality;
            if (MinQualityPC < 0.0 || MinQualityPC > 1.0) {
                    System.err.print("Error: MinQuality level for parallel lines must be >= 0.0 and <= 1.0\n");
                    return(null);
            }
            if (MinQualityJ < 0.0 || MinQualityJ > 1.0) {
                    System.err.print("Error: MinQuality level for junc. must be >= 0.0 and <= 1.0\n");
                    return(null);
            }

        //the angel between two lines
        double DeltaTheta =  Math.abs( Line1.Theta - Line2.Theta);
        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

        //Lines maybe parallel (overlapping/non-overlapping) or collinear
        if (DeltaTheta <= MinDeltaThetaPC) {

            VirtualLine VLine = new VirtualLine();
            double WidthOverHeight=0, Quality=0;
                double[] p_WidthOverHeight= {WidthOverHeight};
                double[] p_Quality={Quality};
                int Status = CheckParallelOrCollinear(Line1,Line2,VLine,MinQualityPC,p_WidthOverHeight,p_Quality);
                WidthOverHeight=p_WidthOverHeight[0]; Quality=p_Quality[0];

            ORTParLineGroup lg;
            switch (Status) {
                case -1:    return null;
                case 0:		/* Parallel non-overlapping lines */
                        if (WidthOverHeight > MaxWidthOverHeight) return null;
                    lg = new ORTParLineGroup(ORTLineGroup.PARALLEL_NO_OVERLAP);
                    break;
                case 1:		/* Parallel overlapping lines */
                        if (WidthOverHeight > MaxWidthOverHeight) return null;
                    lg = new ORTParLineGroup(ORTLineGroup.PARALLEL_OVERLAP);
                    break;
                case 2:		/* Collinear lines */
                    lg = new ORTParLineGroup(ORTLineGroup.COLLINEAR);
                    break;
                default:
                    return null;
            }
            lg.FirstID  = Line1;
            lg.SecondID = Line2;
            lg.VLLine   = VLine;
            lg.WidthOverHeight = WidthOverHeight;
            lg.Quality  = Quality;
            return lg;
        }

        //  ===================== JUNCTION TYPES ==================================
        else if (DeltaTheta >= MinDeltaThetaJ) {

                int jp1=0, jp2=0;
                int[] p_jp1={jp1} ,p_jp2={jp2};
                double JunctionPtCol=0,JunctionPtRow=0,Quality=0;
                double[] p_JunctionPtCol={JunctionPtCol}, p_JunctionPtRow={JunctionPtRow};
                double[] p_Quality={Quality};
                int Status = CheckJunctionType(Line1,Line2,p_jp1,p_jp2,p_JunctionPtCol,p_JunctionPtRow,
                            MinQualityJ,p_Quality);
            jp1=p_jp1[0];jp2=p_jp2[0];
                JunctionPtCol=p_JunctionPtCol[0];JunctionPtRow=p_JunctionPtRow[0];
                Quality=p_Quality[0];

                ORTConjLineGroup lg;
            if ( DeltaTheta >= (PIBY2 - MinDeltaThetaJ) ) {
                if (Status == 0||Status == 4)		/* L junction */
                    lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_L);
                else if (Status > 0 && Status != 4) /* T junction */
                    lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_T);
                else return null;                   // status= -1
            }
            else if (DeltaTheta <= (PIBY2 - MinDeltaThetaJ)) {
                if (Status == 0||Status == 4)		/* L junction */
                    lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_V);
                else if (Status > 0 && Status != 4) /* T junction */
                    lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_LAMBDA);
                else return null;                   // status= -1
            }
            else return null;

            lg.FirstID    = (ORTLine)Line1;
            lg.SecondID   = (ORTLine)Line2;
            lg.ip         = Status;
            lg.jp1        = jp1;
            lg.jp2        = jp2;
            lg.JunctionPt.Col = JunctionPtCol;
            lg.JunctionPt.Row = JunctionPtRow;
            lg.Quality        = Quality;
            return lg;

        } /* Endif DeltaTheta */
        else return null;
    }

    /**
     * Decide the junction relationship between two lines.
     * Given two lines, return a line group to represent the relationship
     * (the method used in lineRelation is a little different here.)
     *
     * @param Line1 The one line of the line pair
     * @param Line2 The otherone in the line pair
     * @param MaxWidthOverHeight Typical 2.0.
     * When the WidthOverHeight > this value, the line group will be discard.
     * @param MinLineLength Typical 8.0.
     * If the length of any line < this value, return null
     * @param MinDeltaTheta Typical 0.06. (in radian)
     * [0,this]:parallel, [this,PI/2]:junction
     * @param MinQuality Typical 0.8.
     * If the quaulity of the group < this value, return null.
     * @return A line group to represent junction type.
     * If the two lines can't form a junction, return null.
     */
    static public ORTLineGroup lineRelation_onlyJunction(ORTLine Line1, ORTLine Line2,
        double MaxWidthOverHeight,  // = 2.0;   when the WidthOverHeight > this value, the line group will be discard
        double MinLineLength,       // = 8.0;   if the length of any line < this value, return null
        double MinDeltaTheta,       // = 0.06;  [0,this]:parallel, [this,PI/2]:junction
        double MinQuality)          //	= 0.8;  if the quaulity of the group < this value, return null
    {
            if (MaxWidthOverHeight < 0.0) {
                    System.err.print("Error: Minimum Width/Height must be >= 0.0\n");
                    return(null);
            }
            if (MinLineLength < 4.0) {
                    System.err.print("Error: MinLineLength must be  >= 4.0\n");
                    return(null);
            }
            if (Line1.Length<MinLineLength||Line2.Length<MinLineLength) return null;

            double MinDeltaThetaJ= MinDeltaTheta;

            double MinQualityJ= MinQuality;
            if (MinQualityJ < 0.0 || MinQualityJ > 1.0) {
                    System.err.print("Error: MinQuality level for junc. must be >= 0.0 and <= 1.0\n");
                    return(null);
            }

        //the angel between two lines
        double DeltaTheta =  Math.abs( Line1.Theta - Line2.Theta);
        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

        //  ===================== JUNCTION TYPES ==================================
        if (DeltaTheta >= MinDeltaThetaJ) {

                int jp1=0, jp2=0;
                int[] p_jp1={jp1} ,p_jp2={jp2};
                double JunctionPtCol=0,JunctionPtRow=0,Quality=0;
                double[] p_JunctionPtCol={JunctionPtCol}, p_JunctionPtRow={JunctionPtRow};
                double[] p_Quality={Quality};
                int Status = CheckJunctionType(Line1,Line2,p_jp1,p_jp2,p_JunctionPtCol,p_JunctionPtRow,
                            MinQualityJ,p_Quality);
            jp1=p_jp1[0];jp2=p_jp2[0];
                JunctionPtCol=p_JunctionPtCol[0];JunctionPtRow=p_JunctionPtRow[0];
                Quality=p_Quality[0];

                ORTConjLineGroup lg;

            if (Status == 0)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_L);
            else if (Status==1||Status==2)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_V);
            else if (Status==3)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_T);
            else if (Status==4)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_LAMBDA);
            else return null;                   // status= -1

            lg.FirstID    = (ORTLine)Line1;
            lg.SecondID   = (ORTLine)Line2;
            lg.ip         = Status;
            lg.jp1        = jp1;
            lg.jp2        = jp2;
            lg.JunctionPt.Col = JunctionPtCol;
            lg.JunctionPt.Row = JunctionPtRow;
            lg.Quality        = Quality;
            return lg;

        } /* Endif DeltaTheta */
        else return null;
    }

    /**
     * Decide the junction relationship between two lines.
     * Given two lines, return a line group to represent the relationship
     * (the method used in lineRelation is a little different here.)
     * only the close relationship is considered
     *
     * @param Line1 The one line of the line pair
     * @param Line2 The otherone in the line pair
     * @param MaxWidthOverHeight Typical 2.0.
     * When the WidthOverHeight > this value, the line group will be discard.
     * @param MinLineLength Typical 8.0.
     * If the length of any line < this value, return null
     * @param MinDeltaTheta Typical 0.06. (in radian)
     * [0,this]:parallel, [this,PI/2]:junction
     * @param MinQuality Typical 0.8.
     * If the quaulity of the group < this value, return null.
     * @return A line group to represent junction type.
     * If the two lines can't form a junction, return null.
     */
    static public ORTLineGroup lineRelation_closeJunction(ORTLine Line1, ORTLine Line2,
        double MaxWidthOverHeight,  // = 2.0;   when the WidthOverHeight > this value, the line group will be discard
        double MinLineLength,       // = 8.0;   if the length of any line < this value, return null
        double MinDeltaTheta,       // = 0.06;  [0,this]:parallel, [this,PI/2]:junction
        double MinQuality)          //	= 0.8;  if the quaulity of the group < this value, return null
    {
            if (MaxWidthOverHeight < 0.0) {
                    System.err.print("Error: Minimum Width/Height must be >= 0.0\n");
                    return(null);
            }
            if (MinLineLength < 4.0) {
                    System.err.print("Error: MinLineLength must be  >= 4.0\n");
                    return(null);
            }
            if (Line1.Length<MinLineLength||Line2.Length<MinLineLength) return null;

            double MinDeltaThetaJ= MinDeltaTheta;

            double MinQualityJ= MinQuality;
            if (MinQualityJ < 0.0 || MinQualityJ > 1.0) {
                    System.err.print("Error: MinQuality level for junc. must be >= 0.0 and <= 1.0\n");
                    return(null);
            }

        //the angel between two lines
        double DeltaTheta =  Math.abs( Line1.Theta - Line2.Theta);
        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

        //  ===================== JUNCTION TYPES ==================================
        if (DeltaTheta >= MinDeltaThetaJ) {

                int jp1=0, jp2=0;
                int[] p_jp1={jp1} ,p_jp2={jp2};
                double JunctionPtCol=0,JunctionPtRow=0,Quality=0;
                double[] p_JunctionPtCol={JunctionPtCol}, p_JunctionPtRow={JunctionPtRow};
                double[] p_Quality={Quality};
                int Status = CheckJunctionType(Line1,Line2,p_jp1,p_jp2,p_JunctionPtCol,p_JunctionPtRow,
                            MinQualityJ,p_Quality);
            jp1=p_jp1[0];jp2=p_jp2[0];
                JunctionPtCol=p_JunctionPtCol[0];JunctionPtRow=p_JunctionPtRow[0];
                Quality=p_Quality[0];

                ORTConjLineGroup lg;

            //only status==3 or status==4 are considered as close junction
            if (Status == 3||Status==4)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_CLOSE);
            else return null;                   // status= -1

            lg.FirstID    = (ORTLine)Line1;
            lg.SecondID   = (ORTLine)Line2;
            lg.ip         = Status;
            lg.jp1        = jp1;
            lg.jp2        = jp2;
            lg.JunctionPt.Col = JunctionPtCol;
            lg.JunctionPt.Row = JunctionPtRow;
            lg.Quality        = Quality;
            return lg;

        } /* Endif DeltaTheta */
        else return null;
    }

    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Name : lpeg

    Usage:
            LPEG -[l p1] [-t p2] [-q p3] < InFile > OutFile

    Command line parameters:

    p1 = MinLineLength      -- Minimum acceptable line length
    p2 = MinDeltaTheta      -- The angle between two lines. This parameter
                            decides which lines maybe parallel/collinear,
    p3 = MinQuality -- Minimum acceptable Quality level


    Output result       :

    0 = successful,
    -1 = error,

    Functionality:

    This program groups line features extracted from an image. The groupings
    are:

            NonOverlapping Parallel lines
            Overlapping Parallel lines
            Collinear lines
            L junctions
            V junctions
            T junctions
            Lambda junctions

    See LPEG.ps for fuller details.

    ***
    Note X junctions are not implemented at this level since Edge detectors
    always break junctions
    ****

    the function first sort the lines according to the orientation
    for the result: orientation_line1<orientation_line2 (except 179 and 0)
    so the pairs (l1,l2) and (l2,l1) can only appear exclusively, never together

    if the colinear line is also considered, then the same pair could
    appear twice, like (l1, l2) and (l2,l1)

    ----------------------------------------------------------------------------*/

    Vector[] lpeg(
            int[] source,
            Dimension d,
            boolean CollinearToReal,    //=false;
            double MaxWidthOverHeight,  // = 2.0;
            double MinLineLength,       //      = 8.0;
            double MinDeltaTheta,       //      = 0.06;
            double MinQuality,          //		= 0.8;
            int OutPutStatus            // 	= -1;  /* All */
        )
    {

        /*
        =======================================================================
        ===================== START OF DECLARATION ============================
        =======================================================================
        */


        int i,j,k;			/* Loop indecies */
        int Status;			/* Status flag */
        int Next;			/* Next argument */
        int Number;

        /*
        Number of lines in corresponding lists

        */
        int N_ListORTLine;		  /* ORT line data */
        int N_ListORTCircularArc;	  /* ORT arc data */
        int N_ListORTParallelNOV;	  /* ORT Parallel non-overlapping line data */
        int N_ListORTParallelOV;	  /* ORT Parallel overlapping line data */
        int N_ListORTCollinear;	  /* ORT collinear line data */
        int N_ListORTLJunction;	  /* ORT L junction data */
        int N_ListORTVJunction;	  /* ORT V junction data */
        int N_ListORTTJunction;	  /* ORT T junction data */
        int N_ListORTLambdaJunction; /* ORT Lambda junction data */

        int N_ListCollinearLine;	  /* Collinear lines considered as "real" */

        /*
        ID numbers of appropriate lists

        */
        Vector ID_ListORTLine;
        Vector ID_ListORTCircularArc;
        Vector ID_ListORTParallelNOV;
        Vector ID_ListORTParallelOV;
        Vector ID_ListORTCollinear;
        Vector ID_ListORTLJunction;
        Vector ID_ListORTVJunction;
        Vector ID_ListORTTJunction;
        Vector ID_ListORTLambdaJunction;
        /*
        Pointers to lists

        */

        VirtualLine        	VLine;
        ORTLine        	    CollinearLine;

        ORTLine        	    ListORTLine;
        ORTCircularArc     	ListORTCircularArc;
        ORTParLineGroup 	ListORTParallelNOV,ListORTParallelOV,ListORTCollinear;
        ORTConjLineGroup    ListORTLJunction,ListORTVJunction,ListORTTJunction=null,ListORTLambdaJunction;

        //Command line parameters
        double MinDeltaThetaPC;
        double MinDeltaThetaJ;

        double MinQualityPC;
        double MinQualityJ;

        double WidthOverHeight=0;

        long Line;			/* Buffers for elements in the Lists */
        long Arc;
        Object Line1;
        Object Line2;
        long Junction;

        ORTLine        	BufferLine1;
        ORTLine        	BufferLine2;

        double JunctionPtCol=0;	/* Junction point parameters */
        double JunctionPtRow=0;

        double DeltaTheta=0;		/* Dummy variable */
        double Quality=0;		/* Quality associated with grouping */

        int ID1,ID2;			/* Buffer to store line IDs */
        int jp1=0,jp2=0;			/* Buffer to store closest junction pt indicator */

        Vector ID_ListBuffer;
        Object Buffer;

        /*
        =======================================================================
        ===================== START OF INITIALISATION =========================
        =======================================================================
        */

        /*
        Set defaults, process command line options, and initialise lists

        */

            if (MaxWidthOverHeight < 0.0) {
                    System.err.print("Error: Minimum Width/Height must be >= 0.0\n");
                    return(null);
            }

            if (MinLineLength < 4.0) {
                    System.err.print("Error: MinLineLength must be  >= 4.0\n");
                    return(null);
            }

            MinDeltaThetaPC = MinDeltaThetaJ = MinDeltaTheta;

            if (MinDeltaThetaPC > 0.1) {
                    System.err.print("Error: MinDeltaThetaParallel/Collinear must be <= 0.1radians\n");
                    return(null);
            }

            if (MinDeltaThetaJ > 0.1) {
                    System.err.print("Error: MinDeltaThetaJunctions must be <= 0.1radians\n");
                    return(null);
            }

            MinQualityPC = MinQualityJ = MinQuality;

            if (MinQualityPC < 0.0 || MinQualityPC > 1.0) {
                    System.err.print("Error: MinQuality level for parallel lines must be >= 0.0 and <= 1.0\n");
                    return(null);
            }

            if (MinQualityJ < 0.0 || MinQualityJ > 1.0) {
                    System.err.print("Error: MinQuality level for junc. must be >= 0.0 and <= 1.0\n");
                    return(null);
            }


        /*
        Read in ORTLine data filtered by length and store in a linked list.

        */
        /*
                CrtORTLineList( &p_InFile,
                                MinLineLength,
                                &ListORTLine,
                                &ID_ListORTLine,
                                &N_ListORTLine);

                CrtORTCircularArcList( &p_InFile,
                                        &ListORTCircularArc,
                                    &ID_ListORTCircularArc,
                                        &N_ListORTCircularArc);

                if (N_ListORTLine < 2){
                        System.err.print("Error: Insufficient number of lines in the list\n");
                        return(-1);
                }
                */

        Vector[] segs= (new Fex()).fex(source, d);
        //!!!!!!!!!!!!!!!!!!!
        //need to sort and filter the lines with small length<MinLineLength
        ID_ListORTLine= segs[0];
        SortByThetaAscending(ID_ListORTLine);
        FilterByLength(ID_ListORTLine,MinLineLength);
        ID_ListORTCircularArc= segs[1];
        N_ListORTLine=ID_ListORTLine.size();
        if (N_ListORTLine < 2) {
            System.err.print("Error: Insufficient number of lines in the list\n");
            return(null);
        }

        N_ListORTCircularArc=ID_ListORTCircularArc.size();


        /*
        Copy the list to a buffer to speedup processing
        */

        //!!!!!!!!!!!!!!!!!!!
        //need to copy the vector!!!!????
        ID_ListBuffer = ID_ListORTLine;

        /*
        Create empty lists for features to be grouped

        */

        ID_ListORTParallelNOV      = new Vector();
        ID_ListORTParallelOV       = new Vector();
        ID_ListORTCollinear        = new Vector();
        ID_ListORTLJunction        = new Vector();
        ID_ListORTVJunction        = new Vector();
        ID_ListORTTJunction        = new Vector();
        ID_ListORTLambdaJunction   = new Vector();

        N_ListORTParallelNOV    = 0;
        N_ListORTParallelOV     = 0;
        N_ListORTCollinear      = 0;
        N_ListORTLJunction      = 0;
        N_ListORTVJunction      = 0;
        N_ListORTTJunction      = 0;
        N_ListORTLambdaJunction = 0;

        /*
        =======================================================================
        ===================== PARALLEL/COLLINEAR ==============================
        =======================================================================
        */

        /*
        Find which pairs of lines Maybe

        ||||	Overlapping parallel, 		||||
        ||||   non-overlapping parallel, or 	||||
        ||||	collinear				||||

        By checking the ACUTE angle between the lines. Note when we get to the end
        of the list we wrap around back to the start.

        */

        //Line1 = FirstElmList(ID_ListORTLine);
        Line1 = ID_ListORTLine.firstElement();

        //!!!!!!!!!!!!!!!!!!!!!!!
        //for (i = 1; i <= N_ListORTLine ; i++) {
        for (i = 0; i < N_ListORTLine ; i++) {
            Line1 = ID_ListORTLine.elementAt(i);
            System.err.println(""+i+"/"+N_ListORTLine);


            j = i;  DeltaTheta = 0.0; k = 0;

            if (OutPutStatus == -1 || OutPutStatus == 0 ||
                OutPutStatus ==  2 || OutPutStatus == 3 || CollinearToReal == true) {

                while (DeltaTheta <= MinDeltaThetaPC && k < N_ListORTLine ) {
                        j++; if ( j >= N_ListORTLine ) j = 0; k++;

                    if ( j != i) {

                        Line2 = ID_ListBuffer.elementAt(j);

                        DeltaTheta =  Math.abs(  ((ORTLine)Line1).Theta -
                                        ((ORTLine)Line2).Theta);

                        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);
                        /*
                        Lines maybe parallel (overlapping/non-overlapping) or collinear

                        */
                        if (DeltaTheta <= MinDeltaThetaPC) {
                            VLine = new VirtualLine();

                                double[] p_WidthOverHeight={WidthOverHeight};
                                double[] p_Quality={Quality};

                                Status = CheckParallelOrCollinear(
                                                            (ORTLine)(Line1),
                                                            (ORTLine)(Line2),
                                                            VLine,
                                                            MinQualityPC,
                                                            p_WidthOverHeight,
                                                            p_Quality);
                                WidthOverHeight=p_WidthOverHeight[0];
                                Quality=p_Quality[0];


                            switch (Status) {

                            case -1:

                                    break;

                            case 0:		/* Parallel non-overlapping lines */

                                ListORTParallelNOV = new ORTParLineGroup(ORTLineGroup.PARALLEL_NO_OVERLAP);
                                        ListORTParallelNOV.FirstID    = (ORTLine)Line1;
                                        ListORTParallelNOV.SecondID   = (ORTLine)Line2;
                                        ListORTParallelNOV.VLLine     = VLine;
                                        ListORTParallelNOV.WidthOverHeight = WidthOverHeight;
                                        ListORTParallelNOV.Quality         = Quality;

                                //AddElmList( ID_ListORTParallelNOV, (long)ListORTParallelNOV );
                                ID_ListORTParallelNOV.addElement(ListORTParallelNOV );
                                N_ListORTParallelNOV++;

                                break;

                            case 1:		/* Parallel overlapping lines */

                                ListORTParallelOV = new ORTParLineGroup(ORTLineGroup.PARALLEL_OVERLAP);
                                        ListORTParallelOV.FirstID    = (ORTLine)Line1;
                                        ListORTParallelOV.SecondID   = (ORTLine)Line2;
                                        ListORTParallelOV.VLLine     = VLine;
                                        ListORTParallelOV.WidthOverHeight = WidthOverHeight;
                                        ListORTParallelOV.Quality         = Quality;

                                //AddElmList( ID_ListORTParallelOV, (long)ListORTParallelOV );
                                ID_ListORTParallelOV.addElement(ListORTParallelOV );
                                N_ListORTParallelOV++;

                                break;

                            case 2:		/* Collinear lines */

                                ListORTCollinear = new ORTParLineGroup(ORTLineGroup.COLLINEAR);
                                        ListORTCollinear.FirstID    = (ORTLine)Line1;
                                        ListORTCollinear.SecondID   = (ORTLine)Line2;
                                        ListORTCollinear.VLLine     = VLine;
                                        ListORTCollinear.Quality    = Quality;

                                //AddElmList( ID_ListORTCollinear, (long)ListORTCollinear );
                                ID_ListORTCollinear.addElement(ListORTCollinear );
                                N_ListORTCollinear++;

                            break;

                                    } /* Endif DeltaTheta */

                        } /* End switch */

                    } /* j != i */

                } /* End while */

            } /* End OutPutStatus */

            /*
            =======================================================================
            ===================== JUNCTION TYPES ==================================
            =======================================================================
            */
            /*
            Find which pairs of lines Maybe

            ||||	L or T 	 		||||

            By checking the angle between the lines. For Junctions the angle (thetamin)
            is derived from that used for Parallel/Collinear lines. In the case of L/T
            junctions the angle is PIBY2 - MinDeltaThetaJ -- PIBY2 + MinDeltaThetaJ. In the
            case of V/Lambda junctions it is MinDeltaThetaJ -- PIBY2 - MinDeltaThetaJ and
            PIBY2 + MinDeltaThetaJ -- PI - MinDeltaThetaJ. Note when we get to the end
            of the list we wrap around back to the start.

            */

            if (OutPutStatus == -1 || OutPutStatus == 1 ||
                OutPutStatus == 3  || OutPutStatus == 4 || CollinearToReal == true) {

                //for (j = (i+1); j <= N_ListORTLine ; j++) {
                for (j = (i+1); j < N_ListORTLine ; j++) {

                    //Line2 = ElmNumList ( ID_ListBuffer, (long) j);
                    Line2 = ID_ListBuffer.elementAt( j);
                    DeltaTheta =  Math.abs(  ((ORTLine)Line1).Theta -
                                            ((ORTLine)Line2).Theta);
                    /*
                    Lines maybe T or L junctions

                    */
                    if (DeltaTheta <= (PIBY2 + MinDeltaThetaJ) &&
                        DeltaTheta >= (PIBY2 - MinDeltaThetaJ) ) {

                            int[] p_jp1={jp1};
                            int[] p_jp2={jp2};
                            double[] p_JunctionPtCol={JunctionPtCol};
                            double[] p_JunctionPtRow={JunctionPtRow};
                            double[] p_Quality={Quality};
                            Status = CheckJunctionType(
                                            ((ORTLine)Line1),
                                            ((ORTLine)Line2),
                                            p_jp1,
                                            p_jp2,
                                            p_JunctionPtCol,
                                            p_JunctionPtRow,
                                            MinQualityJ,
                                            p_Quality);
                        jp1=p_jp1[0];
                            jp2=p_jp2[0];
                            JunctionPtCol=p_JunctionPtCol[0];
                            JunctionPtRow=p_JunctionPtRow[0];
                            Quality=p_Quality[0];


                        if (Status == 0 || Status == 4) {		/* L junction */

                            ListORTLJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_L);
                                    ListORTLJunction.FirstID    = (ORTLine)Line1;
                                    ListORTLJunction.SecondID   = (ORTLine)Line2;
                                    ListORTLJunction.ip         = Status;
                                    ListORTLJunction.jp1        = jp1;
                                    ListORTLJunction.jp2        = jp2;
                                    ListORTLJunction.JunctionPt.Col = JunctionPtCol;
                                    ListORTLJunction.JunctionPt.Row = JunctionPtRow;
                                    ListORTLJunction.Quality        = Quality;

                            //AddElmList( ID_ListORTLJunction, (long)ListORTLJunction );
                            ID_ListORTLJunction.addElement(ListORTLJunction );
                            N_ListORTLJunction++;

                        }

                        if (Status > 0 && Status != 4) { /* T junction */
                            ListORTTJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_T);
                                    ListORTTJunction.FirstID    = (ORTLine)Line1;
                                    ListORTTJunction.SecondID   = (ORTLine)Line2;
                                    ListORTTJunction.ip         = Status;
                                    ListORTTJunction.jp1        = jp1;
                                    ListORTTJunction.jp2        = jp2;
                                    ListORTTJunction.JunctionPt.Col = JunctionPtCol;
                                    ListORTTJunction.JunctionPt.Row = JunctionPtRow;
                                    ListORTTJunction.Quality        = Quality;

                            //AddElmList( ID_ListORTTJunction, (long)ListORTTJunction );
                            ID_ListORTTJunction.addElement(ListORTTJunction );
                            N_ListORTTJunction++;

                        }

                    } /* Endif DeltaTheta */

                    /*
                    Find which pairs of lines Maybe

                    ||||	V or Lambda 	 		||||

                    By checking the angle between the lines. For Junctions the angle (thetamin)
                    is derived from that used for Parallel/Collinear lines. In the case of L/T
                    junctions the angle is PIBY2 - MinDeltaThetaJ -- PIBY2 + MinDeltaThetaJ. In the
                    case of V/Lambda junctions it is MinDeltaThetaJ -- PIBY2 - MinDeltaThetaJ and
                    PIBY2 + MinDeltaThetaJ -- PI - MinDeltaThetaJ. Note when we get to the end
                    of the list we wrap around back to the start.

                    */

                    /*
                    Lines maybe V or Lambda junctions

                    */
                    if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

                    if (DeltaTheta <= (PIBY2 - MinDeltaThetaJ) &&
                        DeltaTheta >= (MinDeltaThetaJ) ) {

                            int[] p_jp1={jp1};
                            int[] p_jp2={jp2};
                            double[] p_JunctionPtCol={JunctionPtCol};
                            double[] p_JunctionPtRow={JunctionPtRow};
                            double[] p_Quality={Quality};
                            Status = CheckJunctionType(
                                                ((ORTLine)Line1),
                                                ((ORTLine)Line2),
                                                p_jp1,
                                                p_jp2,
                                                p_JunctionPtCol,
                                                p_JunctionPtRow,
                                                MinQualityJ,
                                                p_Quality);
                        jp1=p_jp1[0];
                            jp2=p_jp2[0];
                            JunctionPtCol=p_JunctionPtCol[0];
                            JunctionPtRow=p_JunctionPtRow[0];
                            Quality=p_Quality[0];

                        if (Status == 0 || Status == 4) {		/* V junction */

                            ListORTVJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_V);
                                    ListORTVJunction.FirstID    = (ORTLine)Line1;
                                    ListORTVJunction.SecondID   = (ORTLine)Line2;
                                    ListORTVJunction.ip         = Status;
                                    ListORTVJunction.jp1        = jp1;
                                    ListORTVJunction.jp2        = jp2;
                                    ListORTVJunction.JunctionPt.Col = JunctionPtCol;
                                    ListORTVJunction.JunctionPt.Row = JunctionPtRow;
                                    ListORTVJunction.Quality        = Quality;

                            //AddElmList( ID_ListORTVJunction, (long)ListORTVJunction );
                            ID_ListORTVJunction.addElement(ListORTVJunction );
                            N_ListORTVJunction++;

                        }

                        if (Status > 0 && Status != 4) {		/* Lambda junction */

                            ListORTLambdaJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_LAMBDA);
                                    ListORTLambdaJunction.FirstID    = (ORTLine)Line1;
                                    ListORTLambdaJunction.SecondID   = (ORTLine)Line2;
                                    ListORTLambdaJunction.ip         = Status;
                                    ListORTLambdaJunction.jp1        = jp1;
                                    ListORTLambdaJunction.jp2        = jp2;
                                    ListORTLambdaJunction.JunctionPt.Col = JunctionPtCol;
                                    ListORTLambdaJunction.JunctionPt.Row = JunctionPtRow;
                                    ListORTLambdaJunction.Quality        = Quality;

                            //AddElmList( ID_ListORTLambdaJunction, (long)ListORTLambdaJunction );
                            ID_ListORTLambdaJunction.addElement(ListORTLambdaJunction );
                            N_ListORTLambdaJunction++;

                        }

                    } /* Endif DeltaTheta */

                } /* End for j */

            } /* End OutPutStatus */

            //!!!!!!!!!!!!!!!!!!!!
            //Line1 = NextElmList(ID_ListORTLine);
            //move to the begin of the loop!!!!!!yi

        } /* End for i */

        /*
        =======================================================================
                Consider Collinear lines as real lines
        =======================================================================

        Take pairs of collinear lines and combine them into new hypothesized lines.
        This is so we can take into account collinearities when it comes to finding
        triplets and polygons.
        */

        if (CollinearToReal == true) {

            N_ListCollinearLine = N_ListORTLine;
            //for (i = 1; i <= N_ListORTCollinear; i++) {
            for (i = 0; i < N_ListORTCollinear; i++) {

                //Buffer = ElmNumList (ID_ListORTCollinear, (long) i);
                Buffer = ID_ListORTCollinear.elementAt( i);
                ListORTCollinear = (ORTParLineGroup)Buffer;
                N_ListORTLine++;
                CollinearLine = new ORTLine();
                CollinearLine.ID 		= N_ListORTLine;
                CollinearLine.StringID 	= -1; /* not valid for these */
                CollinearLine.Start.Col 	= ListORTCollinear.VLLine.Start.Col;
                CollinearLine.Start.Row 	= ListORTCollinear.VLLine.Start.Row;
                CollinearLine.End.Col 	= ListORTCollinear.VLLine.End.Col;
                CollinearLine.End.Row 	= ListORTCollinear.VLLine.End.Row;
                CollinearLine.MidPoint.Col = (CollinearLine.Start.Col +
                                                CollinearLine.End.Col)/2.0;
                CollinearLine.MidPoint.Row = (CollinearLine.Start.Row +
                                                CollinearLine.End.Row)/2.0;
                CollinearLine.Length 	= ListORTCollinear.VLLine.Length;
                CollinearLine.LengthPerpVar= GeometricUtil.LineLengthPerpVar();
                CollinearLine.LengthParlVar= GeometricUtil.LineLengthParlVar();
                CollinearLine.Theta 	= ListORTCollinear.VLLine.Theta;
                CollinearLine.ThetaVar 	= GeometricUtil.LineSegThetaVar(CollinearLine.Length);
                //AddElmList (ID_ListORTLine, (long) CollinearLine);
                ID_ListORTLine.addElement( CollinearLine);

            } /* endfor i */

            /*
            Now create the new junctions including collinearities
            */

            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //!!!!!!!!!!!!!!!!must change!!!!!!!!!!!!!!!!
            //re-consider the relation between collinearline and other lines
            //the change is correct: N_ListCollinearLine store the old value of N_ListORTLine
            //say there are 5 line in ORTLine, then add 3 new collinear line
            //then scan the vector from [5,8)
            //for (i = N_ListCollinearLine; i <= N_ListORTLine ; i++) {
            for (i = N_ListCollinearLine; i < N_ListORTLine ; i++) {

                //Line1 = ElmNumList (ID_ListORTLine, (long) i);
                Line1 = ID_ListORTLine.elementAt( i);

                //for (j = 1; j <= N_ListORTLine ; j++) {
                for (j = 0; j < N_ListORTLine ; j++) {

                    if (i != j) {

                        //Line2 = ElmNumList (ID_ListORTLine, (long) j);
                        Line2 = ID_ListORTLine.elementAt( j);

                        DeltaTheta =  Math.abs(  ((ORTLine)Line1).Theta -
                                            ((ORTLine)Line2).Theta);
                        /*
                        Lines maybe T or L junctions
                        */
                        if (DeltaTheta <= (PIBY2 + MinDeltaThetaJ) &&
                            DeltaTheta >= (PIBY2 - MinDeltaThetaJ) ) {

                                int[] p_jp1={jp1};
                                int[] p_jp2={jp2};
                                double[] p_JunctionPtCol={JunctionPtCol};
                                double[] p_JunctionPtRow={JunctionPtRow};
                                double[] p_Quality={Quality};
                                Status = CheckJunctionType(
                                                    ((ORTLine)Line1),
                                                    ((ORTLine)Line2),
                                                    p_jp1,
                                                    p_jp2,
                                                    p_JunctionPtCol,
                                                    p_JunctionPtRow,
                                                    MinQualityJ,
                                                    p_Quality);
                            jp1=p_jp1[0];
                                jp2=p_jp2[0];
                                JunctionPtCol=p_JunctionPtCol[0];
                                JunctionPtRow=p_JunctionPtRow[0];
                                Quality=p_Quality[0];


                            if (Status == 0 || Status == 4) {		/* L junction */

                                ListORTLJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_L);
                                        ListORTLJunction.FirstID    = (ORTLine)Line1;
                                        ListORTLJunction.SecondID   = (ORTLine)Line2;
                                        ListORTLJunction.ip         = Status;
                                        ListORTLJunction.jp1        = jp1;
                                        ListORTLJunction.jp2        = jp2;
                                        ListORTLJunction.JunctionPt.Col = JunctionPtCol;
                                        ListORTLJunction.JunctionPt.Row = JunctionPtRow;
                                        ListORTLJunction.Quality        = Quality;

                                //AddElmList( ID_ListORTLJunction, (long)ListORTLJunction );
                                ID_ListORTLJunction.addElement(ListORTLJunction );
                                N_ListORTLJunction++;

                            }

                            if (Status > 0 && Status != 4) { /* T junction */
                                ListORTTJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_T);
                                        ListORTTJunction.FirstID    = (ORTLine)Line1;
                                        ListORTTJunction.SecondID   = (ORTLine)Line2;
                                        ListORTTJunction.ip         = Status;
                                        ListORTTJunction.jp1        = jp1;
                                        ListORTTJunction.jp2        = jp2;
                                        ListORTTJunction.JunctionPt.Col = JunctionPtCol;
                                        ListORTTJunction.JunctionPt.Row = JunctionPtRow;
                                        ListORTTJunction.Quality        = Quality;

                                //AddElmList( ID_ListORTTJunction, (long)ListORTTJunction );
                                ID_ListORTTJunction.addElement(ListORTTJunction );
                                N_ListORTTJunction++;

                            }

                        } /* Endif DeltaTheta */

                        /*
                        Lines maybe V or Lambda junctions

                        */
                        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

                        if (DeltaTheta <= (PIBY2 - MinDeltaThetaJ) &&
                            DeltaTheta >= (MinDeltaThetaJ) ) {

                                int[] p_jp1={jp1};
                                int[] p_jp2={jp2};
                                double[] p_JunctionPtCol={JunctionPtCol};
                                double[] p_JunctionPtRow={JunctionPtRow};
                                double[] p_Quality={Quality};
                                Status = CheckJunctionType(
                                                    ((ORTLine)Line1),
                                                    ((ORTLine)Line2),
                                                    p_jp1,
                                                    p_jp2,
                                                    p_JunctionPtCol,
                                                    p_JunctionPtRow,
                                                    MinQualityJ,
                                                    p_Quality);
                            jp1=p_jp1[0];
                                jp2=p_jp2[0];
                                JunctionPtCol=p_JunctionPtCol[0];
                                JunctionPtRow=p_JunctionPtRow[0];
                                Quality=p_Quality[0];

                            if (Status == 0 || Status == 4) {		/* V junction */

                                ListORTVJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_V);
                                        ListORTVJunction.FirstID    = (ORTLine)Line1;
                                        ListORTVJunction.SecondID   = (ORTLine)Line2;
                                        ListORTVJunction.ip         = Status;
                                        ListORTVJunction.jp1        = jp1;
                                        ListORTVJunction.jp2        = jp2;
                                        ListORTVJunction.JunctionPt.Col = JunctionPtCol;
                                        ListORTVJunction.JunctionPt.Row = JunctionPtRow;
                                        ListORTVJunction.Quality        = Quality;

                                //AddElmList( ID_ListORTVJunction, (long)ListORTVJunction );
                                ID_ListORTTJunction.addElement(ListORTTJunction );
                                N_ListORTVJunction++;

                            }

                            if (Status > 0 && Status != 4) {		/* Lambda junction */

                                ListORTLambdaJunction = new ORTConjLineGroup(ORTLineGroup.JUNCTION_LAMBDA);
                                        ListORTLambdaJunction.FirstID    = (ORTLine)Line1;
                                        ListORTLambdaJunction.SecondID   = (ORTLine)Line2;
                                        ListORTLambdaJunction.ip         = Status;
                                        ListORTLambdaJunction.jp1        = jp1;
                                        ListORTLambdaJunction.jp2        = jp2;
                                        ListORTLambdaJunction.JunctionPt.Col = JunctionPtCol;
                                        ListORTLambdaJunction.JunctionPt.Row = JunctionPtRow;
                                        ListORTLambdaJunction.Quality        = Quality;

                                //AddElmList( ID_ListORTLambdaJunction, (long)ListORTLambdaJunction );
                                ID_ListORTLambdaJunction.addElement(ListORTLambdaJunction );
                                N_ListORTLambdaJunction++;

                            }

                        } /* Endif DeltaTheta */

                    } /* if i != j */

                } /* End for j */

            } /* End for i */

        } /* endif collineartoreal */

        /*
        =======================================================================
        ===================== OUTPUTING RESULTS ===============================
        =======================================================================
        */
        /*
        Put headers in data file so
                DisplayGrp : Program used to display the groupings
                InsertLowLevelTokens : Program used to insert tokens into Oracle
        Can read the individual groupings

        */

        /*
                fprintf(p_OutFile,"#Lines\n");
                for (i = 1 ; i <= N_ListORTLine ; i++) {
                Line = ElmNumList ( ID_ListORTLine, (long)i);
                ListORTLine = ((ORTLine)Line);

                fprintf(p_OutFile,"%d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
                                ListORTLine.ID,
                                ListORTLine.StringID,
                                ListORTLine.Start.Col,
                                ListORTLine.Start.Row,
                                ListORTLine.End.Col,
                                ListORTLine.End.Row,
                                ListORTLine.MidPoint.Col,
                                ListORTLine.MidPoint.Row,
                                ListORTLine.Length,
                                ListORTLine.LengthParlVar,
                                ListORTLine.LengthPerpVar,
                            ListORTLine.Theta,
                            ListORTLine.ThetaVar);
            }


                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#CircularArcs\n");

                for (i=1; i<=N_ListORTCircularArc; i++) {
                    Arc  	  = ElmNumList ( ID_ListORTCircularArc, (long) i);
                    ListORTCircularArc = MACCast(ORTCircularArc,Arc);

                fprintf(p_OutFile,"%d %d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
                ListORTCircularArc.ID,
                ListORTCircularArc.StringID,
                ListORTCircularArc.Direction,
                ListORTCircularArc.Origin.Col,
                ListORTCircularArc.Origin.Row,
                ListORTCircularArc.Start.Col,
                ListORTCircularArc.Start.Row,
                ListORTCircularArc.MidPoint.Col,
                ListORTCircularArc.MidPoint.Row,
                ListORTCircularArc.End.Col,
                ListORTCircularArc.End.Row,
                ListORTCircularArc.VLPoint.Col,
                ListORTCircularArc.VLPoint.Row,
                ListORTCircularArc.Radius,
                ListORTCircularArc.Length,
                ListORTCircularArc.LengthParlVar,
                ListORTCircularArc.LengthPerpVar,
                ListORTCircularArc.Width,
                ListORTCircularArc.Height,
                ListORTCircularArc.Theta);
        }

        //Now output the parallel/collinear data

        if (OutPutStatus == -1 || OutPutStatus == 0 || OutPutStatus == 2) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#OVParallel\n");

                Number = 0;
                for (i = 1 ; i <= N_ListORTParallelOV ; i++) {

                    Line = ElmNumList ( ID_ListORTParallelOV, (long)i);
                    ListORTParallelOV = MACCast(ORTParallelOV,Line);
                    ID1 = ListORTParallelOV.FirstID;
                    ID2 = ListORTParallelOV.SecondID;

                    if (ListORTParallelOV.WidthOverHeight <= MaxWidthOverHeight) {
                    Number++;
                    fprintf(p_OutFile,"%d %d %lf %lf %lf %lf %lf %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTParallelOV.VLLine.Start.Col,
                                        ListORTParallelOV.VLLine.Start.Row,
                                        ListORTParallelOV.VLLine.End.Col,
                                        ListORTParallelOV.VLLine.End.Row,
                                        ListORTParallelOV.VLLine.Length,
                                        ListORTParallelOV.VLLine.Theta,
                                        ListORTParallelOV.WidthOverHeight,
                                        ListORTParallelOV.Quality);
                    }
            }
            System.err.print(" Number of Parallel OV pairs =  %d \n",
                                Number);
        }

        if (OutPutStatus == -1 || OutPutStatus == 0 || OutPutStatus == 2) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#NOVParallel\n");

                Number = 0;
                for ( i = 1 ; i <= N_ListORTParallelNOV ; i++) {

                    Line = ElmNumList ( ID_ListORTParallelNOV, (long)i);
                    ListORTParallelNOV = MACCast(ORTParallelNOV,Line);
                    ID1 = ListORTParallelNOV.FirstID;
                    ID2 = ListORTParallelNOV.SecondID;

                    if (ListORTParallelNOV.WidthOverHeight <= MaxWidthOverHeight) {
                    Number++;
                    fprintf(p_OutFile,"%d %d %lf %lf %lf %lf %lf %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTParallelNOV.VLLine.Start.Col,
                                        ListORTParallelNOV.VLLine.Start.Row,
                                        ListORTParallelNOV.VLLine.End.Col,
                                        ListORTParallelNOV.VLLine.End.Row,
                                        ListORTParallelNOV.VLLine.Length,
                                        ListORTParallelNOV.VLLine.Theta,
                                        ListORTParallelNOV.WidthOverHeight,
                                        ListORTParallelNOV.Quality);
                    }
            }
            System.err.print(" Number of Parallel NOV pairs =  %d \n",
                                Number);
        }

        if (OutPutStatus == 2 || OutPutStatus == 3 || OutPutStatus == -1) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#Collinear\n");

            System.err.print(" Number of Collinear pairs =  %d \n",
                                N_ListORTCollinear);

                for ( i = 1 ; i <= N_ListORTCollinear ; i++) {

                    Line = ElmNumList ( ID_ListORTCollinear, (long)i);
                    ListORTCollinear = MACCast(ORTCollinear,Line);
                    ID1 = ListORTCollinear.FirstID;
                    ID2 = ListORTCollinear.SecondID;
                    fprintf(p_OutFile,"%d %d %lf %lf %lf %lf %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTCollinear.VLLine.Start.Col,
                                        ListORTCollinear.VLLine.Start.Row,
                                        ListORTCollinear.VLLine.End.Col,
                                        ListORTCollinear.VLLine.End.Row,
                                        ListORTCollinear.VLLine.Length,
                                        ListORTCollinear.VLLine.Theta,
                                        ListORTCollinear.Quality);
            }

        }

        //Now the Junctions

        if (OutPutStatus == 1  || OutPutStatus == 3 || OutPutStatus == -1) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#L_Junctions\n");

            System.err.print(" Number of L junctions =  %d \n",
                                N_ListORTLJunction);

                for (i = 1 ; i <= N_ListORTLJunction ; i++) {

                    Line = ElmNumList ( ID_ListORTLJunction, (long)i);
                    ListORTLJunction = MACCast(ORTLJunction,Line);
                    ID1 = ListORTLJunction.FirstID;
                    ID2 = ListORTLJunction.SecondID;
                    fprintf(p_OutFile,"%d %d %d %d %d %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTLJunction.ip,
                                        ListORTLJunction.jp1,
                                        ListORTLJunction.jp2,
                                        ListORTLJunction.JunctionPt.Col,
                                        ListORTLJunction.JunctionPt.Row,
                                        ListORTLJunction.Quality);
            }

        }

        if (OutPutStatus == 1 || OutPutStatus == 3 || OutPutStatus == -1) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#V_Junctions\n");

            System.err.print(" Number of V junctions =  %d \n",
                                N_ListORTVJunction);

                for (i = 1; i <= N_ListORTVJunction ; i++) {

                    Line = ElmNumList ( ID_ListORTVJunction, (long)i);
                    ListORTVJunction = MACCast(ORTVJunction,Line);
                    ID1 = ListORTVJunction.FirstID;
                    ID2 = ListORTVJunction.SecondID;
                    fprintf(p_OutFile,"%d %d %d %d %d %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTVJunction.ip,
                                        ListORTVJunction.jp1,
                                        ListORTVJunction.jp2,
                                        ListORTVJunction.JunctionPt.Col,
                                        ListORTVJunction.JunctionPt.Row,
                                        ListORTVJunction.Quality);
            }
        }

        if (OutPutStatus == 1 || OutPutStatus == 3 || OutPutStatus == -1) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#T_Junctions\n");

            System.err.print(" Number of T junctions =  %d \n",
                                N_ListORTTJunction);

                for (i = 1 ; i <= N_ListORTTJunction ; i++) {

                    Line = ElmNumList ( ID_ListORTTJunction, (long)i);
                    ListORTTJunction = MACCast(ORTTJunction,Line);
                    ID1 = ListORTTJunction.FirstID;
                    ID2 = ListORTTJunction.SecondID;
                    fprintf(p_OutFile,"%d %d %d %d %d %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTTJunction.ip,
                                        ListORTTJunction.jp1,
                                        ListORTTJunction.jp2,
                                        ListORTTJunction.JunctionPt.Col,
                                        ListORTTJunction.JunctionPt.Row,
                                        ListORTTJunction.Quality);
            }
        }


        if (OutPutStatus == 1 || OutPutStatus == 3 || OutPutStatus == -1) {

                fprintf(p_OutFile,"#\n");
                fprintf(p_OutFile,"#Lambda_Junctions\n");

            System.err.print(" Number of Lambda junctions =  %d \n",
                                N_ListORTLambdaJunction);

                for (i = 1 ; i <= N_ListORTLambdaJunction; i++) {

                    Line = ElmNumList ( ID_ListORTLambdaJunction, (long)i);
                    ListORTLambdaJunction = MACCast(ORTLambdaJunction,Line);
                    ID1 = ListORTLambdaJunction.FirstID;
                    ID2 = ListORTLambdaJunction.SecondID;
                    fprintf(p_OutFile,"%d %d %d %d %d %lf %lf %lf\n",
                                        ID1,ID2,
                                        ListORTLambdaJunction.ip,
                                        ListORTLambdaJunction.jp1,
                                        ListORTLambdaJunction.jp2,
                                        ListORTLambdaJunction.JunctionPt.Col,
                                        ListORTLambdaJunction.JunctionPt.Row,
                                        ListORTLambdaJunction.Quality);
            }
        }

        */

        //Free memory used by lists
            ID_ListBuffer=null;
            System.gc();

            //return result
            Vector[] rst= {
                ID_ListORTLine,
                ID_ListORTParallelNOV,
                ID_ListORTParallelOV,
                ID_ListORTCollinear,
                ID_ListORTLJunction,
                ID_ListORTVJunction,
                ID_ListORTTJunction,
                ID_ListORTLambdaJunction,
            };
            return rst;
    }

    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Name : CheckParallelOrCollinear

    Input parameters    :

    Line1 		-- ORT line structure containing data for 1st line
    Line2 		-- ORT line structure containing data for 1st line
    MinQuality		-- Min acceptable Quality level

    Output parameters    :

    VLLine			-- Virtual Line and associated parameters
    Quality		-- Quality level in the grouping

    Output result       :

    0  = Lines are // and non overlapping
    1  = Lines are // and overlapping
    2  = Lines are collinear
    -1  = None of the above

    Called Functions :

    PtLinePerpIntercept
    LineLength
    LineSegColIntercept
    LineSegRowIntercept

    Calling procedure:

    struct ORTLine *Line1;
    struct ORTLine *Line2;
    struct VirtualLine *VLLine;

    double MinQuality;
    double WidthOverHeight;
    double Quality;

    CheckParallelOrCollinear(	Line1,
                                    Line2,
                                VLLine,
                                    MinQuality,
                                    &WidthOverHeight,
                                    &Quality);

    Functionality:

    This function finds lines which are "Perceptually" parallel non-overlapping,
    parallel overlapping and collinear. The Perceptual part comes from deciding the
    difference between the luine angles. A Quality value is associated with the
    lines. Please see below on how it is computed. Essentially it peanalises lines
    that do not have significant overlaps with the virtual line.

    ----------------------------------------------------------------------------*/


    static int CheckParallelOrCollinear(ORTLine Line1,
                                    ORTLine Line2,
                                    VirtualLine VLLine,
                                    double MinQuality,
                                    double[] p_WidthOverHeight,
                                double[] p_Quality)

    //double *WidthOverHeight;
    //double *Quality;

    {

        int i,imax;		/* Dummy variables */

        int Status;		/* Return Status */

        double VLPtCol; 	   /* The initial point through which the VL passes */
        double VLPtRow;  	   /* and is used for collinearity check */

        //!!!!!!!!!!!!!!!!!
        //init=0?????
        double VLColIntercept=0; /* Column intercept of VL */
        double VLRowIntercept=0; /* Row intercept of VL */

        double Theta1,Theta2;

        /*
        The following are intercept points of the perps. dropped from the line
        segments onto the virtual line, and buffers for manipulating them.

        */

        double Line1StartInterceptCol;
        double Line1StartInterceptRow;
        double Line1EndInterceptCol;
        double Line1EndInterceptRow;

        double Line2StartInterceptCol;
        double Line2StartInterceptRow;
        double Line2EndInterceptCol;
        double Line2EndInterceptRow;

        /*
        Lenghts of the projections of the lines onto the Virtual Line
        */

        double Line1ProjectedLength;
        double Line2ProjectedLength;

        /*
        Dummy vars. to store distances
        */

        //double D[5],Dmax;
        double[] D= new double[5];
        double Dmax;

        /*
        The following are the row and col intercept of the two lines used for
        collinearity check, and the distance from the VL initial point to the two
        lines

        */

        double Line1ColIntercept;
        double Line1RowIntercept;
        double Line2ColIntercept;
        double Line2RowIntercept;

        double d1,d2;

        /*
        Some buffers to speed things up a bit
        */

        double SumLength;
        double Grad;

        if (_VERBOSE)
                System.err.print(" Start of function CheckParallelOrCollinear \n");



        /*
        Find the point through which the virtual line passes weighted by the line
        lengths. These values will also be used later to check collinearity.

        */

        p_WidthOverHeight[0] = 0.0;
        SumLength = (Line1.Length) + (Line2.Length);

        VLPtCol = (  ((Line1.MidPoint.Col)  * (Line1.Length)) +
                    ((Line2.MidPoint.Col)  * (Line2.Length)) ) /
                    SumLength;

        VLPtRow = ( ((Line1.MidPoint.Row)  * (Line1.Length)) +
                    ((Line2.MidPoint.Row)  * (Line2.Length)) ) /
                    SumLength;

        /*
        Find the mean orientation of the virtual line weighted by the
        line lengths, (could also inversely weight by the theta variances)

        */

        Theta1 = Line1.Theta; Theta2 = Line2.Theta;
        if (Math.abs(Theta1 - Theta2) > PIBY2) {
            if (Theta1 > PIBY2)
                //Theta1 = Math.PI-Theta1;
                //changed by yi!!!!!!!!!!!
                Theta1 -= Math.PI;
            if (Theta2 > PIBY2)
                //Theta2 = Math.PI-Theta2;
                //changed by yi!!!!!!!!!!!
                Theta2 -= Math.PI;
        }

            VLLine.Theta =  ( ( (Theta1)*(Line1.Length) ) +
                ( (Theta2)*(Line2.Length) ) ) / SumLength;

        if ( (VLLine.Theta) > Math.PI)
            VLLine.Theta = (VLLine.Theta) - Math.PI;

        if ( (VLLine.Theta) < 0.0)
            VLLine.Theta = (VLLine.Theta) + Math.PI;
        /*
        Find other parameters associated with the virtual line

        */

        if ( (VLLine.Theta) < 0.001) { 		/* If VL is horizontal */
            VLRowIntercept = VLPtRow;
        }

        if (GeometricUtil.MACCompareWithPIBY2(VLLine.Theta))		/* If VL is vertical */
            VLColIntercept = VLPtCol;

        /* So we have to work things out */
        if ( !GeometricUtil.MACCompareWithPIBY2(VLLine.Theta) && (VLLine.Theta) >= 0.001) {
            Grad = Math.tan(VLLine.Theta);
            VLRowIntercept = VLPtRow -  ( Grad * VLPtCol );
            VLColIntercept = -VLRowIntercept/Grad;

        }

        /*
        Find intercept point between perp. dropped from the end points of the first
        line onto the virtual line

        */

        double[] tmp=GeometricUtil.PtLinePerpIntercept(Line1.Start.Col,
                            Line1.Start.Row,
                            VLColIntercept,
                            VLRowIntercept,
                            VLLine.Theta);
        Line1StartInterceptCol=tmp[0];
        Line1StartInterceptRow=tmp[1];


        tmp=GeometricUtil.PtLinePerpIntercept(Line1.End.Col,
                            Line1.End.Row,
                            VLColIntercept,
                            VLRowIntercept,
                            VLLine.Theta);
        Line1EndInterceptCol=tmp[0];
        Line1EndInterceptRow=tmp[1];

        /*
        Find intercept point between perp. dropped from the end points of the second
        line onto the virtual line

        */
        tmp=GeometricUtil.PtLinePerpIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            VLColIntercept,
                            VLRowIntercept,
                            VLLine.Theta);
        Line2StartInterceptCol=tmp[0];
        Line2StartInterceptRow=tmp[1];

        tmp=GeometricUtil.PtLinePerpIntercept(Line2.End.Col,
                            Line2.End.Row,
                            VLColIntercept,
                            VLRowIntercept,
                            VLLine.Theta);
        Line2EndInterceptCol=tmp[0];
        Line2EndInterceptRow=tmp[1];

        /*
        Now find the longest distance between the intercept points of the perps
        dropped from the two line segments onto the virtual line.

        */
        D[1] = GeometricUtil.LineLength(Line1StartInterceptCol,Line1StartInterceptRow,
                            Line2StartInterceptCol,Line2StartInterceptRow);

        D[2] = GeometricUtil.LineLength(Line1StartInterceptCol,Line1StartInterceptRow,
                            Line2EndInterceptCol,Line2EndInterceptRow);

        D[3] = GeometricUtil.LineLength(Line1EndInterceptCol,Line1EndInterceptRow,
                            Line2StartInterceptCol,Line2StartInterceptRow);

        D[4] = GeometricUtil.LineLength(Line1EndInterceptCol,Line1EndInterceptRow,
                            Line2EndInterceptCol,Line2EndInterceptRow);

        imax = 1;
        Dmax = D[1];
        for (i=2 ;i<=4; i++) {
            if (D[i] > Dmax) {
                Dmax = D[i];
                imax = i;
            }
        }

        switch (imax) {
            case 1:
            VLLine.Start.Col = Line1StartInterceptCol;
                VLLine.Start.Row = Line1StartInterceptRow;
                VLLine.End.Col   = Line2StartInterceptCol;
                VLLine.End.Row   = Line2StartInterceptRow;
            break;
            case 2:
            VLLine.Start.Col = Line1StartInterceptCol;
                VLLine.Start.Row = Line1StartInterceptRow;
                VLLine.End.Col   = Line2EndInterceptCol;
                VLLine.End.Row   = Line2EndInterceptRow;
            break;
            case 3:
            VLLine.Start.Col = Line1EndInterceptCol;
                VLLine.Start.Row = Line1EndInterceptRow;
                VLLine.End.Col   = Line2StartInterceptCol;
                VLLine.End.Row   = Line2StartInterceptRow;
            break;
            case 4:
            VLLine.Start.Col = Line1EndInterceptCol;
                VLLine.Start.Row = Line1EndInterceptRow;
                VLLine.End.Col   = Line2EndInterceptCol;
                VLLine.End.Row   = Line2EndInterceptRow;
            break;

                }

        /*
        Based on these points we can now compute the Length of the Virtual line which
        is also the length of the Overlap

        */

        VLLine.Length = GeometricUtil.LineLength((VLLine.Start.Col),
                                        (VLLine.Start.Row),
                                        (VLLine.End.Col),
                                        (VLLine.End.Row));

        /*
        Now if there is a significant overlap then the lines are parallel overlapping.
        Otherwise we have to check to see if they are collinear or non-overlapping
        parallel

        */

        Line1ProjectedLength = GeometricUtil.LineLength(Line1StartInterceptCol,
                                            Line1StartInterceptRow,
                                            Line1EndInterceptCol,
                                            Line1EndInterceptRow);

        Line2ProjectedLength = GeometricUtil.LineLength(Line2StartInterceptCol,
                                            Line2StartInterceptRow,
                                            Line2EndInterceptCol,
                                            Line2EndInterceptRow);


        if ( (VLLine.Length) <= (Line1ProjectedLength + Line2ProjectedLength -
                            (Line1.LengthParlVar + Line2.LengthParlVar)
            ) ) { 	/* Significant overlap */

                Status = 1;
            /*
            Compute the ratio of the width to the height for parallel lines
            */
            Line2ColIntercept= GeometricUtil.LineSegColIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

            Line2RowIntercept= GeometricUtil.LineSegRowIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

            p_WidthOverHeight[0] = GeometricUtil.PtLinePerpDistance(Line1.MidPoint.Col,
                                                        Line1.MidPoint.Row,
                                                        Line2ColIntercept,
                                                        Line2RowIntercept,
                                                        Line2.Theta)/
                                        (VLLine.Length);

        } else {  	/* No significant overlap */

            /*
            So now we check if the lines are collinear or non-overlapping parallel
            based on how far the VL Col and Row are from the line segments. We first
            compute some required parameters, and then we check the VLPtCol etc..

            */

            Line1ColIntercept=GeometricUtil.LineSegColIntercept(Line1.Start.Col,
                            Line1.Start.Row,
                            Line1.End.Col,
                            Line1.End.Row);

            Line2ColIntercept=GeometricUtil.LineSegColIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

            Line1RowIntercept=GeometricUtil.LineSegRowIntercept(Line1.Start.Col,
                            Line1.Start.Row,
                            Line1.End.Col,
                            Line1.End.Row);

            Line2RowIntercept=GeometricUtil.LineSegRowIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

            d1 = GeometricUtil.PtLinePerpDistance(VLPtCol,
                                VLPtRow,
                                Line1ColIntercept,
                                Line1RowIntercept,
                                Line1.Theta);

            d2 = GeometricUtil.PtLinePerpDistance(VLPtCol,
                                VLPtRow,
                                Line2ColIntercept,
                                Line2RowIntercept,
                                Line2.Theta);

                if (d1 < Line1.LengthPerpVar && d2 < Line2.LengthPerpVar) {
                        Status = 2;
                }
                else {
                    Status = 0;
                /*
                Compute the ratio of the width to the height for parallel lines
                */
                Line2ColIntercept= GeometricUtil.LineSegColIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

                Line2RowIntercept= GeometricUtil.LineSegRowIntercept(Line2.Start.Col,
                            Line2.Start.Row,
                            Line2.End.Col,
                            Line2.End.Row);

                p_WidthOverHeight[0] = GeometricUtil.PtLinePerpDistance(Line1.MidPoint.Col,
                                                        Line1.MidPoint.Row,
                                                        Line2ColIntercept,
                                                        Line2RowIntercept,
                                                        Line2.Theta)/
                                        (VLLine.Length);

                }

        }

        /*
        Now we compute the Quality level. We use the projected lengths to avoid the
        Quality factor going over 1.0.
        */

        if (Status == 1) {
                p_Quality[0] = (Line1ProjectedLength + Line2ProjectedLength)/
                            (2.0*VLLine.Length);
        } else {

        /*
        The lines are parallel and non-overlapping collinear. In this case the
        confidence level is based on the ratio of the part of the VL which overlaps
        with the lines and the length of the VL
        */
                p_Quality[0] = (Line1ProjectedLength + Line2ProjectedLength)/
                                                VLLine.Length;

        }

        /*
        No minimum quality for collinear lines
        */

        if ( (p_Quality[0]) < MinQuality)
                return(-1);

        if ( (p_Quality[0]) > 1.0) {
                    p_Quality[0] = 1.0;
            if (_VERBOSE) {
                        System.err.print("CheckParallelOrCollinear:\n");
                    System.err.print("Status "+Status+" : Quality factor "+p_Quality[0]+
                        " for Lines "+Line1.ID+", "+Line2.ID+" exceeds 1.0 \n");

            }
        }

        if (Status == 0 ||  Status == 1 || Status == 2) {
            return(Status);
        } else {
            return(-1);
            }



    }

    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Name : CheckJunctionType
    Type : int
    Written on   : 20-Nov-90     By : A. Etemadi
    Modified on  :               By :
    Directory    : ~atae/ORT/LPEG/src/LineGrouping

    ==============================================================================

    Input parameters    :

    Line1			-- First ORT line segment
    Line2			-- Second ORT line segment

    Output parameters    :

    jp1			-- Flag indicating which end point of line1 the
                            junction point is nearest to
    jp2			-- Flag indicating which end point of line2 the
                            junction point is nearest to

    0 = Junction point is nearest start point of line
    1 = Junction point is nearest end point of line

    Where start point and end point are defined by Start.Col, and End.Col

    JunctionPtCol	-- Junction point params
    JunctionPtRow	--

    MinQuality		-- Min. acceptable Quality
    Quality		-- Quality in the junction type

    Output result       :

    -1  = Quality is 0 since position of Junction point is highly uncertain
    0  = Junction point exists and is not on either line segment,
    1  = Junction point exists and is on the first line segment
    2  = Junction point exists and is on the second line segment
    3  = Junction point exists and is on both line segments
    4  = Junction point exists and is very close to the end points of the lines

    Called Functions :

    LineSegRowIntercept
    CheckPtParlLineSeg

    Calling procedure:

    int jp1;
    int jp2;

    struct ORTLine Line1;
    struct ORTLine Line2;

    double JunctionPtCol;
    double JunctionPtRow;

    double MinQuality;
    double Quality;

    CheckJunctionType(Line1,
                        Line2,
                        &jp1,
                        &jp2,
                        &JunctionPtCol,
                        &JunctionPtRow,
                        MinQuality,
                        &Quality);

    Functionality:

    This function computes the intercept point of 2 lines. The lines are extensions
    of two ORT line segments. The function returns a different value depending on
    where the intercept point is relative to the lines (see Output result section
    for details). Whether a point is on the line or not is computed using
    the function CheckPtParlLineSeg so please look there so you undertand what the
    output results really mean. We assign a Quality factor based on how far the
    intercept point is from the end points of the lines closet to the junction
    point. In The case of T and Lambda junctions this distance is computed using
    the line on which the junction point does NOT lie.

    ----------------------------------------------------------------------------*/

    static int CheckJunctionType(ORTLine Line1,
                            ORTLine Line2,
                            int[] p_jp1,
                            int[] p_jp2,
                            double[] p_JunctionPtCol,
                            double[] p_JunctionPtRow,
                            double MinQuality,
                            double[] p_Quality)

    {

        /*
        Return status (see above)

        */
        int Status=0;

        /*
        Line parameters (y = m*x +c) these are c's for Line1 and 2

        */

        double Line1RowIntercept;
        double Line2RowIntercept;

        /*
        Buffers

        */

        int iflag1,iflag2;

        double ECol1,ECol2,ERow1,ERow2;
        double Col1,Col2,Row1,Row2,Dmax; /* Dummay variables for checking Lambda junctions */
        double dtheta;

        if (_VERBOSE)
                System.err.print(" Start of function CheckJunctionType \n");


        /*
        Check if Junction point exists. In the case of lines close in angle the
        junction point is too uncertain so forget it.

        */

        if ( Math.abs(Line1.Theta - Line2.Theta) < 0.001 ||
            Math.abs(Line1.Theta - Line2.Theta) > (Math.PI - 0.001) ) {
            p_Quality[0] = 0.0;
            return(-1);
        }

        /*
        Check to make sure the position of the Junction point is not ambiguous
        due to variances.
        */

        dtheta = Math.abs(Line1.Theta - Line2.Theta);
        if (dtheta > PIBY2)		/* Acute angle is what we want */
            dtheta = Math.PI - dtheta;

        if (dtheta <= (Line1.ThetaVar + Line2.ThetaVar) &&
                    (Line1.ThetaVar + Line2.ThetaVar) != 0.0) {
            p_Quality[0] = 0.0;
            return(-1);
        }

        /*
        First calculate the row intercepts of the lines.

        */

        Line1RowIntercept= GeometricUtil.LineSegRowIntercept(Line1.Start.Col,
                                Line1.Start.Row,
                                Line1.End.Col,
                                Line1.End.Row);

        Line2RowIntercept=GeometricUtil.LineSegRowIntercept(Line2.Start.Col,
                                Line2.Start.Row,
                                Line2.End.Col,
                                Line2.End.Row);

        /*
        Now if one of the lines is vertical, then its real easy to find the
        Junction point.

        */

        if (GeometricUtil.MACCompareWithPIBY2(Line1.Theta)) {	/* 1st line is vertical */
                p_JunctionPtCol[0] = Line1.Start.Col;		/* Find the Junction point */
            p_JunctionPtRow[0] = Math.tan(Line2.Theta)*Line1.Start.Col + Line2RowIntercept;
        }

        if (GeometricUtil.MACCompareWithPIBY2(Line2.Theta)) {	/* 2nd line is vertical */
                p_JunctionPtCol[0] = Line2.Start.Col;		/* Find the Junction point */
            p_JunctionPtRow[0] = Math.tan(Line1.Theta)*Line2.Start.Col + Line1RowIntercept;
        }

        /*
        Otherwise we have to really work it all out...

        */

        if (!GeometricUtil.MACCompareWithPIBY2(Line1.Theta) &&
                !GeometricUtil.MACCompareWithPIBY2(Line2.Theta)) {
                p_JunctionPtCol[0] = (Line2RowIntercept - Line1RowIntercept)/
                                    (Math.tan(Line1.Theta) - Math.tan(Line2.Theta));
                p_JunctionPtRow[0] = Math.tan(Line1.Theta)*(p_JunctionPtCol[0]) + Line1RowIntercept;
        }
        /*
        Now we check where the intercept point is relative to the two lines
        to set the flags for junction types. Note that we use the perp variance of the
        second lines as this is the param. that shifts the junction point along the
        first line.
        */
            iflag1 = CheckPtParlLineSeg( p_JunctionPtCol[0],
                                        p_JunctionPtRow[0],
                                        Line1.LengthParlVar,
                                        Line2.LengthPerpVar,
                                        Line1.Length,
                                        Line1.Theta,
                                        Line1.Start.Col,
                                        Line1.Start.Row,
                                        Line1.End.Col,
                                        Line1.End.Row);
            iflag2 = CheckPtParlLineSeg( p_JunctionPtCol[0],
                                        p_JunctionPtRow[0],
                                        Line2.LengthParlVar,
                                        Line1.LengthPerpVar,
                                        Line2.Length,
                                        Line2.Theta,
                                        Line2.Start.Col,
                                        Line2.Start.Row,
                                        Line2.End.Col,
                                        Line2.End.Row);

            if (iflag1 != 0 && iflag2 != 0)
                Status = 0;

            if (iflag1 == 0 && iflag2 != 0)
                Status = 1;

            if (iflag1 != 0 && iflag2 == 0)
                Status = 2;

            if (iflag1 == 0 && iflag2 == 0)
                Status = 3;

        /*
        Now the remaining end points of the VLs are the ones of the above intercept
        points which are furthest away from the junction point. This is true for V
        and  L junctions, but for T and Lambda junctions there is only one virtual
        line. The end points are also marked with the jp parameter which indicates
        which end point is the one closest to the junction point. This is very useful
        when we want to make larger sets.
        */

        if (GeometricUtil.LineLength(Line1.Start.Col,Line1.Start.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) >
                GeometricUtil.LineLength(Line1.End.Col,Line1.End.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) ) {
            p_jp1[0] = 1;  /* Don't forget this means the Start is FURTHEST away from Junction */
            Col1 = Line1.End.Col;
            Row1 = Line1.End.Row;
            ECol1 = Line1.Start.Col;
            ERow1 = Line1.Start.Row;
            } else {
            p_jp1[0] = 0;
            Col1 = Line1.Start.Col;
            Row1 = Line1.Start.Row;
            ECol1 = Line1.End.Col;
            ERow1 = Line1.End.Row;
            }

        if (GeometricUtil.LineLength(Line2.Start.Col,Line2.Start.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) >
                GeometricUtil.LineLength(Line2.End.Col,Line2.End.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) ) {
            p_jp2[0] = 1;
            Col2 = Line2.End.Col;
            Row2 = Line2.End.Row;
            ECol2 = Line2.Start.Col;
            ERow2 = Line2.Start.Row;
            } else {
            p_jp2[0] = 0;
            Col2 = Line2.Start.Col;
            Row2 = Line2.Start.Row;
            ECol2 = Line2.End.Col;
            ERow2 = Line2.End.Row;
            }


        /*
        This check suggested by KC to avoid problems with Lambda junctions where the
        end points of the lines are very close together. These junctions are called V
        or L  junctions despite the fact that the junction point lies on one of the
        lines.
        */

        Dmax = GeometricUtil.LineLength(Col1,Row1,Col2,Row2);

        if ( Dmax <= (Line1.LengthParlVar + Line2.LengthPerpVar) &&
                Dmax <= (Line2.LengthParlVar + Line1.LengthPerpVar) ) {
            Status = 4;
        }


        /*
        At last we can compute the Quality factor. OK OK so I could have used a case
        statement.. In some cases we subtract the variances so that the Quality
        factor is always below 1.0 and greater than 0.0

        */

        /*
        Note that we use line2perpvar and line1perpvar assymmetrically since
        that is the factor which decides whether a point is considered to be on or off
        a line segment
        */

        if (Status == 0) {
            //changed by Yi, if one line is very long, then it makes the qual very big
            //p_Quality[0] = (Line1.Length + Line2.Length ) /
                    //    (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2) +
                    //    GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1));
                    p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)));

                }

        if (Status == 1)
            p_Quality[0] = (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2));
            /*//changed by Yi
                    p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (Line1.Length+GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),Col2,Row2))
                        );
                    */

        if (Status == 2)
            p_Quality[0] = (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1));
            /*//changed by Yi
                    p_Quality[0] = Math.min(
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)),
                        (Line2.Length)/
                        (Line2.Length+GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),Col1,Row1))
                        );
                    */

        if (Status == 3 || Status == 4)
            p_Quality[0] = (Line1.Length + Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1) +
                        GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2));
                    /*//changed by Yi
            p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)));
            */
        if ( (p_Quality[0]) < MinQuality)
                return(-1);

        if ( (p_Quality[0]) > 1.0) {
                p_Quality[0] = 1.0;
            if (_VERBOSE) {
                System.err.print("Error in CheckJunctionType: Quality factor > 1.0\n");
                System.err.print("This means your lines intersect to form an X shape.\n");
                System.err.print("Status "+Status+": Quality factor "+(p_Quality[0])
                    +" for Lines "+Line1.ID+", "+Line2.ID+" exceeds 1.0 \n");
                    return(-1);
                }

        }

        return(Status);


    }


    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Name :  CheckPtParlLineSeg
    Type : int
    Written on   : 20-Nov-90     By : A. Etemadi
    Modified on  :               By :
    Directory    : ~atae/ORT/ORT/LPEG/src/LineRoutines

    ==============================================================================

    Input parameters    :

    PtCol			-- Col pos. of point
    PtRow			-- Row pos. of point

    LengthParlVar	-- Variance of line parallel direction
    LengthPerpVar	-- Variance of line perp direction
    Length		-- Length of the line
    Theta			-- Orientation of the line
    StartCol            -- The column number of the start point of the line
    StartRow            -- The row number of the start point of the line
    EndCol         	-- The column number of the end point of the line
    EndRow         	-- The row number of the end point of the line


    Output result       :

    -1 = point is not on the line segment
    0 = point is on the line segment

    Called Functions :

    Calling procedure:

    double PtCol;
    double PtRow;

    double LengthParlVar;
    double LengthPerpVar;
    double Line;
    double Theta;
    double StartCol;
    double StartRow;
    double EndCol;
    double EndRow;

        CheckPtParlLineSeg(  PtCol,
                                PtRow,
                                LengthParlVar,
                                LengthPerpVar,
                                Line,
                                Theta,
                                StartCol,
                            StartRow,
                            EndCol,
                            EndRow);

    Functionality:

    This function finds whether a point is on a line segment or not. By "off the
    line segment" we mean that the point is more than 1 LengthParlVar away from the
    end points of the line

                            ******** NOTE *********
    Its is assumed that the point already lies on the line passing through both end
    points of the line segment
                            ******** NOTE *********

    ----------------------------------------------------------------------------*/

    static int  CheckPtParlLineSeg(double PtCol,
                            double PtRow,
                            double LengthParlVar,
                            double LengthPerpVar,
                            double Length,
                            double Theta,
                            double StartCol,
                       double      StartRow,
                            double EndCol,
                            double EndRow)
    {

        double DeltaCols; /* Amount by which end point cols. have to be changed */
        double DeltaRows; /* Amount by which end point rows. have to be changed */

        double Ecol,Erow; /* Buffers to hold end points of line Shorteneded by LengthParlVar */
        double Scol,Srow;


        /*
        Copy column lengths to buffers in case we need to change them, and set
        defaults

        */

        Scol = StartCol; Ecol = EndCol;
        Srow = StartRow; Erow = EndRow;
        DeltaCols = 0.0;
        DeltaRows = 0.0;

        /*
        Now we have to change the end points by more than usual
        to make it preceptually correct
        */

        if (Scol == Ecol) {  	 /* Line is vertical */
                DeltaCols = 0.0;
                //changed by Yi.  This sentence make the line short, rough than longer
                //DeltaRows = - (LengthParlVar + LengthPerpVar);
                DeltaRows = (LengthParlVar + LengthPerpVar);
        }

        if (Srow == Erow) {      /* Line is horizontal */
            //changed by Yi.  This sentence make the line short, rough than longer
                //DeltaCols = - (LengthParlVar + LengthPerpVar);
                DeltaCols = (LengthParlVar + LengthPerpVar);
                DeltaRows = 0.0;
        }

        if (Srow != Erow && Scol != Ecol) {
            //changed by Yi.  This sentence make the line short, rough than longer
                //DeltaCols = - (LengthParlVar + LengthPerpVar) * Math.cos(Theta);
                //DeltaRows = - (LengthParlVar + LengthPerpVar) * Math.sin(Theta);
                DeltaCols = (LengthParlVar + LengthPerpVar) * Math.cos(Theta);
                DeltaRows = (LengthParlVar + LengthPerpVar) * Math.sin(Theta);
        }

        if (DeltaCols<0) DeltaCols=-DeltaCols;
        if (DeltaRows<0) DeltaRows=-DeltaRows;

        /*
        Now change the line at both ends by the length implied by the variance.
        First make sure its not bothered if the start point is furthest away from the
        origin

        */
            if (Scol > Ecol) {
                Scol = Scol + DeltaCols;
                Ecol = Ecol - DeltaCols;
            } else {
                Scol = Scol - DeltaCols;
                Ecol = Ecol + DeltaCols;
            }

            if (Srow > Erow) {
                Srow = Srow + DeltaRows;
                Erow = Erow - DeltaRows;
            } else {
                Srow = Srow - DeltaRows;
                Erow = Erow + DeltaRows;
            }

        /*
        Now check where the point lies relative to the end points of the line
        The 0.00001 factors are because of BLOODY rounding errors
        */

        if ( ( (PtRow >= (Srow-0.00001) && PtRow <= (Erow+0.00001)) ||
                    (PtRow <  (Srow+0.00001) && PtRow >  (Erow-0.00001)) ) &&
                    ( (PtCol >= (Scol-0.00001) && PtCol <= (Ecol+0.00001)) ||
                    (PtCol <  (Scol+0.00001) && PtCol >  (Ecol-0.00001)) ) ) {
                    return(0);
            } else {
                        return(-1);
            }

    }


    /**
    * Functionality:
    * After creating a list of ORT lines, we use this routine to sort the lines
    * in the list in ascending order of Theta.
    */
    void SortByThetaAscending (Vector lines)
    {
        if (lines==null?true:(lines.size()<1)) return;
        for (int i=0;i<lines.size()-1;i++) {
            ORTLine element1 = (ORTLine)lines.elementAt(i);
            for (int j=i+1;j<lines.size();j++) {
                ORTLine element2 = (ORTLine)lines.elementAt(j);
                if (element1.Theta > element2.Theta) {
                    lines.setElementAt(element1, j);
                    element1=element2;
                }
            }
            lines.setElementAt(element1, i);
        }
    }

    /**
    * Functionality:
    * Eliminate the lines with length less than the threshold
    */
    void FilterByLength (Vector lines, double threshold)
    {
        for (int i=0;i<lines.size()-1;i++) {
            ORTLine element1 = (ORTLine)lines.elementAt(i);
            if (element1.Length<threshold) {lines.removeElementAt(i);i--;}
        }
    }


    /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Name : CheckJunctionType
    Type : int
    Written on   : 20-Nov-90     By : A. Etemadi
    Modified on  :               By :
    Directory    : ~atae/ORT/LPEG/src/LineGrouping

    ==============================================================================

    Input parameters    :

    Line1			-- First ORT line segment
    Line2			-- Second ORT line segment

    Output parameters    :

    jp1			-- Flag indicating which end point of line1 the
                            junction point is nearest to
    jp2			-- Flag indicating which end point of line2 the
                            junction point is nearest to

    0 = Junction point is nearest start point of line
    1 = Junction point is nearest end point of line

    Where start point and end point are defined by Start.Col, and End.Col

    JunctionPtCol	-- Junction point params
    JunctionPtRow	--

    MinQuality		-- Min. acceptable Quality
    Quality		-- Quality in the junction type

    Output result       :

    -1  = Quality is 0 since position of Junction point is highly uncertain
    0  = Junction point exists and is not on either line segment,
    1  = Junction point exists and is on the first line segment
    2  = Junction point exists and is on the second line segment
    3  = Junction point exists and is on both line segments
    4  = Junction point exists and is very close to the end points of the lines

    Called Functions :

    LineSegRowIntercept
    CheckPtParlLineSeg

    Calling procedure:

    int jp1;
    int jp2;

    struct ORTLine Line1;
    struct ORTLine Line2;

    double JunctionPtCol;
    double JunctionPtRow;

    double MinQuality;
    double Quality;

    CheckJunctionType(Line1,
                        Line2,
                        &jp1,
                        &jp2,
                        &JunctionPtCol,
                        &JunctionPtRow,
                        MinQuality,
                        &Quality);

    Functionality:

    This function computes the intercept point of 2 lines. The lines are extensions
    of two ORT line segments. The function returns a different value depending on
    where the intercept point is relative to the lines (see Output result section
    for details). Whether a point is on the line or not is computed using
    the function CheckPtParlLineSeg so please look there so you undertand what the
    output results really mean. We assign a Quality factor based on how far the
    intercept point is from the end points of the lines closet to the junction
    point. In The case of T and Lambda junctions this distance is computed using
    the line on which the junction point does NOT lie.

    ----------------------------------------------------------------------------*/

    static int LooseCheckJunctionType(ORTLine Line1,
                            ORTLine Line2,
                            int[] p_jp1,
                            int[] p_jp2,
                            double[] p_JunctionPtCol,
                            double[] p_JunctionPtRow,
                            double MinQuality,
                            double[] p_Quality, double looseRatio)

    {

        /*
        Return status (see above)

        */
        int Status=0;

        /*
        Line parameters (y = m*x +c) these are c's for Line1 and 2

        */

        double Line1RowIntercept;
        double Line2RowIntercept;

        /*
        Buffers

        */

        int iflag1,iflag2;

        double ECol1,ECol2,ERow1,ERow2;
        double Col1,Col2,Row1,Row2,Dmax; /* Dummay variables for checking Lambda junctions */
        double dtheta;

        if (_VERBOSE)
                System.err.print(" Start of function CheckJunctionType \n");


        /*
        Check if Junction point exists. In the case of lines close in angle the
        junction point is too uncertain so forget it.

        */

        if ( Math.abs(Line1.Theta - Line2.Theta) < 0.001 ||
            Math.abs(Line1.Theta - Line2.Theta) > (Math.PI - 0.001) ) {
            p_Quality[0] = 0.0;
            return(-1);
        }

        /*
        Check to make sure the position of the Junction point is not ambiguous
        due to variances.
        */

        dtheta = Math.abs(Line1.Theta - Line2.Theta);
        if (dtheta > PIBY2)		/* Acute angle is what we want */
            dtheta = Math.PI - dtheta;

        if (dtheta <= (Line1.ThetaVar + Line2.ThetaVar) &&
                    (Line1.ThetaVar + Line2.ThetaVar) != 0.0) {
            p_Quality[0] = 0.0;
            return(-1);
        }

        /*
        First calculate the row intercepts of the lines.

        */

        Line1RowIntercept= GeometricUtil.LineSegRowIntercept(Line1.Start.Col,
                                Line1.Start.Row,
                                Line1.End.Col,
                                Line1.End.Row);

        Line2RowIntercept=GeometricUtil.LineSegRowIntercept(Line2.Start.Col,
                                Line2.Start.Row,
                                Line2.End.Col,
                                Line2.End.Row);

        /*
        Now if one of the lines is vertical, then its real easy to find the
        Junction point.

        */

        if (GeometricUtil.MACCompareWithPIBY2(Line1.Theta)) {	/* 1st line is vertical */
                p_JunctionPtCol[0] = Line1.Start.Col;		/* Find the Junction point */
            p_JunctionPtRow[0] = Math.tan(Line2.Theta)*Line1.Start.Col + Line2RowIntercept;
        }

        if (GeometricUtil.MACCompareWithPIBY2(Line2.Theta)) {	/* 2nd line is vertical */
                p_JunctionPtCol[0] = Line2.Start.Col;		/* Find the Junction point */
            p_JunctionPtRow[0] = Math.tan(Line1.Theta)*Line2.Start.Col + Line1RowIntercept;
        }

        /*
        Otherwise we have to really work it all out...

        */

        if (!GeometricUtil.MACCompareWithPIBY2(Line1.Theta) &&
                !GeometricUtil.MACCompareWithPIBY2(Line2.Theta)) {
                p_JunctionPtCol[0] = (Line2RowIntercept - Line1RowIntercept)/
                                    (Math.tan(Line1.Theta) - Math.tan(Line2.Theta));
                p_JunctionPtRow[0] = Math.tan(Line1.Theta)*(p_JunctionPtCol[0]) + Line1RowIntercept;
        }
        /*
        Now we check where the intercept point is relative to the two lines
        to set the flags for junction types. Note that we use the perp variance of the
        second lines as this is the param. that shifts the junction point along the
        first line.
        */
            iflag1 = CheckPtParlLineSeg( p_JunctionPtCol[0],
                                        p_JunctionPtRow[0],
                                        Line1.LengthParlVar*looseRatio,
                                        Line2.LengthPerpVar*looseRatio,
                                        Line1.Length,
                                        Line1.Theta,
                                        Line1.Start.Col,
                                        Line1.Start.Row,
                                        Line1.End.Col,
                                        Line1.End.Row);
            iflag2 = CheckPtParlLineSeg( p_JunctionPtCol[0],
                                        p_JunctionPtRow[0],
                                        Line2.LengthParlVar*looseRatio,
                                        Line1.LengthPerpVar*looseRatio,
                                        Line2.Length,
                                        Line2.Theta,
                                        Line2.Start.Col,
                                        Line2.Start.Row,
                                        Line2.End.Col,
                                        Line2.End.Row);

            if (iflag1 != 0 && iflag2 != 0)
                Status = 0;

            if (iflag1 == 0 && iflag2 != 0)
                Status = 1;

            if (iflag1 != 0 && iflag2 == 0)
                Status = 2;

            if (iflag1 == 0 && iflag2 == 0)
                Status = 3;

        /*
        Now the remaining end points of the VLs are the ones of the above intercept
        points which are furthest away from the junction point. This is true for V
        and  L junctions, but for T and Lambda junctions there is only one virtual
        line. The end points are also marked with the jp parameter which indicates
        which end point is the one closest to the junction point. This is very useful
        when we want to make larger sets.
        */

        if (GeometricUtil.LineLength(Line1.Start.Col,Line1.Start.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) >
                GeometricUtil.LineLength(Line1.End.Col,Line1.End.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) ) {
            p_jp1[0] = 1;  /* Don't forget this means the Start is FURTHEST away from Junction */
            Col1 = Line1.End.Col;
            Row1 = Line1.End.Row;
            ECol1 = Line1.Start.Col;
            ERow1 = Line1.Start.Row;
            } else {
            p_jp1[0] = 0;
            Col1 = Line1.Start.Col;
            Row1 = Line1.Start.Row;
            ECol1 = Line1.End.Col;
            ERow1 = Line1.End.Row;
            }

        if (GeometricUtil.LineLength(Line2.Start.Col,Line2.Start.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) >
                GeometricUtil.LineLength(Line2.End.Col,Line2.End.Row,
                        p_JunctionPtCol[0],p_JunctionPtRow[0]) ) {
            p_jp2[0] = 1;
            Col2 = Line2.End.Col;
            Row2 = Line2.End.Row;
            ECol2 = Line2.Start.Col;
            ERow2 = Line2.Start.Row;
            } else {
            p_jp2[0] = 0;
            Col2 = Line2.Start.Col;
            Row2 = Line2.Start.Row;
            ECol2 = Line2.End.Col;
            ERow2 = Line2.End.Row;
            }


        /*
        This check suggested by KC to avoid problems with Lambda junctions where the
        end points of the lines are very close together. These junctions are called V
        or L  junctions despite the fact that the junction point lies on one of the
        lines.
        */

        Dmax = GeometricUtil.LineLength(Col1,Row1,Col2,Row2);

        if ( Dmax <= (Line1.LengthParlVar + Line2.LengthPerpVar)*looseRatio &&
                Dmax <= (Line2.LengthParlVar + Line1.LengthPerpVar)*looseRatio ) {
            Status = 4;
        }


        /*
        At last we can compute the Quality factor. OK OK so I could have used a case
        statement.. In some cases we subtract the variances so that the Quality
        factor is always below 1.0 and greater than 0.0

        */

        /*
        Note that we use line2perpvar and line1perpvar assymmetrically since
        that is the factor which decides whether a point is considered to be on or off
        a line segment
        */

        if (Status == 0) {
            //changed by Yi, if one line is very long, then it makes the qual very big
            //p_Quality[0] = (Line1.Length + Line2.Length ) /
                    //    (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2) +
                    //    GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1));
                    p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)));

                }

        if (Status == 1)
            p_Quality[0] = (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2));
            /*//changed by Yi
                    p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (Line1.Length+GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),Col2,Row2))
                        );
                    */

        if (Status == 2)
            p_Quality[0] = (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1));
            /*//changed by Yi
                    p_Quality[0] = Math.min(
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)),
                        (Line2.Length)/
                        (Line2.Length+GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),Col1,Row1))
                        );
                    */

        if (Status == 3 || Status == 4)
            p_Quality[0] = (Line1.Length + Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1) +
                        GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2));
                    /*//changed by Yi
            p_Quality[0] = Math.min(
                        (Line2.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol2,ERow2)),
                        (Line1.Length)/
                        (GeometricUtil.LineLength((p_JunctionPtCol[0]),(p_JunctionPtRow[0]),ECol1,ERow1)));
            */
        if ( (p_Quality[0]) < MinQuality)
                return(-1);

        if ( (p_Quality[0]) > 1.0) {
                p_Quality[0] = 1.0;
            if (_VERBOSE) {
                System.err.print("Error in CheckJunctionType: Quality factor > 1.0\n");
                System.err.print("This means your lines intersect to form an X shape.\n");
                System.err.print("Status "+Status+": Quality factor "+(p_Quality[0])
                    +" for Lines "+Line1.ID+", "+Line2.ID+" exceeds 1.0 \n");
                    return(-1);
                }

        }

        return(Status);


    }

    static public ORTLineGroup loose_lineRelation_closeJunction(ORTLine Line1, ORTLine Line2,
        double MaxWidthOverHeight,  // = 2.0;   when the WidthOverHeight > this value, the line group will be discard
        double MinLineLength,       // = 8.0;   if the length of any line < this value, return null
        double MinDeltaTheta,       // = 0.06;  [0,this]:parallel, [this,PI/2]:junction
        double MinQuality,          //	= 0.8;  if the quaulity of the group < this value, return null
        double looseRatio)          // =2.0; when considering the intersecting
    {
            if (MaxWidthOverHeight < 0.0) {
                    System.err.print("Error: Minimum Width/Height must be >= 0.0\n");
                    return(null);
            }
            if (MinLineLength < 4.0) {
                    System.err.print("Error: MinLineLength must be  >= 4.0\n");
                    return(null);
            }
            if (Line1.Length<MinLineLength||Line2.Length<MinLineLength) return null;

            double MinDeltaThetaJ= MinDeltaTheta;

            double MinQualityJ= MinQuality;
            if (MinQualityJ < 0.0 || MinQualityJ > 1.0) {
                    System.err.print("Error: MinQuality level for junc. must be >= 0.0 and <= 1.0\n");
                    return(null);
            }

        //the angel between two lines
        double DeltaTheta =  Math.abs( Line1.Theta - Line2.Theta);
        if (DeltaTheta >  PIBY2) DeltaTheta = Math.abs(Math.PI - DeltaTheta);

        //  ===================== JUNCTION TYPES ==================================
        if (DeltaTheta >= MinDeltaThetaJ) {

                int jp1=0, jp2=0;
                int[] p_jp1={jp1} ,p_jp2={jp2};
                double JunctionPtCol=0,JunctionPtRow=0,Quality=0;
                double[] p_JunctionPtCol={JunctionPtCol}, p_JunctionPtRow={JunctionPtRow};
                double[] p_Quality={Quality};
                int Status = LooseCheckJunctionType(Line1,Line2,p_jp1,p_jp2,p_JunctionPtCol,p_JunctionPtRow,
                            MinQualityJ,p_Quality,looseRatio);
            jp1=p_jp1[0];jp2=p_jp2[0];
                JunctionPtCol=p_JunctionPtCol[0];JunctionPtRow=p_JunctionPtRow[0];
                Quality=p_Quality[0];

                ORTConjLineGroup lg;

            //only status==3 or status==4 are considered as close junction
            if (Status == 3||Status==4)
                lg= new ORTConjLineGroup(ORTLineGroup.JUNCTION_CLOSE);
            else return null;                   // status= -1

            lg.FirstID    = (ORTLine)Line1;
            lg.SecondID   = (ORTLine)Line2;
            lg.ip         = Status;
            lg.jp1        = jp1;
            lg.jp2        = jp2;
            lg.JunctionPt.Col = JunctionPtCol;
            lg.JunctionPt.Row = JunctionPtRow;
            lg.Quality        = Quality;
            return lg;

        } /* Endif DeltaTheta */
        else return null;
    }

    public static void main(String[] args)
    {
        //two lines
        ORTLine l1= new ORTLine(-100, 0, 100, 0);
        ORTLine l2= new ORTLine(0, 5, 0, -100);
        ORTLineGroup lg= Lpeg.loose_lineRelation_closeJunction(l1,l2,2,4,0.35,0.8,3);

        //junction point
        ORTConjLineGroup clg= (ORTConjLineGroup)lg;
        double cx= clg.JunctionPt.Col, cy= clg.JunctionPt.Row;

        Dimension d= new Dimension(800,600);
        int[] demo= new int[d.width*d.height];
        for (int i=0;i<demo.length;i++) demo[i]=0xff000000;
        DrawUtil.ort2image(demo, d, l1, 0xffffffff, 1);
        DrawUtil.ort2image(demo, d, l2, 0xffffffff, 1);
        DrawUtil.drawMark(demo, d, (int)Math.round(cx),(int)Math.round(cy),4,0xffffffff);
        (new DisplayFrame("demo", demo, d)).show();
        System.err.println("quality: " + clg.Quality);

    }



}