        ///Current version
        ///ID:          $Id: polyFunk.cs,v 1.1.1.1 2006/11/14 02:56:41 gupchup Exp $
        ///Revision:    $Revision: 1.1.1.1 $
        ///Date:        $Date: 2006/11/14 02:56:41 $ 

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.IO;

namespace Spherical.Visualizer
{
    public class Line
    {
        public Point p1;
        public Point p2;
        public int realY;

        public Line(Point p1_, Point p2_, int realY_)
        {
            p1 = p1_;
            p2 = p2_;
            realY = realY_;
        }

        public Line(Point p1_, Point p2_)
        {
            p1 = p1_;
            p2 = p2_;
            realY = p2.Y;
        }

        public void shift(int x, int y)
        {
            p1.X += x;
            p2.X += x;
            p1.Y += y;
            p2.Y += y;
        }
    }

    public class polyFunk
    {

        const int OFF = 0;			//don't change 4 now.  set for pix on instide
        const int PIX = 4;			//scaling
        const int X = 11;			//random references
        const int Y = 22;


        /// <summary>
        /// given a span, will return an arraylist of line segments 
        /// that form a bounding polygon(s)
        /// </summary>
        /// <param name="spans"></param>
        /// <returns>ArrayList</returns>
        public static ArrayList getPoly(String spans)
        {
            // if(1==1)return getAll(spans);
            ArrayList hSegments = new ArrayList();
            ArrayList vSegments = new ArrayList();

            loadLines(spans, ref hSegments, ref vSegments);
            horizontalScan(ref hSegments);
            vSegments.AddRange(hSegments);

            return vSegments;
        }


        //reads lines into an ArrayList of lines
        private static void loadLines(String spans,
            ref ArrayList hSegments, ref ArrayList vSegments)
        {
            String[] span = spans.Split(';');

            for (int x = 0; x < span.Length; x++)
            {
                String[] pieces = span[x].Split(',');
                int top_realY = int.Parse(pieces[0]) * PIX;
                int bottom_realY = top_realY + PIX;

                Point tL = new Point(int.Parse(pieces[1]) * PIX, top_realY);
                Point tR = new Point(int.Parse(pieces[2]) * PIX - OFF + PIX, top_realY);
                Point bL = new Point(tL.X, bottom_realY - OFF);			//shift up
                Point bR = new Point(tR.X, bottom_realY - OFF);			//tR is shifted left

                Line top = new Line(tL, tR, top_realY);
                Line bottom = new Line(bL, bR, bottom_realY);
                Line left = new Line(tL, bL, -1);
                Line right = new Line(tR, bR, -1);

                hSegments.Add(top);
                hSegments.Add(bottom);
                vSegments.Add(left);
                vSegments.Add(right);

            }
        }

        //-------------------------------------
        //groups same rows together, then 
        // calls cleanUpRow to remove overlap
        //-------------------------------------
        private static void horizontalScan(ref ArrayList segments)
        {
            ArrayList result = new ArrayList();
            ArrayList lines = new ArrayList();

            lineSort(ref segments, Y);

            for (int a = 0; a < segments.Count; a++)
            {
                Line current = (Line)segments[a];
                lines.Add(current);
                int currentRow = ((Line)segments[a]).realY;

                if (a + 1 >= segments.Count)			//last element
                {
                    cleanUpRow(ref lines);
                    result.AddRange(lines);
                    break;
                }
                else
                {
                    int nextRow = ((Line)segments[a + 1]).realY;
                    if (nextRow != currentRow || (a + 1) >= segments.Count)
                    {
                        cleanUpRow(ref lines);
                        result.AddRange(lines);
                        lines.Clear();
                    }
                }
            }
            segments = result;
        }

        //only cleans up items on same row
        private static void cleanUpRow(ref ArrayList lines)
        {
            if (lines.Count < 2) return;
            lineSort(ref lines, X);					//leftmost line at index 0
            for (int a = 0; a < lines.Count; a++)
            {
                Line current = (Line)lines[a];
                for (int b = a; b < lines.Count; b++)
                {
                    Line compare = (Line)lines[b];
                    if (compare.Equals(current))
                        continue;					//same line
                    if (current.p2.X > compare.p1.X)
                    {
                        //Console.WriteLine("******");
                        //dumpSegments(lines);

                        int leftChunk = (compare.p1.X - current.p1.X);
                        int rightChunk = (compare.p2.X - current.p2.X);

                        //Console.WriteLine(current.p2.X+" "+compare.p1.X);
                        //Console.WriteLine("******");

                        lines.Remove(current);		//take out old lines
                        lines.Remove(compare);

                        if (leftChunk != 0)			//left piece
                        {
                            Point p1 = new Point(current.p1.X, current.p1.Y);
                            Point p2 = new Point(current.p1.X + leftChunk, current.p1.Y);
                            if (!equal(p1, p2)) lines.Add(new Line(p1, p2));
                        }

                        if (rightChunk < 0)			//right piece of current
                        {
                            Point p1 = new Point(current.p2.X + rightChunk, current.p1.Y);
                            Point p2 = new Point(current.p2.X, current.p1.Y);
                            if (!equal(p1, p2)) lines.Add(new Line(p1, p2));
                        }

                        if (rightChunk > 0)			//right piece of compare
                        {
                            Point p1 = new Point(current.p2.X, compare.p1.Y);
                            Point p2 = new Point(current.p2.X + rightChunk, compare.p1.Y);
                            if (!equal(p1, p2)) lines.Add(new Line(p1, p2));
                        }

                        //Console.WriteLine("\t***");
                        //dumpSegments(lines);
                        cleanUpRow(ref lines);
                        return;
                    }
                }
            }
        }

        private static bool equal(Point p1, Point p2)
        {
            if (p1.X == p2.X)
                return p1.Y == p2.Y;
            else
                return false;
        }

        //-----------------------------------------
        //sorts line segments, highest to lowest.  
        // Pass X or Y to specify axis
        //-----------------------------------------
        private static bool lineSort(ref ArrayList segments, int compareBy)
        {
            bool switched = false;
            if (compareBy == Y)
            {
                int last = ((Line)segments[0]).p1.Y;
                for (int x = 1; x < segments.Count; x++)
                {
                    int current = ((Line)segments[x]).p1.Y;

                    if (current < last)
                    {
                        switchItem(ref segments, x, x - 1);
                        switched = true;
                    }

                    last = current;
                }
            }

            else if (compareBy == X)
            {
                int last = ((Line)segments[0]).p1.X;
                for (int x = 1; x < segments.Count; x++)
                {
                    int current = ((Line)segments[x]).p1.X;
                    if (current < last)
                    {
                        switchItem(ref segments, x, x - 1);
                        switched = true;
                    }
                    last = current;
                }
            }

            if (switched)
                return lineSort(ref segments, compareBy);
            return true;
        }


        private static void switchItem(ref ArrayList list, int i1, int i2)
        {
            Object temp = list[i1];
            list[i1] = list[i2];
            list[i2] = temp;
        }

        //------------------
        // Debug stuff
        //------------------

        //----------------------------------------------
        //For Debug.  Will return straight translation.
        //----------------------------------------------
        public static ArrayList getAll(String spans)
        {
            ArrayList hSegments = new ArrayList();
            ArrayList vSegments = new ArrayList();

            loadLines(spans, ref hSegments, ref vSegments);
            vSegments.AddRange(hSegments);

            return vSegments;
        }

        //-----------------------------------------
        //For Debug. prints lists of line segments
        //-----------------------------------------
        public static void dumpSegments(ArrayList list)
        {
            for (int x = 0; x < list.Count; x++)
            {
                Line line = (Line)list[x];
                Console.WriteLine("(" + line.p1.X + "," + line.p1.Y
                    + "), (" + line.p2.X + "," + line.p2.Y + ")");
            }
        }

        //------------------------------------------
        // For Debug. Draw the outline on an image
        //------------------------------------------
        public static void drawSegments(ArrayList list)
        {
            Pen pen = new Pen(Color.Green, 1);
            Bitmap bMap = new Bitmap(2000, 500);
            Graphics g = Graphics.FromImage(bMap);

            for (int x = 0; x < list.Count; x++)
            {
                g.DrawLine(pen, ((Line)list[x]).p1, ((Line)list[x]).p2);
            }

            FileStream fs = File.Create("h:\\out.bmp");
            bMap.Save(fs, ImageFormat.Bmp);
            fs.Close();
        }
        /*
            public static void Main(){
            //String TEST = "53,489,491;54,489,492;55,488,492;56,488,492;57,488,492;58,489,491";
            String TEST = "70,415,416;71,412,419;72,412,420;73,411,422;74,410,423;75,405,406;75,409,423;76,404,423;77,404,423;78,403,424;79,403,424;80,404,424;81,404,424;82,404,424;83,403,424;84,403,423;85,404,423;86,403,423;87,403,423;88,402,424;89,403,423;90,403,423;91,403,423;92,402,422;93,402,422;94,403,421;95,404,421;96,404,421;97, 405,420;98,406,419;99,406,419;100,407,414;100,417,418;101,409,412;102,410,411";
            ArrayList al = getPoly(TEST);
            drawSegments(al);
            dumpSegments(al);
            }
        */
    }
}

/* Revision History

        $Log: polyFunk.cs,v $
        Revision 1.1.1.1  2006/11/14 02:56:41  gupchup
        no message

        Revision 1.2  2006/02/28 16:44:00  budavari
        new lib

        Revision 1.1  2006/02/03 21:16:42  budavari
        Added module for visualization - based on Geom2

        Revision 1.6  2003/04/08 17:12:00  nieto
        Trying to include projection.cs class in project

        Revision 1.5  2003/03/13 02:34:58  nieto
        Modify Mask query to include considerated to be important Masks

*/